From 4e4f3096f20c6e8a4cb7db44656110ec6ea71010 Mon Sep 17 00:00:00 2001 From: Ryan Dyer Date: Thu, 11 Feb 2021 20:07:59 +0000 Subject: [PATCH 001/398] 14324 - Fix kafka_versions being a required field --- aws/resource_aws_msk_configuration.go | 7 +++++-- aws/resource_aws_msk_configuration_test.go | 4 ---- tools/go.sum | 2 ++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_msk_configuration.go b/aws/resource_aws_msk_configuration.go index 345aa0eed1a..c644b789ee4 100644 --- a/aws/resource_aws_msk_configuration.go +++ b/aws/resource_aws_msk_configuration.go @@ -32,7 +32,7 @@ func resourceAwsMskConfiguration() *schema.Resource { }, "kafka_versions": { Type: schema.TypeSet, - Required: true, + Optional: true, ForceNew: true, Elem: &schema.Schema{ Type: schema.TypeString, @@ -59,7 +59,6 @@ func resourceAwsMskConfigurationCreate(d *schema.ResourceData, meta interface{}) conn := meta.(*AWSClient).kafkaconn input := &kafka.CreateConfigurationInput{ - KafkaVersions: expandStringSet(d.Get("kafka_versions").(*schema.Set)), Name: aws.String(d.Get("name").(string)), ServerProperties: []byte(d.Get("server_properties").(string)), } @@ -68,6 +67,10 @@ func resourceAwsMskConfigurationCreate(d *schema.ResourceData, meta interface{}) input.Description = aws.String(v.(string)) } + if v, ok := d.GetOk("kafka_versions"); ok { + input.KafkaVersions = expandStringSet(v.(*schema.Set)) + } + output, err := conn.CreateConfiguration(input) if err != nil { diff --git a/aws/resource_aws_msk_configuration_test.go b/aws/resource_aws_msk_configuration_test.go index 398af256ee7..dce702abbfe 100644 --- a/aws/resource_aws_msk_configuration_test.go +++ b/aws/resource_aws_msk_configuration_test.go @@ -91,7 +91,6 @@ func TestAccAWSMskConfiguration_basic(t *testing.T) { testAccCheckMskConfigurationExists(resourceName, &configuration1), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "kafka", regexp.MustCompile(`configuration/.+`)), resource.TestCheckResourceAttr(resourceName, "description", ""), - resource.TestCheckResourceAttr(resourceName, "kafka_versions.#", "1"), resource.TestCheckResourceAttr(resourceName, "latest_revision", "1"), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestMatchResourceAttr(resourceName, "server_properties", regexp.MustCompile(`auto.create.topics.enable = true`)), @@ -286,7 +285,6 @@ func testAccCheckMskConfigurationExists(resourceName string, configuration *kafk func testAccMskConfigurationConfig(rName string) string { return fmt.Sprintf(` resource "aws_msk_configuration" "test" { - kafka_versions = ["2.1.0"] name = %[1]q server_properties = < Date: Thu, 11 Feb 2021 20:30:03 +0000 Subject: [PATCH 002/398] fix linting for tests --- aws/resource_aws_msk_configuration_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_msk_configuration_test.go b/aws/resource_aws_msk_configuration_test.go index dce702abbfe..a322b06f7bd 100644 --- a/aws/resource_aws_msk_configuration_test.go +++ b/aws/resource_aws_msk_configuration_test.go @@ -285,7 +285,7 @@ func testAccCheckMskConfigurationExists(resourceName string, configuration *kafk func testAccMskConfigurationConfig(rName string) string { return fmt.Sprintf(` resource "aws_msk_configuration" "test" { - name = %[1]q + name = %[1]q server_properties = < Date: Thu, 22 Apr 2021 20:55:42 +0100 Subject: [PATCH 003/398] Add support for Cloudwatch Event API Destination and Connections --- .changelog/18905.txt | 7 + .../service/cloudwatchevents/waiter/waiter.go | 53 ++ aws/provider.go | 2 + ...ce_aws_cloudwatch_event_api_destination.go | 189 ++++ ...s_cloudwatch_event_api_destination_test.go | 366 ++++++++ ...esource_aws_cloudwatch_event_connection.go | 785 ++++++++++++++++ ...ce_aws_cloudwatch_event_connection_test.go | 873 ++++++++++++++++++ ...dwatch_event_api_destination.html.markdown | 53 ++ .../cloudwatch_event_connection.html.markdown | 200 ++++ 9 files changed, 2528 insertions(+) create mode 100644 .changelog/18905.txt create mode 100644 aws/internal/service/cloudwatchevents/waiter/waiter.go create mode 100644 aws/resource_aws_cloudwatch_event_api_destination.go create mode 100644 aws/resource_aws_cloudwatch_event_api_destination_test.go create mode 100644 aws/resource_aws_cloudwatch_event_connection.go create mode 100644 aws/resource_aws_cloudwatch_event_connection_test.go create mode 100644 website/docs/r/cloudwatch_event_api_destination.html.markdown create mode 100644 website/docs/r/cloudwatch_event_connection.html.markdown diff --git a/.changelog/18905.txt b/.changelog/18905.txt new file mode 100644 index 00000000000..a2b9c9de84e --- /dev/null +++ b/.changelog/18905.txt @@ -0,0 +1,7 @@ +```release-note:new-resource +aws_cloudwatch_event_connection +``` + +```release-note:new-resource +aws_cloudwatch_event_api_destination +``` \ No newline at end of file diff --git a/aws/internal/service/cloudwatchevents/waiter/waiter.go b/aws/internal/service/cloudwatchevents/waiter/waiter.go new file mode 100644 index 00000000000..62189935c68 --- /dev/null +++ b/aws/internal/service/cloudwatchevents/waiter/waiter.go @@ -0,0 +1,53 @@ +package waiter + +import ( + "time" + + "github.com/aws/aws-sdk-go/aws" + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const ( + // ConnectionDeletedTimeout is the maximum amount of time to wait for a CloudwatchEvent Connection to delete + ConnectionDeletedTimeout = 2 * time.Minute +) + +// CloudWatchEventConnectionDeleted waits for a CloudwatchEvent Connection to return Deleted +func CloudWatchEventConnectionDeleted(conn *events.CloudWatchEvents, id string) (*events.DescribeConnectionOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{events.ConnectionStateDeleting}, + Target: []string{}, + Refresh: CloudWatchEventConnectionStatus(conn, id), + Timeout: ConnectionDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*events.DescribeConnectionOutput); ok { + return v, err + } + + return nil, err +} + +// CloudWatchEventConnectionStatus fetches the Connection and its Status +func CloudWatchEventConnectionStatus(conn *events.CloudWatchEvents, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + params := events.DescribeConnectionInput{ + Name: aws.String(id), + } + + output, err := conn.DescribeConnection(¶ms) + if tfawserr.ErrMessageContains(err, events.ErrCodeResourceNotFoundException, "") { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.ConnectionState), nil + } +} diff --git a/aws/provider.go b/aws/provider.go index 28610649eac..70b1c2b888c 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -527,6 +527,8 @@ func Provider() *schema.Provider { "aws_cloudwatch_event_rule": resourceAwsCloudWatchEventRule(), "aws_cloudwatch_event_target": resourceAwsCloudWatchEventTarget(), "aws_cloudwatch_event_archive": resourceAwsCloudWatchEventArchive(), + "aws_cloudwatch_event_connection": resourceAwsCloudWatchEventConnection(), + "aws_cloudwatch_event_api_destination": resourceAwsCloudWatchEventApiDestination(), "aws_cloudwatch_log_destination": resourceAwsCloudWatchLogDestination(), "aws_cloudwatch_log_destination_policy": resourceAwsCloudWatchLogDestinationPolicy(), "aws_cloudwatch_log_group": resourceAwsCloudWatchLogGroup(), diff --git a/aws/resource_aws_cloudwatch_event_api_destination.go b/aws/resource_aws_cloudwatch_event_api_destination.go new file mode 100644 index 00000000000..f2ff0d42af1 --- /dev/null +++ b/aws/resource_aws_cloudwatch_event_api_destination.go @@ -0,0 +1,189 @@ +package aws + +import ( + "fmt" + "log" + "math" + "regexp" + + "github.com/aws/aws-sdk-go/aws" + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceAwsCloudWatchEventApiDestination() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsCloudWatchEventApiDestinationCreate, + Read: resourceAwsCloudWatchEventApiDestinationRead, + Update: resourceAwsCloudWatchEventApiDestinationUpdate, + Delete: resourceAwsCloudWatchEventApiDestinationDelete, + 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), + validation.StringMatch(regexp.MustCompile(`^[\.\-_A-Za-z0-9]+`), ""), + ), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "invocation_endpoint": { + Type: schema.TypeString, + Required: true, + }, + "invocation_rate_limit_per_second": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, math.MaxInt64), + Default: 300, + }, + "http_method": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(events.ApiDestinationHttpMethod_Values(), true), + }, + "connection_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsCloudWatchEventApiDestinationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.CreateApiDestinationInput{} + + if name, ok := d.GetOk("name"); ok { + input.Name = aws.String(name.(string)) + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + if invocationEndpoint, ok := d.GetOk("invocation_endpoint"); ok { + input.InvocationEndpoint = aws.String(invocationEndpoint.(string)) + } + if invocationRateLimitPerSecond, ok := d.GetOk("invocation_rate_limit_per_second"); ok { + input.InvocationRateLimitPerSecond = aws.Int64(int64(invocationRateLimitPerSecond.(int))) + } + if httpMethod, ok := d.GetOk("http_method"); ok { + input.HttpMethod = aws.String(httpMethod.(string)) + } + if connectionArn, ok := d.GetOk("connection_arn"); ok { + input.ConnectionArn = aws.String(connectionArn.(string)) + } + + log.Printf("[DEBUG] Creating CloudWatchEvent API Destination: %v", input) + + _, err := conn.CreateApiDestination(input) + if err != nil { + return fmt.Errorf("Creating CloudWatchEvent API Destination (%s) failed: %w", *input.Name, err) + } + + d.SetId(aws.StringValue(input.Name)) + + log.Printf("[INFO] CloudWatchEvent API Destination (%s) created", d.Id()) + + return resourceAwsCloudWatchEventApiDestinationRead(d, meta) +} + +func resourceAwsCloudWatchEventApiDestinationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.DescribeApiDestinationInput{ + Name: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Reading CloudWatchEvent API Destination (%s)", d.Id()) + output, err := conn.DescribeApiDestination(input) + if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] CloudWatchEvent API Destination (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("error reading CloudWatchEvent API Destination: %w", err) + } + + log.Printf("[DEBUG] Found CloudWatchEvent API Destination: %#v", *output) + + d.Set("arn", output.ApiDestinationArn) + d.Set("name", output.Name) + d.Set("description", output.Description) + d.Set("invocation_endpoint", output.InvocationEndpoint) + d.Set("invocation_rate_limit_per_second", output.InvocationRateLimitPerSecond) + d.Set("http_method", output.HttpMethod) + d.Set("connection_arn", output.ConnectionArn) + + return nil +} + +func resourceAwsCloudWatchEventApiDestinationUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.UpdateApiDestinationInput{} + + if name, ok := d.GetOk("name"); ok { + input.Name = aws.String(name.(string)) + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + if invocationEndpoint, ok := d.GetOk("invocation_endpoint"); ok { + input.InvocationEndpoint = aws.String(invocationEndpoint.(string)) + } + if invocationRateLimitPerSecond, ok := d.GetOk("invocation_rate_limit_per_second"); ok { + input.InvocationRateLimitPerSecond = aws.Int64(invocationRateLimitPerSecond.(int64)) + } + if httpMethod, ok := d.GetOk("http_method"); ok { + input.HttpMethod = aws.String(httpMethod.(string)) + } + if connectionArn, ok := d.GetOk("connection_arn"); ok { + input.ConnectionArn = aws.String(connectionArn.(string)) + } + + log.Printf("[DEBUG] Updating CloudWatchEvent API Destination: %s", input) + _, err := conn.UpdateApiDestination(input) + if err != nil { + return fmt.Errorf("error updating CloudWatchEvent API Destination (%s): %w", d.Id(), err) + } + return resourceAwsCloudWatchEventApiDestinationRead(d, meta) +} + +func resourceAwsCloudWatchEventApiDestinationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + log.Printf("[INFO] Deleting CloudWatchEvent API Destination (%s)", d.Id()) + input := &events.DeleteApiDestinationInput{ + Name: aws.String(d.Id()), + } + + _, err := conn.DeleteApiDestination(input) + + if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] CloudWatchEvent API Destination (%s) not found", d.Id()) + return nil + } + if err != nil { + return fmt.Errorf("Error deleting CloudWatchEvent API Destination (%s): %w", d.Id(), err) + } + log.Printf("[INFO] CloudWatchEvent API Destination (%s) deleted", d.Id()) + + return nil +} diff --git a/aws/resource_aws_cloudwatch_event_api_destination_test.go b/aws/resource_aws_cloudwatch_event_api_destination_test.go new file mode 100644 index 00000000000..6ee21570cbd --- /dev/null +++ b/aws/resource_aws_cloudwatch_event_api_destination_test.go @@ -0,0 +1,366 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "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" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +const uuidRegex = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" + +func init() { + resource.AddTestSweepers("aws_cloudwatch_event_api_destination", &resource.Sweeper{ + Name: "aws_cloudwatch_event_api_destination", + F: testSweepCloudWatchEventApiDestination, + Dependencies: []string{ + "aws_cloudwatch_event_connection", + }, + }) +} + +func testSweepCloudWatchEventApiDestination(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("Error getting client: %w", err) + } + conn := client.(*AWSClient).cloudwatcheventsconn + + var sweeperErrs *multierror.Error + + input := &events.ListApiDestinationsInput{ + Limit: aws.Int64(100), + } + var apiDestinations []*events.ApiDestination + for { + output, err := conn.ListApiDestinations(input) + if err != nil { + return err + } + apiDestinations = append(apiDestinations, output.ApiDestinations...) + + if aws.StringValue(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + for _, apiDestination := range apiDestinations { + + input := &events.DeleteApiDestinationInput{ + Name: apiDestination.Name, + } + _, err := conn.DeleteApiDestination(input) + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("Error deleting CloudWatch Event Api Destination (%s): %w", *apiDestination.Name, err)) + continue + } + } + + log.Printf("[INFO] Deleted %d CloudWatch Event Api Destinations", len(apiDestinations)) + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSCloudWatchEventApiDestination_basic(t *testing.T) { + var v1, v2, v3 events.DescribeApiDestinationOutput + name := acctest.RandomWithPrefix("tf-acc-test") + invocationEndpoint := "https://www.hashicorp.com/" + httpMethod := "GET" + + nameModified := acctest.RandomWithPrefix("tf-acc-test") + invocationEndpointModified := "https://www.hashicorp.com/products/terraform" + httpMethodModified := "POST" + + resourceName := "aws_cloudwatch_event_api_destination.basic" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventApiDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventApiDestinationConfig( + name, + invocationEndpoint, + httpMethod, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "events", regexp.MustCompile(fmt.Sprintf("api-destination/%s/%s", name, uuidRegex))), + resource.TestCheckResourceAttr(resourceName, "http_method", httpMethod), + resource.TestCheckResourceAttr(resourceName, "invocation_endpoint", invocationEndpoint), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCloudWatchEventApiDestinationConfig( + nameModified, + invocationEndpointModified, + httpMethodModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v2), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "events", regexp.MustCompile(fmt.Sprintf("api-destination/%s/%s", nameModified, uuidRegex))), + testAccCheckCloudWatchEventApiDestinationRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "http_method", httpMethodModified), + resource.TestCheckResourceAttr(resourceName, "invocation_endpoint", invocationEndpointModified), + ), + }, + { + Config: testAccAWSCloudWatchEventApiDestinationConfig( + nameModified, + invocationEndpointModified, + httpMethodModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v3), + testAccCheckCloudWatchEventApiDestinationNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "http_method", httpMethodModified), + resource.TestCheckResourceAttr(resourceName, "invocation_endpoint", invocationEndpointModified), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventApiDestination_optional(t *testing.T) { + var v1, v2, v3 events.DescribeApiDestinationOutput + name := acctest.RandomWithPrefix("tf-acc-test") + invocationEndpoint := "https://www.hashicorp.com/" + httpMethod := "GET" + description := acctest.RandomWithPrefix("tf-acc-test") + invocationRateLimitPerSecond := 10 + + nameModified := acctest.RandomWithPrefix("tf-acc-test") + invocationEndpointModified := "https://www.hashicorp.com/products/terraform" + httpMethodModified := "POST" + descriptionModified := acctest.RandomWithPrefix("tf-acc-test") + invocationRateLimitPerSecondModified := 12 + + resourceName := "aws_cloudwatch_event_api_destination.optional" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventApiDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventApiDestinationConfig_optional( + name, + invocationEndpoint, + httpMethod, + description, + int64(invocationRateLimitPerSecond), + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "http_method", httpMethod), + resource.TestCheckResourceAttr(resourceName, "invocation_endpoint", invocationEndpoint), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "invocation_rate_limit_per_second", fmt.Sprint(invocationRateLimitPerSecond)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCloudWatchEventApiDestinationConfig_optional( + nameModified, + invocationEndpointModified, + httpMethodModified, + descriptionModified, + int64(invocationRateLimitPerSecondModified), + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v2), + testAccCheckCloudWatchEventApiDestinationRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + 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)), + ), + }, + { + Config: testAccAWSCloudWatchEventApiDestinationConfig_optional( + nameModified, + invocationEndpointModified, + httpMethodModified, + descriptionModified, + int64(invocationRateLimitPerSecondModified), + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v3), + testAccCheckCloudWatchEventApiDestinationNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + 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)), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventApiDestination_disappears(t *testing.T) { + var v events.DescribeApiDestinationOutput + name := acctest.RandomWithPrefix("tf-acc-test") + invocationEndpoint := "https://www.hashicorp.com/" + httpMethod := "GET" + + resourceName := "aws_cloudwatch_event_api_destination.basic" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventApiDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventApiDestinationConfig( + name, + invocationEndpoint, + httpMethod, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudWatchEventApiDestination(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSCloudWatchEventApiDestinationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_cloudwatch_event_api_destination" { + continue + } + + params := events.DescribeApiDestinationInput{ + Name: aws.String(rs.Primary.ID), + } + + resp, err := conn.DescribeApiDestination(¶ms) + + if err == nil { + return fmt.Errorf("CloudWatch Events Api Destination (%s) still exists: %s", rs.Primary.ID, resp) + } + } + + return nil +} + +func testAccCheckCloudWatchEventApiDestinationExists(n string, v *events.DescribeApiDestinationOutput) 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).cloudwatcheventsconn + params := events.DescribeApiDestinationInput{ + Name: aws.String(rs.Primary.ID), + } + resp, err := conn.DescribeApiDestination(¶ms) + if err != nil { + return err + } + if resp == nil { + return fmt.Errorf("CloudWatch Events Api Destination (%s) not found", n) + } + + *v = *resp + + return nil + } +} + +func testAccCheckCloudWatchEventApiDestinationRecreated(i, j *events.DescribeApiDestinationOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.ApiDestinationArn) == aws.StringValue(j.ApiDestinationArn) { + return fmt.Errorf("CloudWatch Events Api Destination not recreated") + } + return nil + } +} + +func testAccCheckCloudWatchEventApiDestinationNotRecreated(i, j *events.DescribeApiDestinationOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.ApiDestinationArn) != aws.StringValue(j.ApiDestinationArn) { + return fmt.Errorf("CloudWatch Events Api Destination was recreated") + } + return nil + } +} + +func testAccAWSCloudWatchEventApiDestinationConfig(name, invocationEndpoint, httpMethod string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_api_destination" "basic" { + name = %[1]q + invocation_endpoint = %[2]q + http_method = %[3]q + connection_arn = aws_cloudwatch_event_connection.test.arn +} + +resource "aws_cloudwatch_event_connection" "test" { + name = %[1]q + authorization_type = "API_KEY" + auth_parameters { + api_key { + key = "testKey" + value = "testValue" + } + } +} +`, name, invocationEndpoint, httpMethod) +} + +func testAccAWSCloudWatchEventApiDestinationConfig_optional(name, invocationEndpoint, httpMethod, description string, invocationRateLimitPerSecond int64) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_api_destination" "optional" { + name = %[1]q + invocation_endpoint = %[2]q + http_method = %[3]q + connection_arn = aws_cloudwatch_event_connection.test.arn + + description = %[4]q + invocation_rate_limit_per_second = %[5]d +} + +resource "aws_cloudwatch_event_connection" "test" { + name = %[1]q + authorization_type = "API_KEY" + auth_parameters { + api_key { + key = "testKey" + value = "testValue" + } + } +} +`, name, invocationEndpoint, httpMethod, description, invocationRateLimitPerSecond) +} diff --git a/aws/resource_aws_cloudwatch_event_connection.go b/aws/resource_aws_cloudwatch_event_connection.go new file mode 100644 index 00000000000..dcc1069f815 --- /dev/null +++ b/aws/resource_aws_cloudwatch_event_connection.go @@ -0,0 +1,785 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + + "github.com/aws/aws-sdk-go/aws" + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "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/cloudwatchevents/waiter" +) + +func resourceAwsCloudWatchEventConnection() *schema.Resource { + connectionHttpParameters := &schema.Resource{ + Schema: map[string]*schema.Schema{ + "body": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Optional: true, + }, + "value": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + "is_value_secret": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, + "header": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Optional: true, + }, + "value": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + "is_value_secret": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, + "query_string": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Optional: true, + }, + "value": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + "is_value_secret": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, + }, + } + + return &schema.Resource{ + Create: resourceAwsCloudWatchEventConnectionCreate, + Read: resourceAwsCloudWatchEventConnectionRead, + Update: resourceAwsCloudWatchEventConnectionUpdate, + Delete: resourceAwsCloudWatchEventConnectionDelete, + 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), + validation.StringMatch(regexp.MustCompile(`^[\.\-_A-Za-z0-9]+`), ""), + ), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "authorization_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(events.ConnectionAuthorizationType_Values(), true), + }, + "auth_parameters": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_key": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ExactlyOneOf: []string{ + "auth_parameters.0.api_key", + "auth_parameters.0.basic", + "auth_parameters.0.oauth", + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + }, + }, + }, + }, + "basic": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ExactlyOneOf: []string{ + "auth_parameters.0.api_key", + "auth_parameters.0.basic", + "auth_parameters.0.oauth", + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "username": { + Type: schema.TypeString, + Required: true, + }, + "password": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + }, + }, + }, + }, + "oauth": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ExactlyOneOf: []string{ + "auth_parameters.0.api_key", + "auth_parameters.0.basic", + "auth_parameters.0.oauth", + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorization_endpoint": { + Type: schema.TypeString, + Required: true, + }, + "http_method": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(events.ConnectionOAuthHttpMethod_Values(), true), + }, + "oauth_http_parameters": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: connectionHttpParameters, + }, + "client_parameters": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "client_id": { + Type: schema.TypeString, + Required: true, + }, + "client_secret": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + }, + }, + }, + }, + }, + }, + }, + "invocation_http_parameters": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: connectionHttpParameters, + }, + }, + }, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsCloudWatchEventConnectionCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.CreateConnectionInput{} + + if name, ok := d.GetOk("name"); ok { + input.Name = aws.String(name.(string)) + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + if authorizationType, ok := d.GetOk("authorization_type"); ok { + input.AuthorizationType = aws.String(authorizationType.(string)) + } + if authParameters, ok := d.GetOk("auth_parameters"); ok { + input.AuthParameters = expandAwsCloudWatchEventCreateConnectionAuthRequestParameters(authParameters.([]interface{})) + } + + log.Printf("[DEBUG] Creating CloudWatchEvent connection: %v", input) + + _, err := conn.CreateConnection(input) + if err != nil { + return fmt.Errorf("Creating CloudWatchEvent connection (%s) failed: %w", *input.Name, err) + } + + d.SetId(aws.StringValue(input.Name)) + + log.Printf("[INFO] CloudWatchEvent connection (%s) created", d.Id()) + + return resourceAwsCloudWatchEventConnectionRead(d, meta) +} + +func resourceAwsCloudWatchEventConnectionRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.DescribeConnectionInput{ + Name: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Reading CloudWatchEvent connection (%s)", d.Id()) + output, err := conn.DescribeConnection(input) + if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] CloudWatchEvent connection (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("error reading CloudWatchEvent connection: %w", err) + } + + log.Printf("[DEBUG] Found CloudWatchEvent connection: %#v", *output) + + d.Set("arn", output.ConnectionArn) + d.Set("name", output.Name) + d.Set("description", output.Description) + d.Set("authorization_type", output.AuthorizationType) + + if output.AuthParameters != nil { + authParameters := flattenAwsCloudWatchEventConnectionAuthParameters(output.AuthParameters, d) + if err := d.Set("auth_parameters", authParameters); err != nil { + return fmt.Errorf("Error setting authParameters error: %w", err) + } + } + + return nil +} + +func resourceAwsCloudWatchEventConnectionUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.UpdateConnectionInput{} + + if name, ok := d.GetOk("name"); ok { + input.Name = aws.String(name.(string)) + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + if authorizationType, ok := d.GetOk("authorization_type"); ok { + input.AuthorizationType = aws.String(authorizationType.(string)) + } + if authParameters, ok := d.GetOk("auth_parameters"); ok { + input.AuthParameters = expandAwsCloudWatchEventUpdateConnectionAuthRequestParameters(authParameters.([]interface{})) + } + + log.Printf("[DEBUG] Updating CloudWatchEvent connection: %s", input) + _, err := conn.UpdateConnection(input) + if err != nil { + return fmt.Errorf("error updating CloudWatchEvent connection (%s): %w", d.Id(), err) + } + return resourceAwsCloudWatchEventConnectionRead(d, meta) +} + +func resourceAwsCloudWatchEventConnectionDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + log.Printf("[INFO] Deleting CloudWatchEvent connection (%s)", d.Id()) + input := &events.DeleteConnectionInput{ + Name: aws.String(d.Id()), + } + _, err := conn.DeleteConnection(input) + + if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] CloudWatchEvent connection (%s) not found", d.Id()) + return nil + } + if err != nil { + return fmt.Errorf("Error deleting CloudWatchEvent connection (%s): %w", d.Id(), err) + } + + _, err = waiter.CloudWatchEventConnectionDeleted(conn, d.Id()) + if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] CloudWatchEvent connection (%s) not found", d.Id()) + return nil + } + if err != nil { + return fmt.Errorf("error waiting for CloudWatchEvent connection (%s) deletion: %s", d.Id(), err) + } + log.Printf("[INFO] CloudWatchEvent connection (%s) deleted", d.Id()) + + return nil +} + +func expandAwsCloudWatchEventCreateConnectionAuthRequestParameters(config []interface{}) *events.CreateConnectionAuthRequestParameters { + authParameters := &events.CreateConnectionAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["api_key"]; ok { + authParameters.ApiKeyAuthParameters = expandAwsCreateConnectionApiKeyAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["basic"]; ok { + authParameters.BasicAuthParameters = expandAwsCreateConnectionBasicAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["oauth"]; ok { + authParameters.OAuthParameters = expandAwsCreateConnectionOAuthAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["invocation_http_parameters"]; ok { + authParameters.InvocationHttpParameters = expandAwsConnectionHttpParameters(val.([]interface{})) + } + } + + return authParameters +} + +func expandAwsCreateConnectionApiKeyAuthRequestParameters(config []interface{}) *events.CreateConnectionApiKeyAuthRequestParameters { + if len(config) == 0 { + return nil + } + apiKeyAuthParameters := &events.CreateConnectionApiKeyAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["key"].(string); ok && val != "" { + apiKeyAuthParameters.ApiKeyName = aws.String(val) + } + if val, ok := param["value"].(string); ok && val != "" { + apiKeyAuthParameters.ApiKeyValue = aws.String(val) + } + } + return apiKeyAuthParameters +} + +func expandAwsCreateConnectionBasicAuthRequestParameters(config []interface{}) *events.CreateConnectionBasicAuthRequestParameters { + if len(config) == 0 { + return nil + } + basicAuthParameters := &events.CreateConnectionBasicAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["username"].(string); ok && val != "" { + basicAuthParameters.Username = aws.String(val) + } + if val, ok := param["password"].(string); ok && val != "" { + basicAuthParameters.Password = aws.String(val) + } + } + return basicAuthParameters +} + +func expandAwsCreateConnectionOAuthAuthRequestParameters(config []interface{}) *events.CreateConnectionOAuthRequestParameters { + if len(config) == 0 { + return nil + } + oAuthParameters := &events.CreateConnectionOAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["authorization_endpoint"].(string); ok && val != "" { + oAuthParameters.AuthorizationEndpoint = aws.String(val) + } + if val, ok := param["http_method"].(string); ok && val != "" { + oAuthParameters.HttpMethod = aws.String(val) + } + if val, ok := param["oauth_http_parameters"]; ok { + oAuthParameters.OAuthHttpParameters = expandAwsConnectionHttpParameters(val.([]interface{})) + } + if val, ok := param["client_parameters"]; ok { + oAuthParameters.ClientParameters = expandAwsCreateConnectionOAuthClientRequestParameters(val.([]interface{})) + } + } + return oAuthParameters +} + +func expandAwsCreateConnectionOAuthClientRequestParameters(config []interface{}) *events.CreateConnectionOAuthClientRequestParameters { + oAuthClientRequestParameters := &events.CreateConnectionOAuthClientRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["client_id"].(string); ok && val != "" { + oAuthClientRequestParameters.ClientID = aws.String(val) + } + if val, ok := param["client_secret"].(string); ok && val != "" { + oAuthClientRequestParameters.ClientSecret = aws.String(val) + } + } + return oAuthClientRequestParameters +} + +func expandAwsConnectionHttpParameters(config []interface{}) *events.ConnectionHttpParameters { + if len(config) == 0 { + return nil + } + httpParameters := &events.ConnectionHttpParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["body"]; ok { + httpParameters.BodyParameters = expandAwsConnectionHttpParametersBody(val.([]interface{})) + } + if val, ok := param["header"]; ok { + httpParameters.HeaderParameters = expandAwsConnectionHttpParametersHeader(val.([]interface{})) + } + if val, ok := param["query_string"]; ok { + httpParameters.QueryStringParameters = expandAwsConnectionHttpParametersQueryString(val.([]interface{})) + } + } + return httpParameters +} + +func expandAwsConnectionHttpParametersBody(config []interface{}) []*events.ConnectionBodyParameter { + if len(config) == 0 { + return nil + } + var parameters []*events.ConnectionBodyParameter + for _, c := range config { + parameter := events.ConnectionBodyParameter{} + + input := c.(map[string]interface{}) + if val, ok := input["key"].(string); ok && val != "" { + parameter.Key = aws.String(val) + } + if val, ok := input["value"].(string); ok && val != "" { + parameter.Value = aws.String(val) + } + if val, ok := input["is_value_secret"].(bool); ok { + parameter.IsValueSecret = aws.Bool(val) + } + parameters = append(parameters, ¶meter) + } + return parameters +} + +func expandAwsConnectionHttpParametersHeader(config []interface{}) []*events.ConnectionHeaderParameter { + if len(config) == 0 { + return nil + } + var parameters []*events.ConnectionHeaderParameter + for _, c := range config { + parameter := events.ConnectionHeaderParameter{} + + input := c.(map[string]interface{}) + if val, ok := input["key"].(string); ok && val != "" { + parameter.Key = aws.String(val) + } + if val, ok := input["value"].(string); ok && val != "" { + parameter.Value = aws.String(val) + } + if val, ok := input["is_value_secret"].(bool); ok { + parameter.IsValueSecret = aws.Bool(val) + } + parameters = append(parameters, ¶meter) + } + return parameters +} + +func expandAwsConnectionHttpParametersQueryString(config []interface{}) []*events.ConnectionQueryStringParameter { + if len(config) == 0 { + return nil + } + var parameters []*events.ConnectionQueryStringParameter + for _, c := range config { + parameter := events.ConnectionQueryStringParameter{} + + input := c.(map[string]interface{}) + if val, ok := input["key"].(string); ok && val != "" { + parameter.Key = aws.String(val) + } + if val, ok := input["value"].(string); ok && val != "" { + parameter.Value = aws.String(val) + } + if val, ok := input["is_value_secret"].(bool); ok { + parameter.IsValueSecret = aws.Bool(val) + } + parameters = append(parameters, ¶meter) + } + return parameters +} + +func flattenAwsCloudWatchEventConnectionAuthParameters( + authParameters *events.ConnectionAuthResponseParameters, + resourceData *schema.ResourceData, +) []map[string]interface{} { + config := make(map[string]interface{}) + + if authParameters.ApiKeyAuthParameters != nil { + config["api_key"] = flattenAwsConnectionApiKeyAuthParameters(authParameters.ApiKeyAuthParameters, resourceData) + } + + if authParameters.BasicAuthParameters != nil { + config["basic"] = flattenAwsConnectionBasicAuthParameters(authParameters.BasicAuthParameters, resourceData) + } + + if authParameters.OAuthParameters != nil { + config["oauth"] = flattenAwsConnectionOAuthParameters(authParameters.OAuthParameters, resourceData) + } + + if authParameters.InvocationHttpParameters != nil { + config["invocation_http_parameters"] = flattenAwsConnectionHttpParameters(authParameters.InvocationHttpParameters, resourceData, "auth_parameters.0.invocation_http_parameters") + } + + result := []map[string]interface{}{config} + return result +} + +func flattenAwsConnectionApiKeyAuthParameters(apiKeyAuthParameters *events.ConnectionApiKeyAuthResponseParameters, resourceData *schema.ResourceData) []map[string]interface{} { + if apiKeyAuthParameters == nil { + return nil + } + + config := make(map[string]interface{}) + if apiKeyAuthParameters.ApiKeyName != nil { + config["key"] = aws.StringValue(apiKeyAuthParameters.ApiKeyName) + } + + if v, ok := resourceData.GetOk("auth_parameters.0.api_key.0.value"); ok { + config["value"] = v.(string) + } + + result := []map[string]interface{}{config} + return result +} + +func flattenAwsConnectionBasicAuthParameters(basicAuthParameters *events.ConnectionBasicAuthResponseParameters, resourceData *schema.ResourceData) []map[string]interface{} { + if basicAuthParameters == nil { + return nil + } + + config := make(map[string]interface{}) + if basicAuthParameters.Username != nil { + config["username"] = aws.StringValue(basicAuthParameters.Username) + } + + if v, ok := resourceData.GetOk("auth_parameters.0.basic.0.password"); ok { + config["password"] = v.(string) + } + + result := []map[string]interface{}{config} + return result +} + +func flattenAwsConnectionOAuthParameters(oAuthParameters *events.ConnectionOAuthResponseParameters, resourceData *schema.ResourceData) []map[string]interface{} { + if oAuthParameters == nil { + return nil + } + + config := make(map[string]interface{}) + if oAuthParameters.AuthorizationEndpoint != nil { + config["authorization_endpoint"] = aws.StringValue(oAuthParameters.AuthorizationEndpoint) + } + if oAuthParameters.HttpMethod != nil { + config["http_method"] = aws.StringValue(oAuthParameters.HttpMethod) + } + config["oauth_http_parameters"] = flattenAwsConnectionHttpParameters(oAuthParameters.OAuthHttpParameters, resourceData, "auth_parameters.0.oauth.0.oauth_http_parameters") + config["client_parameters"] = flattenAwsConnectionOAuthClientResponseParameters(oAuthParameters.ClientParameters, resourceData) + + result := []map[string]interface{}{config} + return result +} + +func flattenAwsConnectionOAuthClientResponseParameters(oAuthClientRequestParameters *events.ConnectionOAuthClientResponseParameters, resourceData *schema.ResourceData) []map[string]interface{} { + if oAuthClientRequestParameters == nil { + return nil + } + + config := make(map[string]interface{}) + if oAuthClientRequestParameters.ClientID != nil { + config["client_id"] = aws.StringValue(oAuthClientRequestParameters.ClientID) + } + + if v, ok := resourceData.GetOk("auth_parameters.0.oauth.0.client_parameters.0.client_secret"); ok { + config["client_secret"] = v.(string) + } + + result := []map[string]interface{}{config} + return result +} + +func flattenAwsConnectionHttpParameters( + httpParameters *events.ConnectionHttpParameters, + resourceData *schema.ResourceData, + path string, +) []map[string]interface{} { + if httpParameters == nil { + return nil + } + + var bodyParameters []map[string]interface{} + for i, param := range httpParameters.BodyParameters { + config := make(map[string]interface{}) + config["is_value_secret"] = aws.BoolValue(param.IsValueSecret) + config["key"] = aws.StringValue(param.Key) + + if param.Value != nil { + config["value"] = aws.StringValue(param.Value) + } else if v, ok := resourceData.GetOk(fmt.Sprintf("%s.0.body.%d.value", path, i)); ok { + config["value"] = v.(string) + } + bodyParameters = append(bodyParameters, config) + } + + var headerParameters []map[string]interface{} + for i, param := range httpParameters.HeaderParameters { + config := make(map[string]interface{}) + config["is_value_secret"] = aws.BoolValue(param.IsValueSecret) + config["key"] = aws.StringValue(param.Key) + + if param.Value != nil { + config["value"] = aws.StringValue(param.Value) + } else if v, ok := resourceData.GetOk(fmt.Sprintf("%s.0.header.%d.value", path, i)); ok { + config["value"] = v.(string) + } + headerParameters = append(headerParameters, config) + } + + var queryStringParameters []map[string]interface{} + for i, param := range httpParameters.QueryStringParameters { + config := make(map[string]interface{}) + config["is_value_secret"] = aws.BoolValue(param.IsValueSecret) + config["key"] = aws.StringValue(param.Key) + + if param.Value != nil { + config["value"] = aws.StringValue(param.Value) + } else if v, ok := resourceData.GetOk(fmt.Sprintf("%s.0.query_string.%d.value", path, i)); ok { + config["value"] = v.(string) + } + queryStringParameters = append(queryStringParameters, config) + } + + parameters := make(map[string]interface{}) + parameters["body"] = bodyParameters + parameters["header"] = headerParameters + parameters["query_string"] = queryStringParameters + + result := []map[string]interface{}{parameters} + return result +} + +func expandAwsCloudWatchEventUpdateConnectionAuthRequestParameters(config []interface{}) *events.UpdateConnectionAuthRequestParameters { + authParameters := &events.UpdateConnectionAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["api_key"]; ok { + authParameters.ApiKeyAuthParameters = expandAwsUpdateConnectionApiKeyAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["basic"]; ok { + authParameters.BasicAuthParameters = expandAwsUpdateConnectionBasicAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["oauth"]; ok { + authParameters.OAuthParameters = expandAwsUpdateConnectionOAuthAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["invocation_http_parameters"]; ok { + authParameters.InvocationHttpParameters = expandAwsConnectionHttpParameters(val.([]interface{})) + } + } + + return authParameters +} + +func expandAwsUpdateConnectionApiKeyAuthRequestParameters(config []interface{}) *events.UpdateConnectionApiKeyAuthRequestParameters { + if len(config) == 0 { + return nil + } + apiKeyAuthParameters := &events.UpdateConnectionApiKeyAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["key"].(string); ok && val != "" { + apiKeyAuthParameters.ApiKeyName = aws.String(val) + } + if val, ok := param["value"].(string); ok && val != "" { + apiKeyAuthParameters.ApiKeyValue = aws.String(val) + } + } + return apiKeyAuthParameters +} + +func expandAwsUpdateConnectionBasicAuthRequestParameters(config []interface{}) *events.UpdateConnectionBasicAuthRequestParameters { + if len(config) == 0 { + return nil + } + basicAuthParameters := &events.UpdateConnectionBasicAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["username"].(string); ok && val != "" { + basicAuthParameters.Username = aws.String(val) + } + if val, ok := param["password"].(string); ok && val != "" { + basicAuthParameters.Password = aws.String(val) + } + } + return basicAuthParameters +} + +func expandAwsUpdateConnectionOAuthAuthRequestParameters(config []interface{}) *events.UpdateConnectionOAuthRequestParameters { + if len(config) == 0 { + return nil + } + oAuthParameters := &events.UpdateConnectionOAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["authorization_endpoint"].(string); ok && val != "" { + oAuthParameters.AuthorizationEndpoint = aws.String(val) + } + if val, ok := param["http_method"].(string); ok && val != "" { + oAuthParameters.HttpMethod = aws.String(val) + } + if val, ok := param["oauth_http_parameters"]; ok { + oAuthParameters.OAuthHttpParameters = expandAwsConnectionHttpParameters(val.([]interface{})) + } + if val, ok := param["client_parameters"]; ok { + oAuthParameters.ClientParameters = expandAwsUpdateConnectionOAuthClientRequestParameters(val.([]interface{})) + } + } + return oAuthParameters +} + +func expandAwsUpdateConnectionOAuthClientRequestParameters(config []interface{}) *events.UpdateConnectionOAuthClientRequestParameters { + oAuthClientRequestParameters := &events.UpdateConnectionOAuthClientRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["client_id"].(string); ok && val != "" { + oAuthClientRequestParameters.ClientID = aws.String(val) + } + if val, ok := param["client_secret"].(string); ok && val != "" { + oAuthClientRequestParameters.ClientSecret = aws.String(val) + } + } + return oAuthClientRequestParameters +} diff --git a/aws/resource_aws_cloudwatch_event_connection_test.go b/aws/resource_aws_cloudwatch_event_connection_test.go new file mode 100644 index 00000000000..ead4d6f872d --- /dev/null +++ b/aws/resource_aws_cloudwatch_event_connection_test.go @@ -0,0 +1,873 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "strconv" + "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" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func init() { + resource.AddTestSweepers("aws_cloudwatch_event_connection", &resource.Sweeper{ + Name: "aws_cloudwatch_event_connection", + F: testSweepCloudWatchEventConnection, + }) +} + +func testSweepCloudWatchEventConnection(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("Error getting client: %w", err) + } + conn := client.(*AWSClient).cloudwatcheventsconn + + var sweeperErrs *multierror.Error + + input := &events.ListConnectionsInput{ + Limit: aws.Int64(100), + } + var connections []*events.Connection + for { + output, err := conn.ListConnections(input) + if err != nil { + return err + } + + if aws.StringValue(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + for _, connection := range connections { + input := &events.DeleteConnectionInput{ + Name: connection.Name, + } + _, err := conn.DeleteConnection(input) + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("Error deleting CloudWatch Event Connection (%s): %w", *connection.Name, err)) + continue + } + } + + log.Printf("[INFO] Deleted %d CloudWatch Event Connections", len(connections)) + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSCloudWatchEventConnection_apiKey(t *testing.T) { + var v1, v2, v3 events.DescribeConnectionOutput + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "API_KEY" + description := acctest.RandomWithPrefix("tf-acc-test") + key := acctest.RandomWithPrefix("tf-acc-test") + value := acctest.RandomWithPrefix("tf-acc-test") + + nameModified := acctest.RandomWithPrefix("tf-acc-test") + descriptionModified := acctest.RandomWithPrefix("tf-acc-test") + keyModified := acctest.RandomWithPrefix("tf-acc-test") + valueModified := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_cloudwatch_event_connection.api_key" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventConnectionConfig_apiKey( + name, + description, + authorizationType, + key, + value, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", key), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"auth_parameters.0.api_key.0.value"}, + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_apiKey( + nameModified, + descriptionModified, + authorizationType, + keyModified, + valueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v2), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "events", regexp.MustCompile(fmt.Sprintf("connection/%s/%s", nameModified, uuidRegex))), + testAccCheckCloudWatchEventConnectionRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", keyModified), + ), + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_apiKey( + nameModified, + descriptionModified, + authorizationType, + keyModified, + valueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v3), + testAccCheckCloudWatchEventConnectionNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", keyModified), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventConnection_basic(t *testing.T) { + var v1, v2, v3 events.DescribeConnectionOutput + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "BASIC" + description := acctest.RandomWithPrefix("tf-acc-test") + username := acctest.RandomWithPrefix("tf-acc-test") + password := acctest.RandomWithPrefix("tf-acc-test") + + nameModified := acctest.RandomWithPrefix("tf-acc-test") + descriptionModified := acctest.RandomWithPrefix("tf-acc-test") + usernameModified := acctest.RandomWithPrefix("tf-acc-test") + passwordModified := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_cloudwatch_event_connection.basic" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventConnectionConfig_basic( + name, + description, + authorizationType, + username, + password, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.basic.0.username", username), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"auth_parameters.0.basic.0.password"}, + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_basic( + nameModified, + descriptionModified, + authorizationType, + usernameModified, + passwordModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v2), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "events", regexp.MustCompile(fmt.Sprintf("connection/%s/%s", nameModified, uuidRegex))), + testAccCheckCloudWatchEventConnectionRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.basic.0.username", usernameModified), + ), + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_basic( + nameModified, + descriptionModified, + authorizationType, + usernameModified, + passwordModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v3), + testAccCheckCloudWatchEventConnectionNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.basic.0.username", usernameModified), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventConnection_oAuth(t *testing.T) { + var v1, v2, v3 events.DescribeConnectionOutput + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "OAUTH_CLIENT_CREDENTIALS" + description := acctest.RandomWithPrefix("tf-acc-test") + // oauth + authorizationEndpoint := "https://www.hashicorp.com/products/terraform" + httpMethod := "POST" + + // client_parameters + clientID := acctest.RandomWithPrefix("tf-acc-test") + clientSecret := acctest.RandomWithPrefix("tf-acc-test") + + // oauth_http_parameters + bodyKey := acctest.RandomWithPrefix("tf-acc-test") + bodyValue := acctest.RandomWithPrefix("tf-acc-test") + bodyIsSecretValue := true + + headerKey := acctest.RandomWithPrefix("tf-acc-test") + headerValue := acctest.RandomWithPrefix("tf-acc-test") + headerIsSecretValue := true + + queryStringKey := acctest.RandomWithPrefix("tf-acc-test") + queryStringValue := acctest.RandomWithPrefix("tf-acc-test") + queryStringIsSecretValue := true + + // modified + nameModified := acctest.RandomWithPrefix("tf-acc-test") + descriptionModified := acctest.RandomWithPrefix("tf-acc-test") + // oauth + authorizationEndpointModified := "https://www.hashicorp.com/" + httpMethodModified := "GET" + + // client_parameters + clientIDModified := acctest.RandomWithPrefix("tf-acc-test") + clientSecretModified := acctest.RandomWithPrefix("tf-acc-test") + + // oauth_http_parameters modified + bodyKeyModified := acctest.RandomWithPrefix("tf-acc-test") + bodyValueModified := acctest.RandomWithPrefix("tf-acc-test") + bodyIsSecretValueModified := false + + headerKeyModified := acctest.RandomWithPrefix("tf-acc-test") + headerValueModified := acctest.RandomWithPrefix("tf-acc-test") + headerIsSecretValueModified := false + + queryStringKeyModified := acctest.RandomWithPrefix("tf-acc-test") + queryStringValueModified := acctest.RandomWithPrefix("tf-acc-test") + queryStringIsSecretValueModified := false + + resourceName := "aws_cloudwatch_event_connection.oauth" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventConnectionConfig_oauth( + name, + description, + authorizationType, + authorizationEndpoint, + httpMethod, + clientID, + clientSecret, + bodyKey, + bodyValue, + bodyIsSecretValue, + headerKey, + headerValue, + headerIsSecretValue, + queryStringKey, + queryStringValue, + queryStringIsSecretValue, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.authorization_endpoint", authorizationEndpoint), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.http_method", httpMethod), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.client_parameters.0.client_id", clientID), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.key", bodyKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.key", headerKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.key", queryStringKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValue)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "auth_parameters.0.oauth.0.client_parameters.0.client_secret", + "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.value", + "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.value", + "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.value", + }, + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_oauth( + nameModified, + descriptionModified, + authorizationType, + authorizationEndpointModified, + httpMethodModified, + clientIDModified, + clientSecretModified, + bodyKeyModified, + bodyValueModified, + bodyIsSecretValueModified, + headerKeyModified, + headerValueModified, + headerIsSecretValueModified, + queryStringKeyModified, + queryStringValueModified, + queryStringIsSecretValueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v2), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "events", regexp.MustCompile(fmt.Sprintf("connection/%s/%s", nameModified, uuidRegex))), + testAccCheckCloudWatchEventConnectionRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.authorization_endpoint", authorizationEndpointModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.http_method", httpMethodModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.client_parameters.0.client_id", clientIDModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.key", bodyKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.key", headerKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.key", queryStringKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + ), + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_oauth( + nameModified, + descriptionModified, + authorizationType, + authorizationEndpointModified, + httpMethodModified, + clientIDModified, + clientSecretModified, + bodyKeyModified, + bodyValueModified, + bodyIsSecretValueModified, + headerKeyModified, + headerValueModified, + headerIsSecretValueModified, + queryStringKeyModified, + queryStringValueModified, + queryStringIsSecretValueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v3), + testAccCheckCloudWatchEventConnectionNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.authorization_endpoint", authorizationEndpointModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.http_method", httpMethodModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.client_parameters.0.client_id", clientIDModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.key", bodyKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.key", headerKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.key", queryStringKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventConnection_invocationHttpParameters(t *testing.T) { + var v1, v2, v3 events.DescribeConnectionOutput + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "API_KEY" + description := acctest.RandomWithPrefix("tf-acc-test") + key := acctest.RandomWithPrefix("tf-acc-test") + value := acctest.RandomWithPrefix("tf-acc-test") + + // invocation_http_parameters + bodyKey := acctest.RandomWithPrefix("tf-acc-test") + bodyValue := acctest.RandomWithPrefix("tf-acc-test") + bodyIsSecretValue := true + + headerKey := acctest.RandomWithPrefix("tf-acc-test") + headerValue := acctest.RandomWithPrefix("tf-acc-test") + headerIsSecretValue := true + + queryStringKey := acctest.RandomWithPrefix("tf-acc-test") + queryStringValue := acctest.RandomWithPrefix("tf-acc-test") + queryStringIsSecretValue := true + + // invocation_http_parameters modified + bodyKeyModified := acctest.RandomWithPrefix("tf-acc-test") + bodyValueModified := acctest.RandomWithPrefix("tf-acc-test") + bodyIsSecretValueModified := false + + headerKeyModified := acctest.RandomWithPrefix("tf-acc-test") + headerValueModified := acctest.RandomWithPrefix("tf-acc-test") + headerIsSecretValueModified := false + + queryStringKeyModified := acctest.RandomWithPrefix("tf-acc-test") + queryStringValueModified := acctest.RandomWithPrefix("tf-acc-test") + queryStringIsSecretValueModified := false + + resourceName := "aws_cloudwatch_event_connection.invocation_http_parameters" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventConnectionConfig_invocationHttpParameters( + name, + description, + authorizationType, + key, + value, + bodyKey, + bodyValue, + bodyIsSecretValue, + headerKey, + headerValue, + headerIsSecretValue, + queryStringKey, + queryStringValue, + queryStringIsSecretValue, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", key), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.key", bodyKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.key", fmt.Sprintf("second-%s", bodyKey)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.is_value_secret", strconv.FormatBool(bodyIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.key", headerKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.key", fmt.Sprintf("second-%s", headerKey)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.is_value_secret", strconv.FormatBool(headerIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.key", queryStringKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.key", fmt.Sprintf("second-%s", queryStringKey)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.is_value_secret", strconv.FormatBool(queryStringIsSecretValue)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "auth_parameters.0.api_key.0.value", + "auth_parameters.0.invocation_http_parameters.0.body.0.value", + "auth_parameters.0.invocation_http_parameters.0.body.1.value", + "auth_parameters.0.invocation_http_parameters.0.header.0.value", + "auth_parameters.0.invocation_http_parameters.0.header.1.value", + "auth_parameters.0.invocation_http_parameters.0.query_string.0.value", + "auth_parameters.0.invocation_http_parameters.0.query_string.1.value", + }, + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_invocationHttpParameters( + name, + description, + authorizationType, + key, + value, + bodyKeyModified, + bodyValueModified, + bodyIsSecretValueModified, + headerKeyModified, + headerValueModified, + headerIsSecretValueModified, + queryStringKeyModified, + queryStringValueModified, + queryStringIsSecretValueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v2), + testAccCheckCloudWatchEventConnectionNotRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", key), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.key", bodyKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.key", fmt.Sprintf("second-%s", bodyKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.key", headerKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.key", fmt.Sprintf("second-%s", headerKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.key", queryStringKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.key", fmt.Sprintf("second-%s", queryStringKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + ), + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_invocationHttpParameters( + name, + description, + authorizationType, + key, + value, + bodyKeyModified, + bodyValueModified, + bodyIsSecretValueModified, + headerKeyModified, + headerValueModified, + headerIsSecretValueModified, + queryStringKeyModified, + queryStringValueModified, + queryStringIsSecretValueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v3), + testAccCheckCloudWatchEventConnectionNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", key), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.key", bodyKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.key", fmt.Sprintf("second-%s", bodyKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.key", headerKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.key", fmt.Sprintf("second-%s", headerKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.key", queryStringKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.key", fmt.Sprintf("second-%s", queryStringKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventConnection_disappears(t *testing.T) { + var v events.DescribeConnectionOutput + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "API_KEY" + description := acctest.RandomWithPrefix("tf-acc-test") + key := acctest.RandomWithPrefix("tf-acc-test") + value := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudwatch_event_connection.api_key" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventConnectionConfig_apiKey( + name, + description, + authorizationType, + key, + value, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudWatchEventConnection(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSCloudWatchEventConnectionDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_cloudwatch_event_connection" { + continue + } + + params := events.DescribeConnectionInput{ + Name: aws.String(rs.Primary.ID), + } + + resp, err := conn.DescribeConnection(¶ms) + + if err == nil { + return fmt.Errorf("CloudWatch Events Connection (%s) still exists: %s", rs.Primary.ID, resp) + } + } + + return nil +} + +func testAccCheckCloudWatchEventConnectionExists(n string, v *events.DescribeConnectionOutput) 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).cloudwatcheventsconn + params := events.DescribeConnectionInput{ + Name: aws.String(rs.Primary.ID), + } + resp, err := conn.DescribeConnection(¶ms) + if err != nil { + return err + } + if resp == nil { + return fmt.Errorf("CloudWatch Events Connection (%s) not found", n) + } + + *v = *resp + + return nil + } +} + +func testAccCheckCloudWatchEventConnectionRecreated(i, j *events.DescribeConnectionOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.ConnectionArn) == aws.StringValue(j.ConnectionArn) { + return fmt.Errorf("CloudWatch Events Connection not recreated") + } + return nil + } +} + +func testAccCheckCloudWatchEventConnectionNotRecreated(i, j *events.DescribeConnectionOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.ConnectionArn) != aws.StringValue(j.ConnectionArn) { + return fmt.Errorf("CloudWatch Events Connection was recreated") + } + return nil + } +} + +func testAccAWSCloudWatchEventConnectionConfig_apiKey(name, description, authorizationType, key, value string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_connection" "api_key" { + name = %[1]q + description = %[2]q + authorization_type = %[3]q + auth_parameters { + api_key { + key = %[4]q + value = %[5]q + } + } +} +`, name, + description, + authorizationType, + key, + value) +} + +func testAccAWSCloudWatchEventConnectionConfig_basic(name, description, authorizationType, username, password string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_connection" "basic" { + name = %[1]q + description = %[2]q + authorization_type = %[3]q + auth_parameters { + basic { + username = %[4]q + password = %[5]q + } + } +} +`, name, + description, + authorizationType, + username, + password) +} + +func testAccAWSCloudWatchEventConnectionConfig_oauth( + name, + description, + authorizationType, + authorizationEndpoint, + httpMethod, + clientID, + clientSecret string, + bodyKey string, + bodyValue string, + bodyIsSecretValue bool, + headerKey string, + headerValue string, + headerIsSecretValue bool, + queryStringKey string, + queryStringValue string, + queryStringIsSecretValue bool) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_connection" "oauth" { + name = %[1]q + description = %[2]q + authorization_type = %[3]q + auth_parameters { + oauth { + authorization_endpoint = %[4]q + http_method = %[5]q + client_parameters { + client_id = %[6]q + client_secret = %[7]q + } + + oauth_http_parameters { + body { + key = %[8]q + value = %[9]q + is_value_secret = %[10]t + } + + header { + key = %[11]q + value = %[12]q + is_value_secret = %[13]t + } + + query_string { + key = %[14]q + value = %[15]q + is_value_secret = %[16]t + } + } + } + } +} +`, name, + description, + authorizationType, + authorizationEndpoint, + httpMethod, + clientID, + clientSecret, + bodyKey, + bodyValue, + bodyIsSecretValue, + headerKey, + headerValue, + headerIsSecretValue, + queryStringKey, + queryStringValue, + queryStringIsSecretValue) +} + +func testAccAWSCloudWatchEventConnectionConfig_invocationHttpParameters( + name, + description, + authorizationType, + key, + value string, + bodyKey string, + bodyValue string, + bodyIsSecretValue bool, + headerKey string, + headerValue string, + headerIsSecretValue bool, + queryStringKey string, + queryStringValue string, + queryStringIsSecretValue bool) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_connection" "invocation_http_parameters" { + name = %[1]q + description = %[2]q + authorization_type = %[3]q + auth_parameters { + api_key { + key = %[4]q + value = %[5]q + } + + invocation_http_parameters { + body { + key = %[6]q + value = %[7]q + is_value_secret = %[8]t + } + + body { + key = "second-%[6]s" + value = "second-%[7]s" + is_value_secret = %[8]t + } + + header { + key = %[9]q + value = %[10]q + is_value_secret = %[11]t + } + + header { + key = "second-%[9]s" + value = "second-%[10]s" + is_value_secret = %[11]t + } + + query_string { + key = %[12]q + value = %[13]q + is_value_secret = %[14]t + } + + query_string { + key = "second-%[12]s" + value = "second-%[13]s" + is_value_secret = %[14]t + } + } + } +} +`, name, + description, + authorizationType, + key, + value, + bodyKey, + bodyValue, + bodyIsSecretValue, + headerKey, + headerValue, + headerIsSecretValue, + queryStringKey, + queryStringValue, + queryStringIsSecretValue) +} diff --git a/website/docs/r/cloudwatch_event_api_destination.html.markdown b/website/docs/r/cloudwatch_event_api_destination.html.markdown new file mode 100644 index 00000000000..c2bf1eca05b --- /dev/null +++ b/website/docs/r/cloudwatch_event_api_destination.html.markdown @@ -0,0 +1,53 @@ +--- +subcategory: "EventBridge (CloudWatch Events)" +layout: "aws" +page_title: "AWS: aws_cloudwatch_event_api_destination" +description: |- + Provides an EventBridge event API Destination resource. +--- + +# Resource: aws_cloudwatch_event_api_destination + +Provides an EventBridge event API Destination resource. + +~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. + + +## Example Usage + +```terraform +resource "aws_cloudwatch_event_api_destination" "test" { + name = "api-destination" + description = "An API Destination" + invocation_endpoint = "https://api.destination.com/endpoint" + http_method = "POST" + invocation_rate_limit_per_second = 20 + connection_arn = aws_cloudwatch_event_connection.test.arn +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the new API Destination. The name must be unique for your account. Maximum of 64 characters consisting of numbers, lower/upper case letters, .,-,_. +* `description` - (Optional) The description of the new API Destination. Maximum of 512 characters. +* `invocation_endpoint` - (Required) URL endpoint to invoke as a target. This could be a valid endpoint generated by a partner service. You can include "*" as path parameters wildcards to be set from the Target HttpParameters. +* `http_method` - (Required) Select the HTTP method used for the invocation endpoint, such as GET, POST, PUT, etc. +* `invocation_rate_limit_per_second` - (Optional) Enter the maximum number of invocations per second to allow for this destination. Enter a value greater than 0 (default 300). +* `connection_arn` - (Required) ARN of the EventBridge Connection to use for the API Destination. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The Amazon Resource Name (ARN) of the event API Destination. + + +## Import + +EventBridge API Destinations can be imported using the `name`, e.g. + +```console +$ terraform import aws_cloudwatch_event_api_destination.test api-destination +``` diff --git a/website/docs/r/cloudwatch_event_connection.html.markdown b/website/docs/r/cloudwatch_event_connection.html.markdown new file mode 100644 index 00000000000..0bfc02384a3 --- /dev/null +++ b/website/docs/r/cloudwatch_event_connection.html.markdown @@ -0,0 +1,200 @@ +--- +subcategory: "EventBridge (CloudWatch Events)" +layout: "aws" +page_title: "AWS: aws_cloudwatch_event_connection" +description: |- + Provides an EventBridge connection resource. +--- + +# Resource: aws_cloudwatch_event_connection + +Provides an EventBridge connection resource. + +~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. + + +## Example Usage + +```terraform +resource "aws_cloudwatch_event_connection" "test" { + name = "ngrok-connection" + description = "A connection description" + authorization_type = "API_KEY" + + auth_parameters { + api_key { + key = "x-signature" + value = "1234" + } + } +} +``` + +## Example Usage Basic Authorization + +```terraform +resource "aws_cloudwatch_event_connection" "test" { + name = "ngrok-connection" + description = "A connection description" + authorization_type = "BASIC" + + auth_parameters { + basic { + username = "user" + password = "Pass1234!" + } + } +} +``` + +## Example Usage OAuth Authorization + +```terraform +resource "aws_cloudwatch_event_connection" "test" { + name = "ngrok-connection" + description = "A connection description" + authorization_type = "BASIC" + + auth_parameters { + oauth { + authorization_endpoint = "https://auth.url.com/endpoint" + http_method = "GET" + + client_parameters { + client_id = "1234567890" + client_secret = "Pass1234!" + } + + oauth_http_parameters { + body { + key = "body-parameter-key" + value = "body-parameter-value" + is_value_secret = false + } + + header { + key = "header-parameter-key" + value = "header-parameter-value" + is_value_secret = false + } + + query_string { + key = "query-string-parameter-key" + value = "query-string-parameter-value" + is_value_secret = false + } + } + } + } +} +``` + +## Example Usage Invocation Http Parameters + +```terraform +resource "aws_cloudwatch_event_connection" "test" { + name = "ngrok-connection" + description = "A connection description" + authorization_type = "BASIC" + + auth_parameters { + basic { + username = "user" + password = "Pass1234!" + } + + invocation_http_parameters { + body { + key = "body-parameter-key" + value = "body-parameter-value" + is_value_secret = false + } + + body { + key = "body-parameter-key2" + value = "body-parameter-value2" + is_value_secret = true + } + + header { + key = "header-parameter-key" + value = "header-parameter-value" + is_value_secret = false + } + + query_string { + key = "query-string-parameter-key" + value = "query-string-parameter-value" + is_value_secret = false + } + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the new connection. Maximum of 64 characters consisting of numbers, lower/upper case letters, .,-,_. +* `description` - (Optional) Enter a description for the connection. Maximum of 512 characters. +* `authorization_type` - (Required) Choose the type of authorization to use to access the API destination. One of `API_KEY`,`BASIC`,`OAUTH_CLIENT_CREDENTIALS`. A secret for the connection is created and stored in AWS Secrets Manager. +* `auth_parameters` - (Required) Parameters used for authorization. A maximum of 1 are allowed. Documented below. +* `invocation_http_parameters` - (Optional) Invocation Http Parameters are additional credentials used to sign each Invocation of the ApiDestination created from this Connection. If the ApiDestination Rule Target has additional HttpParameters, the values will be merged together, with the Connection Invocation Http Parameters taking precedence. Secret values are stored and managed by AWS Secrets Manager. A maximum of 1 are allowed. Documented below. + +`auth_parameters` support the following: + +* `api_key` - (Optional) Parameters used for API_KEY authorization. An API key to include in the header for each authentication request. A maximum of 1 are allowed. Conflicts with `basic` and `oauth`. Documented below. +* `basic` - (Optional) Parameters used for BASIC authorization. A maximum of 1 are allowed. Conflicts with `api_key` and `oauth`. Documented below. +* `oauth` - (Optional) Parameters used for OAUTH_CLIENT_CREDENTIALS authorization. A maximum of 1 are allowed. Conflicts with `basic` and `api_key`. Documented below. + +`api_key` support the following: + +* `key` - (Required) Header Name. +* `value` - (Required) Header Value. Created and stored in AWS Secrets Manager. + +`basic` support the following: + +* `username` - (Required) A username for the authorization. +* `password` - (Required) A password for the authorization. Created and stored in AWS Secrets Manager. + +`oauth` support the following: + +* `authorization_endpoint` - (Required) A username for the authorization. +* `http_method` - (Required) A password for the authorization. Created and stored in AWS Secrets Manager. +* `client_parameters` - (Required) Contains the client parameters for OAuth authorization. Contains the following two parameters. + * `client_id` - (Required) The client ID for the credentials to use for authorization. Created and stored in AWS Secrets Manager. + * `client_secret` - (Required) The client secret for the credentials to use for authorization. Created and stored in AWS Secrets Manager. +* `oauth_http_parameters` - (Required) OAuth Http Parameters are additional credentials used to sign the request to the authorization endpoint to exchange the OAuth Client information for an access token. Secret values are stored and managed by AWS Secrets Manager. A maximum of 1 are allowed. Documented below. + +`invocation_http_parameters` and `oauth_http_parameters` support the following: + +* `body` - (Optional) Contains additional body string parameters for the connection. You can include up to 100 additional body string parameters per request. Each additional parameter counts towards the event payload size, which cannot exceed 64 KB. Each parameter can contain the following: + * `key` - (Required) The key for the parameter. + * `value` - (Required) The value associated with the key. Created and stored in AWS Secrets Manager if is secret. + * `is_value_secret` - (Optional) Specified whether the value is secret. + +* `header` - (Optional) Contains additional header parameters for the connection. You can include up to 100 additional body string parameters per request. Each additional parameter counts towards the event payload size, which cannot exceed 64 KB. Each parameter can contain the following: + * `key` - (Required) The key for the parameter. + * `value` - (Required) The value associated with the key. Created and stored in AWS Secrets Manager if is secret. + * `is_value_secret` - (Optional) Specified whether the value is secret. + +* `query_string` - (Optional) Contains additional query string parameters for the connection. You can include up to 100 additional body string parameters per request. Each additional parameter counts towards the event payload size, which cannot exceed 64 KB. Each parameter can contain the following: + * `key` - (Required) The key for the parameter. + * `value` - (Required) The value associated with the key. Created and stored in AWS Secrets Manager if is secret. + * `is_value_secret` - (Optional) Specified whether the value is secret. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The Amazon Resource Name (ARN) of the event bus. + + +## Import + +EventBridge Connection can be imported using the `name`, e.g. + +```console +$ terraform import aws_cloudwatch_event_connection.test ngrok-connection +``` From 3ce8b2359d646ea3aab30b04071225fceb0d563f Mon Sep 17 00:00:00 2001 From: bill-rich Date: Thu, 29 Apr 2021 13:33:32 -0700 Subject: [PATCH 004/398] Note for postgresql --- .../docs/r/rds_global_cluster.html.markdown | 112 ++++++++++++++---- 1 file changed, 92 insertions(+), 20 deletions(-) diff --git a/website/docs/r/rds_global_cluster.html.markdown b/website/docs/r/rds_global_cluster.html.markdown index 8a47ab5876d..04b3043fa8f 100644 --- a/website/docs/r/rds_global_cluster.html.markdown +++ b/website/docs/r/rds_global_cluster.html.markdown @@ -14,7 +14,60 @@ More information about Aurora global databases can be found in the [Aurora User ## Example Usage -### New Global Cluster +### New MySQL Global Cluster + +```terraform +resource "aws_rds_global_cluster" "example" { + global_cluster_identifier = "global-test" + engine = "aurora" + engine_version = "5.6.mysql_aurora.1.22.2" + database_name = "example_db" +} + +resource "aws_rds_cluster" "primary" { + provider = aws.primary + engine = "aurora" + engine_version = "5.6.mysql_aurora.1.22.2" + cluster_identifier = "test-primary-cluster" + master_username = "username" + master_password = "somepass123" + database_name = "example_db" + global_cluster_identifier = aws_rds_global_cluster.example.id + db_subnet_group_name = "default" +} + +resource "aws_rds_cluster_instance" "primary" { + provider = aws.primary + identifier = "test-primary-cluster-instance" + cluster_identifier = aws_rds_cluster.primary.id + instance_class = "db.r4.large" + db_subnet_group_name = "default" +} + +resource "aws_rds_cluster" "secondary" { + provider = aws.secondary + engine = "aurora" + engine_version = "5.6.mysql_aurora.1.22.2" + cluster_identifier = "test-secondary-cluster" + global_cluster_identifier = aws_rds_global_cluster.example.id + db_subnet_group_name = "default" +} + +resource "aws_rds_cluster_instance" "secondary" { + provider = aws.secondary + identifier = "test-secondary-cluster-instance" + cluster_identifier = aws_rds_cluster.secondary.id + instance_class = "db.r4.large" + db_subnet_group_name = "default" + + depends_on = [ + aws_rds_cluster_instance.primary + ] +} +``` + +### New PostgreSQL Global Cluster + ```terraform provider "aws" { @@ -24,45 +77,64 @@ provider "aws" { provider "aws" { alias = "secondary" - region = "us-west-2" + region = "us-east-1" } resource "aws_rds_global_cluster" "example" { - provider = aws.primary - - global_cluster_identifier = "example" + global_cluster_identifier = "global-test" + engine = "aurora-postgresql" + engine_version = "11.9" + database_name = "example_db" } resource "aws_rds_cluster" "primary" { - provider = aws.primary - - # ... other configuration ... + provider = aws.primary + engine = "aurora-postgresql" + engine_version = "11.9" + cluster_identifier = "test-primary-cluster" + master_username = "username" + master_password = "somepass123" + database_name = "example_db" global_cluster_identifier = aws_rds_global_cluster.example.id + db_subnet_group_name = "default" } resource "aws_rds_cluster_instance" "primary" { - provider = aws.primary - - # ... other configuration ... - cluster_identifier = aws_rds_cluster.primary.id + provider = aws.primary + engine = "aurora-postgresql" + engine_version = "11.9" + identifier = "test-primary-cluster-instance" + cluster_identifier = aws_rds_cluster.primary.id + instance_class = "db.r4.large" + db_subnet_group_name = "default" } resource "aws_rds_cluster" "secondary" { - depends_on = [aws_rds_cluster_instance.primary] - provider = aws.secondary - - # ... other configuration ... + provider = aws.secondary + engine = "aurora-postgresql" + engine_version = "11.9" + cluster_identifier = "test-secondary-cluster" global_cluster_identifier = aws_rds_global_cluster.example.id + skip_final_snapshot = true + db_subnet_group_name = "default" + + depends_on = [ + aws_rds_cluster_instance.primary + ] } resource "aws_rds_cluster_instance" "secondary" { - provider = aws.secondary - - # ... other configuration ... - cluster_identifier = aws_rds_cluster.secondary.id + provider = aws.secondary + engine = "aurora-postgresql" + engine_version = "11.9" + identifier = "test-secondary-cluster-instance" + cluster_identifier = aws_rds_cluster.secondary.id + instance_class = "db.r4.large" + db_subnet_group_name = "default" } ``` + ### New Global Cluster From Existing DB Cluster ```terraform From 5206ed0086c5c07389543a612d47be24839f0143 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 13 May 2021 08:34:28 -0400 Subject: [PATCH 005/398] hashibot: Remove deprecated_import_commenter behavior Reference: https://github.com/hashicorp/terraform-provider-aws/issues/19356 --- .hashibot.hcl | 59 --------------------------------------------------- 1 file changed, 59 deletions(-) diff --git a/.hashibot.hcl b/.hashibot.hcl index a9dbcacc9d4..01441af8f70 100644 --- a/.hashibot.hcl +++ b/.hashibot.hcl @@ -11,65 +11,6 @@ poll "closed_issue_locker" "locker" { EOF } -behavior "deprecated_import_commenter" "hashicorp_terraform" { - import_regexp = "github.com/hashicorp/terraform/" - marker_label = "terraform-plugin-sdk-migration" - - message = <<-EOF - Hello, and thank you for your contribution! - - This project recently migrated to the [standalone Terraform Plugin SDK](https://www.terraform.io/docs/extend/plugin-sdk.html). While the migration helps speed up future feature requests and bug fixes to the Terraform AWS Provider's interface with Terraform, it has the unfortunate consequence of requiring minor changes to pull requests created using the old SDK. - - This pull request appears to include the Go import path `${var.import_path}`, which was from the older SDK. The newer SDK uses import paths beginning with `github.com/hashicorp/terraform-plugin-sdk/`. - - To resolve this situation without losing any existing work, you may be able to Git rebase your branch against the current default (main) branch (example below); replacing any remaining old import paths with the newer ones. - - ```console - $ git fetch --all - $ git rebase origin/main - ``` - - Another option is to create a new branch from the current default (main) with the same code changes (replacing the import paths), submit a new pull request, and close this existing pull request. - - We apologize for this inconvenience and appreciate your effort. Thank you for contributing and helping make the Terraform AWS Provider better for everyone. - EOF -} - -behavior "deprecated_import_commenter" "sdkv1" { - import_regexp = "github.com/hashicorp/terraform-plugin-sdk/(helper/(acctest|customdiff|logging|resource|schema|structure|validation)|terraform)" - marker_label = "terraform-plugin-sdk-v1" - - message = <<-EOF - Hello, and thank you for your contribution! - - This project recently upgraded to [V2 of the Terraform Plugin SDK](https://www.terraform.io/docs/extend/guides/v2-upgrade-guide.html) - - This pull request appears to include at least one V1 import path of the SDK (`${var.import_path}`). Please import the V2 path `github.com/hashicorp/terraform-plugin-sdk/v2/helper/PACKAGE` - - To resolve this situation without losing any existing work, you may be able to Git rebase your branch against the current default (main) branch (example below); replacing any remaining old import paths with the newer ones. - - ```console - $ git fetch --all - $ git rebase origin/main - ``` - - Another option is to create a new branch from the current default (main) with the same code changes (replacing the import paths), submit a new pull request, and close this existing pull request. - - We apologize for this inconvenience and appreciate your effort. Thank you for contributing and helping make the Terraform AWS Provider better for everyone. - EOF -} - -behavior "deprecated_import_commenter" "sdkv1_deprecated" { - import_regexp = "github.com/hashicorp/terraform-plugin-sdk/helper/(hashcode|mutexkv|encryption)" - marker_label = "terraform-plugin-sdk-v1" - - message = <<-EOF - Hello, and thank you for your contribution! - This pull request appears to include the Go import path `${var.import_path}`, which was deprecated after upgrading to [V2 of the Terraform Plugin SDK](https://www.terraform.io/docs/extend/guides/v2-upgrade-guide.html). - You may use a now internalized version of the package found in `github.com/terraform-providers/terraform-provider-aws/aws/internal/PACKAGE`. - EOF -} - queued_behavior "release_commenter" "releases" { repo_prefix = "terraform-provider-" From 39aff9abfcc3fd1586679ae64423c8afb61dd037 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Thu, 13 May 2021 16:01:24 -0700 Subject: [PATCH 006/398] Added schema and expand/flatten functions for customizing wafv2 allow/block/count actions --- aws/resource_aws_wafv2_web_acl.go | 24 +-- aws/wafv2_helper.go | 311 +++++++++++++++++++++++++++++- 2 files changed, 317 insertions(+), 18 deletions(-) diff --git a/aws/resource_aws_wafv2_web_acl.go b/aws/resource_aws_wafv2_web_acl.go index 50a46a5f0b4..1f4c7894287 100644 --- a/aws/resource_aws_wafv2_web_acl.go +++ b/aws/resource_aws_wafv2_web_acl.go @@ -59,8 +59,8 @@ func resourceAwsWafv2WebACL() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "allow": wafv2EmptySchema(), - "block": wafv2EmptySchema(), + "allow": wafv2AllowConfigSchema(), + "block": wafv2BlockConfigSchema(), }, }, }, @@ -102,9 +102,9 @@ func resourceAwsWafv2WebACL() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "allow": wafv2EmptySchema(), - "block": wafv2EmptySchema(), - "count": wafv2EmptySchema(), + "allow": wafv2AllowConfigSchema(), + "block": wafv2BlockConfigSchema(), + "count": wafv2CountConfigSchema(), }, }, }, @@ -119,7 +119,7 @@ func resourceAwsWafv2WebACL() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "count": wafv2EmptySchema(), + "count": wafv2CountConfigSchema(), "none": wafv2EmptySchema(), }, }, @@ -519,7 +519,7 @@ func expandWafv2OverrideAction(l []interface{}) *wafv2.OverrideAction { action := &wafv2.OverrideAction{} if v, ok := m["count"]; ok && len(v.([]interface{})) > 0 { - action.Count = &wafv2.CountAction{} + action.Count = expandWafv2CountAction(v.([]interface{})) } if v, ok := m["none"]; ok && len(v.([]interface{})) > 0 { @@ -538,11 +538,11 @@ func expandWafv2DefaultAction(l []interface{}) *wafv2.DefaultAction { action := &wafv2.DefaultAction{} if v, ok := m["allow"]; ok && len(v.([]interface{})) > 0 { - action.Allow = &wafv2.AllowAction{} + action.Allow = expandWafv2AllowAction(v.([]interface{})) } if v, ok := m["block"]; ok && len(v.([]interface{})) > 0 { - action.Block = &wafv2.BlockAction{} + action.Block = expandWafv2BlockAction(v.([]interface{})) } return action @@ -790,7 +790,7 @@ func flattenWafv2OverrideAction(a *wafv2.OverrideAction) interface{} { m := map[string]interface{}{} if a.Count != nil { - m["count"] = make([]map[string]interface{}, 1) + m["count"] = flattenWafv2Count(a.Count) } if a.None != nil { @@ -808,11 +808,11 @@ func flattenWafv2DefaultAction(a *wafv2.DefaultAction) interface{} { m := map[string]interface{}{} if a.Allow != nil { - m["allow"] = make([]map[string]interface{}, 1) + m["allow"] = flattenWafv2Allow(a.Allow) } if a.Block != nil { - m["block"] = make([]map[string]interface{}, 1) + m["block"] = flattenWafv2Block(a.Block) } return []interface{}{m} diff --git a/aws/wafv2_helper.go b/aws/wafv2_helper.go index 32f12615529..dd9d9efb261 100644 --- a/aws/wafv2_helper.go +++ b/aws/wafv2_helper.go @@ -417,6 +417,125 @@ func wafv2VisibilityConfigSchema() *schema.Schema { } } +func wafv2AllowConfigSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "custom_request_handling": wafv2CustomRequestHandlingSchema(), + }, + }, + } +} + +func wafv2CountConfigSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "custom_request_handling": wafv2CustomRequestHandlingSchema(), + }, + }, + } +} + +func wafv2BlockConfigSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "custom_response": wafv2CustomResponseSchema(), + }, + }, + } +} + +func wafv2CustomRequestHandlingSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "insert_headers": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 64), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9._$-]+$`), "must contain only alphanumeric hyphen, underscore, dot and $ characters"), + ), + }, + "value": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + }, + }, + }, + }, + }, + } +} + +func wafv2CustomResponseSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "custom_response_body_key": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 128), + validation.StringMatch(regexp.MustCompile(`^[\w\-]+$`), "must contain only alphanumeric or hyphen characters"), + ), + }, + "response_code": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(200, 599), + }, + "response_headers": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 64), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9._$-]+$`), "must contain only alphanumeric hyphen, underscore, dot and $ characters"), + ), + }, + "value": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + }, + }, + }, + }, + }, + } +} + func expandWafv2Rules(l []interface{}) []*wafv2.Rule { if len(l) == 0 || l[0] == nil { return nil @@ -457,20 +576,119 @@ func expandWafv2RuleAction(l []interface{}) *wafv2.RuleAction { action := &wafv2.RuleAction{} if v, ok := m["allow"]; ok && len(v.([]interface{})) > 0 { - action.Allow = &wafv2.AllowAction{} + action.Allow = expandWafv2AllowAction(v.([]interface{})) } if v, ok := m["block"]; ok && len(v.([]interface{})) > 0 { - action.Block = &wafv2.BlockAction{} + action.Block = expandWafv2BlockAction(v.([]interface{})) } if v, ok := m["count"]; ok && len(v.([]interface{})) > 0 { - action.Count = &wafv2.CountAction{} + action.Count = expandWafv2CountAction(v.([]interface{})) + } + + return action +} + +func expandWafv2AllowAction(l []interface{}) *wafv2.AllowAction { + action := &wafv2.AllowAction{} + if len(l) == 0 || l[0] == nil { + return action + } + + m := l[0].(map[string]interface{}) + if v, ok := m["custom_request_handling"]; ok && len(v.([]interface{})) > 0 { + action.CustomRequestHandling = expandWafv2CustomRequestHandling(v.([]interface{})) + } + + return action +} + +func expandWafv2CountAction(l []interface{}) *wafv2.CountAction { + action := &wafv2.CountAction{} + if len(l) == 0 || l[0] == nil { + return action + } + + m := l[0].(map[string]interface{}) + if v, ok := m["custom_request_handling"]; ok && len(v.([]interface{})) > 0 { + action.CustomRequestHandling = expandWafv2CustomRequestHandling(v.([]interface{})) + } + + return action +} + +func expandWafv2BlockAction(l []interface{}) *wafv2.BlockAction { + action := &wafv2.BlockAction{} + if len(l) == 0 || l[0] == nil { + return action + } + + m := l[0].(map[string]interface{}) + if v, ok := m["custom_response"]; ok && len(v.([]interface{})) > 0 { + action.CustomResponse = expandWafv2CustomResponse(v.([]interface{})) } return action } +func expandWafv2CustomResponse(l []interface{}) *wafv2.CustomResponse { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + customResponse := &wafv2.CustomResponse{} + + if v, ok := m["response_code"]; ok && v.(int) > 0 { + customResponse.ResponseCode = aws.Int64(int64(v.(int))) + } + if v, ok := m["response_headers"]; ok && len(v.([]interface{})) > 0 { + customResponse.ResponseHeaders = expandWafv2CustomHeaders(v.([]interface{})) + } + if v, ok := m["custom_response_body_key"]; ok && len(v.(string)) > 0 { + customResponse.CustomResponseBodyKey = aws.String(v.(string)) + } + + return customResponse +} + +func expandWafv2CustomRequestHandling(l []interface{}) *wafv2.CustomRequestHandling { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + requestHandling := &wafv2.CustomRequestHandling{} + + if v, ok := m["insert_headers"]; ok && len(v.([]interface{})) > 0 { + requestHandling.InsertHeaders = expandWafv2CustomHeaders(v.([]interface{})) + } + + return requestHandling +} + +func expandWafv2CustomHeaders(l []interface{}) []*wafv2.CustomHTTPHeader { + if len(l) == 0 || l[0] == nil { + return nil + } + + headers := make([]*wafv2.CustomHTTPHeader, 0) + + for _, header := range l { + if header == nil { + continue + } + m := header.(map[string]interface{}) + headers = append(headers, &wafv2.CustomHTTPHeader{ + Name: aws.String(m["name"].(string)), + Value: aws.String(m["value"].(string)), + }) + } + + return headers +} + func expandWafv2VisibilityConfig(l []interface{}) *wafv2.VisibilityConfig { if len(l) == 0 || l[0] == nil { return nil @@ -862,15 +1080,96 @@ func flattenWafv2RuleAction(a *wafv2.RuleAction) interface{} { m := map[string]interface{}{} if a.Allow != nil { - m["allow"] = make([]map[string]interface{}, 1) + m["allow"] = flattenWafv2Allow(a.Allow) } if a.Block != nil { - m["block"] = make([]map[string]interface{}, 1) + m["block"] = flattenWafv2Block(a.Block) } if a.Count != nil { - m["count"] = make([]map[string]interface{}, 1) + m["count"] = flattenWafv2Count(a.Count) + } + + return []interface{}{m} +} + +func flattenWafv2Allow(a *wafv2.AllowAction) interface{} { + if a == nil { + return map[string]interface{}{} + } + m := map[string]interface{}{ + "custom_request_handling": flattenWafv2CustomRequestHandling(a.CustomRequestHandling), + } + + return []interface{}{m} +} + +func flattenWafv2Block(a *wafv2.BlockAction) interface{} { + if a == nil { + return map[string]interface{}{} + } + m := map[string]interface{}{ + "custom_response": flattenWafv2CustomResponse(a.CustomResponse), + } + + return []interface{}{m} +} + +func flattenWafv2Count(a *wafv2.CountAction) interface{} { + if a == nil { + return map[string]interface{}{} + } + m := map[string]interface{}{ + "custom_request_handling": flattenWafv2CustomRequestHandling(a.CustomRequestHandling), + } + + return []interface{}{m} +} + +func flattenWafv2CustomRequestHandling(c *wafv2.CustomRequestHandling) interface{} { + if c == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "insert_headers": flattenWafv2CustomHeaders(c.InsertHeaders), + } + + return []interface{}{m} +} + +func flattenWafv2CustomResponse(r *wafv2.CustomResponse) interface{} { + if r == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "custom_response_body_key": aws.StringValue(r.CustomResponseBodyKey), + "response_code": int(aws.Int64Value(r.ResponseCode)), + "response_headers": flattenWafv2CustomHeaders(r.ResponseHeaders), + } + + return []interface{}{m} +} + +func flattenWafv2CustomHeaders(h []*wafv2.CustomHTTPHeader) interface{} { + out := make([]interface{}, len(h)) + for i, header := range h { + out[i] = flattenWafv2CustomHeader(header) + } + + return out +} + +func flattenWafv2CustomHeader(h *wafv2.CustomHTTPHeader) interface{} { + if h == nil { + return map[string]interface{}{} + } + + m := map[string]interface{}{ + "name": aws.StringValue(h.Name), + "value": aws.StringValue(h.Value), } return []interface{}{m} From f921a0cf245e9440a9377561f8ec8fc242dd6fc7 Mon Sep 17 00:00:00 2001 From: no-brand Date: Sat, 15 May 2021 22:08:36 +0900 Subject: [PATCH 007/398] resource/aws_glue_connection: ConnectionProperties to be opional ConnectionProperties is key-value pairs, and it's not mandatory field. --- aws/resource_aws_glue_connection.go | 8 +- aws/resource_aws_glue_connection_test.go | 88 ++++++++++++++++++++ website/docs/r/glue_connection.html.markdown | 2 +- 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_glue_connection.go b/aws/resource_aws_glue_connection.go index 229fd7d375d..5fccb888fb0 100644 --- a/aws/resource_aws_glue_connection.go +++ b/aws/resource_aws_glue_connection.go @@ -35,7 +35,7 @@ func resourceAwsGlueConnection() *schema.Resource { }, "connection_properties": { Type: schema.TypeMap, - Required: true, + Optional: true, Sensitive: true, ValidateFunc: MapKeyInSlice(glue.ConnectionPropertyKey_Values(), false), Elem: &schema.Schema{Type: schema.TypeString}, @@ -243,8 +243,10 @@ func deleteGlueConnection(conn *glue.Glue, catalogID, connectionName string) err func expandGlueConnectionInput(d *schema.ResourceData) *glue.ConnectionInput { connectionProperties := make(map[string]string) - for k, v := range d.Get("connection_properties").(map[string]interface{}) { - connectionProperties[k] = v.(string) + if val, ok := d.GetOkExists("connection_properties"); ok { + for k, v := range val.(map[string]interface{}) { + connectionProperties[k] = v.(string) + } } connectionInput := &glue.ConnectionInput{ diff --git a/aws/resource_aws_glue_connection_test.go b/aws/resource_aws_glue_connection_test.go index 916a63a7980..3f75319aae1 100644 --- a/aws/resource_aws_glue_connection_test.go +++ b/aws/resource_aws_glue_connection_test.go @@ -157,6 +157,40 @@ 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)) + resourceName := "aws_glue_connection.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSGlueConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSGlueConnectionConfig_Network(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSGlueConnectionExists(resourceName, &connection), + resource.TestCheckResourceAttr(resourceName, "connection_properties.%", "0"), + resource.TestCheckResourceAttr(resourceName, "connection_type", "NETWORK"), + resource.TestCheckResourceAttr(resourceName, "match_criteria.#", "0"), + resource.TestCheckResourceAttr(resourceName, "physical_connection_requirements.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "physical_connection_requirements.0.availability_zone"), + resource.TestCheckResourceAttr(resourceName, "physical_connection_requirements.0.security_group_id_list.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "physical_connection_requirements.0.subnet_id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSGlueConnection_Description(t *testing.T) { var connection glue.Connection @@ -564,3 +598,57 @@ resource "aws_glue_connection" "test" { } `, rName) } + +func testAccAWSGlueConnectionConfig_Network(rName string) string { + return fmt.Sprintf(` +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = "terraform-testacc-glue-connection-network" + } +} + +resource "aws_subnet" "test" { + availability_zone = data.aws_availability_zones.available.names[0] + cidr_block = "10.0.0.0/24" + vpc_id = aws_vpc.test.id + + tags = { + Name = "terraform-testacc-glue-connection-network" + } +} + +resource "aws_security_group" "test" { + name = "%[1]s" + vpc_id = aws_vpc.test.id + + ingress { + protocol = "tcp" + self = true + from_port = 1 + to_port = 65535 + } +} + +resource "aws_glue_connection" "test" { + connection_type = "NETWORK" + name = "%[1]s" + + physical_connection_requirements { + availability_zone = aws_subnet.test.availability_zone + security_group_id_list = [aws_security_group.test.id] + subnet_id = aws_subnet.test.id + } +} +`, rName) +} diff --git a/website/docs/r/glue_connection.html.markdown b/website/docs/r/glue_connection.html.markdown index 51544bb7b7e..a3bfaea58f4 100644 --- a/website/docs/r/glue_connection.html.markdown +++ b/website/docs/r/glue_connection.html.markdown @@ -53,7 +53,7 @@ resource "aws_glue_connection" "example" { The following arguments are supported: * `catalog_id` – (Optional) The ID of the Data Catalog in which to create the connection. If none is supplied, the AWS account ID is used by default. -* `connection_properties` – (Required) A map of key-value pairs used as parameters for this connection. +* `connection_properties` – (Optional) A map of key-value pairs used as parameters for this connection. * `connection_type` – (Optional) The type of the connection. Supported are: `JDBC`, `MONGODB`, `KAFKA`, and `NETWORK`. Defaults to `JBDC`. * `description` – (Optional) Description of the connection. * `match_criteria` – (Optional) A list of criteria that can be used in selecting this connection. From 6dbbe185b581ffa1afd255cd4d192d16346e2c9b Mon Sep 17 00:00:00 2001 From: Michal Matysiak Date: Mon, 17 May 2021 08:58:00 +0100 Subject: [PATCH 008/398] Use service_account_role_arn if already provided. AddonUpdateInput: // The Amazon Resource Name (ARN) of an existing IAM role to bind to the add-on's // service account. The role must be assigned the IAM permissions required by // the add-on. If you don't specify an existing IAM role, then the add-on uses // the permissions assigned to the node IAM role. For more information, see // Amazon EKS node IAM role (https://docs.aws.amazon.com/eks/latest/userguide/create-node-role.html) // in the Amazon EKS User Guide. --- aws/resource_aws_eks_addon.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_eks_addon.go b/aws/resource_aws_eks_addon.go index e2ea7dafd86..47e26946131 100644 --- a/aws/resource_aws_eks_addon.go +++ b/aws/resource_aws_eks_addon.go @@ -241,7 +241,9 @@ func resourceAwsEksAddonUpdate(ctx context.Context, d *schema.ResourceData, meta input.AddonVersion = aws.String(d.Get("addon_version").(string)) } - if d.HasChange("service_account_role_arn") { + // 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") != nil { input.ServiceAccountRoleArn = aws.String(d.Get("service_account_role_arn").(string)) } From 0fff3101dbca2bcdc50cb9ead09a1d3e351fbab4 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Mon, 17 May 2021 14:48:12 -0700 Subject: [PATCH 009/398] Added changes to the changelog --- .changelog/19415.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/19415.txt diff --git a/.changelog/19415.txt b/.changelog/19415.txt new file mode 100644 index 00000000000..483c7aa2360 --- /dev/null +++ b/.changelog/19415.txt @@ -0,0 +1,7 @@ +```release-notes:enhancement +resource/aws_wafv2_web_acl: Add `custom_request_handling` to `allow` and `count` actions. +``` + +```release-notes:enhancement +resource/aws_wafv2_web_acl: Add `custom_response` to `block` actions. +``` \ No newline at end of file From d5fa36e432e65d5af5b8fc33b8954a3076c4ed84 Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Thu, 6 Feb 2020 21:49:23 +0900 Subject: [PATCH 010/398] Add aws_amplify_app resource --- aws/provider.go | 1 + aws/resource_aws_amplify_app.go | 647 +++++++++++++++++++ aws/resource_aws_amplify_app_test.go | 783 +++++++++++++++++++++++ website/allowed-subcategories.txt | 1 + website/docs/r/amplify_app.html.markdown | 187 ++++++ 5 files changed, 1619 insertions(+) create mode 100644 aws/resource_aws_amplify_app.go create mode 100644 aws/resource_aws_amplify_app_test.go create mode 100644 website/docs/r/amplify_app.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 9e6ef2c3179..7862d1bf677 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -447,6 +447,7 @@ func Provider() *schema.Provider { "aws_ami_copy": resourceAwsAmiCopy(), "aws_ami_from_instance": resourceAwsAmiFromInstance(), "aws_ami_launch_permission": resourceAwsAmiLaunchPermission(), + "aws_amplify_app": resourceAwsAmplifyApp(), "aws_api_gateway_account": resourceAwsApiGatewayAccount(), "aws_api_gateway_api_key": resourceAwsApiGatewayApiKey(), "aws_api_gateway_authorizer": resourceAwsApiGatewayAuthorizer(), diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go new file mode 100644 index 00000000000..e2aafd320b6 --- /dev/null +++ b/aws/resource_aws_amplify_app.go @@ -0,0 +1,647 @@ +package aws + +import ( + "encoding/base64" + "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 resourceAwsAmplifyApp() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAmplifyAppCreate, + Read: resourceAwsAmplifyAppRead, + Update: resourceAwsAmplifyAppUpdate, + Delete: resourceAwsAmplifyAppDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "auto_branch_creation_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auto_branch_creation_patterns": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "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), + }, + }, + }, + }, + "build_spec": { + Type: schema.TypeString, + Optional: true, + }, + "enable_auto_branch_creation": { + Type: schema.TypeBool, + Optional: true, + }, + "enable_auto_build": { + 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, + }, + "stage": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // stage is "NONE" by default + if old == "NONE" && new == "" { + return true + } + return false + }, + ValidateFunc: validation.StringInSlice([]string{ + amplify.StageProduction, + amplify.StageBeta, + amplify.StageDevelopment, + amplify.StageExperimental, + amplify.StagePullRequest, + }, false), + }, + }, + }, + }, + "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), + }, + }, + }, + }, + "build_spec": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "custom_rules": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "condition": { + Type: schema.TypeString, + Optional: true, + }, + "source": { + Type: schema.TypeString, + Required: true, + }, + "status": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "200", + "301", + "302", + "404", + }, false), + }, + "target": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "default_domain": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "enable_branch_auto_build": { + Type: schema.TypeBool, + Optional: true, + }, + "environment_variables": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "iam_service_role_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(3, 1024), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9_-]+$`), "should only contains letters, numbers, _ and -"), + ), + }, + "platform": { + Type: schema.TypeString, + Optional: true, + Default: amplify.PlatformWeb, + ValidateFunc: validation.StringInSlice([]string{ + amplify.PlatformWeb, + }, false), + }, + "repository": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "oauth_token": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + "access_token": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + "tags": tagsSchema(), + }, + } +} + +func resourceAwsAmplifyAppCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Print("[DEBUG] Creating Amplify App") + + params := &lify.CreateAppInput{ + Name: aws.String(d.Get("name").(string)), + } + + if v, ok := d.GetOk("auto_branch_creation_config"); ok { + config, patterns, enable := expandAmplifyAutoBranchCreationConfig(v.([]interface{})) + params.AutoBranchCreationConfig = config + params.AutoBranchCreationPatterns = patterns + params.EnableAutoBranchCreation = enable + } + + 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("custom_rules"); ok { + params.CustomRules = expandAmplifyCustomRules(v.([]interface{})) + } + + if v, ok := d.GetOk("description"); ok { + params.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("enable_branch_auto_build"); ok { + params.EnableBranchAutoBuild = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("environment_variables"); ok { + params.EnvironmentVariables = stringMapToPointers(v.(map[string]interface{})) + } + + if v, ok := d.GetOk("iam_service_role_arn"); ok { + params.IamServiceRoleArn = aws.String(v.(string)) + } + + if v, ok := d.GetOk("platform"); ok { + params.Platform = aws.String(v.(string)) + } + + if v, ok := d.GetOk("repository"); ok { + params.Repository = aws.String(v.(string)) + } + + if v, ok := d.GetOk("access_token"); ok { + params.AccessToken = aws.String(v.(string)) + } + + if v, ok := d.GetOk("oauth_token"); ok { + params.OauthToken = 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.CreateApp(params) + if err != nil { + return fmt.Errorf("Error creating Amplify App: %s", err) + } + + d.SetId(*resp.App.AppId) + + return resourceAwsAmplifyAppRead(d, meta) +} + +func resourceAwsAmplifyAppRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Reading Amplify App: %s", d.Id()) + + resp, err := conn.GetApp(&lify.GetAppInput{ + AppId: aws.String(d.Id()), + }) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == amplify.ErrCodeNotFoundException { + log.Printf("[WARN] Amplify App (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + return err + } + + d.Set("arn", resp.App.AppArn) + if err := d.Set("auto_branch_creation_config", flattenAmplifyAutoBranchCreationConfig(resp.App.AutoBranchCreationConfig, resp.App.AutoBranchCreationPatterns, resp.App.EnableAutoBranchCreation)); err != nil { + return fmt.Errorf("error setting auto_branch_creation_config: %s", err) + } + if err := d.Set("basic_auth_config", flattenAmplifyBasicAuthConfig(resp.App.EnableBasicAuth, resp.App.BasicAuthCredentials)); err != nil { + return fmt.Errorf("error setting basic_auth_config: %s", err) + } + d.Set("build_spec", resp.App.BuildSpec) + if err := d.Set("custom_rules", flattenAmplifyCustomRules(resp.App.CustomRules)); err != nil { + return fmt.Errorf("error setting custom_rules: %s", err) + } + d.Set("default_domain", resp.App.DefaultDomain) + d.Set("description", resp.App.Description) + d.Set("enable_branch_auto_build", resp.App.EnableBranchAutoBuild) + if err := d.Set("environment_variables", aws.StringValueMap(resp.App.EnvironmentVariables)); err != nil { + return fmt.Errorf("error setting environment_variables: %s", err) + } + d.Set("iam_service_role_arn", resp.App.IamServiceRoleArn) + d.Set("name", resp.App.Name) + d.Set("platform", resp.App.Platform) + d.Set("repository", resp.App.Repository) + if err := d.Set("tags", keyvaluetags.AmplifyKeyValueTags(resp.App.Tags).IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} + +func resourceAwsAmplifyAppUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Updating Amplify App: %s", d.Id()) + + params := &lify.UpdateAppInput{ + AppId: aws.String(d.Id()), + } + + if d.HasChange("auto_branch_creation_config") { + v := d.Get("auto_branch_creation_config") + config, patterns, enable := expandAmplifyAutoBranchCreationConfig(v.([]interface{})) + params.AutoBranchCreationConfig = config + params.AutoBranchCreationPatterns = patterns + params.EnableAutoBranchCreation = enable + } + + 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("custom_rules") { + params.CustomRules = expandAmplifyCustomRules(d.Get("custom_rules").([]interface{})) + } + + if d.HasChange("description") { + params.Description = aws.String(d.Get("description").(string)) + } + + if d.HasChange("enable_branch_auto_build") { + params.EnableBranchAutoBuild = aws.Bool(d.Get("enable_branch_auto_build").(bool)) + } + + if d.HasChange("environment_variables") { + v := d.Get("environment_variables") + params.EnvironmentVariables = expandAmplifyEnvironmentVariables(v.(map[string]interface{})) + } + + if d.HasChange("iam_service_role_arn") { + params.IamServiceRoleArn = aws.String(d.Get("iam_service_role_arn").(string)) + } + + if d.HasChange("name") { + params.Name = aws.String(d.Get("name").(string)) + } + + if d.HasChange("platform") { + params.Platform = aws.String(d.Get("platform").(string)) + } + + if d.HasChange("repository") { + params.Repository = aws.String(d.Get("repository").(string)) + } + + if v, ok := d.GetOk("access_token"); ok { + params.AccessToken = aws.String(v.(string)) + } + + if v, ok := d.GetOk("oauth_token"); ok { + params.OauthToken = aws.String(v.(string)) + } + + _, err := conn.UpdateApp(params) + if err != nil { + return fmt.Errorf("Error updating Amplify App: %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 resourceAwsAmplifyAppRead(d, meta) +} + +func resourceAwsAmplifyAppDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Deleting Amplify App: %s", d.Id()) + + err := deleteAmplifyApp(conn, d.Id()) + if err != nil { + return fmt.Errorf("Error deleting Amplify App: %s", err) + } + + return nil +} + +func deleteAmplifyApp(conn *amplify.Amplify, appId string) error { + params := &lify.DeleteAppInput{ + AppId: aws.String(appId), + } + + _, err := conn.DeleteApp(params) + return err +} + +func expandAmplifyEnvironmentVariables(envs map[string]interface{}) map[string]*string { + if len(envs) == 0 { + empty := "" + return map[string]*string{"": &empty} + } else { + return stringMapToPointers(envs) + } +} + +func expandAmplifyAutoBranchCreationConfig(v []interface{}) (*amplify.AutoBranchCreationConfig, []*string, *bool) { + config := &lify.AutoBranchCreationConfig{} + patterns := make([]*string, 0) + enable := aws.Bool(false) + + if len(v) == 0 { + return config, patterns, enable + } + + e := v[0].(map[string]interface{}) + + if ev, ok := e["auto_branch_creation_patterns"]; ok && len(ev.([]interface{})) > 0 { + patterns = expandStringList(ev.([]interface{})) + } + + if ev, ok := e["basic_auth_config"]; ok { + enable, credentials := expandAmplifyBasicAuthConfig(ev.([]interface{})) + config.EnableBasicAuth = enable + config.BasicAuthCredentials = credentials + } + + if ev, ok := e["build_spec"].(string); ok && ev != "" { + config.BuildSpec = aws.String(ev) + } + + if ev, ok := e["enable_auto_branch_creation"].(bool); ok { + enable = aws.Bool(ev) + } + + if ev, ok := e["enable_auto_build"].(bool); ok { + config.EnableAutoBuild = aws.Bool(ev) + } + + if ev, ok := e["enable_pull_request_preview"].(bool); ok { + config.EnablePullRequestPreview = aws.Bool(ev) + } + + if ev, ok := e["environment_variables"].(map[string]interface{}); ok { + config.EnvironmentVariables = expandAmplifyEnvironmentVariables(ev) + } + + if ev, ok := e["framework"].(string); ok { + config.Framework = aws.String(ev) + } + + if ev, ok := e["pull_request_environment_name"].(string); ok { + config.PullRequestEnvironmentName = aws.String(ev) + } + + if ev, ok := e["stage"].(string); ok { + config.Stage = aws.String(ev) + } + + return config, patterns, enable +} + +func flattenAmplifyAutoBranchCreationConfig(config *amplify.AutoBranchCreationConfig, patterns []*string, enable *bool) []map[string]interface{} { + value := make(map[string]interface{}) + + if !aws.BoolValue(enable) { + return nil + } + + value["enable_auto_branch_creation"] = aws.BoolValue(enable) + value["auto_branch_creation_patterns"] = patterns + + if config != nil { + value["basic_auth_config"] = flattenAmplifyBasicAuthConfig(config.EnableBasicAuth, config.BasicAuthCredentials) + value["build_spec"] = aws.StringValue(config.BuildSpec) + value["enable_auto_build"] = aws.BoolValue(config.EnableAutoBuild) + value["enable_pull_request_preview"] = aws.BoolValue(config.EnablePullRequestPreview) + value["environment_variables"] = aws.StringValueMap(config.EnvironmentVariables) + value["framework"] = aws.StringValue(config.Framework) + value["pull_request_environment_name"] = aws.StringValue(config.PullRequestEnvironmentName) + value["stage"] = aws.StringValue(config.Stage) + } + + return []map[string]interface{}{value} +} + +func expandAmplifyBasicAuthConfig(v []interface{}) (*bool, *string) { + enable := false + credentials := "" + + if len(v) == 0 { + return aws.Bool(enable), aws.String(credentials) + } + + config := v[0].(map[string]interface{}) + + if ev, ok := config["enable_basic_auth"].(bool); ok { + enable = ev + } + + // build basic_auth_credentials from raw username and password + username, ok1 := config["username"].(string) + password, ok2 := config["password"].(string) + if ok1 && ok2 { + credentials = encodeAmplifyBasicAuthCredentials(username, password) + } + + return aws.Bool(enable), aws.String(credentials) +} + +func flattenAmplifyBasicAuthConfig(enableBasicAuth *bool, basicAuthCredentials *string) []map[string]interface{} { + value := make(map[string]interface{}) + + if !aws.BoolValue(enableBasicAuth) { + return nil + } + + value["enable_basic_auth"] = aws.BoolValue(enableBasicAuth) + + if basicAuthCredentials != nil { + // Decode BasicAuthCredentials to username and password + username, password, _ := decodeAmplifyBasicAuthCredentials(aws.StringValue(basicAuthCredentials)) + value["username"] = username + value["password"] = password + } + + return []map[string]interface{}{value} +} + +func encodeAmplifyBasicAuthCredentials(username string, password string) string { + data := fmt.Sprintf("%s:%s", username, password) + return base64.StdEncoding.EncodeToString([]byte(data)) +} + +func decodeAmplifyBasicAuthCredentials(encoded string) (string, string, error) { + data, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + return "", "", err + } + s := strings.SplitN(string(data), ":", 2) + return s[0], s[1], nil +} + +func expandAmplifyCustomRules(l []interface{}) []*amplify.CustomRule { + rules := make([]*amplify.CustomRule, 0) + + for _, v := range l { + e := v.(map[string]interface{}) + + rule := &lify.CustomRule{} + + if ev, ok := e["condition"].(string); ok && ev != "" { + rule.Condition = aws.String(ev) + } + + if ev, ok := e["source"].(string); ok { + rule.Source = aws.String(ev) + } + + if ev, ok := e["status"].(string); ok && ev != "" { + rule.Status = aws.String(ev) + } + + if ev, ok := e["target"].(string); ok { + rule.Target = aws.String(ev) + } + + rules = append(rules, rule) + } + + return rules +} + +func flattenAmplifyCustomRules(rules []*amplify.CustomRule) []map[string]interface{} { + values := make([]map[string]interface{}, 0) + + for _, rule := range rules { + value := make(map[string]interface{}) + value["condition"] = aws.StringValue(rule.Condition) + value["source"] = aws.StringValue(rule.Source) + value["status"] = aws.StringValue(rule.Status) + value["target"] = aws.StringValue(rule.Target) + values = append(values, value) + } + + return values +} diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go new file mode 100644 index 00000000000..143531c0fc6 --- /dev/null +++ b/aws/resource_aws_amplify_app_test.go @@ -0,0 +1,783 @@ +package aws + +import ( + "fmt" + "os" + "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 TestAccAWSAmplifyApp_basic(t *testing.T) { + var app amplify.App + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+$")), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "repository", ""), + resource.TestCheckResourceAttr(resourceName, "platform", "WEB"), + resource.TestMatchResourceAttr(resourceName, "default_domain", regexp.MustCompile(`\.amplifyapp\.com$`)), + resource.TestCheckResourceAttr(resourceName, "build_spec", ""), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.#", "0"), + resource.TestCheckResourceAttr(resourceName, "basic_auth_config.#", "0"), + resource.TestCheckResourceAttr(resourceName, "custom_rules.#", "0"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.#", "0"), + resource.TestCheckResourceAttr(resourceName, "enable_branch_auto_build", "false"), + resource.TestCheckResourceAttr(resourceName, "iam_service_role_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAmplifyApp_rename(t *testing.T) { + resourceName := "aws_amplify_app.test" + + // name is not unique and can be renamed + rName1 := acctest.RandomWithPrefix("tf-acc-test") + rName2 := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfig_Required(rName1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", rName1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyAppConfig_Required(rName2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", rName2), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyApp_description(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + // once set, description cannot be removed. + description1 := acctest.RandomWithPrefix("tf-acc-test") + description2 := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigDescription(rName, description1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "description", description1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyAppConfigDescription(rName, description2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "description", description2), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyApp_repository(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigRepository(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestMatchResourceAttr(resourceName, "repository", regexp.MustCompile("^https://github.com")), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"access_token"}, + }, + }, + }) +} + +func TestAccAWSAmplifyApp_buildSpec(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + // once set, build_spec cannot be removed. + buildSpec1 := "version: 0.1" + buildSpec2 := "version: 0.2" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigBuildSpec(rName, buildSpec1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "build_spec", buildSpec1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyAppConfigBuildSpec(rName, buildSpec2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "build_spec", buildSpec2), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyApp_customRules(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigCustomRules1(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "custom_rules.#", "1"), + resource.TestCheckResourceAttr(resourceName, "custom_rules.0.source", "/<*>"), + resource.TestCheckResourceAttr(resourceName, "custom_rules.0.status", "404"), + resource.TestCheckResourceAttr(resourceName, "custom_rules.0.target", "/index.html"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyAppConfigCustomRules2(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "custom_rules.#", "2"), + resource.TestCheckResourceAttr(resourceName, "custom_rules.0.source", "/documents"), + resource.TestCheckResourceAttr(resourceName, "custom_rules.0.status", "302"), + resource.TestCheckResourceAttr(resourceName, "custom_rules.0.target", "/documents/us"), + resource.TestCheckResourceAttr(resourceName, "custom_rules.0.condition", ""), + resource.TestCheckResourceAttr(resourceName, "custom_rules.1.source", "/<*>"), + resource.TestCheckResourceAttr(resourceName, "custom_rules.1.status", "200"), + resource.TestCheckResourceAttr(resourceName, "custom_rules.1.target", "/index.html"), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyApp_environmentVariables(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigEnvironmentVariables1(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "1"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyAppConfigEnvironmentVariables2(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: testAccAWSAmplifyAppConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyApp_autoBranchCreationConfig(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigAutoBranchCreationConfig(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_branch_creation", "true"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.auto_branch_creation_patterns.#", "2"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.auto_branch_creation_patterns.0", "*"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.auto_branch_creation_patterns.1", "*/**"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.build_spec", ""), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.framework", ""), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.stage", "NONE"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.#", "0"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_build", "false"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_pull_request_preview", "false"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.pull_request_environment_name", ""), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyAppConfigAutoBranchCreationConfigModified(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_branch_creation", "true"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.auto_branch_creation_patterns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.auto_branch_creation_patterns.0", "feature/*"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.build_spec", "version: 0.1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.framework", "React"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.stage", "DEVELOPMENT"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.0.enable_basic_auth", "true"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.0.username", "username"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.0.password", "password"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_build", "true"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_pull_request_preview", "true"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.pull_request_environment_name", "env"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.%", "1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.ENVVAR1", "1"), + ), + }, + { + Config: testAccAWSAmplifyAppConfigAutoBranchCreationConfigModified2(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_branch_creation", "true"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.#", "0"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.%", "0"), + ), + }, + { + Config: testAccAWSAmplifyAppConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.#", "0"), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyApp_basicAuthConfig(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + username1 := "username1" + password1 := "password1" + username2 := "username2" + password2 := "password2" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigBasicAuthConfig(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: testAccAWSAmplifyAppConfigBasicAuthConfig(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: testAccAWSAmplifyAppConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "basic_auth_config.#", "0"), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyApp_enableBranchAutoBuild(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigEnableBranchAutoBuild(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "enable_branch_auto_build", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyAppConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "enable_branch_auto_build", "false"), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyApp_iamServiceRoleArn(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + roleName1 := acctest.RandomWithPrefix("tf-acc-test") + roleName2 := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigIAMServiceRoleArn(rName, roleName1), + Check: resource.ComposeTestCheckFunc( + resource.TestMatchResourceAttr(resourceName, "iam_service_role_arn", regexp.MustCompile("^arn:[^:]+:iam:[^:]*:[^:]+:role/"+roleName1)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyAppConfigIAMServiceRoleArn(rName, roleName2), + Check: resource.ComposeTestCheckFunc( + resource.TestMatchResourceAttr(resourceName, "iam_service_role_arn", regexp.MustCompile("^arn:[^:]+:iam:[^:]*:[^:]+:role/"+roleName2)), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyApp_tags(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigTags1(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.TAG1", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyAppConfigTags2(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.TAG1", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.TAG2", "2"), + ), + }, + { + Config: testAccAWSAmplifyAppConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + }, + }) +} + +func testAccCheckAWSAmplifyAppExists(resourceName string, app *amplify.App) 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.GetApp(&lify.GetAppInput{ + AppId: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + + if output == nil || output.App == nil { + return fmt.Errorf("Amplify App (%s) not found", rs.Primary.ID) + } + + *app = *output.App + + return nil + } +} + +func testAccCheckAWSAmplifyAppDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_amplify_app" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + + _, err := conn.GetApp(&lify.GetAppInput{ + AppId: aws.String(rs.Primary.ID), + }) + + if isAWSErr(err, amplify.ErrCodeNotFoundException, "") { + continue + } + + if err != nil { + return err + } + } + + return nil +} + +func testAccAWSAmplifyAppConfig_Required(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} +`, rName) +} + +func testAccAWSAmplifyAppConfigDescription(rName string, description string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + description = "%s" +} +`, rName, description) +} + +func testAccAWSAmplifyAppConfigRepository(rName string) string { + repository := os.Getenv("AMPLIFY_GITHUB_REPOSITORY") + accessToken := os.Getenv("AMPLIFY_GITHUB_ACCESS_TOKEN") + + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + repository = "%s" + access_token = "%s" +} +`, rName, repository, accessToken) +} + +func testAccAWSAmplifyAppConfigBuildSpec(rName string, buildSpec string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + build_spec = "%s" +} +`, rName, buildSpec) +} + +func testAccAWSAmplifyAppConfigCustomRules1(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + custom_rules { + source = "/<*>" + status = "404" + target = "/index.html" + } +} +`, rName) +} + +func testAccAWSAmplifyAppConfigCustomRules2(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + custom_rules { + source = "/documents" + status = "302" + target = "/documents/us" + condition = "" + } + + custom_rules { + source = "/<*>" + status = "200" + target = "/index.html" + } +} +`, rName) +} + +func testAccAWSAmplifyAppConfigEnvironmentVariables1(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + environment_variables = { + ENVVAR1 = "1" + } +} +`, rName) +} + +func testAccAWSAmplifyAppConfigEnvironmentVariables2(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + environment_variables = { + ENVVAR1 = "2", + ENVVAR2 = "2" + } +} +`, rName) +} + +func testAccAWSAmplifyAppConfigAutoBranchCreationConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + auto_branch_creation_config { + enable_auto_branch_creation = true + + auto_branch_creation_patterns = [ + "*", + "*/**", + ] + } +} +`, rName) +} + +func testAccAWSAmplifyAppConfigAutoBranchCreationConfigModified(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + auto_branch_creation_config { + enable_auto_branch_creation = true + + auto_branch_creation_patterns = [ + "feature/*", + ] + + build_spec = "version: 0.1" + framework = "React" + stage = "DEVELOPMENT" + + basic_auth_config { + enable_basic_auth = true + username = "username" + password = "password" + } + + enable_auto_build = true + + enable_pull_request_preview = true + pull_request_environment_name = "env" + + environment_variables = { + ENVVAR1 = "1" + } + } +} +`, rName) +} + +func testAccAWSAmplifyAppConfigAutoBranchCreationConfigModified2(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + auto_branch_creation_config { + enable_auto_branch_creation = true + + auto_branch_creation_patterns = [ + "feature/*", + ] + + build_spec = "version: 0.1" + framework = "React" + stage = "DEVELOPMENT" + + enable_auto_build = false + + enable_pull_request_preview = false + pull_request_environment_name = "env" + } +} +`, rName) +} + +func testAccAWSAmplifyAppConfigBasicAuthConfig(rName string, username, password string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + basic_auth_config { + enable_basic_auth = true + username = "%s" + password = "%s" + } +} +`, rName, username, password) +} + +func testAccAWSAmplifyAppConfigEnableBranchAutoBuild(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + enable_branch_auto_build = true +} +`, rName) +} + +func testAccAWSAmplifyAppConfigIAMServiceRoleArn(rName string, roleName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" + + iam_service_role_arn = aws_iam_role.role.arn +} + +resource "aws_iam_role" "role" { + name = "%s" + + assume_role_policy = < **Note:** When you create/update an Amplify App from Terraform, you may end up with the error "BadRequestException: You should at least provide one valid token" because of authentication issues. See the section "Repository with Tokens" below. + +## Example Usage + +```hcl +resource "aws_amplify_app" "app" { + name = "app" + repository = "https://github.com/example/app" + + // The default build_spec added by the Amplify Console for React. + build_spec = <<-EOT + version: 0.1 + frontend: + phases: + preBuild: + commands: + - yarn install + build: + commands: + - yarn run build + artifacts: + baseDirectory: build + files: + - '**/*' + cache: + paths: + - node_modules/**/* + EOT + + // The default custom_rules added by the Amplify Console. + custom_rules { + source = "/<*>" + status = "404" + target = "/index.html" + } +} +``` + +### Repository with Tokens + +If you create a new Amplify App with the `repository` argument, you also need to set `oauth_token` or `access_token` for authentication. For GitHub, get a [personal access token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) and set `access_token` as follows: + +```hcl +resource "aws_amplify_app" "app" { + name = "app" + repository = "https://github.com/example/app" + + // GitHub personal access token + access_token = "..." +``` + +You can omit `access_token` if you import an existing Amplify App created by the Amplify Console (using OAuth for authentication). + +### Auto Branch Creation + +```hcl +resource "aws_amplify_app" "app" { + name = "app" + + auto_branch_creation_config { + // Enable auto branch creation. + enable_auto_branch_creation = true + + // The default patterns added by the Amplify Console. + auto_branch_creation_patterns = [ + "*", + "*/**", + ] + + // Enable auto build for the created branch. + enable_auto_build = true + } +``` + +### Basic Authentication + +```hcl +resource "aws_amplify_app" "app" { + name = "app" + + basic_auth_config { + // Enable basic authentication. + enable_basic_auth = true + + username = "username" + password = "password" + } +} +``` + +### Rewrites and redirects + +```hcl +resource "aws_amplify_app" "app" { + name = "app" + + // Reverse Proxy Rewrite for API requests + // https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html#reverse-proxy-rewrite + custom_rules { + source = "/api/<*>" + status = "200" + target = "https://api.example.com/api/<*>" + } + + // Redirects for Single Page Web Apps (SPA) + // https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html#redirects-for-single-page-web-apps-spa + custom_rules { + source = "" + status = "200" + target = "/index.html" + } +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Name for the Amplify App. +* `access_token` - (Optional) Personal Access token for 3rd party source control system for an Amplify App, used to create webhook and read-only deploy key. Token is not stored. +* `auto_branch_creation_config` - (Optional) Automated branch creation config for the Amplify App. An `auto_branch_creation_config` block is documented below. +* `basic_auth_config` - (Optional) Basic Authentication config for the Amplify App. A `basic_auth_config` block is documented below. +* `build_spec` - (Optional) BuildSpec content for Amplify App. +* `custom_rules` - (Optional) Custom redirect / rewrite rules for the Amplify App. A `custom_rules` block is documented below. +* `description` - (Optional) Description for the Amplify App. +* `enable_branch_auto_build` - (Optional) Enables auto-building of branches for the Amplify App. +* `environment_variables` - (Optional) Environment Variables for the Amplify App. +* `iam_service_role_arn` - (Optional) IAM service role ARN for the Amplify App. +* `oauth_token` - (Optional) OAuth token for 3rd party source control system for an Amplify App, used to create webhook and read-only deploy key. OAuth token is not stored. +* `platform` - (Optional) Platform for the Amplify App. +* `repository` - (Optional) Repository for the Amplify App. +* `tags` - (Optional) Key-value mapping of resource tags. + +An `auto_branch_creation_config` block supports the following arguments: + +* `enable_auto_branch_creation` - (Optional) Enables automated branch creation for the Amplify App. +* `auto_branch_creation_patterns` - (Optional) Automated branch creation glob patterns for the Amplify App. +* `basic_auth_config` - (Optional) Basic Authentication config for the auto created branch. A `basic_auth_config` block is documented below. +* `build_spec` - (Optional) BuildSpec for the auto created branch. +* `enable_auto_build` - (Optional) Enables auto building for the auto created branch. +* `enable_basic_auth` - (Optional) Enables Basic Auth for the auto created branch. +* `enable_pull_request_preview` - (Optional) Enables Pull Request Preview for auto created branch. +* `environment_variables` - (Optional) Environment Variables for the auto created branch. +* `framework` - (Optional) Framework for the auto created 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". + +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. + +A `custom_rules` block supports the following arguments: + +* `source` - (Required) The source pattern for a URL rewrite or redirect rule. +* `target` - (Required) The target pattern for a URL rewrite or redirect rule. +* `condition` - (Optional) The condition for a URL rewrite or redirect rule, e.g. country code. +* `status` - (Optional) The status code for a URL rewrite or redirect rule. + +## Attribute Reference + +The following attributes are exported: + +* `arn` - ARN for the Amplify App. +* `default_domain` - Default domain for the Amplify App. + +## Import + +Amplify App can be imported using Amplify App ID (appId), e.g. + +``` +$ terraform import aws_amplify_app.app d2ypk4k47z8u6 +``` + +App ID can be obtained from App ARN (e.g. `arn:aws:amplify:us-east-1:12345678:apps/d2ypk4k47z8u6`). From 3a88502453e110cd2cab651e8cfee136857dab46 Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Fri, 7 Feb 2020 10:57:11 +0900 Subject: [PATCH 011/398] Ensure that the number of tags is 0 --- aws/resource_aws_amplify_app_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 143531c0fc6..60a3db5d270 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -40,6 +40,7 @@ func TestAccAWSAmplifyApp_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "environment_variables.#", "0"), resource.TestCheckResourceAttr(resourceName, "enable_branch_auto_build", "false"), resource.TestCheckResourceAttr(resourceName, "iam_service_role_arn", ""), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { From c8bd2b38f3734a72ccbd5460e139e349ad62f28a Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Fri, 7 Feb 2020 10:57:52 +0900 Subject: [PATCH 012/398] Add a note why we ignore access_token state --- aws/resource_aws_amplify_app_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 60a3db5d270..0b461ca489d 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -135,9 +135,11 @@ func TestAccAWSAmplifyApp_repository(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + // access_token is ignored because AWS does not store access_token and oauth_token + // See https://docs.aws.amazon.com/sdk-for-go/api/service/amplify/#CreateAppInput ImportStateVerifyIgnore: []string{"access_token"}, }, }, From 0bbbcfc755e5b29c7e6f92b0e0843ddef653398f Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Fri, 13 Mar 2020 22:37:45 +0900 Subject: [PATCH 013/398] Fixes for 'make website-lint' --- website/docs/r/amplify_app.html.markdown | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/website/docs/r/amplify_app.html.markdown b/website/docs/r/amplify_app.html.markdown index 03430406ab3..955d428f83b 100644 --- a/website/docs/r/amplify_app.html.markdown +++ b/website/docs/r/amplify_app.html.markdown @@ -16,7 +16,7 @@ Provides an Amplify App resource, a fullstack serverless app hosted on the [AWS ```hcl resource "aws_amplify_app" "app" { - name = "app" + name = "app" repository = "https://github.com/example/app" // The default build_spec added by the Amplify Console for React. @@ -54,11 +54,12 @@ If you create a new Amplify App with the `repository` argument, you also need to ```hcl resource "aws_amplify_app" "app" { - name = "app" + name = "app" repository = "https://github.com/example/app" // GitHub personal access token access_token = "..." +} ``` You can omit `access_token` if you import an existing Amplify App created by the Amplify Console (using OAuth for authentication). @@ -82,6 +83,7 @@ resource "aws_amplify_app" "app" { // Enable auto build for the created branch. enable_auto_build = true } +} ``` ### Basic Authentication @@ -121,6 +123,7 @@ resource "aws_amplify_app" "app" { status = "200" target = "/index.html" } +} ``` ## Argument Reference From e444048dd9fea4da44e60bf527b55a5bf8f7aed3 Mon Sep 17 00:00:00 2001 From: Ashish Mohite Date: Mon, 2 Nov 2020 12:56:33 +0530 Subject: [PATCH 014/398] [FIX] Upgrade to v2 --- aws/resource_aws_amplify_app.go | 4 ++-- aws/resource_aws_amplify_app_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index e2aafd320b6..e6c05abf265 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -10,8 +10,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" ) diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 0b461ca489d..93099f153f1 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_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 TestAccAWSAmplifyApp_basic(t *testing.T) { From c60fdeb6e2bdb7f3a03658d05bf2554be85c013c Mon Sep 17 00:00:00 2001 From: Ashish Mohite Date: Sat, 7 Nov 2020 11:26:29 +0530 Subject: [PATCH 015/398] Fix linting error --- aws/resource_aws_amplify_app.go | 3 ++- aws/resource_aws_amplify_app_test.go | 27 ++++++++++++++------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index e6c05abf265..214c613e8fc 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -310,6 +310,7 @@ func resourceAwsAmplifyAppCreate(d *schema.ResourceData, meta interface{}) error func resourceAwsAmplifyAppRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig log.Printf("[DEBUG] Reading Amplify App: %s", d.Id()) resp, err := conn.GetApp(&lify.GetAppInput{ @@ -345,7 +346,7 @@ func resourceAwsAmplifyAppRead(d *schema.ResourceData, meta interface{}) error { d.Set("name", resp.App.Name) d.Set("platform", resp.App.Platform) d.Set("repository", resp.App.Repository) - if err := d.Set("tags", keyvaluetags.AmplifyKeyValueTags(resp.App.Tags).IgnoreAws().Map()); err != nil { + if err := d.Set("tags", keyvaluetags.AmplifyKeyValueTags(resp.App.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 93099f153f1..1fbc5653634 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -27,7 +27,7 @@ func TestAccAWSAmplifyApp_basic(t *testing.T) { Config: testAccAWSAmplifyAppConfig_Required(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+$")), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+`)), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "description", ""), resource.TestCheckResourceAttr(resourceName, "repository", ""), @@ -420,7 +420,7 @@ func TestAccAWSAmplifyApp_iamServiceRoleArn(t *testing.T) { { Config: testAccAWSAmplifyAppConfigIAMServiceRoleArn(rName, roleName1), Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr(resourceName, "iam_service_role_arn", regexp.MustCompile("^arn:[^:]+:iam:[^:]*:[^:]+:role/"+roleName1)), + testAccMatchResourceAttrGlobalARN(resourceName, "iam_service_role_arn", "iam", regexp.MustCompile("role/"+roleName1)), ), }, { @@ -431,7 +431,7 @@ func TestAccAWSAmplifyApp_iamServiceRoleArn(t *testing.T) { { Config: testAccAWSAmplifyAppConfigIAMServiceRoleArn(rName, roleName2), Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr(resourceName, "iam_service_role_arn", regexp.MustCompile("^arn:[^:]+:iam:[^:]*:[^:]+:role/"+roleName2)), + testAccMatchResourceAttrGlobalARN(resourceName, "iam_service_role_arn", "iam", regexp.MustCompile("role/"+roleName2)), ), }, }, @@ -637,10 +637,10 @@ resource "aws_amplify_app" "test" { auto_branch_creation_config { enable_auto_branch_creation = true - auto_branch_creation_patterns = [ - "*", - "*/**", - ] + auto_branch_creation_patterns = [ + "*", + "*/**", + ] } } `, rName) @@ -654,9 +654,9 @@ resource "aws_amplify_app" "test" { auto_branch_creation_config { enable_auto_branch_creation = true - auto_branch_creation_patterns = [ - "feature/*", - ] + auto_branch_creation_patterns = [ + "feature/*", + ] build_spec = "version: 0.1" framework = "React" @@ -678,6 +678,7 @@ resource "aws_amplify_app" "test" { } } } + `, rName) } @@ -689,9 +690,9 @@ resource "aws_amplify_app" "test" { auto_branch_creation_config { enable_auto_branch_creation = true - auto_branch_creation_patterns = [ - "feature/*", - ] + auto_branch_creation_patterns = [ + "feature/*", + ] build_spec = "version: 0.1" framework = "React" From 7a3fca3f76ce74c9fef07b207ccbba0611ecddf0 Mon Sep 17 00:00:00 2001 From: Ashish Mohite Date: Sat, 7 Nov 2020 11:50:14 +0530 Subject: [PATCH 016/398] Fix documentation linting --- website/docs/r/amplify_app.html.markdown | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/website/docs/r/amplify_app.html.markdown b/website/docs/r/amplify_app.html.markdown index 955d428f83b..c13f3876816 100644 --- a/website/docs/r/amplify_app.html.markdown +++ b/website/docs/r/amplify_app.html.markdown @@ -19,7 +19,7 @@ resource "aws_amplify_app" "app" { name = "app" repository = "https://github.com/example/app" - // The default build_spec added by the Amplify Console for React. + # The default build_spec added by the Amplify Console for React. build_spec = <<-EOT version: 0.1 frontend: @@ -39,7 +39,7 @@ resource "aws_amplify_app" "app" { - node_modules/**/* EOT - // The default custom_rules added by the Amplify Console. + # The default custom_rules added by the Amplify Console. custom_rules { source = "/<*>" status = "404" @@ -57,7 +57,7 @@ resource "aws_amplify_app" "app" { name = "app" repository = "https://github.com/example/app" - // GitHub personal access token + # GitHub personal access token access_token = "..." } ``` @@ -71,16 +71,16 @@ resource "aws_amplify_app" "app" { name = "app" auto_branch_creation_config { - // Enable auto branch creation. + # Enable auto branch creation. enable_auto_branch_creation = true - // The default patterns added by the Amplify Console. + # The default patterns added by the Amplify Console. auto_branch_creation_patterns = [ "*", "*/**", ] - // Enable auto build for the created branch. + # Enable auto build for the created branch. enable_auto_build = true } } @@ -93,7 +93,7 @@ resource "aws_amplify_app" "app" { name = "app" basic_auth_config { - // Enable basic authentication. + # Enable basic authentication. enable_basic_auth = true username = "username" @@ -108,16 +108,16 @@ resource "aws_amplify_app" "app" { resource "aws_amplify_app" "app" { name = "app" - // Reverse Proxy Rewrite for API requests - // https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html#reverse-proxy-rewrite + # Reverse Proxy Rewrite for API requests + # https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html#reverse-proxy-rewrite custom_rules { source = "/api/<*>" status = "200" target = "https://api.example.com/api/<*>" } - // Redirects for Single Page Web Apps (SPA) - // https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html#redirects-for-single-page-web-apps-spa + # Redirects for Single Page Web Apps (SPA) + # https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html#redirects-for-single-page-web-apps-spa custom_rules { source = "" status = "200" From 153c41132da48fbd7e0ba15eb56b5125fe14a3f1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 18 May 2021 11:19:36 -0400 Subject: [PATCH 017/398] Add CHANGELOG. --- .changelog/15966.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/15966.txt diff --git a/.changelog/15966.txt b/.changelog/15966.txt new file mode 100644 index 00000000000..feafab97221 --- /dev/null +++ b/.changelog/15966.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_amplify_app +``` \ No newline at end of file From 1a706da5f434f84167bb8b8d56d9b48a0998ff68 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Tue, 18 May 2021 11:39:39 -0700 Subject: [PATCH 018/398] Added wafv2 acceptance tests for CustomRequestHandling and CustomResponse and got them passing. --- aws/resource_aws_wafv2_web_acl_test.go | 275 +++++++++++++++++++++++++ aws/wafv2_helper.go | 21 +- 2 files changed, 289 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_wafv2_web_acl_test.go b/aws/resource_aws_wafv2_web_acl_test.go index a8c29520c3c..a3e52a13139 100644 --- a/aws/resource_aws_wafv2_web_acl_test.go +++ b/aws/resource_aws_wafv2_web_acl_test.go @@ -1134,6 +1134,174 @@ func TestAccAwsWafv2WebACL_RuleGroupReferenceStatement(t *testing.T) { }) } +func TestAccAwsWafv2WebACL_CustomRequestHandling(t *testing.T) { + var v wafv2.WebACL + webACLName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_web_acl.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWafv2ScopeRegional(t) }, + ErrorCheck: testAccErrorCheck(t, wafv2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2WebACLDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2WebACLConfig_CustomRequestHandling(webACLName, "allow", "x-hdr1", "x-hdr2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2WebACLExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), + resource.TestCheckResourceAttr(resourceName, "name", webACLName), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.allow.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.block.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scope", "REGIONAL"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "name": "rule-1", + "action.#": "1", + "action.0.allow.#": "1", + "action.0.allow.0.custom_request_handling.#": "1", + "action.0.allow.0.custom_request_handling.0.insert_headers.#": "2", + "action.0.allow.0.custom_request_handling.0.insert_headers.0.name": "x-hdr1", + "action.0.allow.0.custom_request_handling.0.insert_headers.0.value": "test-value-1", + "action.0.allow.0.custom_request_handling.0.insert_headers.1.name": "x-hdr2", + "action.0.allow.0.custom_request_handling.0.insert_headers.1.value": "test-value-2", + "action.0.block.#": "0", + "action.0.count.#": "0", + "priority": "1", + }), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, + { + Config: testAccAwsWafv2WebACLConfig_CustomRequestHandling(webACLName, "count", "x-hdr1", "x-hdr2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2WebACLExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), + resource.TestCheckResourceAttr(resourceName, "name", webACLName), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.allow.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.block.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scope", "REGIONAL"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "name": "rule-1", + "action.#": "1", + "action.0.allow.#": "0", + "action.0.block.#": "0", + "action.0.count.#": "1", + "action.0.count.0.custom_request_handling.#": "1", + "action.0.count.0.custom_request_handling.0.insert_headers.#": "2", + "action.0.count.0.custom_request_handling.0.insert_headers.0.name": "x-hdr1", + "action.0.count.0.custom_request_handling.0.insert_headers.0.value": "test-value-1", + "action.0.count.0.custom_request_handling.0.insert_headers.1.name": "x-hdr2", + "action.0.count.0.custom_request_handling.0.insert_headers.1.value": "test-value-2", + "priority": "1", + }), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2WebACLImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2WebACL_CustomResponse(t *testing.T) { + var v wafv2.WebACL + webACLName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_web_acl.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWafv2ScopeRegional(t) }, + ErrorCheck: testAccErrorCheck(t, wafv2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2WebACLDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2WebACLConfig_CustomResponse(webACLName, 401, 403, "x-hdr1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2WebACLExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), + resource.TestCheckResourceAttr(resourceName, "name", webACLName), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.allow.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.block.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.block.0.custom_response.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.block.0.custom_response.0.response_code", "401"), + resource.TestCheckResourceAttr(resourceName, "scope", "REGIONAL"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "name": "rule-1", + "action.#": "1", + "action.0.allow.#": "0", + "action.0.block.#": "1", + "action.0.block.0.custom_response.#": "1", + "action.0.block.0.custom_response.0.response_code": "403", + "action.0.block.0.custom_response.0.response_headers.#": "1", + "action.0.block.0.custom_response.0.response_headers.0.name": "x-hdr1", + "action.0.block.0.custom_response.0.response_headers.0.value": "custom-response-header-value", + "action.0.count.#": "0", + "priority": "1", + }), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, + { + Config: testAccAwsWafv2WebACLConfig_CustomResponse(webACLName, 404, 429, "x-hdr2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2WebACLExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), + resource.TestCheckResourceAttr(resourceName, "name", webACLName), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.allow.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.block.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.block.0.custom_response.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.block.0.custom_response.0.response_code", "404"), + resource.TestCheckResourceAttr(resourceName, "scope", "REGIONAL"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "name": "rule-1", + "action.#": "1", + "action.0.allow.#": "0", + "action.0.block.#": "1", + "action.0.block.0.custom_response.#": "1", + "action.0.block.0.custom_response.0.response_code": "429", + "action.0.block.0.custom_response.0.response_headers.#": "1", + "action.0.block.0.custom_response.0.response_headers.0.name": "x-hdr2", + "action.0.block.0.custom_response.0.response_headers.0.value": "custom-response-header-value", + "action.0.count.#": "0", + "priority": "1", + }), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2WebACLImportStateIdFunc(resourceName), + }, + }, + }) +} + func TestAccAwsWafv2WebACL_Tags(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") @@ -1538,6 +1706,113 @@ resource "aws_wafv2_web_acl" "test" { `, name, countryCodes) } +func testAccAwsWafv2WebACLConfig_CustomRequestHandling(name, actionName string, firstHeader string, secondHeader string) string { + return fmt.Sprintf(` +resource "aws_wafv2_web_acl" "test" { + name = "%[1]s" + description = "%[1]s" + scope = "REGIONAL" + + default_action { + allow {} + } + + rule { + name = "rule-1" + priority = 1 + + action { + %[2]s { + custom_request_handling { + insert_headers { + name = "%[3]s" + value = "test-value-1" + } + + insert_headers { + name = "%[4]s" + value = "test-value-2" + } + } + } + } + + statement { + geo_match_statement { + country_codes = ["US", "CA"] + } + } + + 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 + } +} +`, name, actionName, firstHeader, secondHeader) +} + +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" + scope = "REGIONAL" + + default_action { + block { + custom_response { + response_code = %[2]d + } + } + } + + rule { + name = "rule-1" + priority = 1 + + action { + block { + custom_response { + response_code = %[3]d + + response_headers { + name = "%[4]s" + value = "custom-response-header-value" + } + } + } + } + + statement { + geo_match_statement { + country_codes = ["US", "CA"] + } + } + + 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 + } +} +`, name, defaultStatusCode, countryBlockStatusCode, countryHeaderName) +} + func testAccAwsWafv2WebACLConfig_GeoMatchStatement_ForwardedIPConfig(name, fallbackBehavior, headerName string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { diff --git a/aws/wafv2_helper.go b/aws/wafv2_helper.go index dd9d9efb261..29c94b688b7 100644 --- a/aws/wafv2_helper.go +++ b/aws/wafv2_helper.go @@ -1098,8 +1098,10 @@ func flattenWafv2Allow(a *wafv2.AllowAction) interface{} { if a == nil { return map[string]interface{}{} } - m := map[string]interface{}{ - "custom_request_handling": flattenWafv2CustomRequestHandling(a.CustomRequestHandling), + m := map[string]interface{}{} + + if a.CustomRequestHandling != nil { + m["custom_request_handling"] = flattenWafv2CustomRequestHandling(a.CustomRequestHandling) } return []interface{}{m} @@ -1109,8 +1111,11 @@ func flattenWafv2Block(a *wafv2.BlockAction) interface{} { if a == nil { return map[string]interface{}{} } - m := map[string]interface{}{ - "custom_response": flattenWafv2CustomResponse(a.CustomResponse), + + m := map[string]interface{}{} + + if a.CustomResponse != nil { + m["custom_response"] = flattenWafv2CustomResponse(a.CustomResponse) } return []interface{}{m} @@ -1120,8 +1125,10 @@ func flattenWafv2Count(a *wafv2.CountAction) interface{} { if a == nil { return map[string]interface{}{} } - m := map[string]interface{}{ - "custom_request_handling": flattenWafv2CustomRequestHandling(a.CustomRequestHandling), + m := map[string]interface{}{} + + if a.CustomRequestHandling != nil { + m["custom_request_handling"] = flattenWafv2CustomRequestHandling(a.CustomRequestHandling) } return []interface{}{m} @@ -1172,7 +1179,7 @@ func flattenWafv2CustomHeader(h *wafv2.CustomHTTPHeader) interface{} { "value": aws.StringValue(h.Value), } - return []interface{}{m} + return m } func flattenWafv2RootStatement(s *wafv2.Statement) interface{} { From 5754c4a7abbd8728d3c3829bd1b3695f7414f2f8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 18 May 2021 17:16:50 -0400 Subject: [PATCH 019/398] r/aws_amplify_app: Standard 'name' and 'tags' handling. --- aws/internal/service/amplify/finder/finder.go | 36 ++ aws/resource_aws_amplify_app.go | 586 ++++++++++-------- aws/resource_aws_amplify_app_test.go | 238 ++++--- website/docs/r/amplify_app.html.markdown | 8 +- 4 files changed, 540 insertions(+), 328 deletions(-) create mode 100644 aws/internal/service/amplify/finder/finder.go diff --git a/aws/internal/service/amplify/finder/finder.go b/aws/internal/service/amplify/finder/finder.go new file mode 100644 index 00000000000..142893ee72f --- /dev/null +++ b/aws/internal/service/amplify/finder/finder.go @@ -0,0 +1,36 @@ +package finder + +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/resource" +) + +func AppByID(conn *amplify.Amplify, id string) (*amplify.App, error) { + input := &lify.GetAppInput{ + AppId: aws.String(id), + } + + output, err := conn.GetApp(input) + + if tfawserr.ErrCodeEquals(err, amplify.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.App == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.App, nil +} diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index 214c613e8fc..cca1028013e 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -1,18 +1,18 @@ package aws import ( - "encoding/base64" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsAmplifyApp() *schema.Resource { @@ -25,76 +25,78 @@ func resourceAwsAmplifyApp() *schema.Resource { State: schema.ImportStatePassthrough, }, + CustomizeDiff: SetTagsDiff, + Schema: map[string]*schema.Schema{ + "access_token": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "arn": { Type: schema.TypeString, Computed: true, }, + "auto_branch_creation_config": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "auto_branch_creation_patterns": { - Type: schema.TypeList, - Optional: true, - MinItems: 1, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "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), }, + "build_spec": { - Type: schema.TypeString, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 25000), + }, + + "enable_auto_build": { + Type: schema.TypeBool, Optional: true, }, - "enable_auto_branch_creation": { + + "enable_basic_auth": { Type: schema.TypeBool, Optional: true, }, - "enable_auto_build": { + + "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, 255), }, + "stage": { Type: schema.TypeString, Optional: true, @@ -103,61 +105,58 @@ func resourceAwsAmplifyApp() *schema.Resource { if old == "NONE" && new == "" { return true } - return false + return old == new }, - ValidateFunc: validation.StringInSlice([]string{ - amplify.StageProduction, - amplify.StageBeta, - amplify.StageDevelopment, - amplify.StageExperimental, - amplify.StagePullRequest, - }, false), + ValidateFunc: validation.StringInSlice(amplify.Stage_Values(), false), }, }, }, }, - "basic_auth_config": { - Type: schema.TypeList, + + "auto_branch_creation_patterns": { + Type: schema.TypeSet, 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), - }, - }, - }, + Elem: &schema.Schema{Type: schema.TypeString}, }, + + "basic_auth_credentials": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.StringLenBetween(1, 2000), + }, + "build_spec": { Type: schema.TypeString, Optional: true, - Computed: true, + //TODO + //Computed: true, + ValidateFunc: validation.StringLenBetween(1, 25000), }, - "custom_rules": { + + "custom_headers": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 25000), + }, + + "custom_rule": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "condition": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 2048), }, + "source": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 2048), }, + "status": { Type: schema.TypeString, Optional: true, @@ -166,188 +165,271 @@ func resourceAwsAmplifyApp() *schema.Resource { "301", "302", "404", + "404-200", }, false), }, + "target": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 2048), }, }, }, }, + "default_domain": { Type: schema.TypeString, Computed: true, }, + "description": { - Type: schema.TypeString, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1000), + }, + + "enable_auto_branch_creation": { + Type: schema.TypeBool, Optional: true, }, + + "enable_basic_auth": { + Type: schema.TypeBool, + Optional: true, + }, + "enable_branch_auto_build": { Type: schema.TypeBool, Optional: true, }, + + "enable_branch_auto_deletion": { + Type: schema.TypeBool, + Optional: true, + }, + "environment_variables": { Type: schema.TypeMap, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "iam_service_role_arn": { Type: schema.TypeString, Optional: true, ValidateFunc: validateArn, }, + "name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.All( - validation.StringLenBetween(3, 1024), - validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9_-]+$`), "should only contains letters, numbers, _ and -"), - ), + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), + ConflictsWith: []string{"name_prefix"}, + }, + + "name_prefix": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"name"}, + }, + + "oauth_token": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.StringLenBetween(1, 1000), }, + "platform": { Type: schema.TypeString, Optional: true, - Default: amplify.PlatformWeb, - ValidateFunc: validation.StringInSlice([]string{ - amplify.PlatformWeb, - }, false), + //TODO + //Default: amplify.PlatformWeb, + ValidateFunc: validation.StringInSlice(amplify.Platform_Values(), false), }, + + "production_branch": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "branch_name": { + Type: schema.TypeBool, + Computed: true, + }, + + "last_deploy_time": { + Type: schema.TypeString, + Computed: true, + }, + + "status": { + Type: schema.TypeString, + Computed: true, + }, + + "thumbnail_url": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, + "repository": { Type: schema.TypeString, Optional: true, - ForceNew: true, + //TODO + //ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 1000), }, - "oauth_token": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "access_token": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "tags": tagsSchema(), + + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), }, } } func resourceAwsAmplifyAppCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Print("[DEBUG] Creating Amplify App") + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) - params := &lify.CreateAppInput{ - Name: aws.String(d.Get("name").(string)), - } + name := naming.Generate(d.Get("name").(string), d.Get("name_prefix").(string)) - if v, ok := d.GetOk("auto_branch_creation_config"); ok { - config, patterns, enable := expandAmplifyAutoBranchCreationConfig(v.([]interface{})) - params.AutoBranchCreationConfig = config - params.AutoBranchCreationPatterns = patterns - params.EnableAutoBranchCreation = enable + input := &lify.CreateAppInput{ + Name: aws.String(name), } - 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("auto_branch_creation_config"); ok { + config, patterns, enable := expandAmplifyAutoBranchCreationConfig(v.([]interface{})) + params.AutoBranchCreationConfig = config + params.AutoBranchCreationPatterns = patterns + params.EnableAutoBranchCreation = enable + } - if v, ok := d.GetOk("build_spec"); ok { - params.BuildSpec = 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("custom_rules"); ok { - params.CustomRules = expandAmplifyCustomRules(v.([]interface{})) - } + 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("custom_rules"); ok { + params.CustomRules = expandAmplifyCustomRules(v.([]interface{})) + } - if v, ok := d.GetOk("enable_branch_auto_build"); ok { - params.EnableBranchAutoBuild = aws.Bool(v.(bool)) - } + if v, ok := d.GetOk("description"); ok { + params.Description = aws.String(v.(string)) + } - if v, ok := d.GetOk("environment_variables"); ok { - params.EnvironmentVariables = stringMapToPointers(v.(map[string]interface{})) - } + if v, ok := d.GetOk("enable_branch_auto_build"); ok { + params.EnableBranchAutoBuild = aws.Bool(v.(bool)) + } - if v, ok := d.GetOk("iam_service_role_arn"); ok { - params.IamServiceRoleArn = aws.String(v.(string)) - } + if v, ok := d.GetOk("environment_variables"); ok { + params.EnvironmentVariables = stringMapToPointers(v.(map[string]interface{})) + } - if v, ok := d.GetOk("platform"); ok { - params.Platform = aws.String(v.(string)) - } + if v, ok := d.GetOk("iam_service_role_arn"); ok { + params.IamServiceRoleArn = aws.String(v.(string)) + } - if v, ok := d.GetOk("repository"); ok { - params.Repository = aws.String(v.(string)) - } + if v, ok := d.GetOk("platform"); ok { + params.Platform = aws.String(v.(string)) + } - if v, ok := d.GetOk("access_token"); ok { - params.AccessToken = aws.String(v.(string)) - } + if v, ok := d.GetOk("repository"); ok { + params.Repository = aws.String(v.(string)) + } - if v, ok := d.GetOk("oauth_token"); ok { - params.OauthToken = aws.String(v.(string)) - } + if v, ok := d.GetOk("access_token"); ok { + params.AccessToken = aws.String(v.(string)) + } + + if v, ok := d.GetOk("oauth_token"); ok { + params.OauthToken = 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.CreateApp(params) + log.Printf("[DEBUG] Creating Amplify App: %s", input) + output, err := conn.CreateApp(input) + if err != nil { - return fmt.Errorf("Error creating Amplify App: %s", err) + return fmt.Errorf("error creating Amplify App (%s): %w", name, err) } - d.SetId(*resp.App.AppId) + d.SetId(aws.StringValue(output.App.AppId)) return resourceAwsAmplifyAppRead(d, meta) } func resourceAwsAmplifyAppRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - log.Printf("[DEBUG] Reading Amplify App: %s", d.Id()) - resp, err := conn.GetApp(&lify.GetAppInput{ - AppId: aws.String(d.Id()), - }) - if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == amplify.ErrCodeNotFoundException { - log.Printf("[WARN] Amplify App (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - return err - } + app, err := finder.AppByID(conn, d.Id()) - d.Set("arn", resp.App.AppArn) - if err := d.Set("auto_branch_creation_config", flattenAmplifyAutoBranchCreationConfig(resp.App.AutoBranchCreationConfig, resp.App.AutoBranchCreationPatterns, resp.App.EnableAutoBranchCreation)); err != nil { - return fmt.Errorf("error setting auto_branch_creation_config: %s", err) - } - if err := d.Set("basic_auth_config", flattenAmplifyBasicAuthConfig(resp.App.EnableBasicAuth, resp.App.BasicAuthCredentials)); err != nil { - return fmt.Errorf("error setting basic_auth_config: %s", err) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Amplify App (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil } - d.Set("build_spec", resp.App.BuildSpec) - if err := d.Set("custom_rules", flattenAmplifyCustomRules(resp.App.CustomRules)); err != nil { - return fmt.Errorf("error setting custom_rules: %s", err) + + if err != nil { + return fmt.Errorf("error reading Amplify App (%s): %w", d.Id(), err) } - d.Set("default_domain", resp.App.DefaultDomain) - d.Set("description", resp.App.Description) - d.Set("enable_branch_auto_build", resp.App.EnableBranchAutoBuild) - if err := d.Set("environment_variables", aws.StringValueMap(resp.App.EnvironmentVariables)); err != nil { - return fmt.Errorf("error setting environment_variables: %s", err) + + d.Set("arn", app.AppArn) + + d.Set("name", app.Name) + d.Set("name_prefix", naming.NamePrefixFromName(aws.StringValue(app.Name))) + + /* + if err := d.Set("auto_branch_creation_config", flattenAmplifyAutoBranchCreationConfig(resp.App.AutoBranchCreationConfig, resp.App.AutoBranchCreationPatterns, resp.App.EnableAutoBranchCreation)); err != nil { + return fmt.Errorf("error setting auto_branch_creation_config: %s", err) + } + if err := d.Set("basic_auth_config", flattenAmplifyBasicAuthConfig(resp.App.EnableBasicAuth, resp.App.BasicAuthCredentials)); err != nil { + return fmt.Errorf("error setting basic_auth_config: %s", err) + } + d.Set("build_spec", resp.App.BuildSpec) + if err := d.Set("custom_rules", flattenAmplifyCustomRules(resp.App.CustomRules)); err != nil { + return fmt.Errorf("error setting custom_rules: %s", err) + } + d.Set("default_domain", resp.App.DefaultDomain) + d.Set("description", resp.App.Description) + d.Set("enable_branch_auto_build", resp.App.EnableBranchAutoBuild) + if err := d.Set("environment_variables", aws.StringValueMap(resp.App.EnvironmentVariables)); err != nil { + return fmt.Errorf("error setting environment_variables: %s", err) + } + d.Set("iam_service_role_arn", resp.App.IamServiceRoleArn) + d.Set("name", resp.App.Name) + d.Set("platform", resp.App.Platform) + d.Set("repository", resp.App.Repository) + */ + + tags := keyvaluetags.AmplifyKeyValueTags(app.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) + + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) } - d.Set("iam_service_role_arn", resp.App.IamServiceRoleArn) - d.Set("name", resp.App.Name) - d.Set("platform", resp.App.Platform) - d.Set("repository", resp.App.Repository) - if err := d.Set("tags", keyvaluetags.AmplifyKeyValueTags(resp.App.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 @@ -355,80 +437,82 @@ func resourceAwsAmplifyAppRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsAmplifyAppUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Updating Amplify App: %s", d.Id()) - params := &lify.UpdateAppInput{ - AppId: aws.String(d.Id()), - } + /* - if d.HasChange("auto_branch_creation_config") { - v := d.Get("auto_branch_creation_config") - config, patterns, enable := expandAmplifyAutoBranchCreationConfig(v.([]interface{})) - params.AutoBranchCreationConfig = config - params.AutoBranchCreationPatterns = patterns - params.EnableAutoBranchCreation = enable - } + params := &lify.UpdateAppInput{ + AppId: aws.String(d.Id()), + } - if d.HasChange("basic_auth_config") { - enable, credentials := expandAmplifyBasicAuthConfig(d.Get("basic_auth_config").([]interface{})) - params.EnableBasicAuth = enable - params.BasicAuthCredentials = credentials - } + if d.HasChange("auto_branch_creation_config") { + v := d.Get("auto_branch_creation_config") + config, patterns, enable := expandAmplifyAutoBranchCreationConfig(v.([]interface{})) + params.AutoBranchCreationConfig = config + params.AutoBranchCreationPatterns = patterns + params.EnableAutoBranchCreation = enable + } - if d.HasChange("build_spec") { - params.BuildSpec = aws.String(d.Get("build_spec").(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("custom_rules") { - params.CustomRules = expandAmplifyCustomRules(d.Get("custom_rules").([]interface{})) - } + 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("custom_rules") { + params.CustomRules = expandAmplifyCustomRules(d.Get("custom_rules").([]interface{})) + } - if d.HasChange("enable_branch_auto_build") { - params.EnableBranchAutoBuild = aws.Bool(d.Get("enable_branch_auto_build").(bool)) - } + if d.HasChange("description") { + params.Description = aws.String(d.Get("description").(string)) + } - if d.HasChange("environment_variables") { - v := d.Get("environment_variables") - params.EnvironmentVariables = expandAmplifyEnvironmentVariables(v.(map[string]interface{})) - } + if d.HasChange("enable_branch_auto_build") { + params.EnableBranchAutoBuild = aws.Bool(d.Get("enable_branch_auto_build").(bool)) + } - if d.HasChange("iam_service_role_arn") { - params.IamServiceRoleArn = aws.String(d.Get("iam_service_role_arn").(string)) - } + if d.HasChange("environment_variables") { + v := d.Get("environment_variables") + params.EnvironmentVariables = expandAmplifyEnvironmentVariables(v.(map[string]interface{})) + } - if d.HasChange("name") { - params.Name = aws.String(d.Get("name").(string)) - } + if d.HasChange("iam_service_role_arn") { + params.IamServiceRoleArn = aws.String(d.Get("iam_service_role_arn").(string)) + } - if d.HasChange("platform") { - params.Platform = aws.String(d.Get("platform").(string)) - } + if d.HasChange("name") { + params.Name = aws.String(d.Get("name").(string)) + } - if d.HasChange("repository") { - params.Repository = aws.String(d.Get("repository").(string)) - } + if d.HasChange("platform") { + params.Platform = aws.String(d.Get("platform").(string)) + } - if v, ok := d.GetOk("access_token"); ok { - params.AccessToken = aws.String(v.(string)) - } + if d.HasChange("repository") { + params.Repository = aws.String(d.Get("repository").(string)) + } - if v, ok := d.GetOk("oauth_token"); ok { - params.OauthToken = aws.String(v.(string)) - } + if v, ok := d.GetOk("access_token"); ok { + params.AccessToken = aws.String(v.(string)) + } - _, err := conn.UpdateApp(params) - if err != nil { - return fmt.Errorf("Error updating Amplify App: %s", err) - } + if v, ok := d.GetOk("oauth_token"); ok { + params.OauthToken = aws.String(v.(string)) + } + + _, err := conn.UpdateApp(params) + if err != nil { + return fmt.Errorf("Error updating Amplify App: %s", 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) } } @@ -437,25 +521,24 @@ func resourceAwsAmplifyAppUpdate(d *schema.ResourceData, meta interface{}) error func resourceAwsAmplifyAppDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Deleting Amplify App: %s", d.Id()) - err := deleteAmplifyApp(conn, d.Id()) - if err != nil { - return fmt.Errorf("Error deleting Amplify App: %s", err) - } + log.Printf("[DEBUG] Deleting Amplify App (%s)", d.Id()) + _, err := conn.DeleteApp(&lify.DeleteAppInput{ + AppId: aws.String(d.Id()), + }) - return nil -} + if tfawserr.ErrCodeEquals(err, amplify.ErrCodeResourceNotFoundException) { + return nil + } -func deleteAmplifyApp(conn *amplify.Amplify, appId string) error { - params := &lify.DeleteAppInput{ - AppId: aws.String(appId), + if err != nil { + return fmt.Errorf("error deleting Amplify App (%s): %w", d.Id(), err) } - _, err := conn.DeleteApp(params) - return err + return nil } +/* func expandAmplifyEnvironmentVariables(envs map[string]interface{}) map[string]*string { if len(envs) == 0 { empty := "" @@ -646,3 +729,4 @@ func flattenAmplifyCustomRules(rules []*amplify.CustomRule) []map[string]interfa return values } +*/ diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 1fbc5653634..825f6b811a4 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -6,13 +6,17 @@ 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/naming" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) +// TODO sweeper + func TestAccAWSAmplifyApp_basic(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") @@ -20,11 +24,12 @@ func TestAccAWSAmplifyApp_basic(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfig_Required(rName), + Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+`)), @@ -52,6 +57,105 @@ func TestAccAWSAmplifyApp_basic(t *testing.T) { }) } +func TestAccAWSAmplifyApp_Name_Generated(t *testing.T) { + var app amplify.App + resourceName := "aws_amplify_app.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigNameGenerated(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAmplifyApp_NamePrefix(t *testing.T) { + var app amplify.App + resourceName := "aws_amplify_app.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigNamePrefix("tf-acc-test-prefix-"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + naming.TestCheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAmplifyApp_Tags(t *testing.T) { + var app amplify.App + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyAppConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSAmplifyAppConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + func TestAccAWSAmplifyApp_rename(t *testing.T) { resourceName := "aws_amplify_app.test" @@ -61,11 +165,12 @@ func TestAccAWSAmplifyApp_rename(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfig_Required(rName1), + Config: testAccAWSAmplifyAppConfigName(rName1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "name", rName1), ), @@ -76,7 +181,7 @@ func TestAccAWSAmplifyApp_rename(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfig_Required(rName2), + Config: testAccAWSAmplifyAppConfigName(rName2), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "name", rName2), ), @@ -95,6 +200,7 @@ func TestAccAWSAmplifyApp_description(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ @@ -125,6 +231,7 @@ func TestAccAWSAmplifyApp_repository(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ @@ -156,6 +263,7 @@ func TestAccAWSAmplifyApp_buildSpec(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ @@ -186,6 +294,7 @@ func TestAccAWSAmplifyApp_customRules(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ @@ -226,6 +335,7 @@ func TestAccAWSAmplifyApp_environmentVariables(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ @@ -250,7 +360,7 @@ func TestAccAWSAmplifyApp_environmentVariables(t *testing.T) { ), }, { - Config: testAccAWSAmplifyAppConfig_Required(rName), + Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), ), @@ -265,6 +375,7 @@ func TestAccAWSAmplifyApp_autoBranchCreationConfig(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ @@ -319,7 +430,7 @@ func TestAccAWSAmplifyApp_autoBranchCreationConfig(t *testing.T) { ), }, { - Config: testAccAWSAmplifyAppConfig_Required(rName), + Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.#", "0"), ), @@ -339,6 +450,7 @@ func TestAccAWSAmplifyApp_basicAuthConfig(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ @@ -366,7 +478,7 @@ func TestAccAWSAmplifyApp_basicAuthConfig(t *testing.T) { ), }, { - Config: testAccAWSAmplifyAppConfig_Required(rName), + Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "basic_auth_config.#", "0"), ), @@ -381,6 +493,7 @@ func TestAccAWSAmplifyApp_enableBranchAutoBuild(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ @@ -396,7 +509,7 @@ func TestAccAWSAmplifyApp_enableBranchAutoBuild(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfig_Required(rName), + Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "enable_branch_auto_build", "false"), ), @@ -414,6 +527,7 @@ func TestAccAWSAmplifyApp_iamServiceRoleArn(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ @@ -438,103 +552,77 @@ func TestAccAWSAmplifyApp_iamServiceRoleArn(t *testing.T) { }) } -func TestAccAWSAmplifyApp_tags(t *testing.T) { - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_amplify_app.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAmplifyAppDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAmplifyAppConfigTags1(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.TAG1", "1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyAppConfigTags2(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.TAG1", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.TAG2", "2"), - ), - }, - { - Config: testAccAWSAmplifyAppConfig_Required(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - ), - }, - }, - }) -} - -func testAccCheckAWSAmplifyAppExists(resourceName string, app *amplify.App) resource.TestCheckFunc { +func testAccCheckAWSAmplifyAppExists(n string, v *amplify.App) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[resourceName] + rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", resourceName) + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Amplify App ID is set") } conn := testAccProvider.Meta().(*AWSClient).amplifyconn - output, err := conn.GetApp(&lify.GetAppInput{ - AppId: aws.String(rs.Primary.ID), - }) + output, err := finder.AppByID(conn, rs.Primary.ID) + if err != nil { return err } - if output == nil || output.App == nil { - return fmt.Errorf("Amplify App (%s) not found", rs.Primary.ID) - } - - *app = *output.App + *v = *output return nil } } func testAccCheckAWSAmplifyAppDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_amplify_app" { continue } - conn := testAccProvider.Meta().(*AWSClient).amplifyconn - - _, err := conn.GetApp(&lify.GetAppInput{ - AppId: aws.String(rs.Primary.ID), - }) + _, err := finder.AppByID(conn, rs.Primary.ID) - if isAWSErr(err, amplify.ErrCodeNotFoundException, "") { + if tfresource.NotFound(err) { continue } if err != nil { return err } + + return fmt.Errorf("Amplify App %s still exists", rs.Primary.ID) } return nil } -func testAccAWSAmplifyAppConfig_Required(rName string) string { +func testAccAWSAmplifyAppConfigName(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q } `, rName) } +func testAccAWSAmplifyAppConfigNameGenerated() string { + return ` +resource "aws_amplify_app" "test" {} +` +} + +func testAccAWSAmplifyAppConfigNamePrefix(namePrefix string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name_prefix = %[1]q +} +`, namePrefix) +} + func testAccAWSAmplifyAppConfigDescription(rName string, description string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { @@ -761,27 +849,27 @@ POLICY `, rName, roleName) } -func testAccAWSAmplifyAppConfigTags1(rName string) string { +func testAccAWSAmplifyAppConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q tags = { - TAG1 = "1", + %[2]q = %[3]q } } -`, rName) +`, rName, tagKey1, tagValue1) } -func testAccAWSAmplifyAppConfigTags2(rName string) string { +func testAccAWSAmplifyAppConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + 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_app.html.markdown b/website/docs/r/amplify_app.html.markdown index c13f3876816..ec5d63afc6a 100644 --- a/website/docs/r/amplify_app.html.markdown +++ b/website/docs/r/amplify_app.html.markdown @@ -130,7 +130,9 @@ resource "aws_amplify_app" "app" { The following arguments are supported: -* `name` - (Required) Name for the Amplify App. +* `name` - (Optional) Name of the Amplify App. 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`. + * `access_token` - (Optional) Personal Access token for 3rd party source control system for an Amplify App, used to create webhook and read-only deploy key. Token is not stored. * `auto_branch_creation_config` - (Optional) Automated branch creation config for the Amplify App. An `auto_branch_creation_config` block is documented below. * `basic_auth_config` - (Optional) Basic Authentication config for the Amplify App. A `basic_auth_config` block is documented below. @@ -143,7 +145,8 @@ The following arguments are supported: * `oauth_token` - (Optional) OAuth token for 3rd party source control system for an Amplify App, used to create webhook and read-only deploy key. OAuth token is not stored. * `platform` - (Optional) Platform for the Amplify App. * `repository` - (Optional) Repository for the Amplify App. -* `tags` - (Optional) Key-value mapping of resource tags. +* `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. + An `auto_branch_creation_config` block supports the following arguments: @@ -178,6 +181,7 @@ The following attributes are exported: * `arn` - ARN for the Amplify App. * `default_domain` - Default domain for the Amplify App. +* `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 4f7eda019ab9964752c0e0804237b225e2b5ede1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 19 May 2021 11:33:59 -0400 Subject: [PATCH 020/398] r/aws_amplify_app: Standard attribute handling. --- aws/resource_aws_amplify_app.go | 240 ++++++++++++++++++++++++++++++-- 1 file changed, 230 insertions(+), 10 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index cca1028013e..2499b1dae3f 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" @@ -100,13 +101,14 @@ func resourceAwsAmplifyApp() *schema.Resource { "stage": { Type: schema.TypeString, Optional: true, - DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - // stage is "NONE" by default - if old == "NONE" && new == "" { - return true - } - return old == new - }, + //TODO + // DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // // stage is "NONE" by default + // if old == "NONE" && new == "" { + // return true + // } + // return old == new + // }, ValidateFunc: validation.StringInSlice(amplify.Stage_Values(), false), }, }, @@ -259,7 +261,7 @@ func resourceAwsAmplifyApp() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "branch_name": { - Type: schema.TypeBool, + Type: schema.TypeString, Computed: true, }, @@ -274,7 +276,7 @@ func resourceAwsAmplifyApp() *schema.Resource { }, "thumbnail_url": { - Type: schema.TypeBool, + Type: schema.TypeString, Computed: true, }, }, @@ -306,6 +308,70 @@ func resourceAwsAmplifyAppCreate(d *schema.ResourceData, meta interface{}) error Name: aws.String(name), } + if v, ok := d.GetOk("access_token"); ok { + input.AccessToken = aws.String(v.(string)) + } + + if v, ok := d.GetOk("auto_branch_creation_config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.AutoBranchCreationConfig = expandAmplifyAutoBranchCreationConfig(v.([]interface{})[0].(map[string]interface{})) + } + + if v, ok := d.GetOk("auto_branch_creation_patterns"); ok && v.(*schema.Set).Len() > 0 { + input.AutoBranchCreationPatterns = expandStringSet(v.(*schema.Set)) + } + + if v, ok := d.GetOk("basic_auth_credentials"); ok { + 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("custom_headers"); ok { + input.CustomHeaders = aws.String(v.(string)) + } + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("enable_auto_branch_creation"); ok { + input.EnableAutoBranchCreation = 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_branch_auto_build"); ok { + input.EnableBranchAutoBuild = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("enable_branch_auto_deletion"); ok { + input.EnableBranchAutoDeletion = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("environment_variables"); ok && len(v.(map[string]interface{})) > 0 { + input.EnvironmentVariables = expandStringMap(v.(map[string]interface{})) + } + + if v, ok := d.GetOk("iam_service_role_arn"); ok { + input.IamServiceRoleArn = aws.String(v.(string)) + } + + if v, ok := d.GetOk("oauth_token"); ok { + input.OauthToken = aws.String(v.(string)) + } + + if v, ok := d.GetOk("platform"); ok { + input.Platform = aws.String(v.(string)) + } + + if v, ok := d.GetOk("repository"); ok { + input.Platform = aws.String(v.(string)) + } + /* if v, ok := d.GetOk("auto_branch_creation_config"); ok { config, patterns, enable := expandAmplifyAutoBranchCreationConfig(v.([]interface{})) @@ -395,9 +461,37 @@ func resourceAwsAmplifyAppRead(d *schema.ResourceData, meta interface{}) error { } d.Set("arn", app.AppArn) - + if app.AutoBranchCreationConfig != nil { + if err := d.Set("auto_branch_creation_config", []interface{}{flattenAmplifyAutoBranchCreationConfig(app.AutoBranchCreationConfig)}); err != nil { + return fmt.Errorf("error setting auto_branch_creation_config: %w", err) + } + } else { + d.Set("auto_branch_creation_config", nil) + } + d.Set("auto_branch_creation_patterns", aws.StringValueSlice(app.AutoBranchCreationPatterns)) + d.Set("basic_auth_credentials", app.BasicAuthCredentials) + d.Set("build_spec", app.BuildSpec) + d.Set("custom_headers", app.CustomHeaders) + + d.Set("default_domain", app.DefaultDomain) + d.Set("description", app.Description) + d.Set("enable_auto_branch_creation", app.EnableAutoBranchCreation) + d.Set("enable_basic_auth", app.EnableBasicAuth) + d.Set("enable_branch_auto_build", app.EnableBranchAutoBuild) + d.Set("enable_branch_auto_deletion", app.EnableBranchAutoDeletion) + d.Set("environment_variables", aws.StringValueMap(app.EnvironmentVariables)) + d.Set("iam_service_role_arn", app.IamServiceRoleArn) d.Set("name", app.Name) d.Set("name_prefix", naming.NamePrefixFromName(aws.StringValue(app.Name))) + d.Set("platform", app.Platform) + if app.ProductionBranch != nil { + if err := d.Set("production_branch", []interface{}{flattenAmplifyProductionBranch(app.ProductionBranch)}); err != nil { + return fmt.Errorf("error setting production_branch: %w", err) + } + } else { + d.Set("production_branch", nil) + } + d.Set("repository", app.Repository) /* if err := d.Set("auto_branch_creation_config", flattenAmplifyAutoBranchCreationConfig(resp.App.AutoBranchCreationConfig, resp.App.AutoBranchCreationPatterns, resp.App.EnableAutoBranchCreation)); err != nil { @@ -538,6 +632,132 @@ func resourceAwsAmplifyAppDelete(d *schema.ResourceData, meta interface{}) error return nil } +func expandAmplifyAutoBranchCreationConfig(tfMap map[string]interface{}) *amplify.AutoBranchCreationConfig { + if tfMap == nil { + return nil + } + + apiObject := &lify.AutoBranchCreationConfig{} + + if v, ok := tfMap["basic_auth_credentials"].(string); ok && v != "" { + apiObject.BasicAuthCredentials = aws.String(v) + } + + if v, ok := tfMap["build_spec"].(string); ok && v != "" { + apiObject.BuildSpec = aws.String(v) + } + + if v, ok := tfMap["enable_auto_build"].(bool); ok && v { + apiObject.EnableAutoBuild = aws.Bool(v) + } + + if v, ok := tfMap["enable_basic_auth"].(bool); ok && v { + apiObject.EnableBasicAuth = aws.Bool(v) + } + + if v, ok := tfMap["enable_performance_mode"].(bool); ok && v { + apiObject.EnablePerformanceMode = aws.Bool(v) + } + + if v, ok := tfMap["enable_pull_request_preview"].(bool); ok && v { + apiObject.EnablePullRequestPreview = aws.Bool(v) + } + + if v, ok := tfMap["environment_variables"].(map[string]interface{}); ok && len(v) > 0 { + apiObject.EnvironmentVariables = expandStringMap(v) + } + + if v, ok := tfMap["framework"].(string); ok && v != "" { + apiObject.Framework = aws.String(v) + } + + if v, ok := tfMap["pull_request_environment_name"].(string); ok && v != "" { + apiObject.PullRequestEnvironmentName = aws.String(v) + } + + if v, ok := tfMap["stage"].(string); ok && v != "" { + apiObject.Stage = aws.String(v) + } + + return apiObject +} + +func flattenAmplifyAutoBranchCreationConfig(apiObject *amplify.AutoBranchCreationConfig) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.BasicAuthCredentials; v != nil { + tfMap["basic_auth_credentials"] = aws.StringValue(v) + } + + if v := apiObject.BuildSpec; v != nil { + tfMap["build_spec"] = aws.StringValue(v) + } + + if v := apiObject.EnableAutoBuild; v != nil { + tfMap["enable_auto_build"] = aws.BoolValue(v) + } + + if v := apiObject.EnableBasicAuth; v != nil { + tfMap["enable_basic_auth"] = aws.BoolValue(v) + } + + if v := apiObject.EnablePerformanceMode; v != nil { + tfMap["enable_performance_mode"] = aws.BoolValue(v) + } + + if v := apiObject.EnablePullRequestPreview; v != nil { + tfMap["enable_pull_request_preview"] = aws.BoolValue(v) + } + + if v := apiObject.EnvironmentVariables; v != nil { + tfMap["environment_variables"] = aws.StringValueMap(v) + } + + if v := apiObject.Framework; v != nil { + tfMap["framework"] = aws.StringValue(v) + } + + if v := apiObject.PullRequestEnvironmentName; v != nil { + tfMap["pull_request_environment_name"] = aws.StringValue(v) + } + + if v := apiObject.Stage; v != nil { + tfMap["stage"] = aws.StringValue(v) + } + + return tfMap +} + +func flattenAmplifyProductionBranch(apiObject *amplify.ProductionBranch) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.BranchName; v != nil { + tfMap["branch_name"] = aws.StringValue(v) + } + + if v := apiObject.LastDeployTime; v != nil { + tfMap["last_deploy_time"] = aws.TimeValue(v).Format(time.RFC3339) + } + + if v := apiObject.Status; v != nil { + tfMap["status"] = aws.StringValue(v) + } + + if v := apiObject.ThumbnailUrl; v != nil { + tfMap["thumbnail_url"] = aws.StringValue(v) + } + + return tfMap +} + /* func expandAmplifyEnvironmentVariables(envs map[string]interface{}) map[string]*string { if len(envs) == 0 { From c555bb7d093ce4eba9891b96ca8dbd4a21b86dd6 Mon Sep 17 00:00:00 2001 From: bill-rich Date: Wed, 19 May 2021 09:36:40 -0700 Subject: [PATCH 021/398] Improve example code maintainability --- .../docs/r/rds_global_cluster.html.markdown | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/website/docs/r/rds_global_cluster.html.markdown b/website/docs/r/rds_global_cluster.html.markdown index 04b3043fa8f..a418d42d4f5 100644 --- a/website/docs/r/rds_global_cluster.html.markdown +++ b/website/docs/r/rds_global_cluster.html.markdown @@ -26,8 +26,8 @@ resource "aws_rds_global_cluster" "example" { resource "aws_rds_cluster" "primary" { provider = aws.primary - engine = "aurora" - engine_version = "5.6.mysql_aurora.1.22.2" + engine = aws_rds_global_cluster.example.engine + engine_version = aws_rds_global_cluster.example.engine_version cluster_identifier = "test-primary-cluster" master_username = "username" master_password = "somepass123" @@ -46,8 +46,8 @@ resource "aws_rds_cluster_instance" "primary" { resource "aws_rds_cluster" "secondary" { provider = aws.secondary - engine = "aurora" - engine_version = "5.6.mysql_aurora.1.22.2" + engine = aws_rds_global_cluster.example.engine + engine_version = aws_rds_global_cluster.example.engine_version cluster_identifier = "test-secondary-cluster" global_cluster_identifier = aws_rds_global_cluster.example.id db_subnet_group_name = "default" @@ -89,8 +89,8 @@ resource "aws_rds_global_cluster" "example" { resource "aws_rds_cluster" "primary" { provider = aws.primary - engine = "aurora-postgresql" - engine_version = "11.9" + engine = aws_rds_global_cluster.example.engine + engine_version = aws_rds_global_cluster.example.engine_version cluster_identifier = "test-primary-cluster" master_username = "username" master_password = "somepass123" @@ -101,8 +101,8 @@ resource "aws_rds_cluster" "primary" { resource "aws_rds_cluster_instance" "primary" { provider = aws.primary - engine = "aurora-postgresql" - engine_version = "11.9" + engine = aws_rds_global_cluster.example.engine + engine_version = aws_rds_global_cluster.example.engine_version identifier = "test-primary-cluster-instance" cluster_identifier = aws_rds_cluster.primary.id instance_class = "db.r4.large" @@ -111,8 +111,8 @@ resource "aws_rds_cluster_instance" "primary" { resource "aws_rds_cluster" "secondary" { provider = aws.secondary - engine = "aurora-postgresql" - engine_version = "11.9" + engine = aws_rds_global_cluster.example.engine + engine_version = aws_rds_global_cluster.example.engine_version cluster_identifier = "test-secondary-cluster" global_cluster_identifier = aws_rds_global_cluster.example.id skip_final_snapshot = true @@ -125,8 +125,8 @@ resource "aws_rds_cluster" "secondary" { resource "aws_rds_cluster_instance" "secondary" { provider = aws.secondary - engine = "aurora-postgresql" - engine_version = "11.9" + engine = aws_rds_global_cluster.example.engine + engine_version = aws_rds_global_cluster.example.engine_version identifier = "test-secondary-cluster-instance" cluster_identifier = aws_rds_cluster.secondary.id instance_class = "db.r4.large" From b715e65a18a399b16acc13517fd28cd6b000a908 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Wed, 19 May 2021 10:23:03 -0700 Subject: [PATCH 022/398] Made changes to acceptance tests to fix terrafmt issues --- aws/resource_aws_wafv2_web_acl_test.go | 75 ++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 11 deletions(-) diff --git a/aws/resource_aws_wafv2_web_acl_test.go b/aws/resource_aws_wafv2_web_acl_test.go index a3e52a13139..dfea54bf118 100644 --- a/aws/resource_aws_wafv2_web_acl_test.go +++ b/aws/resource_aws_wafv2_web_acl_test.go @@ -1146,7 +1146,7 @@ func TestAccAwsWafv2WebACL_CustomRequestHandling(t *testing.T) { CheckDestroy: testAccCheckAwsWafv2WebACLDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsWafv2WebACLConfig_CustomRequestHandling(webACLName, "allow", "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/.+$`)), @@ -1177,7 +1177,7 @@ func TestAccAwsWafv2WebACL_CustomRequestHandling(t *testing.T) { ), }, { - Config: testAccAwsWafv2WebACLConfig_CustomRequestHandling(webACLName, "count", "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/.+$`)), @@ -1706,7 +1706,7 @@ resource "aws_wafv2_web_acl" "test" { `, name, countryCodes) } -func testAccAwsWafv2WebACLConfig_CustomRequestHandling(name, actionName string, 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" @@ -1722,15 +1722,15 @@ resource "aws_wafv2_web_acl" "test" { priority = 1 action { - %[2]s { - custom_request_handling { + count { + custom_request_handling { insert_headers { - name = "%[3]s" + name = "%[2]s" value = "test-value-1" } insert_headers { - name = "%[4]s" + name = "%[3]s" value = "test-value-2" } } @@ -1756,7 +1756,60 @@ resource "aws_wafv2_web_acl" "test" { sampled_requests_enabled = false } } -`, name, actionName, firstHeader, secondHeader) +`, name, firstHeader, secondHeader) +} + +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" + scope = "REGIONAL" + + default_action { + allow {} + } + + rule { + name = "rule-1" + priority = 1 + + action { + allow { + custom_request_handling { + insert_headers { + name = "%[2]s" + value = "test-value-1" + } + + insert_headers { + name = "%[3]s" + value = "test-value-2" + } + } + } + } + + statement { + geo_match_statement { + country_codes = ["US", "CA"] + } + } + + 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 + } +} +`, name, firstHeader, secondHeader) } func testAccAwsWafv2WebACLConfig_CustomResponse(name string, defaultStatusCode int, countryBlockStatusCode int, countryHeaderName string) string { @@ -1780,11 +1833,11 @@ resource "aws_wafv2_web_acl" "test" { action { block { - custom_response { + custom_response { response_code = %[3]d - + response_headers { - name = "%[4]s" + name = "%[4]s" value = "custom-response-header-value" } } From bcec1a5beff68188b38397ec906a60af6bdee4bc Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 19 May 2021 14:57:05 -0400 Subject: [PATCH 023/398] r/aws_amplify_app: Get simple tests working. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplifyApp_Name\|TestAccAWSAmplifyApp_basic\|TestAccAWSAmplifyApp_disappears\|TestAccAWSAmplifyApp_Tags' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplifyApp_Name\|TestAccAWSAmplifyApp_basic\|TestAccAWSAmplifyApp_disappears\|TestAccAWSAmplifyApp_Tags -timeout 180m === RUN TestAccAWSAmplifyApp_basic === PAUSE TestAccAWSAmplifyApp_basic === RUN TestAccAWSAmplifyApp_Name_Generated === PAUSE TestAccAWSAmplifyApp_Name_Generated === RUN TestAccAWSAmplifyApp_NamePrefix === PAUSE TestAccAWSAmplifyApp_NamePrefix === RUN TestAccAWSAmplifyApp_Tags === PAUSE TestAccAWSAmplifyApp_Tags === CONT TestAccAWSAmplifyApp_basic === CONT TestAccAWSAmplifyApp_Tags === CONT TestAccAWSAmplifyApp_Name_Generated === CONT TestAccAWSAmplifyApp_NamePrefix --- PASS: TestAccAWSAmplifyApp_Name_Generated (14.40s) --- PASS: TestAccAWSAmplifyApp_NamePrefix (14.90s) --- PASS: TestAccAWSAmplifyApp_basic (19.53s) --- PASS: TestAccAWSAmplifyApp_Tags (30.27s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 33.242s --- aws/internal/service/amplify/finder/finder.go | 2 +- aws/resource_aws_amplify_app.go | 113 +++++++++++++++++- aws/resource_aws_amplify_app_test.go | 108 +++++++++-------- 3 files changed, 168 insertions(+), 55 deletions(-) diff --git a/aws/internal/service/amplify/finder/finder.go b/aws/internal/service/amplify/finder/finder.go index 142893ee72f..8f67fbb18f1 100644 --- a/aws/internal/service/amplify/finder/finder.go +++ b/aws/internal/service/amplify/finder/finder.go @@ -14,7 +14,7 @@ func AppByID(conn *amplify.Amplify, id string) (*amplify.App, error) { output, err := conn.GetApp(input) - if tfawserr.ErrCodeEquals(err, amplify.ErrCodeResourceNotFoundException) { + if tfawserr.ErrCodeEquals(err, amplify.ErrCodeNotFoundException) { return nil, &resource.NotFoundError{ LastError: err, LastRequest: input, diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index 2499b1dae3f..bcd1e94e019 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -248,10 +248,9 @@ func resourceAwsAmplifyApp() *schema.Resource { }, "platform": { - Type: schema.TypeString, - Optional: true, - //TODO - //Default: amplify.PlatformWeb, + Type: schema.TypeString, + Optional: true, + Default: amplify.PlatformWeb, ValidateFunc: validation.StringInSlice(amplify.Platform_Values(), false), }, @@ -332,6 +331,10 @@ func resourceAwsAmplifyAppCreate(d *schema.ResourceData, meta interface{}) error input.CustomHeaders = aws.String(v.(string)) } + if v, ok := d.GetOk("custom_rule"); ok && len(v.([]interface{})) > 0 { + input.CustomRules = expandAmplifyCustomRules(v.([]interface{})) + } + if v, ok := d.GetOk("description"); ok { input.Description = aws.String(v.(string)) } @@ -472,7 +475,9 @@ func resourceAwsAmplifyAppRead(d *schema.ResourceData, meta interface{}) error { d.Set("basic_auth_credentials", app.BasicAuthCredentials) d.Set("build_spec", app.BuildSpec) d.Set("custom_headers", app.CustomHeaders) - + if err := d.Set("custom_rule", flattenAmplifyCustomRules(app.CustomRules)); err != nil { + return fmt.Errorf("error setting custom_rule: %w", err) + } d.Set("default_domain", app.DefaultDomain) d.Set("description", app.Description) d.Set("enable_auto_branch_creation", app.EnableAutoBranchCreation) @@ -621,7 +626,7 @@ func resourceAwsAmplifyAppDelete(d *schema.ResourceData, meta interface{}) error AppId: aws.String(d.Id()), }) - if tfawserr.ErrCodeEquals(err, amplify.ErrCodeResourceNotFoundException) { + if tfawserr.ErrCodeEquals(err, amplify.ErrCodeNotFoundException) { return nil } @@ -732,6 +737,102 @@ func flattenAmplifyAutoBranchCreationConfig(apiObject *amplify.AutoBranchCreatio return tfMap } +func expandAmplifyCustomRule(tfMap map[string]interface{}) *amplify.CustomRule { + if tfMap == nil { + return nil + } + + apiObject := &lify.CustomRule{} + + if v, ok := tfMap["condition"].(string); ok && v != "" { + apiObject.Condition = aws.String(v) + } + + if v, ok := tfMap["source"].(string); ok && v != "" { + apiObject.Source = aws.String(v) + } + + if v, ok := tfMap["status"].(string); ok && v != "" { + apiObject.Status = aws.String(v) + } + + if v, ok := tfMap["target"].(string); ok && v != "" { + apiObject.Target = aws.String(v) + } + + return apiObject +} + +func expandAmplifyCustomRules(tfList []interface{}) []*amplify.CustomRule { + if len(tfList) == 0 { + return nil + } + + var apiObjects []*amplify.CustomRule + + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + + if !ok { + continue + } + + apiObject := expandAmplifyCustomRule(tfMap) + + if apiObject == nil { + continue + } + + apiObjects = append(apiObjects, apiObject) + } + + return apiObjects +} + +func flattenAmplifyCustomRule(apiObject *amplify.CustomRule) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Condition; v != nil { + tfMap["condition"] = aws.StringValue(v) + } + + if v := apiObject.Source; v != nil { + tfMap["source"] = aws.StringValue(v) + } + + if v := apiObject.Status; v != nil { + tfMap["status"] = aws.StringValue(v) + } + + if v := apiObject.Target; v != nil { + tfMap["target"] = aws.StringValue(v) + } + + return tfMap +} + +func flattenAmplifyCustomRules(apiObjects []*amplify.CustomRule) []interface{} { + if len(apiObjects) == 0 { + return nil + } + + var tfList []interface{} + + for _, apiObject := range apiObjects { + if apiObject == nil { + continue + } + + tfList = append(tfList, flattenAmplifyCustomRule(apiObject)) + } + + return tfList +} + func flattenAmplifyProductionBranch(apiObject *amplify.ProductionBranch) map[string]interface{} { if apiObject == nil { return nil diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 825f6b811a4..602fec007d6 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -1,6 +1,7 @@ package aws import ( + "encoding/base64" "fmt" "os" "regexp" @@ -23,28 +24,37 @@ func TestAccAWSAmplifyApp_basic(t *testing.T) { resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { Config: testAccAWSAmplifyAppConfigName(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckNoResourceAttr(resourceName, "access_token"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+`)), - resource.TestCheckResourceAttr(resourceName, "name", rName), - resource.TestCheckResourceAttr(resourceName, "description", ""), - resource.TestCheckResourceAttr(resourceName, "repository", ""), - resource.TestCheckResourceAttr(resourceName, "platform", "WEB"), - resource.TestMatchResourceAttr(resourceName, "default_domain", regexp.MustCompile(`\.amplifyapp\.com$`)), - resource.TestCheckResourceAttr(resourceName, "build_spec", ""), resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.#", "0"), - resource.TestCheckResourceAttr(resourceName, "basic_auth_config.#", "0"), - resource.TestCheckResourceAttr(resourceName, "custom_rules.#", "0"), - resource.TestCheckResourceAttr(resourceName, "environment_variables.#", "0"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_patterns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", ""), + resource.TestCheckResourceAttr(resourceName, "build_spec", ""), + resource.TestCheckResourceAttr(resourceName, "custom_headers", ""), + resource.TestCheckResourceAttr(resourceName, "custom_rule.#", "0"), + resource.TestMatchResourceAttr(resourceName, "default_domain", regexp.MustCompile(`\.amplifyapp\.com$`)), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "enable_auto_branch_creation", "false"), + resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "false"), resource.TestCheckResourceAttr(resourceName, "enable_branch_auto_build", "false"), + resource.TestCheckResourceAttr(resourceName, "enable_branch_auto_deletion", "false"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), resource.TestCheckResourceAttr(resourceName, "iam_service_role_arn", ""), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "name_prefix", ""), + resource.TestCheckNoResourceAttr(resourceName, "oauth_token"), + resource.TestCheckResourceAttr(resourceName, "platform", "WEB"), + resource.TestCheckResourceAttr(resourceName, "production_branch.#", "0"), + resource.TestCheckResourceAttr(resourceName, "repository", ""), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, @@ -62,7 +72,7 @@ func TestAccAWSAmplifyApp_Name_Generated(t *testing.T) { resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -89,7 +99,7 @@ func TestAccAWSAmplifyApp_NamePrefix(t *testing.T) { resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -117,7 +127,7 @@ func TestAccAWSAmplifyApp_Tags(t *testing.T) { resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -164,7 +174,7 @@ func TestAccAWSAmplifyApp_rename(t *testing.T) { rName2 := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -199,7 +209,7 @@ func TestAccAWSAmplifyApp_description(t *testing.T) { description2 := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -230,7 +240,7 @@ func TestAccAWSAmplifyApp_repository(t *testing.T) { resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -262,7 +272,7 @@ func TestAccAWSAmplifyApp_buildSpec(t *testing.T) { buildSpec2 := "version: 0.2" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -293,7 +303,7 @@ func TestAccAWSAmplifyApp_customRules(t *testing.T) { resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -334,7 +344,7 @@ func TestAccAWSAmplifyApp_environmentVariables(t *testing.T) { resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -374,7 +384,7 @@ func TestAccAWSAmplifyApp_autoBranchCreationConfig(t *testing.T) { resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -439,28 +449,26 @@ func TestAccAWSAmplifyApp_autoBranchCreationConfig(t *testing.T) { }) } -func TestAccAWSAmplifyApp_basicAuthConfig(t *testing.T) { +func TestAccAWSAmplifyApp_BasicAuthCredentials(t *testing.T) { + var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" - username1 := "username1" - password1 := "password1" - username2 := "username2" - password2 := "password2" + credentials1 := base64.StdEncoding.EncodeToString([]byte("username1:password1")) + credentials2 := base64.StdEncoding.EncodeToString([]byte("username2:password2")) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigBasicAuthConfig(rName, username1, password1), + Config: testAccAWSAmplifyAppConfigBasicAuthCredentials(rName, credentials1), 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), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", credentials1), + resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "true"), ), }, { @@ -469,18 +477,19 @@ func TestAccAWSAmplifyApp_basicAuthConfig(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigBasicAuthConfig(rName, username2, password2), + Config: testAccAWSAmplifyAppConfigBasicAuthCredentials(rName, credentials2), 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), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", credentials2), + resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "true"), ), }, { Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "basic_auth_config.#", "0"), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", ""), + resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "false"), ), }, }, @@ -492,7 +501,7 @@ func TestAccAWSAmplifyApp_enableBranchAutoBuild(t *testing.T) { resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -526,7 +535,7 @@ func TestAccAWSAmplifyApp_iamServiceRoleArn(t *testing.T) { roleName2 := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyAppDestroy, @@ -601,6 +610,12 @@ func testAccCheckAWSAmplifyAppDestroy(s *terraform.State) error { return nil } +func testAccPreCheckAWSAmplify(t *testing.T) { + if testAccGetPartition() == "aws-us-gov" { + t.Skip("AWS Amplify is not supported in GovCloud partition") + } +} + func testAccAWSAmplifyAppConfigName(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { @@ -795,18 +810,15 @@ resource "aws_amplify_app" "test" { `, rName) } -func testAccAWSAmplifyAppConfigBasicAuthConfig(rName string, username, password string) string { +func testAccAWSAmplifyAppConfigBasicAuthCredentials(rName, basicAuthCredentials string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q - basic_auth_config { - enable_basic_auth = true - username = "%s" - password = "%s" - } + basic_auth_credentials = %[2]q + enable_basic_auth = true } -`, rName, username, password) +`, rName, basicAuthCredentials) } func testAccAWSAmplifyAppConfigEnableBranchAutoBuild(rName string) string { From e638796e76fffff2c404906b08ef57c85c1b42c0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 19 May 2021 15:59:32 -0400 Subject: [PATCH 024/398] Suppress diff for 'basic_auth_credentials' if basic auth isn't enabled. --- aws/resource_aws_amplify_app.go | 87 +++++++++++++++++----------- aws/resource_aws_amplify_app_test.go | 3 +- 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index bcd1e94e019..58e17bb7627 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -126,6 +126,14 @@ func resourceAwsAmplifyApp() *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 + }, }, "build_spec": { @@ -372,7 +380,7 @@ func resourceAwsAmplifyAppCreate(d *schema.ResourceData, meta interface{}) error } if v, ok := d.GetOk("repository"); ok { - input.Platform = aws.String(v.(string)) + input.Repository = aws.String(v.(string)) } /* @@ -537,76 +545,85 @@ func resourceAwsAmplifyAppRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsAmplifyAppUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - /* - - params := &lify.UpdateAppInput{ + if d.HasChangesExcept("tags", "tags_all") { + input := &lify.UpdateAppInput{ AppId: aws.String(d.Id()), } + if d.HasChange("access_token") { + input.AccessToken = aws.String(d.Get("access_token").(string)) + } + if d.HasChange("auto_branch_creation_config") { - v := d.Get("auto_branch_creation_config") - config, patterns, enable := expandAmplifyAutoBranchCreationConfig(v.([]interface{})) - params.AutoBranchCreationConfig = config - params.AutoBranchCreationPatterns = patterns - params.EnableAutoBranchCreation = enable + input.AutoBranchCreationConfig = expandAmplifyAutoBranchCreationConfig(d.Get("auto_branch_creation_config").([]interface{})[0].(map[string]interface{})) } - if d.HasChange("basic_auth_config") { - enable, credentials := expandAmplifyBasicAuthConfig(d.Get("basic_auth_config").([]interface{})) - params.EnableBasicAuth = enable - params.BasicAuthCredentials = credentials + if d.HasChange("auto_branch_creation_patterns") { + input.AutoBranchCreationPatterns = expandStringSet(d.Get("auto_branch_creation_patterns").(*schema.Set)) + } + + if d.HasChange("basic_auth_credentials") { + input.BasicAuthCredentials = aws.String(d.Get("basic_auth_credentials").(string)) } if d.HasChange("build_spec") { - params.BuildSpec = aws.String(d.Get("build_spec").(string)) + input.BuildSpec = aws.String(d.Get("build_spec").(string)) + } + + if d.HasChange("custom_headers") { + input.CustomHeaders = aws.String(d.Get("custom_headers").(string)) } - if d.HasChange("custom_rules") { - params.CustomRules = expandAmplifyCustomRules(d.Get("custom_rules").([]interface{})) + if d.HasChange("custom_rule") { + input.CustomRules = expandAmplifyCustomRules(d.Get("custom_rule").([]interface{})) } if d.HasChange("description") { - params.Description = aws.String(d.Get("description").(string)) + input.Description = aws.String(d.Get("description").(string)) + } + + if d.HasChange("enable_auto_branch_creation") { + input.EnableAutoBranchCreation = aws.Bool(d.Get("enable_auto_branch_creation").(bool)) + } + + if d.HasChange("enable_basic_auth") { + input.EnableBasicAuth = aws.Bool(d.Get("enable_basic_auth").(bool)) } if d.HasChange("enable_branch_auto_build") { - params.EnableBranchAutoBuild = aws.Bool(d.Get("enable_branch_auto_build").(bool)) + input.EnableBranchAutoBuild = aws.Bool(d.Get("enable_branch_auto_build").(bool)) + } + + if d.HasChange("enable_branch_auto_deletion") { + input.EnableBranchAutoDeletion = aws.Bool(d.Get("enable_branch_auto_deletion").(bool)) } if d.HasChange("environment_variables") { - v := d.Get("environment_variables") - params.EnvironmentVariables = expandAmplifyEnvironmentVariables(v.(map[string]interface{})) + input.EnvironmentVariables = expandStringMap(d.Get("environment_variables").(map[string]interface{})) } if d.HasChange("iam_service_role_arn") { - params.IamServiceRoleArn = aws.String(d.Get("iam_service_role_arn").(string)) + input.IamServiceRoleArn = aws.String(d.Get("iam_service_role_arn").(string)) } - if d.HasChange("name") { - params.Name = aws.String(d.Get("name").(string)) + if d.HasChange("oauth_token") { + input.OauthToken = aws.String(d.Get("oauth_token").(string)) } if d.HasChange("platform") { - params.Platform = aws.String(d.Get("platform").(string)) + input.Platform = aws.String(d.Get("platform").(string)) } if d.HasChange("repository") { - params.Repository = aws.String(d.Get("repository").(string)) - } - - if v, ok := d.GetOk("access_token"); ok { - params.AccessToken = aws.String(v.(string)) + input.Repository = aws.String(d.Get("repository").(string)) } - if v, ok := d.GetOk("oauth_token"); ok { - params.OauthToken = aws.String(v.(string)) - } + _, err := conn.UpdateApp(input) - _, err := conn.UpdateApp(params) if err != nil { - return fmt.Errorf("Error updating Amplify App: %s", err) + return fmt.Errorf("error updating Amplify App (%s): %w", d.Id(), err) } - */ + } if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 602fec007d6..caef2ec7e53 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -488,7 +488,8 @@ func TestAccAWSAmplifyApp_BasicAuthCredentials(t *testing.T) { Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", ""), + // Clearing basic_auth_credentials not reflected in API. + // resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", ""), resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "false"), ), }, From 35d2d6a04020e1afcef49132cdb6e05287b8aa38 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Wed, 19 May 2021 13:03:26 -0700 Subject: [PATCH 025/398] Added support for custom_request_handling and custom_response to the actions in WAFv2 RuleSet resources. --- aws/resource_aws_wafv2_rule_group.go | 6 +- aws/resource_aws_wafv2_rule_group_test.go | 277 +++++++++++++++++++++- 2 files changed, 276 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_wafv2_rule_group.go b/aws/resource_aws_wafv2_rule_group.go index e809c195209..3543e7dbb8c 100644 --- a/aws/resource_aws_wafv2_rule_group.go +++ b/aws/resource_aws_wafv2_rule_group.go @@ -86,9 +86,9 @@ func resourceAwsWafv2RuleGroup() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "allow": wafv2EmptySchema(), - "block": wafv2EmptySchema(), - "count": wafv2EmptySchema(), + "allow": wafv2AllowConfigSchema(), + "block": wafv2BlockConfigSchema(), + "count": wafv2CountConfigSchema(), }, }, }, diff --git a/aws/resource_aws_wafv2_rule_group_test.go b/aws/resource_aws_wafv2_rule_group_test.go index 9aba6423d58..a68c2367ce8 100644 --- a/aws/resource_aws_wafv2_rule_group_test.go +++ b/aws/resource_aws_wafv2_rule_group_test.go @@ -1160,13 +1160,34 @@ func TestAccAwsWafv2RuleGroup_RuleAction(t *testing.T) { resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ "action.#": "1", "action.0.allow.#": "1", - "action.0.block.#": "0", - "action.0.count.#": "0", + "action.0.allow.0.custom_request_handling.#": "0", + "action.0.block.#": "0", + "action.0.count.#": "0", }), ), }, { Config: testAccAwsWafv2RuleGroupConfig_RuleActionBlock(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "action.#": "1", + "action.0.allow.#": "0", + "action.0.block.#": "1", + "action.0.block.0.custom_response.#": "0", + "action.0.count.#": "0", + }), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_RuleActionCount(ruleGroupName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), @@ -1179,13 +1200,60 @@ func TestAccAwsWafv2RuleGroup_RuleAction(t *testing.T) { resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ "action.#": "1", "action.0.allow.#": "0", - "action.0.block.#": "1", + "action.0.block.#": "0", + "action.0.count.#": "1", + "action.0.count.0.custom_request_handling.#": "0", + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_RuleAction_CustomRequestHandling(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWafv2ScopeRegional(t) }, + ErrorCheck: testAccErrorCheck(t, wafv2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_RuleActionAllow_CustomRequestHandling(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "action.#": "1", + "action.0.allow.#": "1", + "action.0.allow.0.custom_request_handling.#": "1", + "action.0.allow.0.custom_request_handling.0.insert_headers.#": "2", + "action.0.allow.0.custom_request_handling.0.insert_headers.0.name": "x-hdr1", + "action.0.allow.0.custom_request_handling.0.insert_headers.0.value": "test-val1", + "action.0.allow.0.custom_request_handling.0.insert_headers.1.name": "x-hdr2", + "action.0.allow.0.custom_request_handling.0.insert_headers.1.value": "test-val2", + "action.0.block.#": "0", "action.0.count.#": "0", }), ), }, { - Config: testAccAwsWafv2RuleGroupConfig_RuleActionCount(ruleGroupName), + Config: testAccAwsWafv2RuleGroupConfig_RuleActionCount_CustomRequestHandling(ruleGroupName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), @@ -1200,6 +1268,59 @@ func TestAccAwsWafv2RuleGroup_RuleAction(t *testing.T) { "action.0.allow.#": "0", "action.0.block.#": "0", "action.0.count.#": "1", + "action.0.count.0.custom_request_handling.#": "1", + "action.0.count.0.custom_request_handling.0.insert_headers.#": "2", + "action.0.count.0.custom_request_handling.0.insert_headers.0.name": "x-hdr1", + "action.0.count.0.custom_request_handling.0.insert_headers.0.value": "test-val1", + "action.0.count.0.custom_request_handling.0.insert_headers.1.name": "x-hdr2", + "action.0.count.0.custom_request_handling.0.insert_headers.1.value": "test-val2", + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_RuleAction_CustomResponse(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWafv2ScopeRegional(t) }, + ErrorCheck: testAccErrorCheck(t, wafv2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_RuleActionBlock_CustomResponse(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "action.#": "1", + "action.0.allow.#": "0", + "action.0.block.#": "1", + "action.0.block.0.custom_response.#": "1", + "action.0.block.0.custom_response.0.response_code": "429", + "action.0.block.0.custom_response.0.response_headers.#": "2", + "action.0.block.0.custom_response.0.response_headers.0.name": "x-hdr1", + "action.0.block.0.custom_response.0.response_headers.0.value": "test-val1", + "action.0.block.0.custom_response.0.response_headers.1.name": "x-hdr2", + "action.0.block.0.custom_response.0.response_headers.1.value": "test-val2", + "action.0.count.#": "0", }), ), }, @@ -1753,6 +1874,55 @@ resource "aws_wafv2_rule_group" "test" { `, name) } +func testAccAwsWafv2RuleGroupConfig_RuleActionAllow_CustomRequestHandling(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow { + custom_request_handling { + insert_headers { + name = "x-hdr1" + value = "test-val1" + } + + insert_headers { + name = "x-hdr2" + value = "test-val2" + } + } + } + } + + statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } + + 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 + } +} +`, name) +} + func testAccAwsWafv2RuleGroupConfig_RuleActionBlock(name string) string { return fmt.Sprintf(` resource "aws_wafv2_rule_group" "test" { @@ -1790,6 +1960,56 @@ resource "aws_wafv2_rule_group" "test" { `, name) } +func testAccAwsWafv2RuleGroupConfig_RuleActionBlock_CustomResponse(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + block { + custom_response { + response_code = 429 + response_headers { + name = "x-hdr1" + value = "test-val1" + } + + response_headers { + name = "x-hdr2" + value = "test-val2" + } + } + } + } + + statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } + + 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 + } +} +`, name) +} + func testAccAwsWafv2RuleGroupConfig_RuleActionCount(name string) string { return fmt.Sprintf(` resource "aws_wafv2_rule_group" "test" { @@ -1827,6 +2047,55 @@ resource "aws_wafv2_rule_group" "test" { `, name) } +func testAccAwsWafv2RuleGroupConfig_RuleActionCount_CustomRequestHandling(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + count { + custom_request_handling { + insert_headers { + name = "x-hdr1" + value = "test-val1" + } + + insert_headers { + name = "x-hdr2" + value = "test-val2" + } + } + } + } + + statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } + + 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 + } +} +`, name) +} + func testAccAwsWafv2RuleGroupConfig_ByteMatchStatement(name string) string { return fmt.Sprintf(` resource "aws_wafv2_rule_group" "test" { From d4d79f6f9950f4f0deac168c3da264a46e189164 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Wed, 19 May 2021 13:13:16 -0700 Subject: [PATCH 026/398] Renamed insert_headers and response_headers to no longer be plural. Made them `TypeSet` instead of `TypeList` --- aws/resource_aws_wafv2_rule_group_test.go | 48 +++++++++++----------- aws/resource_aws_wafv2_web_acl_test.go | 50 +++++++++++------------ aws/wafv2_helper.go | 16 ++++---- 3 files changed, 57 insertions(+), 57 deletions(-) diff --git a/aws/resource_aws_wafv2_rule_group_test.go b/aws/resource_aws_wafv2_rule_group_test.go index a68c2367ce8..39fa6ccee12 100644 --- a/aws/resource_aws_wafv2_rule_group_test.go +++ b/aws/resource_aws_wafv2_rule_group_test.go @@ -1241,12 +1241,12 @@ func TestAccAwsWafv2RuleGroup_RuleAction_CustomRequestHandling(t *testing.T) { resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ "action.#": "1", "action.0.allow.#": "1", - "action.0.allow.0.custom_request_handling.#": "1", - "action.0.allow.0.custom_request_handling.0.insert_headers.#": "2", - "action.0.allow.0.custom_request_handling.0.insert_headers.0.name": "x-hdr1", - "action.0.allow.0.custom_request_handling.0.insert_headers.0.value": "test-val1", - "action.0.allow.0.custom_request_handling.0.insert_headers.1.name": "x-hdr2", - "action.0.allow.0.custom_request_handling.0.insert_headers.1.value": "test-val2", + "action.0.allow.0.custom_request_handling.#": "1", + "action.0.allow.0.custom_request_handling.0.insert_header.#": "2", + "action.0.allow.0.custom_request_handling.0.insert_header.0.name": "x-hdr1", + "action.0.allow.0.custom_request_handling.0.insert_header.0.value": "test-val1", + "action.0.allow.0.custom_request_handling.0.insert_header.1.name": "x-hdr2", + "action.0.allow.0.custom_request_handling.0.insert_header.1.value": "test-val2", "action.0.block.#": "0", "action.0.count.#": "0", }), @@ -1268,12 +1268,12 @@ func TestAccAwsWafv2RuleGroup_RuleAction_CustomRequestHandling(t *testing.T) { "action.0.allow.#": "0", "action.0.block.#": "0", "action.0.count.#": "1", - "action.0.count.0.custom_request_handling.#": "1", - "action.0.count.0.custom_request_handling.0.insert_headers.#": "2", - "action.0.count.0.custom_request_handling.0.insert_headers.0.name": "x-hdr1", - "action.0.count.0.custom_request_handling.0.insert_headers.0.value": "test-val1", - "action.0.count.0.custom_request_handling.0.insert_headers.1.name": "x-hdr2", - "action.0.count.0.custom_request_handling.0.insert_headers.1.value": "test-val2", + "action.0.count.0.custom_request_handling.#": "1", + "action.0.count.0.custom_request_handling.0.insert_header.#": "2", + "action.0.count.0.custom_request_handling.0.insert_header.0.name": "x-hdr1", + "action.0.count.0.custom_request_handling.0.insert_header.0.value": "test-val1", + "action.0.count.0.custom_request_handling.0.insert_header.1.name": "x-hdr2", + "action.0.count.0.custom_request_handling.0.insert_header.1.value": "test-val2", }), ), }, @@ -1314,12 +1314,12 @@ func TestAccAwsWafv2RuleGroup_RuleAction_CustomResponse(t *testing.T) { "action.0.allow.#": "0", "action.0.block.#": "1", "action.0.block.0.custom_response.#": "1", - "action.0.block.0.custom_response.0.response_code": "429", - "action.0.block.0.custom_response.0.response_headers.#": "2", - "action.0.block.0.custom_response.0.response_headers.0.name": "x-hdr1", - "action.0.block.0.custom_response.0.response_headers.0.value": "test-val1", - "action.0.block.0.custom_response.0.response_headers.1.name": "x-hdr2", - "action.0.block.0.custom_response.0.response_headers.1.value": "test-val2", + "action.0.block.0.custom_response.0.response_code": "429", + "action.0.block.0.custom_response.0.response_header.#": "2", + "action.0.block.0.custom_response.0.response_header.0.name": "x-hdr1", + "action.0.block.0.custom_response.0.response_header.0.value": "test-val1", + "action.0.block.0.custom_response.0.response_header.1.name": "x-hdr2", + "action.0.block.0.custom_response.0.response_header.1.value": "test-val2", "action.0.count.#": "0", }), ), @@ -1888,12 +1888,12 @@ resource "aws_wafv2_rule_group" "test" { action { allow { custom_request_handling { - insert_headers { + insert_header { name = "x-hdr1" value = "test-val1" } - insert_headers { + insert_header { name = "x-hdr2" value = "test-val2" } @@ -1975,12 +1975,12 @@ resource "aws_wafv2_rule_group" "test" { block { custom_response { response_code = 429 - response_headers { + response_header { name = "x-hdr1" value = "test-val1" } - response_headers { + response_header { name = "x-hdr2" value = "test-val2" } @@ -2061,12 +2061,12 @@ resource "aws_wafv2_rule_group" "test" { action { count { custom_request_handling { - insert_headers { + insert_header { name = "x-hdr1" value = "test-val1" } - insert_headers { + insert_header { name = "x-hdr2" value = "test-val2" } diff --git a/aws/resource_aws_wafv2_web_acl_test.go b/aws/resource_aws_wafv2_web_acl_test.go index dfea54bf118..7451f528b19 100644 --- a/aws/resource_aws_wafv2_web_acl_test.go +++ b/aws/resource_aws_wafv2_web_acl_test.go @@ -1160,12 +1160,12 @@ func TestAccAwsWafv2WebACL_CustomRequestHandling(t *testing.T) { "name": "rule-1", "action.#": "1", "action.0.allow.#": "1", - "action.0.allow.0.custom_request_handling.#": "1", - "action.0.allow.0.custom_request_handling.0.insert_headers.#": "2", - "action.0.allow.0.custom_request_handling.0.insert_headers.0.name": "x-hdr1", - "action.0.allow.0.custom_request_handling.0.insert_headers.0.value": "test-value-1", - "action.0.allow.0.custom_request_handling.0.insert_headers.1.name": "x-hdr2", - "action.0.allow.0.custom_request_handling.0.insert_headers.1.value": "test-value-2", + "action.0.allow.0.custom_request_handling.#": "1", + "action.0.allow.0.custom_request_handling.0.insert_header.#": "2", + "action.0.allow.0.custom_request_handling.0.insert_header.0.name": "x-hdr1", + "action.0.allow.0.custom_request_handling.0.insert_header.0.value": "test-value-1", + "action.0.allow.0.custom_request_handling.0.insert_header.1.name": "x-hdr2", + "action.0.allow.0.custom_request_handling.0.insert_header.1.value": "test-value-2", "action.0.block.#": "0", "action.0.count.#": "0", "priority": "1", @@ -1193,12 +1193,12 @@ func TestAccAwsWafv2WebACL_CustomRequestHandling(t *testing.T) { "action.0.allow.#": "0", "action.0.block.#": "0", "action.0.count.#": "1", - "action.0.count.0.custom_request_handling.#": "1", - "action.0.count.0.custom_request_handling.0.insert_headers.#": "2", - "action.0.count.0.custom_request_handling.0.insert_headers.0.name": "x-hdr1", - "action.0.count.0.custom_request_handling.0.insert_headers.0.value": "test-value-1", - "action.0.count.0.custom_request_handling.0.insert_headers.1.name": "x-hdr2", - "action.0.count.0.custom_request_handling.0.insert_headers.1.value": "test-value-2", + "action.0.count.0.custom_request_handling.#": "1", + "action.0.count.0.custom_request_handling.0.insert_header.#": "2", + "action.0.count.0.custom_request_handling.0.insert_header.0.name": "x-hdr1", + "action.0.count.0.custom_request_handling.0.insert_header.0.value": "test-value-1", + "action.0.count.0.custom_request_handling.0.insert_header.1.name": "x-hdr2", + "action.0.count.0.custom_request_handling.0.insert_header.1.value": "test-value-2", "priority": "1", }), resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), @@ -1247,10 +1247,10 @@ func TestAccAwsWafv2WebACL_CustomResponse(t *testing.T) { "action.0.allow.#": "0", "action.0.block.#": "1", "action.0.block.0.custom_response.#": "1", - "action.0.block.0.custom_response.0.response_code": "403", - "action.0.block.0.custom_response.0.response_headers.#": "1", - "action.0.block.0.custom_response.0.response_headers.0.name": "x-hdr1", - "action.0.block.0.custom_response.0.response_headers.0.value": "custom-response-header-value", + "action.0.block.0.custom_response.0.response_code": "403", + "action.0.block.0.custom_response.0.response_header.#": "1", + "action.0.block.0.custom_response.0.response_header.0.name": "x-hdr1", + "action.0.block.0.custom_response.0.response_header.0.value": "custom-response-header-value", "action.0.count.#": "0", "priority": "1", }), @@ -1279,10 +1279,10 @@ func TestAccAwsWafv2WebACL_CustomResponse(t *testing.T) { "action.0.allow.#": "0", "action.0.block.#": "1", "action.0.block.0.custom_response.#": "1", - "action.0.block.0.custom_response.0.response_code": "429", - "action.0.block.0.custom_response.0.response_headers.#": "1", - "action.0.block.0.custom_response.0.response_headers.0.name": "x-hdr2", - "action.0.block.0.custom_response.0.response_headers.0.value": "custom-response-header-value", + "action.0.block.0.custom_response.0.response_code": "429", + "action.0.block.0.custom_response.0.response_header.#": "1", + "action.0.block.0.custom_response.0.response_header.0.name": "x-hdr2", + "action.0.block.0.custom_response.0.response_header.0.value": "custom-response-header-value", "action.0.count.#": "0", "priority": "1", }), @@ -1724,12 +1724,12 @@ resource "aws_wafv2_web_acl" "test" { action { count { custom_request_handling { - insert_headers { + insert_header { name = "%[2]s" value = "test-value-1" } - insert_headers { + insert_header { name = "%[3]s" value = "test-value-2" } @@ -1777,12 +1777,12 @@ resource "aws_wafv2_web_acl" "test" { action { allow { custom_request_handling { - insert_headers { + insert_header { name = "%[2]s" value = "test-value-1" } - insert_headers { + insert_header { name = "%[3]s" value = "test-value-2" } @@ -1836,7 +1836,7 @@ resource "aws_wafv2_web_acl" "test" { custom_response { response_code = %[3]d - response_headers { + response_header { name = "%[4]s" value = "custom-response-header-value" } diff --git a/aws/wafv2_helper.go b/aws/wafv2_helper.go index 29c94b688b7..3ab6a262f36 100644 --- a/aws/wafv2_helper.go +++ b/aws/wafv2_helper.go @@ -463,8 +463,8 @@ func wafv2CustomRequestHandlingSchema() *schema.Schema { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "insert_headers": { - Type: schema.TypeList, + "insert_header": { + Type: schema.TypeSet, Required: true, MinItems: 1, Elem: &schema.Resource{ @@ -510,8 +510,8 @@ func wafv2CustomResponseSchema() *schema.Schema { Required: true, ValidateFunc: validation.IntBetween(200, 599), }, - "response_headers": { - Type: schema.TypeList, + "response_header": { + Type: schema.TypeSet, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -643,7 +643,7 @@ func expandWafv2CustomResponse(l []interface{}) *wafv2.CustomResponse { if v, ok := m["response_code"]; ok && v.(int) > 0 { customResponse.ResponseCode = aws.Int64(int64(v.(int))) } - if v, ok := m["response_headers"]; ok && len(v.([]interface{})) > 0 { + if v, ok := m["response_header"]; ok && len(v.([]interface{})) > 0 { customResponse.ResponseHeaders = expandWafv2CustomHeaders(v.([]interface{})) } if v, ok := m["custom_response_body_key"]; ok && len(v.(string)) > 0 { @@ -661,7 +661,7 @@ func expandWafv2CustomRequestHandling(l []interface{}) *wafv2.CustomRequestHandl m := l[0].(map[string]interface{}) requestHandling := &wafv2.CustomRequestHandling{} - if v, ok := m["insert_headers"]; ok && len(v.([]interface{})) > 0 { + if v, ok := m["insert_header"]; ok && len(v.([]interface{})) > 0 { requestHandling.InsertHeaders = expandWafv2CustomHeaders(v.([]interface{})) } @@ -1140,7 +1140,7 @@ func flattenWafv2CustomRequestHandling(c *wafv2.CustomRequestHandling) interface } m := map[string]interface{}{ - "insert_headers": flattenWafv2CustomHeaders(c.InsertHeaders), + "insert_header": flattenWafv2CustomHeaders(c.InsertHeaders), } return []interface{}{m} @@ -1154,7 +1154,7 @@ func flattenWafv2CustomResponse(r *wafv2.CustomResponse) interface{} { m := map[string]interface{}{ "custom_response_body_key": aws.StringValue(r.CustomResponseBodyKey), "response_code": int(aws.Int64Value(r.ResponseCode)), - "response_headers": flattenWafv2CustomHeaders(r.ResponseHeaders), + "response_header": flattenWafv2CustomHeaders(r.ResponseHeaders), } return []interface{}{m} From b8400090a254a70ca57bb84d41d6ab274824c052 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Wed, 19 May 2021 13:15:13 -0700 Subject: [PATCH 027/398] Removing `custom_response_body_key` from the custom_response schema for now as it requires additional work to support. Can be addressed in a later PR. --- aws/wafv2_helper.go | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/aws/wafv2_helper.go b/aws/wafv2_helper.go index 3ab6a262f36..f77c7d28dc8 100644 --- a/aws/wafv2_helper.go +++ b/aws/wafv2_helper.go @@ -497,14 +497,6 @@ func wafv2CustomResponseSchema() *schema.Schema { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "custom_response_body_key": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.All( - validation.StringLenBetween(0, 128), - validation.StringMatch(regexp.MustCompile(`^[\w\-]+$`), "must contain only alphanumeric or hyphen characters"), - ), - }, "response_code": { Type: schema.TypeInt, Required: true, @@ -646,9 +638,6 @@ func expandWafv2CustomResponse(l []interface{}) *wafv2.CustomResponse { if v, ok := m["response_header"]; ok && len(v.([]interface{})) > 0 { customResponse.ResponseHeaders = expandWafv2CustomHeaders(v.([]interface{})) } - if v, ok := m["custom_response_body_key"]; ok && len(v.(string)) > 0 { - customResponse.CustomResponseBodyKey = aws.String(v.(string)) - } return customResponse } @@ -1152,9 +1141,8 @@ func flattenWafv2CustomResponse(r *wafv2.CustomResponse) interface{} { } m := map[string]interface{}{ - "custom_response_body_key": aws.StringValue(r.CustomResponseBodyKey), - "response_code": int(aws.Int64Value(r.ResponseCode)), - "response_header": flattenWafv2CustomHeaders(r.ResponseHeaders), + "response_code": int(aws.Int64Value(r.ResponseCode)), + "response_header": flattenWafv2CustomHeaders(r.ResponseHeaders), } return []interface{}{m} From 335160c751e9b18cd47eef6773432f3e3d85ee1e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 19 May 2021 16:32:19 -0400 Subject: [PATCH 028/398] r/aws_amplify_app: Remove 'name_prefix' as it's not compatible with name updating. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplifyApp_Name\|TestAccAWSAmplifyApp_basic' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplifyApp_Name\|TestAccAWSAmplifyApp_basic -timeout 180m === RUN TestAccAWSAmplifyApp_basic === PAUSE TestAccAWSAmplifyApp_basic === RUN TestAccAWSAmplifyApp_Name === PAUSE TestAccAWSAmplifyApp_Name === CONT TestAccAWSAmplifyApp_basic === CONT TestAccAWSAmplifyApp_Name --- PASS: TestAccAWSAmplifyApp_basic (13.33s) --- PASS: TestAccAWSAmplifyApp_Name (22.50s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 26.372s --- aws/resource_aws_amplify_app.go | 48 ++------ aws/resource_aws_amplify_app_test.go | 137 ++++++----------------- website/docs/r/amplify_app.html.markdown | 3 +- 3 files changed, 43 insertions(+), 145 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index 58e17bb7627..203ea55645f 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.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" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -232,20 +231,9 @@ func resourceAwsAmplifyApp() *schema.Resource { }, "name": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 255), - ConflictsWith: []string{"name_prefix"}, - }, - - "name_prefix": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ConflictsWith: []string{"name"}, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, "oauth_token": { @@ -309,7 +297,7 @@ func resourceAwsAmplifyAppCreate(d *schema.ResourceData, meta interface{}) error defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) - name := naming.Generate(d.Get("name").(string), d.Get("name_prefix").(string)) + name := d.Get("name").(string) input := &lify.CreateAppInput{ Name: aws.String(name), @@ -495,7 +483,6 @@ func resourceAwsAmplifyAppRead(d *schema.ResourceData, meta interface{}) error { d.Set("environment_variables", aws.StringValueMap(app.EnvironmentVariables)) d.Set("iam_service_role_arn", app.IamServiceRoleArn) d.Set("name", app.Name) - d.Set("name_prefix", naming.NamePrefixFromName(aws.StringValue(app.Name))) d.Set("platform", app.Platform) if app.ProductionBranch != nil { if err := d.Set("production_branch", []interface{}{flattenAmplifyProductionBranch(app.ProductionBranch)}); err != nil { @@ -506,29 +493,6 @@ func resourceAwsAmplifyAppRead(d *schema.ResourceData, meta interface{}) error { } d.Set("repository", app.Repository) - /* - if err := d.Set("auto_branch_creation_config", flattenAmplifyAutoBranchCreationConfig(resp.App.AutoBranchCreationConfig, resp.App.AutoBranchCreationPatterns, resp.App.EnableAutoBranchCreation)); err != nil { - return fmt.Errorf("error setting auto_branch_creation_config: %s", err) - } - if err := d.Set("basic_auth_config", flattenAmplifyBasicAuthConfig(resp.App.EnableBasicAuth, resp.App.BasicAuthCredentials)); err != nil { - return fmt.Errorf("error setting basic_auth_config: %s", err) - } - d.Set("build_spec", resp.App.BuildSpec) - if err := d.Set("custom_rules", flattenAmplifyCustomRules(resp.App.CustomRules)); err != nil { - return fmt.Errorf("error setting custom_rules: %s", err) - } - d.Set("default_domain", resp.App.DefaultDomain) - d.Set("description", resp.App.Description) - d.Set("enable_branch_auto_build", resp.App.EnableBranchAutoBuild) - if err := d.Set("environment_variables", aws.StringValueMap(resp.App.EnvironmentVariables)); err != nil { - return fmt.Errorf("error setting environment_variables: %s", err) - } - d.Set("iam_service_role_arn", resp.App.IamServiceRoleArn) - d.Set("name", resp.App.Name) - d.Set("platform", resp.App.Platform) - d.Set("repository", resp.App.Repository) - */ - tags := keyvaluetags.AmplifyKeyValueTags(app.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { @@ -606,6 +570,10 @@ func resourceAwsAmplifyAppUpdate(d *schema.ResourceData, meta interface{}) error input.IamServiceRoleArn = aws.String(d.Get("iam_service_role_arn").(string)) } + if d.HasChange("name") { + input.Name = aws.String(d.Get("name").(string)) + } + if d.HasChange("oauth_token") { input.OauthToken = aws.String(d.Get("oauth_token").(string)) } diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index caef2ec7e53..6b28c8d2dd1 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -11,7 +11,6 @@ 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" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -50,7 +49,6 @@ func TestAccAWSAmplifyApp_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), resource.TestCheckResourceAttr(resourceName, "iam_service_role_arn", ""), resource.TestCheckResourceAttr(resourceName, "name", rName), - resource.TestCheckResourceAttr(resourceName, "name_prefix", ""), resource.TestCheckNoResourceAttr(resourceName, "oauth_token"), resource.TestCheckResourceAttr(resourceName, "platform", "WEB"), resource.TestCheckResourceAttr(resourceName, "production_branch.#", "0"), @@ -67,8 +65,9 @@ func TestAccAWSAmplifyApp_basic(t *testing.T) { }) } -func TestAccAWSAmplifyApp_Name_Generated(t *testing.T) { +func TestAccAWSAmplifyApp_Tags(t *testing.T) { var app amplify.App + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ @@ -78,11 +77,11 @@ func TestAccAWSAmplifyApp_Name_Generated(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigNameGenerated(), + Config: testAccAWSAmplifyAppConfigTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), - resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, { @@ -90,42 +89,35 @@ func TestAccAWSAmplifyApp_Name_Generated(t *testing.T) { ImportState: true, ImportStateVerify: true, }, - }, - }) -} - -func TestAccAWSAmplifyApp_NamePrefix(t *testing.T) { - var app amplify.App - resourceName := "aws_amplify_app.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, - ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAmplifyAppDestroy, - Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigNamePrefix("tf-acc-test-prefix-"), + Config: testAccAWSAmplifyAppConfigTags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - naming.TestCheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), - resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + Config: testAccAWSAmplifyAppConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), }, }, }) } -func TestAccAWSAmplifyApp_Tags(t *testing.T) { +func TestAccAWSAmplifyApp_BasicAuthCredentials(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.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), @@ -133,11 +125,11 @@ func TestAccAWSAmplifyApp_Tags(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigTags1(rName, "key1", "value1"), + Config: testAccAWSAmplifyAppConfigBasicAuthCredentials(rName, credentials1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", credentials1), + resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "true"), ), }, { @@ -146,32 +138,31 @@ func TestAccAWSAmplifyApp_Tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Config: testAccAWSAmplifyAppConfigBasicAuthCredentials(rName, credentials2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", credentials2), + resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "true"), ), }, { - Config: testAccAWSAmplifyAppConfigTags1(rName, "key2", "value2"), + Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + // Clearing basic_auth_credentials not reflected in API. + // resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", ""), + resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "false"), ), }, }, }) } -func TestAccAWSAmplifyApp_rename(t *testing.T) { - resourceName := "aws_amplify_app.test" - - // name is not unique and can be renamed +func TestAccAWSAmplifyApp_Name(t *testing.T) { + var app amplify.App rName1 := acctest.RandomWithPrefix("tf-acc-test") rName2 := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, @@ -182,6 +173,7 @@ func TestAccAWSAmplifyApp_rename(t *testing.T) { { Config: testAccAWSAmplifyAppConfigName(rName1), Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), resource.TestCheckResourceAttr(resourceName, "name", rName1), ), }, @@ -193,6 +185,7 @@ func TestAccAWSAmplifyApp_rename(t *testing.T) { { Config: testAccAWSAmplifyAppConfigName(rName2), Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), resource.TestCheckResourceAttr(resourceName, "name", rName2), ), }, @@ -449,54 +442,6 @@ func TestAccAWSAmplifyApp_autoBranchCreationConfig(t *testing.T) { }) } -func TestAccAWSAmplifyApp_BasicAuthCredentials(t *testing.T) { - var app amplify.App - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_amplify_app.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: testAccCheckAWSAmplifyAppDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAmplifyAppConfigBasicAuthCredentials(rName, credentials1), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", credentials1), - resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "true"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyAppConfigBasicAuthCredentials(rName, credentials2), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", credentials2), - resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "true"), - ), - }, - { - Config: testAccAWSAmplifyAppConfigName(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - // Clearing basic_auth_credentials not reflected in API. - // resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", ""), - resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "false"), - ), - }, - }, - }) -} - func TestAccAWSAmplifyApp_enableBranchAutoBuild(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -625,20 +570,6 @@ resource "aws_amplify_app" "test" { `, rName) } -func testAccAWSAmplifyAppConfigNameGenerated() string { - return ` -resource "aws_amplify_app" "test" {} -` -} - -func testAccAWSAmplifyAppConfigNamePrefix(namePrefix string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name_prefix = %[1]q -} -`, namePrefix) -} - func testAccAWSAmplifyAppConfigDescription(rName string, description string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { diff --git a/website/docs/r/amplify_app.html.markdown b/website/docs/r/amplify_app.html.markdown index ec5d63afc6a..65f85c63bf8 100644 --- a/website/docs/r/amplify_app.html.markdown +++ b/website/docs/r/amplify_app.html.markdown @@ -130,8 +130,7 @@ resource "aws_amplify_app" "app" { The following arguments are supported: -* `name` - (Optional) Name of the Amplify App. 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`. +* `name` - (Required) Name of the Amplify App. * `access_token` - (Optional) Personal Access token for 3rd party source control system for an Amplify App, used to create webhook and read-only deploy key. Token is not stored. * `auto_branch_creation_config` - (Optional) Automated branch creation config for the Amplify App. An `auto_branch_creation_config` block is documented below. From cd8129c5fe99db17ec4aecf85bf78fd03820c036 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Wed, 19 May 2021 13:56:42 -0700 Subject: [PATCH 029/398] Fixed a bug introduced when response_header and insert_header were changed to TypeSet. --- aws/wafv2_helper.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/wafv2_helper.go b/aws/wafv2_helper.go index f77c7d28dc8..caa411ba1af 100644 --- a/aws/wafv2_helper.go +++ b/aws/wafv2_helper.go @@ -635,8 +635,8 @@ func expandWafv2CustomResponse(l []interface{}) *wafv2.CustomResponse { if v, ok := m["response_code"]; ok && v.(int) > 0 { customResponse.ResponseCode = aws.Int64(int64(v.(int))) } - if v, ok := m["response_header"]; ok && len(v.([]interface{})) > 0 { - customResponse.ResponseHeaders = expandWafv2CustomHeaders(v.([]interface{})) + if v, ok := m["response_header"]; ok && len(v.(*schema.Set).List()) > 0 { + customResponse.ResponseHeaders = expandWafv2CustomHeaders(v.(*schema.Set).List()) } return customResponse @@ -650,8 +650,8 @@ func expandWafv2CustomRequestHandling(l []interface{}) *wafv2.CustomRequestHandl m := l[0].(map[string]interface{}) requestHandling := &wafv2.CustomRequestHandling{} - if v, ok := m["insert_header"]; ok && len(v.([]interface{})) > 0 { - requestHandling.InsertHeaders = expandWafv2CustomHeaders(v.([]interface{})) + if v, ok := m["insert_header"]; ok && len(v.(*schema.Set).List()) > 0 { + requestHandling.InsertHeaders = expandWafv2CustomHeaders(v.(*schema.Set).List()) } return requestHandling From 94a9d17e4e766eb774174d7ef8696fbac221f8dd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 19 May 2021 17:26:45 -0400 Subject: [PATCH 030/398] r/aws_amplify_app: ForceNew if 'description' changes to "". Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplifyApp_Description' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplifyApp_Description -timeout 180m === RUN TestAccAWSAmplifyApp_Description === PAUSE TestAccAWSAmplifyApp_Description === CONT TestAccAWSAmplifyApp_Description --- PASS: TestAccAWSAmplifyApp_Description (33.31s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 36.482s --- aws/resource_aws_amplify_app.go | 10 +++++- aws/resource_aws_amplify_app_test.go | 53 +++++++++++++++++++++------- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index 203ea55645f..1070e34d2ae 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -1,6 +1,7 @@ package aws import ( + "context" "fmt" "log" "time" @@ -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" @@ -25,7 +27,13 @@ func resourceAwsAmplifyApp() *schema.Resource { State: schema.ImportStatePassthrough, }, - CustomizeDiff: SetTagsDiff, + CustomizeDiff: customdiff.Sequence( + SetTagsDiff, + customdiff.ForceNewIfChange("description", func(_ context.Context, old, new, meta interface{}) bool { + // Any existing description cannot be cleared. + return new.(string) == "" + }), + ), Schema: map[string]*schema.Schema{ "access_token": { diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 6b28c8d2dd1..942fbb12966 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -7,6 +7,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" @@ -193,14 +194,11 @@ func TestAccAWSAmplifyApp_Name(t *testing.T) { }) } -func TestAccAWSAmplifyApp_description(t *testing.T) { +func TestAccAWSAmplifyApp_Description(t *testing.T) { + var app1, app2, app3 amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" - // once set, description cannot be removed. - description1 := acctest.RandomWithPrefix("tf-acc-test") - description2 := acctest.RandomWithPrefix("tf-acc-test") - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), @@ -208,9 +206,10 @@ func TestAccAWSAmplifyApp_description(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigDescription(rName, description1), + Config: testAccAWSAmplifyAppConfigDescription(rName, "description 1"), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "description", description1), + testAccCheckAWSAmplifyAppExists(resourceName, &app1), + resource.TestCheckResourceAttr(resourceName, "description", "description 1"), ), }, { @@ -219,9 +218,19 @@ func TestAccAWSAmplifyApp_description(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigDescription(rName, description2), + Config: testAccAWSAmplifyAppConfigDescription(rName, "description 2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app2), + testAccCheckAWSAmplifyAppNotRecreated(&app1, &app2), + resource.TestCheckResourceAttr(resourceName, "description", "description 2"), + ), + }, + { + Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "description", description2), + testAccCheckAWSAmplifyAppExists(resourceName, &app3), + testAccCheckAWSAmplifyAppRecreated(&app2, &app3), + resource.TestCheckResourceAttr(resourceName, "description", ""), ), }, }, @@ -562,6 +571,26 @@ func testAccPreCheckAWSAmplify(t *testing.T) { } } +func testAccCheckAWSAmplifyAppNotRecreated(before, after *amplify.App) resource.TestCheckFunc { + return func(s *terraform.State) error { + if before, after := aws.StringValue(before.AppId), aws.StringValue(after.AppId); before != after { + return fmt.Errorf("Amplify App (%s/%s) recreated", before, after) + } + + return nil + } +} + +func testAccCheckAWSAmplifyAppRecreated(before, after *amplify.App) resource.TestCheckFunc { + return func(s *terraform.State) error { + if before, after := aws.StringValue(before.AppId), aws.StringValue(after.AppId); before == after { + return fmt.Errorf("Amplify App (%s) not recreated", before) + } + + return nil + } +} + func testAccAWSAmplifyAppConfigName(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { @@ -570,12 +599,12 @@ resource "aws_amplify_app" "test" { `, rName) } -func testAccAWSAmplifyAppConfigDescription(rName string, description string) string { +func testAccAWSAmplifyAppConfigDescription(rName, description string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q - description = "%s" + description = %[2]q } `, rName, description) } From 407f9fe2520ff3e7b103fa1c695c34c5dd07a760 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 19 May 2021 17:36:39 -0400 Subject: [PATCH 031/398] r/aws_amplify_app: ForceNew if 'build_spec' changes to "". Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplifyApp_BuildSpec' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplifyApp_BuildSpec -timeout 180m === RUN TestAccAWSAmplifyApp_BuildSpec === PAUSE TestAccAWSAmplifyApp_BuildSpec === CONT TestAccAWSAmplifyApp_BuildSpec --- PASS: TestAccAWSAmplifyApp_BuildSpec (33.73s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 37.005s --- aws/resource_aws_amplify_app.go | 6 +++++- aws/resource_aws_amplify_app_test.go | 32 +++++++++++++++++----------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index 1070e34d2ae..62422b1d0b3 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -29,8 +29,12 @@ func resourceAwsAmplifyApp() *schema.Resource { CustomizeDiff: customdiff.Sequence( SetTagsDiff, + customdiff.ForceNewIfChange("build_spec", func(_ context.Context, old, new, meta interface{}) bool { + // Any existing value cannot be cleared. + return new.(string) == "" + }), customdiff.ForceNewIfChange("description", func(_ context.Context, old, new, meta interface{}) bool { - // Any existing description cannot be cleared. + // Any existing value cannot be cleared. return new.(string) == "" }), ), diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 942fbb12966..a61704d2c3f 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -265,14 +265,11 @@ func TestAccAWSAmplifyApp_repository(t *testing.T) { }) } -func TestAccAWSAmplifyApp_buildSpec(t *testing.T) { +func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { + var app1, app2, app3 amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" - // once set, build_spec cannot be removed. - buildSpec1 := "version: 0.1" - buildSpec2 := "version: 0.2" - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), @@ -280,9 +277,10 @@ func TestAccAWSAmplifyApp_buildSpec(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigBuildSpec(rName, buildSpec1), + Config: testAccAWSAmplifyAppConfigBuildSpec(rName, "version: 0.1"), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "build_spec", buildSpec1), + testAccCheckAWSAmplifyAppExists(resourceName, &app1), + resource.TestCheckResourceAttr(resourceName, "build_spec", "version: 0.1"), ), }, { @@ -291,9 +289,19 @@ func TestAccAWSAmplifyApp_buildSpec(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigBuildSpec(rName, buildSpec2), + Config: testAccAWSAmplifyAppConfigBuildSpec(rName, "version: 0.2"), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "build_spec", buildSpec2), + testAccCheckAWSAmplifyAppExists(resourceName, &app2), + testAccCheckAWSAmplifyAppNotRecreated(&app1, &app2), + resource.TestCheckResourceAttr(resourceName, "build_spec", "version: 0.2"), + ), + }, + { + Config: testAccAWSAmplifyAppConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app3), + testAccCheckAWSAmplifyAppRecreated(&app2, &app3), + resource.TestCheckResourceAttr(resourceName, "build_spec", ""), ), }, }, @@ -623,12 +631,12 @@ resource "aws_amplify_app" "test" { `, rName, repository, accessToken) } -func testAccAWSAmplifyAppConfigBuildSpec(rName string, buildSpec string) string { +func testAccAWSAmplifyAppConfigBuildSpec(rName, buildSpec string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q - build_spec = "%s" + build_spec = %[2]q } `, rName, buildSpec) } From 4b7eac59c963dd881f75dd1ad78c0d5acd5302cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 May 2021 22:49:21 +0000 Subject: [PATCH 032/398] 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.42 to 1.38.43. - [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.42...v1.38.43) Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../aws/aws-sdk-go/aws/endpoints/defaults.go | 24 ++++++++++++++++--- .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 1ef8ab220aa..18aae82fc02 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.42 + github.com/aws/aws-sdk-go v1.38.43 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 7cad4d483ac..ee93f351187 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.42 h1:94blpbGDe2q5e0Xoop7131uzI2CH2qitQoptSMrkJP8= -github.com/aws/aws-sdk-go v1.38.42/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.43 h1:OKe9+Cdmrkhe0KXgpKhrDqidPhXQ4bv1FzzKnrmTJ5g= +github.com/aws/aws-sdk-go v1.38.43/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 060bff6c82b..b927bd350a6 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 @@ -5086,9 +5086,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: "qldb-fips.us-east-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-1", + }, + }, + "fips-us-east-2": endpoint{ + Hostname: "qldb-fips.us-east-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-2", + }, + }, + "fips-us-west-2": endpoint{ + Hostname: "qldb-fips.us-west-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-west-2", + }, + }, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-2": endpoint{}, }, }, "ram": 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 7573425b44d..a29d39b7cda 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.42" +const SDKVersion = "1.38.43" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 0c9348e184c..ff401fc6f4f 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.42 +# github.com/aws/aws-sdk-go v1.38.43 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From f5ff5146a76780ab954ca9b6b277692e3d97c910 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 May 2021 05:47:47 +0000 Subject: [PATCH 033/398] build(deps): bump hashicorp/github in /infrastructure/repository Bumps [hashicorp/github](https://github.com/hashicorp/terraform-provider-github) from 3.1.0 to 4.9.4. - [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) 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 e00ed481a6b..0f72141b88d 100644 --- a/infrastructure/repository/main.tf +++ b/infrastructure/repository/main.tf @@ -10,7 +10,7 @@ terraform { required_providers { github = { source = "hashicorp/github" - version = "3.1.0" + version = "4.9.4" } } From db6706763098d9415fbc0f086b46983d9e8857e8 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:03:46 -0400 Subject: [PATCH 034/398] i/r/servicecat_tag_option_budget_assoc: Add finder --- .../service/servicecatalog/finder/finder.go | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/aws/internal/service/servicecatalog/finder/finder.go b/aws/internal/service/servicecatalog/finder/finder.go index 252ddc8a86d..497218da55b 100644 --- a/aws/internal/service/servicecatalog/finder/finder.go +++ b/aws/internal/service/servicecatalog/finder/finder.go @@ -69,3 +69,32 @@ func ProductPortfolioAssociation(conn *servicecatalog.ServiceCatalog, acceptLang return result, err } + +func BudgetResourceAssociation(conn *servicecatalog.ServiceCatalog, budgetName, resourceID string) (*servicecatalog.BudgetDetail, error) { + input := &servicecatalog.ListBudgetsForResourceInput{ + ResourceId: aws.String(resourceID), + } + + var result *servicecatalog.BudgetDetail + + err := conn.ListBudgetsForResourcePages(input, func(page *servicecatalog.ListBudgetsForResourceOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, budget := range page.Budgets { + if budget == nil { + continue + } + + if aws.StringValue(budget.BudgetName) == budgetName { + result = budget + return false + } + } + + return !lastPage + }) + + return result, err +} From dbc84f2470d7030b11c4302bd45cfbe28890d12b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:04:12 -0400 Subject: [PATCH 035/398] i/r/servicecat_tag_option_budget_assoc: Add id funcs --- 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 0c545813232..1aa89da2789 100644 --- a/aws/internal/service/servicecatalog/id.go +++ b/aws/internal/service/servicecatalog/id.go @@ -32,3 +32,17 @@ func ProductPortfolioAssociationParseID(id string) (string, string, string, erro func ProductPortfolioAssociationCreateID(acceptLanguage, portfolioID, productID string) string { return strings.Join([]string{acceptLanguage, portfolioID, productID}, ":") } + +func BudgetResourceAssociationParseID(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), budgetName:resourceID", id) + } + + return parts[0], parts[1], nil +} + +func BudgetResourceAssociationID(budgetName, resourceID string) string { + return strings.Join([]string{budgetName, resourceID}, ":") +} From 57e169a6f18b0cf3496c36e2c985f18c5c811a5b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:04:42 -0400 Subject: [PATCH 036/398] i/r/servicecat_tag_option_budget_assoc: Add waiter/status funcs --- .../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 fa895722c72..ad804e572e6 100644 --- a/aws/internal/service/servicecatalog/waiter/status.go +++ b/aws/internal/service/servicecatalog/waiter/status.go @@ -226,3 +226,27 @@ func ServiceActionStatus(conn *servicecatalog.ServiceCatalog, acceptLanguage, id return output.ServiceActionDetail, servicecatalog.StatusAvailable, nil } } + +func BudgetResourceAssociationStatus(conn *servicecatalog.ServiceCatalog, budgetName, resourceID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.BudgetResourceAssociation(conn, budgetName, resourceID) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil, StatusNotFound, &resource.NotFoundError{ + Message: fmt.Sprintf("tag option resource association not found (%s): %s", tfservicecatalog.BudgetResourceAssociationID(budgetName, resourceID), err), + } + } + + if err != nil { + return nil, servicecatalog.StatusFailed, fmt.Errorf("error describing tag option resource association: %w", err) + } + + if output == nil { + return nil, StatusNotFound, &resource.NotFoundError{ + Message: fmt.Sprintf("finding tag option resource association (%s): empty response", tfservicecatalog.BudgetResourceAssociationID(budgetName, resourceID)), + } + } + + return output, servicecatalog.StatusAvailable, err + } +} diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index 4d58948483a..530a0629f7c 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -29,6 +29,9 @@ const ( ServiceActionReadyTimeout = 3 * time.Minute ServiceActionDeleteTimeout = 3 * time.Minute + BudgetResourceAssociationReadyTimeout = 3 * time.Minute + BudgetResourceAssociationDeleteTimeout = 3 * time.Minute + StatusNotFound = "NOT_FOUND" StatusUnavailable = "UNAVAILABLE" @@ -300,3 +303,33 @@ func ServiceActionDeleted(conn *servicecatalog.ServiceCatalog, acceptLanguage, i return err } + +func BudgetResourceAssociationReady(conn *servicecatalog.ServiceCatalog, budgetName, resourceID string) (*servicecatalog.BudgetDetail, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{StatusNotFound, StatusUnavailable}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: BudgetResourceAssociationStatus(conn, budgetName, resourceID), + Timeout: BudgetResourceAssociationReadyTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*servicecatalog.BudgetDetail); ok { + return output, err + } + + return nil, err +} + +func BudgetResourceAssociationDeleted(conn *servicecatalog.ServiceCatalog, budgetName, resourceID string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{servicecatalog.StatusAvailable}, + Target: []string{StatusNotFound, StatusUnavailable}, + Refresh: BudgetResourceAssociationStatus(conn, budgetName, resourceID), + Timeout: BudgetResourceAssociationDeleteTimeout, + } + + _, err := stateConf.WaitForState() + + return err +} From ca214f1042c742e916103ee1e249e766392f788d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:05:28 -0400 Subject: [PATCH 037/398] provider: Add new resource --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index e19ff3f6484..8bccd0f5150 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1021,6 +1021,7 @@ func Provider() *schema.Provider { "aws_securityhub_organization_admin_account": resourceAwsSecurityHubOrganizationAdminAccount(), "aws_securityhub_product_subscription": resourceAwsSecurityHubProductSubscription(), "aws_securityhub_standards_subscription": resourceAwsSecurityHubStandardsSubscription(), + "aws_servicecatalog_budget_resource_association": resourceAwsServiceCatalogBudgetResourceAssociation(), "aws_servicecatalog_constraint": resourceAwsServiceCatalogConstraint(), "aws_servicecatalog_organizations_access": resourceAwsServiceCatalogOrganizationsAccess(), "aws_servicecatalog_portfolio": resourceAwsServiceCatalogPortfolio(), From a70c472ae2678acd0631eb9f6de49eba03c7c30d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:06:05 -0400 Subject: [PATCH 038/398] r/servicecatalog_budget_resource_association: New resource --- ...vicecatalog_budget_resource_association.go | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_budget_resource_association.go diff --git a/aws/resource_aws_servicecatalog_budget_resource_association.go b/aws/resource_aws_servicecatalog_budget_resource_association.go new file mode 100644 index 00000000000..1d7a4925a9f --- /dev/null +++ b/aws/resource_aws_servicecatalog_budget_resource_association.go @@ -0,0 +1,146 @@ +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" + 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 resourceAwsServiceCatalogBudgetResourceAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsServiceCatalogBudgetResourceAssociationCreate, + Read: resourceAwsServiceCatalogBudgetResourceAssociationRead, + Delete: resourceAwsServiceCatalogBudgetResourceAssociationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "budget_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "resource_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceAwsServiceCatalogBudgetResourceAssociationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + input := &servicecatalog.AssociateBudgetWithResourceInput{ + BudgetName: aws.String(d.Get("budget_name").(string)), + ResourceId: aws.String(d.Get("resource_id").(string)), + } + + var output *servicecatalog.AssociateBudgetWithResourceOutput + err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + var err error + + output, err = conn.AssociateBudgetWithResource(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.AssociateBudgetWithResource(input) + } + + if err != nil { + return fmt.Errorf("error associating Service Catalog Budget with Resource: %w", err) + } + + if output == nil { + return fmt.Errorf("error creating Service Catalog Budget Resource Association: empty response") + } + + d.SetId(tfservicecatalog.BudgetResourceAssociationID(d.Get("budget_name").(string), d.Get("resource_id").(string))) + + return resourceAwsServiceCatalogBudgetResourceAssociationRead(d, meta) +} + +func resourceAwsServiceCatalogBudgetResourceAssociationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + budgetName, resourceID, err := tfservicecatalog.BudgetResourceAssociationParseID(d.Id()) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", d.Id(), err) + } + + output, err := waiter.BudgetResourceAssociationReady(conn, budgetName, resourceID) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Service Catalog Budget Resource Association (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error describing Service Catalog Budget Resource Association (%s): %w", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting Service Catalog Budget Resource Association (%s): empty response", d.Id()) + } + + d.Set("resource_id", resourceID) + d.Set("budget_name", output.BudgetName) + + return nil +} + +func resourceAwsServiceCatalogBudgetResourceAssociationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + budgetName, resourceID, err := tfservicecatalog.BudgetResourceAssociationParseID(d.Id()) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", d.Id(), err) + } + + input := &servicecatalog.DisassociateBudgetFromResourceInput{ + ResourceId: aws.String(resourceID), + BudgetName: aws.String(budgetName), + } + + _, err = conn.DisassociateBudgetFromResource(input) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { + return fmt.Errorf("error disassociating Service Catalog Budget from Resource (%s): %w", d.Id(), err) + } + + err = waiter.BudgetResourceAssociationDeleted(conn, budgetName, resourceID) + + if err != nil && !tfresource.NotFound(err) { + return fmt.Errorf("error waiting for Service Catalog Budget Resource Disassociation (%s): %w", d.Id(), err) + } + + return nil +} From c8d14eb18a7e0ba2e68b82d5e2c4f462a2fba844 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:06:40 -0400 Subject: [PATCH 039/398] tests/r/servicecatalog_budget_resource_association: New resource --- ...atalog_budget_resource_association_test.go | 268 ++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_budget_resource_association_test.go diff --git a/aws/resource_aws_servicecatalog_budget_resource_association_test.go b/aws/resource_aws_servicecatalog_budget_resource_association_test.go new file mode 100644 index 00000000000..1faf44cbfde --- /dev/null +++ b/aws/resource_aws_servicecatalog_budget_resource_association_test.go @@ -0,0 +1,268 @@ +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 budget resource associations +func init() { + resource.AddTestSweepers("aws_servicecatalog_budget_resource_association", &resource.Sweeper{ + Name: "aws_servicecatalog_budget_resource_association", + Dependencies: []string{}, + F: testSweepServiceCatalogBudgetResourceAssociations, + }) +} + +func testSweepServiceCatalogBudgetResourceAssociations(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 _, port := range page.PortfolioDetails { + if port == nil { + continue + } + + resInput := &servicecatalog.ListBudgetsForResourceInput{ + ResourceId: port.Id, + } + + err = conn.ListBudgetsForResourcePages(resInput, func(page *servicecatalog.ListBudgetsForResourceOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, budget := range page.Budgets { + if budget == nil { + continue + } + + r := resourceAwsServiceCatalogBudgetResourceAssociation() + d := r.Data(nil) + d.SetId(tfservicecatalog.BudgetResourceAssociationID(aws.StringValue(budget.BudgetName), aws.StringValue(port.Id))) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } + + return !lastPage + }) + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error describing Service Catalog Budget Resource (Portfolio) Associations for %s: %w", region, err)) + } + + prodInput := &servicecatalog.SearchProductsAsAdminInput{} + + err = conn.SearchProductsAsAdminPages(prodInput, func(page *servicecatalog.SearchProductsAsAdminOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, pvd := range page.ProductViewDetails { + if pvd == nil || pvd.ProductViewSummary == nil { + continue + } + + resInput := &servicecatalog.ListBudgetsForResourceInput{ + ResourceId: pvd.ProductViewSummary.ProductId, + } + + err = conn.ListBudgetsForResourcePages(resInput, func(page *servicecatalog.ListBudgetsForResourceOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, budget := range page.Budgets { + if budget == nil { + continue + } + + r := resourceAwsServiceCatalogBudgetResourceAssociation() + d := r.Data(nil) + d.SetId(tfservicecatalog.BudgetResourceAssociationID(aws.StringValue(budget.BudgetName), aws.StringValue(pvd.ProductViewSummary.ProductId))) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } + + return !lastPage + }) + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error describing Service Catalog Budget Resource (Product) Associations for %s: %w", region, err)) + } + + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping Service Catalog Budget Resource Associations for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping Service Catalog Budget Resource Associations sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() +} + +func TestAccAWSServiceCatalogBudgetResourceAssociation_basic(t *testing.T) { + resourceName := "aws_servicecatalog_budget_resource_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: testAccCheckAwsServiceCatalogBudgetResourceAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogBudgetResourceAssociationConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogBudgetResourceAssociationExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "resource_id", "aws_servicecatalog_portfolio.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "budget_name", "aws_budgets_budget.test", "name"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSServiceCatalogBudgetResourceAssociation_disappears(t *testing.T) { + resourceName := "aws_servicecatalog_budget_resource_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: testAccCheckAwsServiceCatalogBudgetResourceAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogBudgetResourceAssociationConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogBudgetResourceAssociationExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsServiceCatalogBudgetResourceAssociation(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAwsServiceCatalogBudgetResourceAssociationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).scconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_servicecatalog_budget_resource_association" { + continue + } + + budgetName, resourceID, err := tfservicecatalog.BudgetResourceAssociationParseID(rs.Primary.ID) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", rs.Primary.ID, err) + } + + err = waiter.BudgetResourceAssociationDeleted(conn, budgetName, resourceID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return fmt.Errorf("waiting for Service Catalog Budget Resource Association to be destroyed (%s): %w", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckAwsServiceCatalogBudgetResourceAssociationExists(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) + } + + budgetName, resourceID, err := tfservicecatalog.BudgetResourceAssociationParseID(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.BudgetResourceAssociationReady(conn, budgetName, resourceID) + + if err != nil { + return fmt.Errorf("waiting for Service Catalog Budget Resource Association existence (%s): %w", rs.Primary.ID, err) + } + + return nil + } +} + +func testAccAWSServiceCatalogBudgetResourceAssociationConfig_base(rName, budgetType, limitAmount, limitUnit, timePeriodStart, timeUnit string) string { + return fmt.Sprintf(` +resource "aws_servicecatalog_portfolio" "test" { + name = %[1]q + description = %[1]q + provider_name = %[1]q +} + +resource "aws_budgets_budget" "test" { + name = %[1]q + budget_type = %[2]q + limit_amount = %[3]q + limit_unit = %[4]q + time_period_start = %[5]q + time_unit = %[6]q +} +`, rName, budgetType, limitAmount, limitUnit, timePeriodStart, timeUnit) +} + +func testAccAWSServiceCatalogBudgetResourceAssociationConfig_basic(rName string) string { + return composeConfig(testAccAWSServiceCatalogBudgetResourceAssociationConfig_base(rName, "COST", "100.0", "USD", "2017-01-01_12:00", "MONTHLY"), fmt.Sprintf(` +resource "aws_servicecatalog_budget_resource_association" "test" { + resource_id = aws_servicecatalog_portfolio.test.id + budget_name = %[1]q +} +`, rName)) +} From b90d414f636564cd4f62df22f5196b162457bf6b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:07:08 -0400 Subject: [PATCH 040/398] docs/r/servicecatalog_budget_resource_association: New resource --- ..._budget_resource_association.html.markdown | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 website/docs/r/servicecatalog_budget_resource_association.html.markdown diff --git a/website/docs/r/servicecatalog_budget_resource_association.html.markdown b/website/docs/r/servicecatalog_budget_resource_association.html.markdown new file mode 100644 index 00000000000..7673ba5751d --- /dev/null +++ b/website/docs/r/servicecatalog_budget_resource_association.html.markdown @@ -0,0 +1,45 @@ +--- +subcategory: "Service Catalog" +layout: "aws" +page_title: "AWS: aws_servicecatalog_budget_resource_association" +description: |- + Manages a Service Catalog Budget Resource Association +--- + +# Resource: aws_servicecatalog_budget_resource_association + +Manages a Service Catalog Budget Resource Association. + +-> A "resource" is either a Service Catalog portfolio or product. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_servicecatalog_budget_resource_association" "example" { + budget_name = "budget-pjtvyakdlyo3m" + resource_id = "prod-dnigbtea24ste" +} +``` + +## Argument Reference + +The following arguments are required: + +* `budget_name` - (Required) Budget name. +* `resource_id` - (Required) Resource identifier. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - Identifier of the association. + +## Import + +`aws_servicecatalog_budget_resource_association` can be imported using the budget name and resource ID, e.g. + +``` +$ terraform import aws_servicecatalog_budget_resource_association.example budget-pjtvyakdlyo3m:prod-dnigbtea24ste +``` From 70ef01faaaf4172692b7ea3e1788a607a44938f0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:14:59 -0400 Subject: [PATCH 041/398] tests/r/servicecatalog_budget_resource_association: Precheck --- ...aws_servicecatalog_budget_resource_association_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_servicecatalog_budget_resource_association_test.go b/aws/resource_aws_servicecatalog_budget_resource_association_test.go index 1faf44cbfde..160fb3c9886 100644 --- a/aws/resource_aws_servicecatalog_budget_resource_association_test.go +++ b/aws/resource_aws_servicecatalog_budget_resource_association_test.go @@ -141,8 +141,8 @@ func TestAccAWSServiceCatalogBudgetResourceAssociation_basic(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck("budgets", t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID, "budgets"), Providers: testAccProviders, CheckDestroy: testAccCheckAwsServiceCatalogBudgetResourceAssociationDestroy, Steps: []resource.TestStep{ @@ -168,8 +168,8 @@ func TestAccAWSServiceCatalogBudgetResourceAssociation_disappears(t *testing.T) rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck("budgets", t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID, "budgets"), Providers: testAccProviders, CheckDestroy: testAccCheckAwsServiceCatalogBudgetResourceAssociationDestroy, Steps: []resource.TestStep{ From 3df8d2d52cb4773f8b3fd2d7d76f088c77e35aa2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 20 May 2021 09:20:24 -0400 Subject: [PATCH 042/398] Update CHANGELOG after 3.42.0 release. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 861ed880e64..47eb6123126 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## 3.43.0 (Unreleased) + ## 3.42.0 (May 20, 2021) FEATURES: From eb557c46e6db70badfae81d42f1c9dc1a6509906 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 20 May 2021 09:56:30 -0400 Subject: [PATCH 043/398] Run 'make fmt'. --- aws/resource_aws_glue_connection_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_glue_connection_test.go b/aws/resource_aws_glue_connection_test.go index 3f75319aae1..8c25778feac 100644 --- a/aws/resource_aws_glue_connection_test.go +++ b/aws/resource_aws_glue_connection_test.go @@ -600,7 +600,7 @@ resource "aws_glue_connection" "test" { } func testAccAWSGlueConnectionConfig_Network(rName string) string { - return fmt.Sprintf(` + return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" From a9e561beb3d2b81c8072caa08e2d6c97e6f6696f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 20 May 2021 10:18:52 -0400 Subject: [PATCH 044/398] Add CHANGELOG entry. --- .changelog/19375.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19375.txt diff --git a/.changelog/19375.txt b/.changelog/19375.txt new file mode 100644 index 00000000000..57e09778192 --- /dev/null +++ b/.changelog/19375.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_glue_connection: `connection_properties` are optional +``` \ No newline at end of file From 7691c9b21404c46812d9fa1d320299d3c4066df6 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 13 May 2021 08:38:01 -0400 Subject: [PATCH 045/398] hashibot: Migrate closed_issue_locker behavior to GitHub Actions Reference: https://github.com/hashicorp/terraform-provider-aws/issues/19356 --- .github/workflows/lock.yml | 23 +++++++++++++++++++++++ .hashibot.hcl | 13 ------------- 2 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/lock.yml diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml new file mode 100644 index 00000000000..412aa5a4a66 --- /dev/null +++ b/.github/workflows/lock.yml @@ -0,0 +1,23 @@ +name: 'Lock Threads' + +on: + schedule: + - cron: '50 1 * * *' + +jobs: + lock: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v2 + with: + github-token: ${{ github.token }} + issue-lock-comment: > + I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. + + If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. + issue-lock-inactive-days: '30' + pr-lock-comment: > + I'm going to lock this pull request because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. + + If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. + pr-lock-inactive-days: '30' diff --git a/.hashibot.hcl b/.hashibot.hcl index 7d61e87612d..02bfaaf4498 100644 --- a/.hashibot.hcl +++ b/.hashibot.hcl @@ -1,16 +1,3 @@ -poll "closed_issue_locker" "locker" { - schedule = "0 10 17 * * *" - closed_for = "720h" # 30 days - max_issues = 500 - sleep_between_issues = "5s" - - message = <<-EOF - I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. - - If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks! - EOF -} - queued_behavior "release_commenter" "releases" { repo_prefix = "terraform-provider-" From ff0de123b3f3389be658b416803c964b04c6c963 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 13 May 2021 08:59:02 -0400 Subject: [PATCH 046/398] hashibot: Migrate pull_request_path_labeler behavior to GitHub Actions Reference: https://github.com/hashicorp/terraform-provider-aws/issues/19356 Lift and shift of existing labeling configuration with conversion to YAML syntax. --- .github/labeler-pr-triage.yml | 806 +++++++++++++++ .github/workflows/pull_requests.yml | 9 + .hashibot.hcl | 988 ------------------- docs/contributing/contribution-checklists.md | 23 +- 4 files changed, 825 insertions(+), 1001 deletions(-) create mode 100644 .github/labeler-pr-triage.yml diff --git a/.github/labeler-pr-triage.yml b/.github/labeler-pr-triage.yml new file mode 100644 index 00000000000..4329332f996 --- /dev/null +++ b/.github/labeler-pr-triage.yml @@ -0,0 +1,806 @@ +dependencies: + - '.github/dependabot.yml' +documentation: + - 'docs/**/*' + - 'website/**/*' + - '*.md' +examples: + - 'examples/**/*' +provider: + - '*.md' + - '.github/**/*' + - '.gitignore' + - '.go-version' + - 'aws/auth_helpers.go' + - 'aws/awserr.go' + - 'aws/config.go' + - 'aws/*_aws_arn*' + - 'aws/*_aws_ip_ranges*' + - 'aws/*_aws_partition*' + - 'aws/*_aws_region*' + - 'aws/internal/flatmap/**/*' + - 'aws/internal/keyvaluetags/**/*' + - 'aws/internal/naming/**/*' + - 'aws/provider.go' + - 'aws/utils.go' + - 'docs/*.md' + - 'docs/contributing/**/*' + - 'GNUmakefile' + - 'infrastructure/**/*' + - 'main.go' + - 'website/docs/index.html.markdown' + - 'website/**/arn*' + - 'website/**/ip_ranges*' + - 'website/**/partition*' + - 'website/**/region*' +service/accessanalyzer: + - 'aws/internal/service/accessanalyzer/**/*' + - '**/*_accessanalyzer_*' + - '**/accessanalyzer_*' +service/acm: + - 'aws/internal/service/acm/**/*' + - '**/*_acm_*' + - '**/acm_*' +service/acmpca: + - 'aws/internal/service/acmpca/**/*' + - '**/*_acmpca_*' + - '**/acmpca_*' +service/alexaforbusiness: + - 'aws/internal/service/alexaforbusiness/**/*' + - '**/*_alexaforbusiness_*' + - '**/alexaforbusiness_*' +service/amplify: + - 'aws/internal/service/amplify/**/*' + - '**/*_amplify_*' + - '**/amplify_*' +service/apigateway: + - 'aws/internal/service/apigateway/**/*' + - '**/*_api_gateway_[^v][^2][^_]*' + - '**/*_api_gateway_vpc_link*' + - '**/api_gateway_[^v][^2][^_]*' + - '**/api_gateway_vpc_link*' +service/apigatewayv2: + - 'aws/internal/service/apigatewayv2/**/*' + - '**/*_api_gateway_v2_*' + - '**/*_apigatewayv2_*' + - '**/api_gateway_v2_*' + - '**/apigatewayv2_*' +service/appconfig: + - 'aws/internal/service/appconfig/**/*' + - '**/*_appconfig_*' + - '**/appconfig_*' +service/applicationautoscaling: + - 'aws/internal/service/applicationautoscaling/**/*' + - '**/*_appautoscaling_*' + - '**/appautoscaling_*' +service/applicationinsights: + - 'aws/internal/service/applicationinsights/**/*' + - '**/*_applicationinsights_*' + - '**/applicationinsights_*' +service/appmesh: + - 'aws/internal/service/appmesh/**/*' + - '**/*_appmesh_*' + - '**/appmesh_*' +service/appstream: + - 'aws/internal/service/appstream/**/*' + - '**/*_appstream_*' + - '**/appstream_*' +service/appsync: + - 'aws/internal/service/appsync/**/*' + - '**/*_appsync_*' + - '**/appsync_*' +service/athena: + - 'aws/internal/service/athena/**/*' + - '**/*_athena_*' + - '**/athena_*' +service/auditmanager: + - 'aws/internal/service/auditmanager/**/*' + - '**/*_auditmanager_*' + - '**/auditmanager_*' +service/autoscaling: + - 'aws/internal/service/autoscaling/**/*' + - '**/*_autoscaling_*' + - '**/autoscaling_*' + - 'aws/*_aws_launch_configuration*' + - 'website/**/launch_configuration*' +service/autoscalingplans: + - 'aws/internal/service/autoscalingplans/**/*' + - '**/*_autoscalingplans_*' + - '**/autoscalingplans_*' +service/backup: + - 'aws/internal/service/backup/**/*' + - '**/*backup_*' + - '**/backup_*' +service/batch: + - 'aws/internal/service/batch/**/*' + - '**/*_batch_*' + - '**/batch_*' +service/budgets: + - 'aws/internal/service/budgets/**/*' + - '**/*_budgets_*' + - '**/budgets_*' +service/cloud9: + - 'aws/internal/service/cloud9/**/*' + - '**/*_cloud9_*' + - '**/cloud9_*' +service/clouddirectory: + - 'aws/internal/service/clouddirectory/**/*' + - '**/*_clouddirectory_*' + - '**/clouddirectory_*' +service/cloudformation: + - 'aws/internal/service/cloudformation/**/*' + - '**/*_cloudformation_*' + - '**/cloudformation_*' +service/cloudfront: + - 'aws/internal/service/cloudfront/**/*' + - '**/*_cloudfront_*' + - '**/cloudfront_*' +service/cloudhsmv2: + - 'aws/internal/service/cloudhsmv2/**/*' + - '**/*_cloudhsm_v2_*' + - '**/cloudhsm_v2_*' +service/cloudsearch: + - 'aws/internal/service/cloudsearch/**/*' + - '**/*_cloudsearch_*' + - '**/cloudsearch_*' +service/cloudtrail: + - 'aws/internal/service/cloudtrail/**/*' + - '**/*_cloudtrail*' + - '**/cloudtrail*' +service/cloudwatch: + - 'aws/internal/service/cloudwatch/**/*' + - '**/*_cloudwatch_dashboard*' + - '**/*_cloudwatch_metric_alarm*' + - '**/cloudwatch_dashboard*' + - '**/cloudwatch_metric_alarm*' +service/cloudwatchevents: + - 'aws/internal/service/cloudwatchevents/**/*' + - '**/*_cloudwatch_event_*' + - '**/cloudwatch_event_*' +service/cloudwatchlogs: + - 'aws/internal/service/cloudwatchlogs/**/*' + - '**/*_cloudwatch_log_*' + - '**/cloudwatch_log_*' + - '**/*_cloudwatch_query_definition*' + - '**/cloudwatch_query_definition*' +service/codeartifact: + - 'aws/internal/service/codeartifact/**/*' + - '**/*_codeartifact_*' + - '**/codeartifact_*' +service/codebuild: + - 'aws/internal/service/codebuild/**/*' + - '**/*_codebuild_*' + - '**/codebuild_*' +service/codecommit: + - 'aws/internal/service/codecommit/**/*' + - '**/*_codecommit_*' + - '**/codecommit_*' +service/codedeploy: + - 'aws/internal/service/codedeploy/**/*' + - '**/*_codedeploy_*' + - '**/codedeploy_*' +service/codepipeline: + - 'aws/internal/service/codepipeline/**/*' + - '**/*_codepipeline_*' + - '**/codepipeline_*' +service/codestar: + - 'aws/internal/service/codestar/**/*' + - '**/*_codestar_*' + - '**/codestar_*' +service/codestarconnections: + - 'aws/internal/service/codestarconnections/**/*' + - '**/*_codestarconnections_*' + - '**/codestarconnections_*' +service/codestarnotifications: + - 'aws/internal/service/codestarnotifications/**/*' + - '**/*_codestarnotifications_*' + - '**/codestarnotifications_*' +service/cognito: + - 'aws/internal/service/cognitoidentity/**/*' + - 'aws/internal/service/cognitoidentityprovider/**/*' + - '**/*_cognito_*' + - '**/cognito_*' +service/comprehend: + - 'aws/internal/service/comprehend/**/*' + - '**/*_comprehend_*' + - '**/comprehend_*' +service/configservice: + - 'aws/internal/service/configservice/**/*' + - 'aws/*_aws_config_*' + - 'website/**/config_*' +service/connect: + - 'aws/internal/service/connect/**/*' + - 'aws/*_aws_connect_*' + - 'website/**/connect_*' +service/costandusagereportservice: + - 'aws/internal/service/costandusagereportservice/**/*' + - 'aws/*_aws_cur_*' + - 'website/**/cur_*' +service/databasemigrationservice: + - 'aws/internal/service/databasemigrationservice/**/*' + - '**/*_dms_*' + - '**/dms_*' +service/dataexchange: + - 'aws/internal/service/dataexchange/**/*' + - '**/*_dataexchange_*' + - '**/dataexchange_*' +service/datapipeline: + - 'aws/internal/service/datapipeline/**/*' + - '**/*_datapipeline_*' + - '**/datapipeline_*' +service/datasync: + - 'aws/internal/service/datasync/**/*' + - '**/*_datasync_*' + - '**/datasync_*' +service/dax: + - 'aws/internal/service/dax/**/*' + - '**/*_dax_*' + - '**/dax_*' +service/detective: + - 'aws/internal/service/detective/**/*' + - '**/*_detective_*' + - '**/detective_*' +service/devicefarm: + - 'aws/internal/service/devicefarm/**/*' + - '**/*_devicefarm_*' + - '**/devicefarm_*' +service/directconnect: + - 'aws/internal/service/directconnect/**/*' + - '**/*_dx_*' + - '**/dx_*' +service/directoryservice: + - 'aws/internal/service/directoryservice/**/*' + - '**/*_directory_service_*' + - '**/directory_service_*' +service/dlm: + - 'aws/internal/service/dlm/**/*' + - '**/*_dlm_*' + - '**/dlm_*' +service/docdb: + - 'aws/internal/service/docdb/**/*' + - '**/*_docdb_*' + - '**/docdb_*' +service/dynamodb: + - 'aws/internal/service/dynamodb/**/*' + - '**/*_dynamodb_*' + - '**/dynamodb_*' + # Special casing this one because the files aren't _ec2_ +service/ec2: + - 'aws/internal/service/ec2/**/*' + - '**/*_ec2_*' + - '**/ec2_*' + - 'aws/*_aws_ami*' + - 'aws/*_aws_availability_zone*' + - 'aws/*_aws_customer_gateway*' + - 'aws/*_aws_default_network_acl*' + - 'aws/*_aws_default_route_table*' + - 'aws/*_aws_default_security_group*' + - 'aws/*_aws_default_subnet*' + - 'aws/*_aws_default_vpc*' + - 'aws/*_aws_ebs_*' + - 'aws/*_aws_egress_only_internet_gateway*' + - 'aws/*_aws_eip*' + - 'aws/*_aws_flow_log*' + - 'aws/*_aws_instance*' + - 'aws/*_aws_internet_gateway*' + - 'aws/*_aws_key_pair*' + - 'aws/*_aws_launch_template*' + - 'aws/*_aws_main_route_table_association*' + - 'aws/*_aws_nat_gateway*' + - 'aws/*_aws_network_acl*' + - 'aws/*_aws_network_interface*' + - 'aws/*_aws_placement_group*' + - 'aws/*_aws_prefix_list*' + - 'aws/*_aws_route_table*' + - 'aws/*_aws_route.*' + - 'aws/*_aws_security_group*' + - 'aws/*_aws_snapshot_create_volume_permission*' + - 'aws/*_aws_spot*' + - 'aws/*_aws_subnet*' + - 'aws/*_aws_vpc*' + - 'aws/*_aws_vpn*' + - 'aws/*_aws_volume_attachment*' + - 'website/**/availability_zone*' + - 'website/**/customer_gateway*' + - 'website/**/default_network_acl*' + - 'website/**/default_route_table*' + - 'website/**/default_security_group*' + - 'website/**/default_subnet*' + - 'website/**/default_vpc*' + - 'website/**/ebs_*' + - 'website/**/egress_only_internet_gateway*' + - 'website/**/eip*' + - 'website/**/flow_log*' + - 'website/**/instance*' + - 'website/**/internet_gateway*' + - 'website/**/key_pair*' + - 'website/**/launch_template*' + - 'website/**/main_route_table_association*' + - 'website/**/nat_gateway*' + - 'website/**/network_acl*' + - 'website/**/network_interface*' + - 'website/**/placement_group*' + - 'website/**/prefix_list*' + - 'website/**/route_table*' + - 'website/**/route.*' + - 'website/**/security_group*' + - 'website/**/snapshot_create_volume_permission*' + - 'website/**/spot_*' + - 'website/**/subnet*' + - 'website/**/vpc*' + - 'website/**/vpn*' + - 'website/**/volume_attachment*' +service/ecr: + - 'aws/internal/service/ecr/**/*' + - '**/*_ecr_*' + - '**/ecr_*' +service/ecrpublic: + - 'aws/internal/service/ecrpublic/**/*' + - '**/*_ecrpublic_*' + - '**/ecrpublic_*' +service/ecs: + - 'aws/internal/service/ecs/**/*' + - '**/*_ecs_*' + - '**/ecs_*' +service/efs: + - 'aws/internal/service/efs/**/*' + - '**/*_efs_*' + - '**/efs_*' +service/eks: + - 'aws/internal/service/eks/**/*' + - '**/*_eks_*' + - '**/eks_*' +service/elastic-transcoder: + - 'aws/internal/service/elastictranscoder/**/*' + - '**/*_elastictranscoder_*' + - '**/elastictranscoder_*' + - '**/*_elastic_transcoder_*' + - '**/elastic_transcoder_*' +service/elasticache: + - 'aws/internal/service/elasticache/**/*' + - '**/*_elasticache_*' + - '**/elasticache_*' +service/elasticbeanstalk: + - 'aws/internal/service/elasticbeanstalk/**/*' + - '**/*_elastic_beanstalk_*' + - '**/elastic_beanstalk_*' +service/elasticsearch: + - 'aws/internal/service/elasticsearchservice/**/*' + - '**/*_elasticsearch_*' + - '**/elasticsearch_*' + - '**/*_elasticsearchservice*' +service/elb: + - 'aws/internal/service/elb/**/*' + - 'aws/*_aws_app_cookie_stickiness_policy*' + - 'aws/*_aws_elb*' + - 'aws/*_aws_lb_cookie_stickiness_policy*' + - 'aws/*_aws_lb_ssl_negotiation_policy*' + - 'aws/*_aws_load_balancer*' + - 'aws/*_aws_proxy_protocol_policy*' + - 'website/**/app_cookie_stickiness_policy*' + - 'website/**/elb*' + - 'website/**/lb_cookie_stickiness_policy*' + - 'website/**/lb_ssl_negotiation_policy*' + - 'website/**/load_balancer*' + - 'website/**/proxy_protocol_policy*' +service/elbv2: + - 'aws/internal/service/elbv2/**/*' + - 'aws/*_lb.*' + - 'aws/*_lb_listener*' + - 'aws/*_lb_target_group*' + - 'website/**/lb.*' + - 'website/**/lb_listener*' + - 'website/**/lb_target_group*' +service/emr: + - 'aws/internal/service/emr/**/*' + - '**/*_emr_*' + - '**/emr_*' +service/emrcontainers: + - 'aws/internal/service/emrcontainers/**/*' + - '**/*_emrcontainers_*' + - '**/emrcontainers_*' +service/eventbridge: + # EventBridge is rebranded CloudWatch Events + - 'aws/internal/service/cloudwatchevents/**/*' + - '**/*_cloudwatch_event_*' + - '**/cloudwatch_event_*' +service/firehose: + - 'aws/internal/service/firehose/**/*' + - '**/*_firehose_*' + - '**/firehose_*' +service/fms: + - 'aws/internal/service/fms/**/*' + - '**/*_fms_*' + - '**/fms_*' +service/fsx: + - 'aws/internal/service/fsx/**/*' + - '**/*_fsx_*' + - '**/fsx_*' +service/gamelift: + - 'aws/internal/service/gamelift/**/*' + - '**/*_gamelift_*' + - '**/gamelift_*' +service/glacier: + - 'aws/internal/service/glacier/**/*' + - '**/*_glacier_*' + - '**/glacier_*' +service/globalaccelerator: + - 'aws/internal/service/globalaccelerator/**/*' + - '**/*_globalaccelerator_*' + - '**/globalaccelerator_*' +service/glue: + - 'aws/internal/service/glue/**/*' + - '**/*_glue_*' + - '**/glue_*' +service/greengrass: + - 'aws/internal/service/greengrass/**/*' + - '**/*_greengrass_*' + - '**/greengrass_*' +service/guardduty: + - 'aws/internal/service/guardduty/**/*' + - '**/*_guardduty_*' + - '**/guardduty_*' +service/iam: + - 'aws/internal/service/iam/**/*' + - '**/*_iam_*' + - '**/iam_*' +service/identitystore: + - 'aws/internal/service/identitystore/**/*' + - '**/*_identitystore_*' + - '**/identitystore_*' +service/imagebuilder: + - 'aws/internal/service/imagebuilder/**/*' + - '**/*_imagebuilder_*' + - '**/imagebuilder_*' +service/inspector: + - 'aws/internal/service/inspector/**/*' + - '**/*_inspector_*' + - '**/inspector_*' +service/iot: + - 'aws/internal/service/iot/**/*' + - '**/*_iot_*' + - '**/iot_*' +service/iotanalytics: + - 'aws/internal/service/iotanalytics/**/*' + - '**/*_iotanalytics_*' + - '**/iotanalytics_*' +service/iotevents: + - 'aws/internal/service/iotevents/**/*' + - '**/*_iotevents_*' + - '**/iotevents_*' +service/kafka: + - 'aws/internal/service/kafka/**/*' + - '**/*_msk_*' + - '**/msk_*' +service/kinesis: + - 'aws/internal/service/kinesis/**/*' + - 'aws/*_aws_kinesis_stream*' + - 'website/kinesis_stream*' +service/kinesisanalytics: + - 'aws/internal/service/kinesisanalytics/**/*' + - '**/*_kinesis_analytics_*' + - '**/kinesis_analytics_*' +service/kinesisanalyticsv2: + - 'aws/internal/service/kinesisanalyticsv2/**/*' + - '**/*_kinesisanalyticsv2_*' + - '**/kinesisanalyticsv2_*' +service/kms: + - 'aws/internal/service/kms/**/*' + - '**/*_kms_*' + - '**/kms_*' +service/lakeformation: + - 'aws/internal/service/lakeformation/**/*' + - '**/*_lakeformation_*' + - '**/lakeformation_*' +service/lambda: + - 'aws/internal/service/lambda/**/*' + - '**/*_lambda_*' + - '**/lambda_*' +service/lexmodelbuildingservice: + - 'aws/internal/service/lexmodelbuildingservice/**/*' + - '**/*_lex_*' + - '**/lex_*' +service/licensemanager: + - 'aws/internal/service/licensemanager/**/*' + - '**/*_licensemanager_*' + - '**/licensemanager_*' +service/lightsail: + - 'aws/internal/service/lightsail/**/*' + - '**/*_lightsail_*' + - '**/lightsail_*' +service/machinelearning: + - 'aws/internal/service/machinelearning/**/*' + - '**/*_machinelearning_*' + - '**/machinelearning_*' +service/macie: + - 'aws/internal/service/macie/**/*' + - '**/*_macie_*' + - '**/macie_*' +service/macie2: + - 'aws/internal/service/macie2/**/*' + - '**/*_macie2_*' + - '**/macie2_*' +service/marketplacecatalog: + - 'aws/internal/service/marketplacecatalog/**/*' + - '**/*_marketplace_catalog_*' + - '**/marketplace_catalog_*' +service/mediaconnect: + - 'aws/internal/service/mediaconnect/**/*' + - '**/*_media_connect_*' + - '**/media_connect_*' +service/mediaconvert: + - 'aws/internal/service/mediaconvert/**/*' + - '**/*_media_convert_*' + - '**/media_convert_*' +service/medialive: + - 'aws/internal/service/medialive/**/*' + - '**/*_media_live_*' + - '**/media_live_*' +service/mediapackage: + - 'aws/internal/service/mediapackage/**/*' + - '**/*_media_package_*' + - '**/media_package_*' +service/mediastore: + - 'aws/internal/service/mediastore/**/*' + - '**/*_media_store_*' + - '**/media_store_*' +service/mediatailor: + - 'aws/internal/service/mediatailor/**/*' + - '**/*_media_tailor_*' + - '**/media_tailor_*' +service/mobile: + - 'aws/internal/service/mobile/**/*' + - '**/*_mobile_*' + - '**/mobile_*' +service/mq: + - 'aws/internal/service/mq/**/*' + - '**/*_mq_*' + - '**/mq_*' +service/mwaa: + - 'aws/internal/service/mwaa/**/*' + - '**/*_mwaa_*' + - '**/mwaa_*' +service/neptune: + - 'aws/internal/service/neptune/**/*' + - '**/*_neptune_*' + - '**/neptune_*' +service/networkfirewall: + - 'aws/internal/service/networkfirewall/**/*' + - '**/*_networkfirewall_*' + - '**/networkfirewall_*' +service/networkmanager: + - 'aws/internal/service/networkmanager/**/*' + - '**/*_networkmanager_*' + - '**/networkmanager_*' +service/opsworks: + - 'aws/internal/service/opsworks/**/*' + - '**/*_opsworks_*' + - '**/opsworks_*' +service/organizations: + - 'aws/internal/service/organizations/**/*' + - '**/*_organizations_*' + - '**/organizations_*' +service/outposts: + - 'aws/internal/service/outposts/**/*' + - '**/*_outposts_*' + - '**/outposts_*' +service/pinpoint: + - 'aws/internal/service/pinpoint/**/*' + - '**/*_pinpoint_*' + - '**/pinpoint_*' +service/polly: + - 'aws/internal/service/polly/**/*' + - '**/*_polly_*' + - '**/polly_*' +service/pricing: + - 'aws/internal/service/pricing/**/*' + - '**/*_pricing_*' + - '**/pricing_*' +service/prometheusservice: + - 'aws/internal/service/prometheus/**/*' + - '**/*_prometheus_*' + - '**/prometheus_*' +service/qldb: + - 'aws/internal/service/qldb/**/*' + - '**/*_qldb_*' + - '**/qldb_*' +service/quicksight: + - 'aws/internal/service/quicksight/**/*' + - '**/*_quicksight_*' + - '**/quicksight_*' +service/ram: + - 'aws/internal/service/ram/**/*' + - '**/*_ram_*' + - '**/ram_*' +service/rds: + - 'aws/internal/service/rds/**/*' + - 'aws/*_aws_db_*' + - 'aws/*_aws_rds_*' + - 'website/**/db_*' + - 'website/**/rds_*' +service/redshift: + - 'aws/internal/service/redshift/**/*' + - '**/*_redshift_*' + - '**/redshift_*' +service/resourcegroups: + - 'aws/internal/service/resourcegroups/**/*' + - '**/*_resourcegroups_*' + - '**/resourcegroups_*' +service/resourcegroupstaggingapi: + - 'aws/internal/service/resourcegroupstaggingapi/**/*' + - '**/*_resourcegroupstaggingapi_*' + - '**/resourcegroupstaggingapi_*' +service/robomaker: + - 'aws/internal/service/robomaker/**/*' + - '**/*_robomaker_*' + - '**/robomaker_*' +service/route53: + - 'aws/internal/service/route53/**/*' + - '**/*_route53_delegation_set*' + - '**/*_route53_health_check*' + - '**/*_route53_query_log*' + - '**/*_route53_record*' + - '**/*_route53_vpc_association_authorization*' + - '**/*_route53_zone*' + - '**/route53_delegation_set*' + - '**/route53_health_check*' + - '**/route53_query_log*' + - '**/route53_record*' + - '**/route53_vpc_association_authorization*' + - '**/route53_zone*' +service/route53domains: + - 'aws/internal/service/route53domains/**/*' + - '**/*_route53domains_*' + - '**/route53domains_*' +service/route53resolver: + - 'aws/internal/service/route53resolver/**/*' + - '**/*_route53_resolver_*' + - '**/route53_resolver_*' +service/s3: + - 'aws/internal/service/s3/**/*' + - '**/*_s3_bucket*' + - '**/s3_bucket*' + - '**/*_s3_object*' + - '**/s3_object*' + - 'aws/*_aws_canonical_user_id*' + - 'website/**/canonical_user_id*' +service/s3control: + - 'aws/internal/service/s3control/**/*' + - '**/*_s3_account_*' + - '**/s3_account_*' + - '**/*_s3control_*' + - '**/s3control_*' +service/s3outposts: + - 'aws/internal/service/s3outposts/**/*' + - '**/*_s3outposts_*' + - '**/s3outposts_*' +service/sagemaker: + - 'aws/internal/service/sagemaker/**/*' + - '**/*_sagemaker_*' + - '**/sagemaker_*' +service/secretsmanager: + - 'aws/internal/service/secretsmanager/**/*' + - '**/*_secretsmanager_*' + - '**/secretsmanager_*' +service/securityhub: + - 'aws/internal/service/securityhub/**/*' + - '**/*_securityhub_*' + - '**/securityhub_*' +service/serverlessapplicationrepository: + - 'aws/internal/service/serverlessapplicationrepository/**/*' + - '**/*_serverlessapplicationrepository_*' + - '**/serverlessapplicationrepository_*' +service/servicecatalog: + - 'aws/internal/service/servicecatalog/**/*' + - '**/*_servicecatalog_*' + - '**/servicecatalog_*' +service/servicediscovery: + - 'aws/internal/service/servicediscovery/**/*' + - '**/*_service_discovery_*' + - '**/service_discovery_*' +service/servicequotas: + - 'aws/internal/service/servicequotas/**/*' + - '**/*_servicequotas_*' + - '**/servicequotas_*' +service/ses: + - 'aws/internal/service/ses/**/*' + - '**/*_ses_*' + - '**/ses_*' +service/sfn: + - 'aws/internal/service/sfn/**/*' + - '**/*_sfn_*' + - '**/sfn_*' +service/shield: + - 'aws/internal/service/shield/**/*' + - '**/*_shield_*' + - '**/shield_*' +service/signer: + - '**/*_signer_*' + - '**/signer_*' +service/simpledb: + - 'aws/internal/service/simpledb/**/*' + - '**/*_simpledb_*' + - '**/simpledb_*' +service/snowball: + - 'aws/internal/service/snowball/**/*' + - '**/*_snowball_*' + - '**/snowball_*' +service/sns: + - 'aws/internal/service/sns/**/*' + - '**/*_sns_*' + - '**/sns_*' +service/sqs: + - 'aws/internal/service/sqs/**/*' + - '**/*_sqs_*' + - '**/sqs_*' +service/ssm: + - 'aws/internal/service/ssm/**/*' + - '**/*_ssm_*' + - '**/ssm_*' +service/ssoadmin: + - 'aws/internal/service/ssoadmin/**/*' + - '**/*_ssoadmin_*' + - '**/ssoadmin_*' +service/storagegateway: + - 'aws/internal/service/storagegateway/**/*' + - '**/*_storagegateway_*' + - '**/storagegateway_*' +service/sts: + - 'aws/internal/service/sts/**/*' + - 'aws/*_aws_caller_identity*' + - 'website/**/caller_identity*' +service/swf: + - 'aws/internal/service/swf/**/*' + - '**/*_swf_*' + - '**/swf_*' +service/synthetics: + - 'aws/internal/service/synthetics/**/*' + - '**/*_synthetics_*' + - '**/synthetics_*' +service/timestreamwrite: + - 'aws/internal/service/timestreamwrite/**/*' + - '**/*_timestreamwrite_*' + - '**/timestreamwrite_*' +service/transfer: + - 'aws/internal/service/transfer/**/*' + - '**/*_transfer_*' + - '**/transfer_*' +service/waf: + - 'aws/internal/service/waf/**/*' + - 'aws/internal/service/wafregional/**/*' + - '**/*_waf_*' + - '**/waf_*' + - '**/*_wafregional_*' + - '**/wafregional_*' +service/wafv2: + - 'aws/internal/service/wafv2/**/*' + - '**/*_wafv2_*' + - '**/wafv2_*' +service/workdocs: + - 'aws/internal/service/workdocs/**/*' + - '**/*_workdocs_*' + - '**/workdocs_*' +service/worklink: + - 'aws/internal/service/worklink/**/*' + - '**/*_worklink_*' + - '**/worklink_*' +service/workmail: + - 'aws/internal/service/workmail/**/*' + - '**/*_workmail_*' + - '**/workmail_*' +service/workspaces: + - 'aws/internal/service/workspaces/**/*' + - '**/*_workspaces_*' + - '**/workspaces_*' +service/xray: + - 'aws/internal/service/xray/**/*' + - '**/*_xray_*' + - '**/xray_*' +tests: + - '**/*_test.go' + - '**/testdata/**/*' + - '.github/workflows/*' + - '.golangci.yml' + - '.markdownlinkcheck.json' + - '.markdownlint.yml' + - 'staticcheck.conf' diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml index 34c4ab61392..fbdc6f65c56 100644 --- a/.github/workflows/pull_requests.yml +++ b/.github/workflows/pull_requests.yml @@ -3,6 +3,15 @@ on: name: Pull Request Target (All types) jobs: + Labeler: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Apply Labels + uses: actions/labeler@v3 + with: + configuration-path: .github/labeler-pr-triage.yml + repo-token: ${{ secrets.GITHUB_TOKEN }} NeedsTriageLabeler: runs-on: ubuntu-latest steps: diff --git a/.hashibot.hcl b/.hashibot.hcl index 02bfaaf4498..fec801df926 100644 --- a/.hashibot.hcl +++ b/.hashibot.hcl @@ -559,994 +559,6 @@ behavior "regexp_issue_labeler_v2" "service_labels" { } } -behavior "pull_request_path_labeler" "service_labels" { - label_map = { - # label provider related changes - "provider" = [ - "*.md", - ".github/**/*", - ".gitignore", - ".go-version", - ".hashibot.hcl", - "aws/auth_helpers.go", - "aws/awserr.go", - "aws/config.go", - "aws/*_aws_arn*", - "aws/*_aws_ip_ranges*", - "aws/*_aws_partition*", - "aws/*_aws_region*", - "aws/internal/flatmap/*", - "aws/internal/keyvaluetags/*", - "aws/internal/naming/*", - "aws/provider.go", - "aws/utils.go", - "docs/*.md", - "docs/contributing/**/*", - "GNUmakefile", - "infrastructure/**/*", - "main.go", - "website/docs/index.html.markdown", - "website/**/arn*", - "website/**/ip_ranges*", - "website/**/partition*", - "website/**/region*" - ] - "dependencies" = [ - ".github/dependabot.yml", - ] - "documentation" = [ - "docs/**/*", - "website/**/*", - "*.md", - ] - "examples" = [ - "examples/**/*", - ] - "tests" = [ - "**/*_test.go", - "**/testdata/**/*", - "**/test-fixtures/**/*", - ".github/workflows/*", - ".gometalinter.json", - ".markdownlinkcheck.json", - ".markdownlint.yml", - "staticcheck.conf" - ] - # label services - "service/accessanalyzer" = [ - "aws/internal/service/accessanalyzer/**/*", - "**/*_accessanalyzer_*", - "**/accessanalyzer_*" - ] - "service/acm" = [ - "aws/internal/service/acm/**/*", - "**/*_acm_*", - "**/acm_*" - ] - "service/acmpca" = [ - "aws/internal/service/acmpca/**/*", - "**/*_acmpca_*", - "**/acmpca_*" - ] - "service/alexaforbusiness" = [ - "aws/internal/service/alexaforbusiness/**/*", - "**/*_alexaforbusiness_*", - "**/alexaforbusiness_*" - ] - "service/amplify" = [ - "aws/internal/service/amplify/**/*", - "**/*_amplify_*", - "**/amplify_*" - ] - "service/apigateway" = [ - "aws/internal/service/apigateway/**/*", - "**/*_api_gateway_[^v][^2][^_]*", - "**/*_api_gateway_vpc_link*", - "**/api_gateway_[^v][^2][^_]*", - "**/api_gateway_vpc_link*" - ] - "service/apigatewayv2" = [ - "aws/internal/service/apigatewayv2/**/*", - "**/*_api_gateway_v2_*", - "**/*_apigatewayv2_*", - "**/api_gateway_v2_*", - "**/apigatewayv2_*" - ] - "service/appconfig" = [ - "aws/internal/service/appconfig/**/*", - "**/*_appconfig_*", - "**/appconfig_*" - ] - "service/applicationautoscaling" = [ - "aws/internal/service/applicationautoscaling/**/*", - "**/*_appautoscaling_*", - "**/appautoscaling_*" - ] - "service/applicationinsights" = [ - "aws/internal/service/applicationinsights/**/*", - "**/*_applicationinsights_*", - "**/applicationinsights_*" - ] - "service/appmesh" = [ - "aws/internal/service/appmesh/**/*", - "**/*_appmesh_*", - "**/appmesh_*" - ] - "service/apprunner" = [ - "aws/internal/service/apprunner/**/*", - "**/*_apprunner_*", - "**/apprunner_*" - ] - "service/appstream" = [ - "aws/internal/service/appstream/**/*", - "**/*_appstream_*", - "**/appstream_*" - ] - "service/appsync" = [ - "aws/internal/service/appsync/**/*", - "**/*_appsync_*", - "**/appsync_*" - ] - "service/athena" = [ - "aws/internal/service/athena/**/*", - "**/*_athena_*", - "**/athena_*" - ] - "service/auditmanager" = [ - "aws/internal/service/auditmanager/**/*", - "**/*_auditmanager_*", - "**/auditmanager_*" - ] - "service/autoscaling" = [ - "aws/internal/service/autoscaling/**/*", - "**/*_autoscaling_*", - "**/autoscaling_*", - "aws/*_aws_launch_configuration*", - "website/**/launch_configuration*" - ] - "service/autoscalingplans" = [ - "aws/internal/service/autoscalingplans/**/*", - "**/*_autoscalingplans_*", - "**/autoscalingplans_*" - ] - "service/backup" = [ - "aws/internal/service/backup/**/*", - "**/*backup_*", - "**/backup_*" - ] - "service/batch" = [ - "aws/internal/service/batch/**/*", - "**/*_batch_*", - "**/batch_*" - ] - "service/budgets" = [ - "aws/internal/service/budgets/**/*", - "**/*_budgets_*", - "**/budgets_*" - ] - "service/cloud9" = [ - "aws/internal/service/cloud9/**/*", - "**/*_cloud9_*", - "**/cloud9_*" - ] - "service/clouddirectory" = [ - "aws/internal/service/clouddirectory/**/*", - "**/*_clouddirectory_*", - "**/clouddirectory_*" - ] - "service/cloudformation" = [ - "aws/internal/service/cloudformation/**/*", - "**/*_cloudformation_*", - "**/cloudformation_*" - ] - "service/cloudfront" = [ - "aws/internal/service/cloudfront/**/*", - "**/*_cloudfront_*", - "**/cloudfront_*" - ] - "service/cloudhsmv2" = [ - "aws/internal/service/cloudhsmv2/**/*", - "**/*_cloudhsm_v2_*", - "**/cloudhsm_v2_*" - ] - "service/cloudsearch" = [ - "aws/internal/service/cloudsearch/**/*", - "**/*_cloudsearch_*", - "**/cloudsearch_*" - ] - "service/cloudtrail" = [ - "aws/internal/service/cloudtrail/**/*", - "**/*_cloudtrail*", - "**/cloudtrail*" - ] - "service/cloudwatch" = [ - "aws/internal/service/cloudwatch/**/*", - "**/*_cloudwatch_dashboard*", - "**/*_cloudwatch_metric_alarm*", - "**/cloudwatch_dashboard*", - "**/cloudwatch_metric_alarm*" - ] - "service/cloudwatchevents" = [ - "aws/internal/service/cloudwatchevents/**/*", - "**/*_cloudwatch_event_*", - "**/cloudwatch_event_*" - ] - "service/cloudwatchlogs" = [ - "aws/internal/service/cloudwatchlogs/**/*", - "**/*_cloudwatch_log_*", - "**/cloudwatch_log_*", - "**/*_cloudwatch_query_definition*", - "**/cloudwatch_query_definition*" - ] - "service/codeartifact" = [ - "aws/internal/service/codeartifact/**/*", - "**/*_codeartifact_*", - "**/codeartifact_*" - ] - "service/codebuild" = [ - "aws/internal/service/codebuild/**/*", - "**/*_codebuild_*", - "**/codebuild_*" - ] - "service/codecommit" = [ - "aws/internal/service/codecommit/**/*", - "**/*_codecommit_*", - "**/codecommit_*" - ] - "service/codedeploy" = [ - "aws/internal/service/codedeploy/**/*", - "**/*_codedeploy_*", - "**/codedeploy_*" - ] - "service/codepipeline" = [ - "aws/internal/service/codepipeline/**/*", - "**/*_codepipeline_*", - "**/codepipeline_*" - ] - "service/codestar" = [ - "aws/internal/service/codestar/**/*", - "**/*_codestar_*", - "**/codestar_*" - ] - "service/codestarconnections" = [ - "aws/internal/service/codestarconnections/**/*", - "**/*_codestarconnections_*", - "**/codestarconnections_*" - ] - "service/codestarnotifications" = [ - "aws/internal/service/codestarnotifications/**/*", - "**/*_codestarnotifications_*", - "**/codestarnotifications_*" - ] - "service/cognito" = [ - "aws/internal/service/cognitoidentity/**/*", - "aws/internal/service/cognitoidentityprovider/**/*", - "**/*_cognito_*", - "**/cognito_*" - ] - "service/comprehend" = [ - "aws/internal/service/comprehend/**/*", - "**/*_comprehend_*", - "**/comprehend_*" - ] - "service/configservice" = [ - "aws/internal/service/configservice/**/*", - "aws/*_aws_config_*", - "website/**/config_*" - ] - "service/connect" = [ - "aws/internal/service/connect/**/*", - "aws/*_aws_connect_*", - "website/**/connect_*" - ] - "service/costandusagereportservice" = [ - "aws/internal/service/costandusagereportservice/**/*", - "aws/*_aws_cur_*", - "website/**/cur_*" - ] - "service/databasemigrationservice" = [ - "aws/internal/service/databasemigrationservice/**/*", - "**/*_dms_*", - "**/dms_*" - ] - "service/dataexchange" = [ - "aws/internal/service/dataexchange/**/*", - "**/*_dataexchange_*", - "**/dataexchange_*", - ] - "service/datapipeline" = [ - "aws/internal/service/datapipeline/**/*", - "**/*_datapipeline_*", - "**/datapipeline_*", - ] - "service/datasync" = [ - "aws/internal/service/datasync/**/*", - "**/*_datasync_*", - "**/datasync_*", - ] - "service/dax" = [ - "aws/internal/service/dax/**/*", - "**/*_dax_*", - "**/dax_*" - ] - "service/detective" = [ - "aws/internal/service/detective/**/*", - "**/*_detective_*", - "**/detective_*" - ] - "service/devicefarm" = [ - "aws/internal/service/devicefarm/**/*", - "**/*_devicefarm_*", - "**/devicefarm_*" - ] - "service/directconnect" = [ - "aws/internal/service/directconnect/**/*", - "**/*_dx_*", - "**/dx_*" - ] - "service/directoryservice" = [ - "aws/internal/service/directoryservice/**/*", - "**/*_directory_service_*", - "**/directory_service_*" - ] - "service/dlm" = [ - "aws/internal/service/dlm/**/*", - "**/*_dlm_*", - "**/dlm_*" - ] - "service/docdb" = [ - "aws/internal/service/docdb/**/*", - "**/*_docdb_*", - "**/docdb_*" - ] - "service/dynamodb" = [ - "aws/internal/service/dynamodb/**/*", - "**/*_dynamodb_*", - "**/dynamodb_*" - ] - # Special casing this one because the files aren't _ec2_ - "service/ec2" = [ - "aws/internal/service/ec2/**/*", - "**/*_ec2_*", - "**/ec2_*", - "aws/*_aws_ami*", - "aws/*_aws_availability_zone*", - "aws/*_aws_customer_gateway*", - "aws/*_aws_default_network_acl*", - "aws/*_aws_default_route_table*", - "aws/*_aws_default_security_group*", - "aws/*_aws_default_subnet*", - "aws/*_aws_default_vpc*", - "aws/*_aws_ebs_*", - "aws/*_aws_egress_only_internet_gateway*", - "aws/*_aws_eip*", - "aws/*_aws_flow_log*", - "aws/*_aws_instance*", - "aws/*_aws_internet_gateway*", - "aws/*_aws_key_pair*", - "aws/*_aws_launch_template*", - "aws/*_aws_main_route_table_association*", - "aws/*_aws_nat_gateway*", - "aws/*_aws_network_acl*", - "aws/*_aws_network_interface*", - "aws/*_aws_placement_group*", - "aws/*_aws_prefix_list*", - "aws/*_aws_route_table*", - "aws/*_aws_route.*", - "aws/*_aws_security_group*", - "aws/*_aws_snapshot_create_volume_permission*", - "aws/*_aws_spot*", - "aws/*_aws_subnet*", - "aws/*_aws_vpc*", - "aws/*_aws_vpn*", - "aws/*_aws_volume_attachment*", - "website/**/availability_zone*", - "website/**/customer_gateway*", - "website/**/default_network_acl*", - "website/**/default_route_table*", - "website/**/default_security_group*", - "website/**/default_subnet*", - "website/**/default_vpc*", - "website/**/ebs_*", - "website/**/egress_only_internet_gateway*", - "website/**/eip*", - "website/**/flow_log*", - "website/**/instance*", - "website/**/internet_gateway*", - "website/**/key_pair*", - "website/**/launch_template*", - "website/**/main_route_table_association*", - "website/**/nat_gateway*", - "website/**/network_acl*", - "website/**/network_interface*", - "website/**/placement_group*", - "website/**/prefix_list*", - "website/**/route_table*", - "website/**/route.*", - "website/**/security_group*", - "website/**/snapshot_create_volume_permission*", - "website/**/spot_*", - "website/**/subnet*", - "website/**/vpc*", - "website/**/vpn*", - "website/**/volume_attachment*" - ] - "service/ecr" = [ - "aws/internal/service/ecr/**/*", - "**/*_ecr_*", - "**/ecr_*" - ] - "service/ecrpublic" = [ - "aws/internal/service/ecrpublic/**/*", - "**/*_ecrpublic_*", - "**/ecrpublic_*" - ] - "service/ecs" = [ - "aws/internal/service/ecs/**/*", - "**/*_ecs_*", - "**/ecs_*" - ] - "service/efs" = [ - "aws/internal/service/efs/**/*", - "**/*_efs_*", - "**/efs_*" - ] - "service/eks" = [ - "aws/internal/service/eks/**/*", - "**/*_eks_*", - "**/eks_*" - ] - "service/elastic-transcoder" = [ - "aws/internal/service/elastictranscoder/**/*", - "**/*_elastictranscoder_*", - "**/elastictranscoder_*", - "**/*_elastic_transcoder_*", - "**/elastic_transcoder_*" - ] - "service/elasticache" = [ - "aws/internal/service/elasticache/**/*", - "**/*_elasticache_*", - "**/elasticache_*" - ] - "service/elasticbeanstalk" = [ - "aws/internal/service/elasticbeanstalk/**/*", - "**/*_elastic_beanstalk_*", - "**/elastic_beanstalk_*" - ] - "service/elasticsearch" = [ - "aws/internal/service/elasticsearchservice/**/*", - "**/*_elasticsearch_*", - "**/elasticsearch_*", - "**/*_elasticsearchservice*" - ] - "service/elb" = [ - "aws/internal/service/elb/**/*", - "aws/*_aws_app_cookie_stickiness_policy*", - "aws/*_aws_elb*", - "aws/*_aws_lb_cookie_stickiness_policy*", - "aws/*_aws_lb_ssl_negotiation_policy*", - "aws/*_aws_load_balancer*", - "aws/*_aws_proxy_protocol_policy*", - "website/**/app_cookie_stickiness_policy*", - "website/**/elb*", - "website/**/lb_cookie_stickiness_policy*", - "website/**/lb_ssl_negotiation_policy*", - "website/**/load_balancer*", - "website/**/proxy_protocol_policy*" - ] - "service/elbv2" = [ - "aws/internal/service/elbv2/**/*", - "aws/*_lb.*", - "aws/*_lb_listener*", - "aws/*_lb_target_group*", - "website/**/lb.*", - "website/**/lb_listener*", - "website/**/lb_target_group*" - ] - "service/emr" = [ - "aws/internal/service/emr/**/*", - "**/*_emr_*", - "**/emr_*" - ] - "service/emrcontainers" = [ - "aws/internal/service/emrcontainers/**/*", - "**/*_emrcontainers_*", - "**/emrcontainers_*" - ] - "service/eventbridge" = [ - # EventBridge is rebranded CloudWatch Events - "aws/internal/service/cloudwatchevents/**/*", - "**/*_cloudwatch_event_*", - "**/cloudwatch_event_*" - ] - "service/firehose" = [ - "aws/internal/service/firehose/**/*", - "**/*_firehose_*", - "**/firehose_*" - ] - "service/fms" = [ - "aws/internal/service/fms/**/*", - "**/*_fms_*", - "**/fms_*" - ] - "service/fsx" = [ - "aws/internal/service/fsx/**/*", - "**/*_fsx_*", - "**/fsx_*" - ] - "service/gamelift" = [ - "aws/internal/service/gamelift/**/*", - "**/*_gamelift_*", - "**/gamelift_*" - ] - "service/glacier" = [ - "aws/internal/service/glacier/**/*", - "**/*_glacier_*", - "**/glacier_*" - ] - "service/globalaccelerator" = [ - "aws/internal/service/globalaccelerator/**/*", - "**/*_globalaccelerator_*", - "**/globalaccelerator_*" - ] - "service/glue" = [ - "aws/internal/service/glue/**/*", - "**/*_glue_*", - "**/glue_*" - ] - "service/greengrass" = [ - "aws/internal/service/greengrass/**/*", - "**/*_greengrass_*", - "**/greengrass_*" - ] - "service/guardduty" = [ - "aws/internal/service/guardduty/**/*", - "**/*_guardduty_*", - "**/guardduty_*" - ] - "service/iam" = [ - "aws/internal/service/iam/**/*", - "**/*_iam_*", - "**/iam_*" - ] - "service/identitystore" = [ - "aws/internal/service/identitystore/**/*", - "**/*_identitystore_*", - "**/identitystore_*" - ] - "service/imagebuilder" = [ - "aws/internal/service/imagebuilder/**/*", - "**/*_imagebuilder_*", - "**/imagebuilder_*" - ] - "service/inspector" = [ - "aws/internal/service/inspector/**/*", - "**/*_inspector_*", - "**/inspector_*" - ] - "service/iot" = [ - "aws/internal/service/iot/**/*", - "**/*_iot_*", - "**/iot_*" - ] - "service/iotanalytics" = [ - "aws/internal/service/iotanalytics/**/*", - "**/*_iotanalytics_*", - "**/iotanalytics_*" - ] - "service/iotevents" = [ - "aws/internal/service/iotevents/**/*", - "**/*_iotevents_*", - "**/iotevents_*" - ] - "service/kafka" = [ - "aws/internal/service/kafka/**/*", - "**/*_msk_*", - "**/msk_*", - ] - "service/kinesis" = [ - "aws/internal/service/kinesis/**/*", - "aws/*_aws_kinesis_stream*", - "website/kinesis_stream*" - ] - "service/kinesisanalytics" = [ - "aws/internal/service/kinesisanalytics/**/*", - "**/*_kinesis_analytics_*", - "**/kinesis_analytics_*" - ] - "service/kinesisanalyticsv2" = [ - "aws/internal/service/kinesisanalyticsv2/**/*", - "**/*_kinesisanalyticsv2_*", - "**/kinesisanalyticsv2_*" - ] - "service/kms" = [ - "aws/internal/service/kms/**/*", - "**/*_kms_*", - "**/kms_*" - ] - "service/lakeformation" = [ - "aws/internal/service/lakeformation/**/*", - "**/*_lakeformation_*", - "**/lakeformation_*" - ] - "service/lambda" = [ - "aws/internal/service/lambda/**/*", - "**/*_lambda_*", - "**/lambda_*" - ] - "service/lexmodelbuildingservice" = [ - "aws/internal/service/lexmodelbuildingservice/**/*", - "**/*_lex_*", - "**/lex_*" - ] - "service/licensemanager" = [ - "aws/internal/service/licensemanager/**/*", - "**/*_licensemanager_*", - "**/licensemanager_*" - ] - "service/lightsail" = [ - "aws/internal/service/lightsail/**/*", - "**/*_lightsail_*", - "**/lightsail_*" - ] - "service/machinelearning" = [ - "aws/internal/service/machinelearning/**/*", - "**/*_machinelearning_*", - "**/machinelearning_*" - ] - "service/macie" = [ - "aws/internal/service/macie/**/*", - "**/*_macie_*", - "**/macie_*" - ] - "service/macie2" = [ - "aws/internal/service/macie2/**/*", - "**/*_macie2_*", - "**/macie2_*" - ] - "service/marketplacecatalog" = [ - "aws/internal/service/marketplacecatalog/**/*", - "**/*_marketplace_catalog_*", - "**/marketplace_catalog_*" - ] - "service/mediaconnect" = [ - "aws/internal/service/mediaconnect/**/*", - "**/*_media_connect_*", - "**/media_connect_*" - ] - "service/mediaconvert" = [ - "aws/internal/service/mediaconvert/**/*", - "**/*_media_convert_*", - "**/media_convert_*" - ] - "service/medialive" = [ - "aws/internal/service/medialive/**/*", - "**/*_media_live_*", - "**/media_live_*" - ] - "service/mediapackage" = [ - "aws/internal/service/mediapackage/**/*", - "**/*_media_package_*", - "**/media_package_*" - ] - "service/mediastore" = [ - "aws/internal/service/mediastore/**/*", - "**/*_media_store_*", - "**/media_store_*" - ] - "service/mediatailor" = [ - "aws/internal/service/mediatailor/**/*", - "**/*_media_tailor_*", - "**/media_tailor_*", - ] - "service/mobile" = [ - "aws/internal/service/mobile/**/*", - "**/*_mobile_*", - "**/mobile_*" - ], - "service/mq" = [ - "aws/internal/service/mq/**/*", - "**/*_mq_*", - "**/mq_*" - ] - "service/mwaa" = [ - "aws/internal/service/mwaa/**/*", - "**/*_mwaa_*", - "**/mwaa_*" - ] - "service/neptune" = [ - "aws/internal/service/neptune/**/*", - "**/*_neptune_*", - "**/neptune_*" - ] - "service/networkfirewall" = [ - "aws/internal/service/networkfirewall/**/*", - "**/*_networkfirewall_*", - "**/networkfirewall_*", - ] - "service/networkmanager" = [ - "aws/internal/service/networkmanager/**/*", - "**/*_networkmanager_*", - "**/networkmanager_*" - ] - "service/opsworks" = [ - "aws/internal/service/opsworks/**/*", - "**/*_opsworks_*", - "**/opsworks_*" - ] - "service/organizations" = [ - "aws/internal/service/organizations/**/*", - "**/*_organizations_*", - "**/organizations_*" - ] - "service/outposts" = [ - "aws/internal/service/outposts/**/*", - "**/*_outposts_*", - "**/outposts_*" - ] - "service/pinpoint" = [ - "aws/internal/service/pinpoint/**/*", - "**/*_pinpoint_*", - "**/pinpoint_*" - ] - "service/polly" = [ - "aws/internal/service/polly/**/*", - "**/*_polly_*", - "**/polly_*" - ] - "service/pricing" = [ - "aws/internal/service/pricing/**/*", - "**/*_pricing_*", - "**/pricing_*" - ] - "service/prometheusservice" = [ - "aws/internal/service/prometheus/**/*", - "**/*_prometheus_*", - "**/prometheus_*", - ] - "service/qldb" = [ - "aws/internal/service/qldb/**/*", - "**/*_qldb_*", - "**/qldb_*" - ] - "service/quicksight" = [ - "aws/internal/service/quicksight/**/*", - "**/*_quicksight_*", - "**/quicksight_*" - ] - "service/ram" = [ - "aws/internal/service/ram/**/*", - "**/*_ram_*", - "**/ram_*" - ] - "service/rds" = [ - "aws/internal/service/rds/**/*", - "aws/*_aws_db_*", - "aws/*_aws_rds_*", - "website/**/db_*", - "website/**/rds_*" - ] - "service/redshift" = [ - "aws/internal/service/redshift/**/*", - "**/*_redshift_*", - "**/redshift_*" - ] - "service/resourcegroups" = [ - "aws/internal/service/resourcegroups/**/*", - "**/*_resourcegroups_*", - "**/resourcegroups_*" - ] - "service/resourcegroupstaggingapi" = [ - "aws/internal/service/resourcegroupstaggingapi/**/*", - "**/*_resourcegroupstaggingapi_*", - "**/resourcegroupstaggingapi_*" - ] - "service/robomaker" = [ - "aws/internal/service/robomaker/**/*", - "**/*_robomaker_*", - "**/robomaker_*", - ] - "service/route53" = [ - "aws/internal/service/route53/**/*", - "**/*_route53_delegation_set*", - "**/*_route53_health_check*", - "**/*_route53_query_log*", - "**/*_route53_record*", - "**/*_route53_vpc_association_authorization*", - "**/*_route53_zone*", - "**/route53_delegation_set*", - "**/route53_health_check*", - "**/route53_query_log*", - "**/route53_record*", - "**/route53_vpc_association_authorization*", - "**/route53_zone*" - ] - "service/route53domains" = [ - "aws/internal/service/route53domains/**/*", - "**/*_route53domains_*", - "**/route53domains_*" - ] - "service/route53resolver" = [ - "aws/internal/service/route53resolver/**/*", - "**/*_route53_resolver_*", - "**/route53_resolver_*" - ] - "service/s3" = [ - "aws/internal/service/s3/**/*", - "**/*_s3_bucket*", - "**/s3_bucket*", - "**/*_s3_object*", - "**/s3_object*", - "aws/*_aws_canonical_user_id*", - "website/**/canonical_user_id*" - ] - "service/s3control" = [ - "aws/internal/service/s3control/**/*", - "**/*_s3_account_*", - "**/s3_account_*", - "**/*_s3control_*", - "**/s3control_*" - ] - "service/s3outposts" = [ - "aws/internal/service/s3outposts/**/*", - "**/*_s3outposts_*", - "**/s3outposts_*" - ] - "service/sagemaker" = [ - "aws/internal/service/sagemaker/**/*", - "**/*_sagemaker_*", - "**/sagemaker_*" - ] - "service/secretsmanager" = [ - "aws/internal/service/secretsmanager/**/*", - "**/*_secretsmanager_*", - "**/secretsmanager_*" - ] - "service/securityhub" = [ - "aws/internal/service/securityhub/**/*", - "**/*_securityhub_*", - "**/securityhub_*" - ] - "service/serverlessapplicationrepository" = [ - "aws/internal/service/serverlessapplicationrepository/**/*", - "**/*_serverlessapplicationrepository_*", - "**/serverlessapplicationrepository_*" - ] - "service/servicecatalog" = [ - "aws/internal/service/servicecatalog/**/*", - "**/*_servicecatalog_*", - "**/servicecatalog_*" - ] - "service/servicediscovery" = [ - "aws/internal/service/servicediscovery/**/*", - "**/*_service_discovery_*", - "**/service_discovery_*" - ] - "service/servicequotas" = [ - "aws/internal/service/servicequotas/**/*", - "**/*_servicequotas_*", - "**/servicequotas_*" - ] - "service/ses" = [ - "aws/internal/service/ses/**/*", - "**/*_ses_*", - "**/ses_*" - ] - "service/sfn" = [ - "aws/internal/service/sfn/**/*", - "**/*_sfn_*", - "**/sfn_*" - ] - "service/shield" = [ - "aws/internal/service/shield/**/*", - "**/*_shield_*", - "**/shield_*", - ], - "service/signer" = [ - "**/*_signer_*", - "**/signer_*" - ] - "service/simpledb" = [ - "aws/internal/service/simpledb/**/*", - "**/*_simpledb_*", - "**/simpledb_*" - ] - "service/snowball" = [ - "aws/internal/service/snowball/**/*", - "**/*_snowball_*", - "**/snowball_*" - ] - "service/sns" = [ - "aws/internal/service/sns/**/*", - "**/*_sns_*", - "**/sns_*" - ] - "service/sqs" = [ - "aws/internal/service/sqs/**/*", - "**/*_sqs_*", - "**/sqs_*" - ] - "service/ssm" = [ - "aws/internal/service/ssm/**/*", - "**/*_ssm_*", - "**/ssm_*" - ] - "service/ssoadmin" = [ - "aws/internal/service/ssoadmin/**/*", - "**/*_ssoadmin_*", - "**/ssoadmin_*" - ] - "service/storagegateway" = [ - "aws/internal/service/storagegateway/**/*", - "**/*_storagegateway_*", - "**/storagegateway_*" - ] - "service/sts" = [ - "aws/internal/service/sts/**/*", - "aws/*_aws_caller_identity*", - "website/**/caller_identity*" - ] - "service/swf" = [ - "aws/internal/service/swf/**/*", - "**/*_swf_*", - "**/swf_*" - ] - "service/synthetics" = [ - "aws/internal/service/synthetics/**/*", - "**/*_synthetics_*", - "**/synthetics_*" - ] - "service/timestreamwrite" = [ - "aws/internal/service/timestreamwrite/**/*", - "**/*_timestreamwrite_*", - "**/timestreamwrite_*" - ] - "service/transfer" = [ - "aws/internal/service/transfer/**/*", - "**/*_transfer_*", - "**/transfer_*" - ] - "service/waf" = [ - "aws/internal/service/waf/**/*", - "aws/internal/service/wafregional/**/*", - "**/*_waf_*", - "**/waf_*", - "**/*_wafregional_*", - "**/wafregional_*" - ] - "service/wafv2" = [ - "aws/internal/service/wafv2/**/*", - "**/*_wafv2_*", - "**/wafv2_*", - ] - "service/workdocs" = [ - "aws/internal/service/workdocs/**/*", - "**/*_workdocs_*", - "**/workdocs_*" - ] - "service/worklink" = [ - "aws/internal/service/worklink/**/*", - "**/*_worklink_*", - "**/worklink_*" - ] - "service/workmail" = [ - "aws/internal/service/workmail/**/*", - "**/*_workmail_*", - "**/workmail_*" - ] - "service/workspaces" = [ - "aws/internal/service/workspaces/**/*", - "**/*_workspaces_*", - "**/workspaces_*" - ] - "service/xray" = [ - "aws/internal/service/xray/**/*", - "**/*_xray_*", - "**/xray_*" - ] - } -} - behavior "remove_labels_on_reply" "remove_stale" { labels = ["waiting-response", "stale"] only_non_maintainers = true diff --git a/docs/contributing/contribution-checklists.md b/docs/contributing/contribution-checklists.md index 1e241b8bdc2..63048478a51 100644 --- a/docs/contributing/contribution-checklists.md +++ b/docs/contributing/contribution-checklists.md @@ -623,7 +623,7 @@ into Terraform. - In `website/docs/guides/custom-service-endpoints.html.md`: Add the service name in the list of customizable endpoints. - In `infrastructure/repository/labels-service.tf`: Add the new service to create a repository label. - - In `.hashibot.hcl`: Add the new service to automated issue and pull request labeling. e.g. with the `quicksight` service + - In `.hashibot.hcl`: Add the new service to automated issue labeling. e.g. with the `quicksight` service ```hcl behavior "regexp_issue_labeler_v2" "service_labels" { @@ -637,20 +637,17 @@ into Terraform. # ... other services ... } } + ``` - behavior "pull_request_path_labeler" "service_labels" - # ... other configuration ... + - In `.github/labeler-pr-triage.yml`: Add the new service to automated pull request labeling. e.g. with the `quicksight` service - label_map = { - # ... other services ... - "service/quicksight" = [ - "aws/internal/service/quicksight/**/*", - "**/*_quicksight_*", - "**/quicksight_*", - ], - # ... other services ... - } - } + ```yaml + # ... other services ... + service/quicksight: + - 'aws/internal/service/quicksight/**/*' + - '**/*_quicksight_*' + - '**/quicksight_*' + # ... other services ... ``` - Run the following then submit the pull request: From d2dc2d19af477c05df859e9b7d8e09c3eebe1f8c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 20 May 2021 10:30:47 -0400 Subject: [PATCH 047/398] Add AppRunner service to PR labeler (#19432). --- .github/labeler-pr-triage.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/labeler-pr-triage.yml b/.github/labeler-pr-triage.yml index 4329332f996..51eaf227749 100644 --- a/.github/labeler-pr-triage.yml +++ b/.github/labeler-pr-triage.yml @@ -81,6 +81,10 @@ service/appmesh: - 'aws/internal/service/appmesh/**/*' - '**/*_appmesh_*' - '**/appmesh_*' +service/apprunner: + - 'aws/internal/service/apprunner/**/*' + - '**/*_apprunner_*' + - '**/apprunner_*' service/appstream: - 'aws/internal/service/appstream/**/*' - '**/*_appstream_*' From bbe02a0a1d742e778876569b4f5c2be3a1fd21c6 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 20 May 2021 14:39:08 +0000 Subject: [PATCH 048/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47eb6123126..ad0990e2a95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 3.43.0 (Unreleased) +BUG FIXES: + +* resource/aws_glue_connection: `connection_properties` are optional ([#19375](https://github.com/hashicorp/terraform-provider-aws/issues/19375)) + ## 3.42.0 (May 20, 2021) FEATURES: From cdfd2ed034e5cb5ac6eb38b5c0cf3287026d4f26 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 10:45:31 -0400 Subject: [PATCH 049/398] r/eks_addon: Fix nil check --- aws/resource_aws_eks_addon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_eks_addon.go b/aws/resource_aws_eks_addon.go index 47e26946131..cae762dc9a3 100644 --- a/aws/resource_aws_eks_addon.go +++ b/aws/resource_aws_eks_addon.go @@ -243,7 +243,7 @@ func resourceAwsEksAddonUpdate(ctx context.Context, d *schema.ResourceData, meta // 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") != nil { + 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)) } From 5e83162f005a8c3e2ed830d6b2df71f426c6a230 Mon Sep 17 00:00:00 2001 From: Alexey Kozyachiy Date: Thu, 20 May 2021 11:08:34 -0400 Subject: [PATCH 050/398] Add AWS Chime serivce (#19343) * Add AWS Chime serivce * Add Changelog file * Remove resource * fix changelog file * Add Chime service to PR labeler. * CHANGELOG entry not needed. Co-authored-by: Alexey.Kozyachiy Co-authored-by: Kit Ewbank --- .github/labeler-pr-triage.yml | 4 ++++ .hashibot.hcl | 3 +++ aws/config.go | 3 +++ aws/provider.go | 1 + website/allowed-subcategories.txt | 1 + website/docs/guides/custom-service-endpoints.html.md | 1 + 6 files changed, 13 insertions(+) diff --git a/.github/labeler-pr-triage.yml b/.github/labeler-pr-triage.yml index 51eaf227749..2458add8c9c 100644 --- a/.github/labeler-pr-triage.yml +++ b/.github/labeler-pr-triage.yml @@ -123,6 +123,10 @@ service/budgets: - 'aws/internal/service/budgets/**/*' - '**/*_budgets_*' - '**/budgets_*' +service/chime: + - 'aws/internal/service/chime/**/*' + - '**/*_chime_*' + - '**/chime_*' service/cloud9: - 'aws/internal/service/cloud9/**/*' - '**/*_cloud9_*' diff --git a/.hashibot.hcl b/.hashibot.hcl index fec801df926..62351a747fc 100644 --- a/.hashibot.hcl +++ b/.hashibot.hcl @@ -91,6 +91,9 @@ behavior "regexp_issue_labeler_v2" "service_labels" { "service/budgets" = [ "aws_budgets_", ], + "service/chime" = [ + "aws_chime_", + ], "service/cloud9" = [ "aws_cloud9_", ], diff --git a/aws/config.go b/aws/config.go index 372e3401250..4b47c42ced4 100644 --- a/aws/config.go +++ b/aws/config.go @@ -28,6 +28,7 @@ import ( "github.com/aws/aws-sdk-go/service/backup" "github.com/aws/aws-sdk-go/service/batch" "github.com/aws/aws-sdk-go/service/budgets" + "github.com/aws/aws-sdk-go/service/chime" "github.com/aws/aws-sdk-go/service/cloud9" "github.com/aws/aws-sdk-go/service/cloudformation" "github.com/aws/aws-sdk-go/service/cloudfront" @@ -233,6 +234,7 @@ type AWSClient struct { batchconn *batch.Batch budgetconn *budgets.Budgets cfconn *cloudformation.CloudFormation + chimeconn *chime.Chime cloud9conn *cloud9.Cloud9 cloudfrontconn *cloudfront.CloudFront cloudhsmv2conn *cloudhsmv2.CloudHSMV2 @@ -481,6 +483,7 @@ func (c *Config) Client() (interface{}, error) { batchconn: batch.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["batch"])})), budgetconn: budgets.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["budgets"])})), cfconn: cloudformation.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["cloudformation"])})), + chimeconn: chime.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["chime"])})), cloud9conn: cloud9.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["cloud9"])})), cloudfrontconn: cloudfront.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["cloudfront"])})), cloudhsmv2conn: cloudhsmv2.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["cloudhsm"])})), diff --git a/aws/provider.go b/aws/provider.go index e19ff3f6484..69008e6522c 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1269,6 +1269,7 @@ func init() { "backup", "batch", "budgets", + "chime", "cloud9", "cloudformation", "cloudfront", diff --git a/website/allowed-subcategories.txt b/website/allowed-subcategories.txt index fbeef224590..4880319d4d5 100644 --- a/website/allowed-subcategories.txt +++ b/website/allowed-subcategories.txt @@ -17,6 +17,7 @@ Amazon Managed Service for Prometheus (AMP) Backup Batch Budgets +Chime Cloud9 CloudFormation CloudFront diff --git a/website/docs/guides/custom-service-endpoints.html.md b/website/docs/guides/custom-service-endpoints.html.md index fc513621a1d..e23f99ffa08 100644 --- a/website/docs/guides/custom-service-endpoints.html.md +++ b/website/docs/guides/custom-service-endpoints.html.md @@ -73,6 +73,7 @@ The Terraform AWS Provider allows the following endpoints to be customized:
  • backup
  • batch
  • budgets
  • +
  • chime
  • cloud9
  • cloudformation
  • cloudfront
  • From 6bc640666d62e7c6ea598cb0a4bb5b1db1124f90 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 20 May 2021 11:15:16 -0400 Subject: [PATCH 051/398] r/aws_amplify_app: Add test sweeper. Acceptance test output: % TEST=./aws SWEEP=us-west-2 SWEEPARGS=-sweep-run=aws_amplify_app make sweep WARNING: This will destroy infrastructure. Use only in development accounts. go test ./aws -v -sweep=us-west-2 -sweep-run=aws_amplify_app -timeout 60m 2021/05/20 11:13:49 [DEBUG] Running Sweepers for region (us-west-2): 2021/05/20 11:13:49 [DEBUG] Running Sweeper (aws_amplify_app) in region (us-west-2) 2021/05/20 11:13:49 [INFO] AWS Auth provider used: "EnvProvider" 2021/05/20 11:13:49 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/05/20 11:13:50 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/05/20 11:13:50 [DEBUG] Deleting Amplify App (d3e2rpqo82owxg) 2021/05/20 11:13:51 Sweeper Tests ran successfully: - aws_amplify_app ok github.com/terraform-providers/terraform-provider-aws/aws 4.452s --- aws/internal/service/amplify/lister/list.go | 3 ++ .../service/amplify/lister/list_pages_gen.go | 31 +++++++++++ aws/resource_aws_amplify_app_test.go | 52 ++++++++++++++++++- 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 aws/internal/service/amplify/lister/list.go create mode 100644 aws/internal/service/amplify/lister/list_pages_gen.go diff --git a/aws/internal/service/amplify/lister/list.go b/aws/internal/service/amplify/lister/list.go new file mode 100644 index 00000000000..3b7007c9979 --- /dev/null +++ b/aws/internal/service/amplify/lister/list.go @@ -0,0 +1,3 @@ +//go:generate go run ../../../generators/listpages/main.go -function=ListApps github.com/aws/aws-sdk-go/service/amplify + +package lister diff --git a/aws/internal/service/amplify/lister/list_pages_gen.go b/aws/internal/service/amplify/lister/list_pages_gen.go new file mode 100644 index 00000000000..30fa4b12930 --- /dev/null +++ b/aws/internal/service/amplify/lister/list_pages_gen.go @@ -0,0 +1,31 @@ +// Code generated by "aws/internal/generators/listpages/main.go -function=ListApps github.com/aws/aws-sdk-go/service/amplify"; DO NOT EDIT. + +package lister + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/amplify" +) + +func ListAppsPages(conn *amplify.Amplify, input *amplify.ListAppsInput, fn func(*amplify.ListAppsOutput, bool) bool) error { + return ListAppsPagesWithContext(context.Background(), conn, input, fn) +} + +func ListAppsPagesWithContext(ctx context.Context, conn *amplify.Amplify, input *amplify.ListAppsInput, fn func(*amplify.ListAppsOutput, bool) bool) error { + for { + output, err := conn.ListAppsWithContext(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_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index a61704d2c3f..e5fa6643b9b 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -3,20 +3,70 @@ package aws import ( "encoding/base64" "fmt" + "log" "os" "regexp" "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" + "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/amplify/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/lister" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -// TODO sweeper +func init() { + resource.AddTestSweepers("aws_amplify_app", &resource.Sweeper{ + Name: "aws_amplify_app", + F: testSweepAmplifyApps, + }) +} + +func testSweepAmplifyApps(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).amplifyconn + input := &lify.ListAppsInput{} + var sweeperErrs *multierror.Error + + err = lister.ListAppsPages(conn, input, func(page *amplify.ListAppsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, app := range page.Apps { + r := resourceAwsAmplifyApp() + d := r.Data(nil) + d.SetId(aws.StringValue(app.AppId)) + 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 Amplify Apps 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 Amplify Apps: %w", err)) + } + + return sweeperErrs.ErrorOrNil() +} func TestAccAWSAmplifyApp_basic(t *testing.T) { var app amplify.App From 9b05180934329a35249dc374e7d7880f014dde1b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 20 May 2021 11:20:05 -0400 Subject: [PATCH 052/398] r/aws_amplify_app: Add '_disappears' test (#15945). Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplifyApp_disappears' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplifyApp_disappears -timeout 180m === RUN TestAccAWSAmplifyApp_disappears === PAUSE TestAccAWSAmplifyApp_disappears === CONT TestAccAWSAmplifyApp_disappears --- PASS: TestAccAWSAmplifyApp_disappears (10.95s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 14.084s --- aws/resource_aws_amplify_app_test.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index e5fa6643b9b..c1e396f7a69 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -116,6 +116,29 @@ func TestAccAWSAmplifyApp_basic(t *testing.T) { }) } +func TestAccAWSAmplifyApp_disappears(t *testing.T) { + var app amplify.App + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigName(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + testAccCheckResourceDisappears(testAccProvider, resourceAwsAmplifyApp(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func TestAccAWSAmplifyApp_Tags(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") From f3f3ac053c53c1e088203068b9b3f6badbf9ee8f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 20 May 2021 11:41:52 -0400 Subject: [PATCH 053/398] r/aws_amplify_app: Send empty array to clear 'custom_rule'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplifyApp_CustomRules' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplifyApp_CustomRules -timeout 180m === RUN TestAccAWSAmplifyApp_CustomRules === PAUSE TestAccAWSAmplifyApp_CustomRules === CONT TestAccAWSAmplifyApp_CustomRules --- PASS: TestAccAWSAmplifyApp_CustomRules (30.06s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 33.169s --- aws/resource_aws_amplify_app.go | 6 +- aws/resource_aws_amplify_app_test.go | 150 +++++++++++---------------- 2 files changed, 63 insertions(+), 93 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index 62422b1d0b3..ef0ad4a8f80 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -551,7 +551,11 @@ func resourceAwsAmplifyAppUpdate(d *schema.ResourceData, meta interface{}) error } if d.HasChange("custom_rule") { - input.CustomRules = expandAmplifyCustomRules(d.Get("custom_rule").([]interface{})) + if v := d.Get("custom_rule").([]interface{}); len(v) > 0 { + input.CustomRules = expandAmplifyCustomRules(v) + } else { + input.CustomRules = []*amplify.CustomRule{} + } } if d.HasChange("description") { diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index c1e396f7a69..4605a94cd32 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -232,42 +232,7 @@ func TestAccAWSAmplifyApp_BasicAuthCredentials(t *testing.T) { }) } -func TestAccAWSAmplifyApp_Name(t *testing.T) { - var app amplify.App - rName1 := acctest.RandomWithPrefix("tf-acc-test") - rName2 := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_amplify_app.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, - ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAmplifyAppDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAmplifyAppConfigName(rName1), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "name", rName1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyAppConfigName(rName2), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "name", rName2), - ), - }, - }, - }) -} - -func TestAccAWSAmplifyApp_Description(t *testing.T) { +func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { var app1, app2, app3 amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -279,10 +244,10 @@ func TestAccAWSAmplifyApp_Description(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigDescription(rName, "description 1"), + Config: testAccAWSAmplifyAppConfigBuildSpec(rName, "version: 0.1"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app1), - resource.TestCheckResourceAttr(resourceName, "description", "description 1"), + resource.TestCheckResourceAttr(resourceName, "build_spec", "version: 0.1"), ), }, { @@ -291,11 +256,11 @@ func TestAccAWSAmplifyApp_Description(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigDescription(rName, "description 2"), + Config: testAccAWSAmplifyAppConfigBuildSpec(rName, "version: 0.2"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app2), testAccCheckAWSAmplifyAppNotRecreated(&app1, &app2), - resource.TestCheckResourceAttr(resourceName, "description", "description 2"), + resource.TestCheckResourceAttr(resourceName, "build_spec", "version: 0.2"), ), }, { @@ -303,14 +268,15 @@ func TestAccAWSAmplifyApp_Description(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app3), testAccCheckAWSAmplifyAppRecreated(&app2, &app3), - resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "build_spec", ""), ), }, }, }) } -func TestAccAWSAmplifyApp_repository(t *testing.T) { +func TestAccAWSAmplifyApp_CustomRules(t *testing.T) { + var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -321,26 +287,48 @@ func TestAccAWSAmplifyApp_repository(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigRepository(rName), + Config: testAccAWSAmplifyAppConfigCustomRules(rName), Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr(resourceName, "repository", regexp.MustCompile("^https://github.com")), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "custom_rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.source", "/<*>"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.status", "404"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.target", "/index.html"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - // access_token is ignored because AWS does not store access_token and oauth_token - // See https://docs.aws.amazon.com/sdk-for-go/api/service/amplify/#CreateAppInput - ImportStateVerifyIgnore: []string{"access_token"}, + }, + { + Config: testAccAWSAmplifyAppConfigCustomRulesUpdated(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "custom_rule.#", "2"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.condition", ""), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.source", "/documents"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.status", "302"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.target", "/documents/us"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.1.source", "/<*>"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.1.status", "200"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.1.target", "/index.html"), + ), + }, + { + Config: testAccAWSAmplifyAppConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "custom_rule.#", "0"), + ), }, }, }) } -func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { - var app1, app2, app3 amplify.App - rName := acctest.RandomWithPrefix("tf-acc-test") +func TestAccAWSAmplifyApp_Name(t *testing.T) { + var app amplify.App + rName1 := acctest.RandomWithPrefix("tf-acc-test") + rName2 := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ @@ -350,10 +338,10 @@ func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigBuildSpec(rName, "version: 0.1"), + Config: testAccAWSAmplifyAppConfigName(rName1), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app1), - resource.TestCheckResourceAttr(resourceName, "build_spec", "version: 0.1"), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "name", rName1), ), }, { @@ -362,26 +350,17 @@ func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigBuildSpec(rName, "version: 0.2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app2), - testAccCheckAWSAmplifyAppNotRecreated(&app1, &app2), - resource.TestCheckResourceAttr(resourceName, "build_spec", "version: 0.2"), - ), - }, - { - Config: testAccAWSAmplifyAppConfigName(rName), + Config: testAccAWSAmplifyAppConfigName(rName2), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app3), - testAccCheckAWSAmplifyAppRecreated(&app2, &app3), - resource.TestCheckResourceAttr(resourceName, "build_spec", ""), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "name", rName2), ), }, }, }) } -func TestAccAWSAmplifyApp_customRules(t *testing.T) { +func TestAccAWSAmplifyApp_repository(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -392,31 +371,18 @@ func TestAccAWSAmplifyApp_customRules(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigCustomRules1(rName), + Config: testAccAWSAmplifyAppConfigRepository(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "custom_rules.#", "1"), - resource.TestCheckResourceAttr(resourceName, "custom_rules.0.source", "/<*>"), - resource.TestCheckResourceAttr(resourceName, "custom_rules.0.status", "404"), - resource.TestCheckResourceAttr(resourceName, "custom_rules.0.target", "/index.html"), + resource.TestMatchResourceAttr(resourceName, "repository", regexp.MustCompile("^https://github.com")), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyAppConfigCustomRules2(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "custom_rules.#", "2"), - resource.TestCheckResourceAttr(resourceName, "custom_rules.0.source", "/documents"), - resource.TestCheckResourceAttr(resourceName, "custom_rules.0.status", "302"), - resource.TestCheckResourceAttr(resourceName, "custom_rules.0.target", "/documents/us"), - resource.TestCheckResourceAttr(resourceName, "custom_rules.0.condition", ""), - resource.TestCheckResourceAttr(resourceName, "custom_rules.1.source", "/<*>"), - resource.TestCheckResourceAttr(resourceName, "custom_rules.1.status", "200"), - resource.TestCheckResourceAttr(resourceName, "custom_rules.1.target", "/index.html"), - ), + // access_token is ignored because AWS does not store access_token and oauth_token + // See https://docs.aws.amazon.com/sdk-for-go/api/service/amplify/#CreateAppInput + ImportStateVerifyIgnore: []string{"access_token"}, }, }, }) @@ -714,12 +680,12 @@ resource "aws_amplify_app" "test" { `, rName, buildSpec) } -func testAccAWSAmplifyAppConfigCustomRules1(rName string) string { +func testAccAWSAmplifyAppConfigCustomRules(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q - custom_rules { + custom_rule { source = "/<*>" status = "404" target = "/index.html" @@ -728,19 +694,19 @@ resource "aws_amplify_app" "test" { `, rName) } -func testAccAWSAmplifyAppConfigCustomRules2(rName string) string { +func testAccAWSAmplifyAppConfigCustomRulesUpdated(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q - custom_rules { + custom_rule { + condition = "" source = "/documents" status = "302" target = "/documents/us" - condition = "" } - custom_rules { + custom_rule { source = "/<*>" status = "200" target = "/index.html" From 1babcd6e2fbc27c609542c19ec0fe9577fd1cee3 Mon Sep 17 00:00:00 2001 From: Simon Davis Date: Thu, 20 May 2021 09:08:28 -0700 Subject: [PATCH 054/398] specify ref as release event ref is last commit on release (#19457) --- .github/workflows/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d313a20f0ab..5e34f3655fa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,8 @@ jobs: steps: - uses: actions/checkout@v2 with: - fetch-depth: 0 + fetch-depth: 0 + ref: main - run: | CHANGELOG_FILE_NAME="CHANGELOG.md" PREVIOUS_RELEASE_TAG=$(git describe --abbrev=0 --match='v*.*.*' --tags) From 38f37d78d5af441c64393c92054f7f99aa7bb7b0 Mon Sep 17 00:00:00 2001 From: Simon Davis Date: Thu, 20 May 2021 09:12:17 -0700 Subject: [PATCH 055/398] Specify strings to avoid float issue --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5e34f3655fa..90969c0596b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,10 +10,10 @@ jobs: - uses: breathingdust/github-asana-tidy@v1 with: asana_pat: ${{ secrets.asana_pat }} - asana_target_section_gid: 1141945723817371 - asana_workspace_gid: 90955849329269 - asana_project_gid: 632425409545160 - asana_github_url_field_gid: 1134594824474912 + asana_target_section_gid: '1141945723817371' + asana_workspace_gid: '90955849329269' + asana_project_gid: '632425409545160' + asana_github_url_field_gid: '1134594824474912' github_release_name: ${{ github.event.release.tag_name }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} project-archive: From e32f493e3ba205c41dff686b4157fffd6a44cc74 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 12:26:41 -0400 Subject: [PATCH 056/398] r/servicecatalog_budget_resource_association: Add changelog --- .changelog/19452.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19452.txt diff --git a/.changelog/19452.txt b/.changelog/19452.txt new file mode 100644 index 00000000000..970016a5d0e --- /dev/null +++ b/.changelog/19452.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_servicecatalog_budget_resource_association +``` \ No newline at end of file From 0680c37f382659966e010083e2e4dc3b39b7e244 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 12:27:03 -0400 Subject: [PATCH 057/398] r/eks_addon: Add changelog --- .changelog/19454.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19454.txt diff --git a/.changelog/19454.txt b/.changelog/19454.txt new file mode 100644 index 00000000000..6ff5b428703 --- /dev/null +++ b/.changelog/19454.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_eks_addon: Use `service_account_role_arn`, if set, on updates +``` \ No newline at end of file From acb3ebfcc67eb0e4ef457e09dff5e0a6d0990497 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 12:28:25 -0400 Subject: [PATCH 058/398] docs/r/servicecatalog_budg_res_assoc: Update --- .../r/servicecatalog_budget_resource_association.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/servicecatalog_budget_resource_association.html.markdown b/website/docs/r/servicecatalog_budget_resource_association.html.markdown index 7673ba5751d..f1071ef69ef 100644 --- a/website/docs/r/servicecatalog_budget_resource_association.html.markdown +++ b/website/docs/r/servicecatalog_budget_resource_association.html.markdown @@ -10,7 +10,7 @@ description: |- Manages a Service Catalog Budget Resource Association. --> A "resource" is either a Service Catalog portfolio or product. +-> **Tip:** A "resource" is either a Service Catalog portfolio or product. ## Example Usage From 4b781c887f4698e647b3e14a8c3a686e6d9d341f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 20 May 2021 12:48:20 -0400 Subject: [PATCH 059/398] r/aws_amplify_app: Send map with empty key and value to clear 'environment_variables'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplifyApp_EnvironmentVariables' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplifyApp_EnvironmentVariables -timeout 180m === RUN TestAccAWSAmplifyApp_EnvironmentVariables === PAUSE TestAccAWSAmplifyApp_EnvironmentVariables === CONT TestAccAWSAmplifyApp_EnvironmentVariables --- PASS: TestAccAWSAmplifyApp_EnvironmentVariables (29.91s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 33.543s --- aws/resource_aws_amplify_app.go | 6 ++- aws/resource_aws_amplify_app_test.go | 76 +++++++++++++++------------- 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index ef0ad4a8f80..43c1de024b5 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -579,7 +579,11 @@ func resourceAwsAmplifyAppUpdate(d *schema.ResourceData, meta interface{}) error } if d.HasChange("environment_variables") { - input.EnvironmentVariables = expandStringMap(d.Get("environment_variables").(map[string]interface{})) + 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("iam_service_role_arn") { diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 4605a94cd32..cb3d82c7ce6 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -325,10 +325,9 @@ func TestAccAWSAmplifyApp_CustomRules(t *testing.T) { }) } -func TestAccAWSAmplifyApp_Name(t *testing.T) { +func TestAccAWSAmplifyApp_EnvironmentVariables(t *testing.T) { var app amplify.App - rName1 := acctest.RandomWithPrefix("tf-acc-test") - rName2 := acctest.RandomWithPrefix("tf-acc-test") + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ @@ -338,10 +337,11 @@ func TestAccAWSAmplifyApp_Name(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigName(rName1), + Config: testAccAWSAmplifyAppConfigEnvironmentVariables(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "name", rName1), + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "1"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "1"), ), }, { @@ -350,18 +350,29 @@ func TestAccAWSAmplifyApp_Name(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigName(rName2), + Config: testAccAWSAmplifyAppConfigEnvironmentVariablesUpdated(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "name", rName2), + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "2"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "2"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR2", "2"), + ), + }, + { + Config: testAccAWSAmplifyAppConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), ), }, }, }) } -func TestAccAWSAmplifyApp_repository(t *testing.T) { - rName := acctest.RandomWithPrefix("tf-acc-test") +func TestAccAWSAmplifyApp_Name(t *testing.T) { + var app amplify.App + rName1 := acctest.RandomWithPrefix("tf-acc-test") + rName2 := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ @@ -371,24 +382,29 @@ func TestAccAWSAmplifyApp_repository(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigRepository(rName), + Config: testAccAWSAmplifyAppConfigName(rName1), Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr(resourceName, "repository", regexp.MustCompile("^https://github.com")), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "name", rName1), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - // access_token is ignored because AWS does not store access_token and oauth_token - // See https://docs.aws.amazon.com/sdk-for-go/api/service/amplify/#CreateAppInput - ImportStateVerifyIgnore: []string{"access_token"}, + }, + { + Config: testAccAWSAmplifyAppConfigName(rName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "name", rName2), + ), }, }, }) } -func TestAccAWSAmplifyApp_environmentVariables(t *testing.T) { +func TestAccAWSAmplifyApp_repository(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -399,30 +415,18 @@ func TestAccAWSAmplifyApp_environmentVariables(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigEnvironmentVariables1(rName), + Config: testAccAWSAmplifyAppConfigRepository(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "1"), - resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "1"), + resource.TestMatchResourceAttr(resourceName, "repository", regexp.MustCompile("^https://github.com")), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyAppConfigEnvironmentVariables2(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: testAccAWSAmplifyAppConfigName(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), - ), + // access_token is ignored because AWS does not store access_token and oauth_token + // See https://docs.aws.amazon.com/sdk-for-go/api/service/amplify/#CreateAppInput + ImportStateVerifyIgnore: []string{"access_token"}, }, }, }) @@ -715,10 +719,10 @@ resource "aws_amplify_app" "test" { `, rName) } -func testAccAWSAmplifyAppConfigEnvironmentVariables1(rName string) string { +func testAccAWSAmplifyAppConfigEnvironmentVariables(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q environment_variables = { ENVVAR1 = "1" @@ -727,10 +731,10 @@ resource "aws_amplify_app" "test" { `, rName) } -func testAccAWSAmplifyAppConfigEnvironmentVariables2(rName string) string { +func testAccAWSAmplifyAppConfigEnvironmentVariablesUpdated(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q environment_variables = { ENVVAR1 = "2", From 6373499dcf60b0a0155716db017adca6248e0e35 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 20 May 2021 17:33:05 +0000 Subject: [PATCH 060/398] Update CHANGELOG.md for #19452 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad0990e2a95..60f47f683e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ ## 3.43.0 (Unreleased) +FEATURES: + +* **New Resource:** `aws_servicecatalog_budget_resource_association` ([#19452](https://github.com/hashicorp/terraform-provider-aws/issues/19452)) + BUG FIXES: +* 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)) ## 3.42.0 (May 20, 2021) From 025f54ec7309a686cbf2a0ec328a927faa77eb83 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 20:24:55 -0400 Subject: [PATCH 061/398] i/r/servicecat_tag_option_resource_assoc: Add finder --- .../service/servicecatalog/finder/finder.go | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/aws/internal/service/servicecatalog/finder/finder.go b/aws/internal/service/servicecatalog/finder/finder.go index 497218da55b..79157804479 100644 --- a/aws/internal/service/servicecatalog/finder/finder.go +++ b/aws/internal/service/servicecatalog/finder/finder.go @@ -98,3 +98,32 @@ func BudgetResourceAssociation(conn *servicecatalog.ServiceCatalog, budgetName, return result, err } + +func TagOptionResourceAssociation(conn *servicecatalog.ServiceCatalog, tagOptionID, resourceID string) (*servicecatalog.ResourceDetail, error) { + input := &servicecatalog.ListResourcesForTagOptionInput{ + TagOptionId: aws.String(tagOptionID), + } + + var result *servicecatalog.ResourceDetail + + err := conn.ListResourcesForTagOptionPages(input, func(page *servicecatalog.ListResourcesForTagOptionOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, deet := range page.ResourceDetails { + if deet == nil { + continue + } + + if aws.StringValue(deet.Id) == resourceID { + result = deet + return false + } + } + + return !lastPage + }) + + return result, err +} From c2de85ccd5308e0a58b0e08d314da16bf68ed3f7 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 20:25:27 -0400 Subject: [PATCH 062/398] i/r/servicecat_tag_option_resource_assoc: Add id funcs --- 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 1aa89da2789..14bfac365e6 100644 --- a/aws/internal/service/servicecatalog/id.go +++ b/aws/internal/service/servicecatalog/id.go @@ -46,3 +46,17 @@ func BudgetResourceAssociationParseID(id string) (string, string, error) { func BudgetResourceAssociationID(budgetName, resourceID string) string { return strings.Join([]string{budgetName, resourceID}, ":") } + +func TagOptionResourceAssociationParseID(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), tagOptionID:resourceID", id) + } + + return parts[0], parts[1], nil +} + +func TagOptionResourceAssociationID(tagOptionID, resourceID string) string { + return strings.Join([]string{tagOptionID, resourceID}, ":") +} From 66f3942fc7f557ac526df1b8669848d547d6513e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 20:25:53 -0400 Subject: [PATCH 063/398] i/r/servicecat_tag_option_resource_assoc: Add waiter --- .../service/servicecatalog/waiter/status.go | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/aws/internal/service/servicecatalog/waiter/status.go b/aws/internal/service/servicecatalog/waiter/status.go index ad804e572e6..2ea72602cc7 100644 --- a/aws/internal/service/servicecatalog/waiter/status.go +++ b/aws/internal/service/servicecatalog/waiter/status.go @@ -250,3 +250,27 @@ func BudgetResourceAssociationStatus(conn *servicecatalog.ServiceCatalog, budget return output, servicecatalog.StatusAvailable, err } } + +func TagOptionResourceAssociationStatus(conn *servicecatalog.ServiceCatalog, tagOptionID, resourceID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.TagOptionResourceAssociation(conn, tagOptionID, resourceID) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil, StatusNotFound, &resource.NotFoundError{ + Message: fmt.Sprintf("tag option resource association not found (%s): %s", tfservicecatalog.TagOptionResourceAssociationID(tagOptionID, resourceID), err), + } + } + + if err != nil { + return nil, servicecatalog.StatusFailed, fmt.Errorf("error describing tag option resource association: %w", err) + } + + if output == nil { + return nil, StatusNotFound, &resource.NotFoundError{ + Message: fmt.Sprintf("finding tag option resource association (%s): empty response", tfservicecatalog.TagOptionResourceAssociationID(tagOptionID, resourceID)), + } + } + + return output, servicecatalog.StatusAvailable, err + } +} From 4dae28ce30a20ecc4038d30b9df54249dd35cb61 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 20:26:08 -0400 Subject: [PATCH 064/398] i/r/servicecat_tag_option_resource_assoc: Add waiter --- .../service/servicecatalog/waiter/waiter.go | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index 530a0629f7c..3d8b4293b7c 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -32,6 +32,9 @@ const ( BudgetResourceAssociationReadyTimeout = 3 * time.Minute BudgetResourceAssociationDeleteTimeout = 3 * time.Minute + TagOptionResourceAssociationReadyTimeout = 3 * time.Minute + TagOptionResourceAssociationDeleteTimeout = 3 * time.Minute + StatusNotFound = "NOT_FOUND" StatusUnavailable = "UNAVAILABLE" @@ -333,3 +336,33 @@ func BudgetResourceAssociationDeleted(conn *servicecatalog.ServiceCatalog, budge return err } + +func TagOptionResourceAssociationReady(conn *servicecatalog.ServiceCatalog, tagOptionID, resourceID string) (*servicecatalog.ResourceDetail, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{StatusNotFound, StatusUnavailable}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: TagOptionResourceAssociationStatus(conn, tagOptionID, resourceID), + Timeout: TagOptionResourceAssociationReadyTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*servicecatalog.ResourceDetail); ok { + return output, err + } + + return nil, err +} + +func TagOptionResourceAssociationDeleted(conn *servicecatalog.ServiceCatalog, tagOptionID, resourceID string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{servicecatalog.StatusAvailable}, + Target: []string{StatusNotFound, StatusUnavailable}, + Refresh: TagOptionResourceAssociationStatus(conn, tagOptionID, resourceID), + Timeout: TagOptionResourceAssociationDeleteTimeout, + } + + _, err := stateConf.WaitForState() + + return err +} From 82e14867f90b5e4b957c6699b05b8afa1fbd909b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 20:26:37 -0400 Subject: [PATCH 065/398] provider: Add resource --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index 4f7d14ec632..ffb54b872c7 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1029,6 +1029,7 @@ func Provider() *schema.Provider { "aws_servicecatalog_product": resourceAwsServiceCatalogProduct(), "aws_servicecatalog_service_action": resourceAwsServiceCatalogServiceAction(), "aws_servicecatalog_tag_option": resourceAwsServiceCatalogTagOption(), + "aws_servicecatalog_tag_option_resource_association": resourceAwsServiceCatalogTagOptionResourceAssociation(), "aws_servicecatalog_product_portfolio_association": resourceAwsServiceCatalogProductPortfolioAssociation(), "aws_service_discovery_http_namespace": resourceAwsServiceDiscoveryHttpNamespace(), "aws_service_discovery_private_dns_namespace": resourceAwsServiceDiscoveryPrivateDnsNamespace(), From fb68ce7c029cbdcc89f0e6b3c9f8903bdf7b9886 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 20:27:37 -0400 Subject: [PATCH 066/398] r/servicecat_tag_option_resource_assoc: New resource --- ...catalog_tag_option_resource_association.go | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_tag_option_resource_association.go diff --git a/aws/resource_aws_servicecatalog_tag_option_resource_association.go b/aws/resource_aws_servicecatalog_tag_option_resource_association.go new file mode 100644 index 00000000000..1b1678d3721 --- /dev/null +++ b/aws/resource_aws_servicecatalog_tag_option_resource_association.go @@ -0,0 +1,170 @@ +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" + 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 resourceAwsServiceCatalogTagOptionResourceAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsServiceCatalogTagOptionResourceAssociationCreate, + Read: resourceAwsServiceCatalogTagOptionResourceAssociationRead, + Delete: resourceAwsServiceCatalogTagOptionResourceAssociationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "resource_arn": { + Type: schema.TypeString, + Computed: true, + }, + "resource_created_time": { + Type: schema.TypeString, + Computed: true, + }, + "resource_description": { + Type: schema.TypeString, + Computed: true, + }, + "resource_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "resource_name": { + Type: schema.TypeString, + Computed: true, + }, + "tag_option_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceAwsServiceCatalogTagOptionResourceAssociationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + input := &servicecatalog.AssociateTagOptionWithResourceInput{ + ResourceId: aws.String(d.Get("resource_id").(string)), + TagOptionId: aws.String(d.Get("tag_option_id").(string)), + } + + var output *servicecatalog.AssociateTagOptionWithResourceOutput + err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + var err error + + output, err = conn.AssociateTagOptionWithResource(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.AssociateTagOptionWithResource(input) + } + + if err != nil { + return fmt.Errorf("error associating Service Catalog Tag Option with Resource: %w", err) + } + + if output == nil { + return fmt.Errorf("error creating Service Catalog Tag Option Resource Association: empty response") + } + + d.SetId(tfservicecatalog.TagOptionResourceAssociationID(d.Get("tag_option_id").(string), d.Get("resource_id").(string))) + + return resourceAwsServiceCatalogTagOptionResourceAssociationRead(d, meta) +} + +func resourceAwsServiceCatalogTagOptionResourceAssociationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + tagOptionID, resourceID, err := tfservicecatalog.TagOptionResourceAssociationParseID(d.Id()) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", d.Id(), err) + } + + output, err := waiter.TagOptionResourceAssociationReady(conn, tagOptionID, resourceID) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Service Catalog Tag Option Resource Association (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error describing Service Catalog Tag Option Resource Association (%s): %w", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting Service Catalog Tag Option Resource Association (%s): empty response", d.Id()) + } + + if output.CreatedTime != nil { + d.Set("resource_created_time", output.CreatedTime.Format(time.RFC3339)) + } + + d.Set("resource_arn", output.ARN) + d.Set("resource_description", output.Description) + d.Set("resource_id", output.Id) + d.Set("resource_name", output.Name) + d.Set("tag_option_id", tagOptionID) + + return nil +} + +func resourceAwsServiceCatalogTagOptionResourceAssociationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + tagOptionID, resourceID, err := tfservicecatalog.TagOptionResourceAssociationParseID(d.Id()) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", d.Id(), err) + } + + input := &servicecatalog.DisassociateTagOptionFromResourceInput{ + ResourceId: aws.String(resourceID), + TagOptionId: aws.String(tagOptionID), + } + + _, err = conn.DisassociateTagOptionFromResource(input) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { + return fmt.Errorf("error disassociating Service Catalog Tag Option from Resource (%s): %w", d.Id(), err) + } + + err = waiter.TagOptionResourceAssociationDeleted(conn, tagOptionID, resourceID) + + if err != nil && !tfresource.NotFound(err) { + return fmt.Errorf("error waiting for Service Catalog Tag Option Resource Disassociation (%s): %w", d.Id(), err) + } + + return nil +} From 5b188d9fea228d845a15f555177eb2a067ff8a89 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 20:28:11 -0400 Subject: [PATCH 067/398] tests/r/servicecat_tag_option_resource_assoc: New resource --- ...og_tag_option_resource_association_test.go | 220 ++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_tag_option_resource_association_test.go diff --git a/aws/resource_aws_servicecatalog_tag_option_resource_association_test.go b/aws/resource_aws_servicecatalog_tag_option_resource_association_test.go new file mode 100644 index 00000000000..296307055d7 --- /dev/null +++ b/aws/resource_aws_servicecatalog_tag_option_resource_association_test.go @@ -0,0 +1,220 @@ +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 tag option resource associations +func init() { + resource.AddTestSweepers("aws_servicecatalog_tag_option_resource_association", &resource.Sweeper{ + Name: "aws_servicecatalog_tag_option_resource_association", + Dependencies: []string{}, + F: testSweepServiceCatalogTagOptionResourceAssociations, + }) +} + +func testSweepServiceCatalogTagOptionResourceAssociations(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.ListTagOptionsInput{} + + err = conn.ListTagOptionsPages(input, func(page *servicecatalog.ListTagOptionsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, tag := range page.TagOptionDetails { + if tag == nil { + continue + } + + resInput := &servicecatalog.ListResourcesForTagOptionInput{ + TagOptionId: tag.Id, + } + + err = conn.ListResourcesForTagOptionPages(resInput, func(page *servicecatalog.ListResourcesForTagOptionOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, resource := range page.ResourceDetails { + if resource == nil { + continue + } + + r := resourceAwsServiceCatalogTagOptionResourceAssociation() + d := r.Data(nil) + d.SetId(aws.StringValue(resource.Id)) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } + + return !lastPage + }) + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error describing Service Catalog Tag Option Resource Associations for %s: %w", region, err)) + } + + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping Service Catalog Tag Option Resource Associations for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping Service Catalog Tag Option Resource Associations sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() +} + +func TestAccAWSServiceCatalogTagOptionResourceAssociation_basic(t *testing.T) { + resourceName := "aws_servicecatalog_tag_option_resource_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: testAccCheckAwsServiceCatalogTagOptionResourceAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogTagOptionResourceAssociationConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogTagOptionResourceAssociationExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "resource_id", "aws_servicecatalog_portfolio.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "tag_option_id", "aws_servicecatalog_tag_option.test", "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSServiceCatalogTagOptionResourceAssociation_disappears(t *testing.T) { + resourceName := "aws_servicecatalog_tag_option_resource_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: testAccCheckAwsServiceCatalogTagOptionResourceAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogTagOptionResourceAssociationConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogTagOptionResourceAssociationExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsServiceCatalogTagOptionResourceAssociation(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAwsServiceCatalogTagOptionResourceAssociationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).scconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_servicecatalog_tag_option_resource_association" { + continue + } + + tagOptionID, resourceID, err := tfservicecatalog.TagOptionResourceAssociationParseID(rs.Primary.ID) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", rs.Primary.ID, err) + } + + err = waiter.TagOptionResourceAssociationDeleted(conn, tagOptionID, resourceID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return fmt.Errorf("waiting for Service Catalog Tag Option Resource Association to be destroyed (%s): %w", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckAwsServiceCatalogTagOptionResourceAssociationExists(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) + } + + tagOptionID, resourceID, err := tfservicecatalog.TagOptionResourceAssociationParseID(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.TagOptionResourceAssociationReady(conn, tagOptionID, resourceID) + + if err != nil { + return fmt.Errorf("waiting for Service Catalog Tag Option Resource Association existence (%s): %w", rs.Primary.ID, err) + } + + return nil + } +} + +func testAccAWSServiceCatalogTagOptionResourceAssociationConfig_base(rName string) string { + return fmt.Sprintf(` +resource "aws_servicecatalog_portfolio" "test" { + name = %[1]q + description = %[1]q + provider_name = %[1]q +} + +resource "aws_servicecatalog_tag_option" "test" { + key = %[1]q + value = %[1]q +} +`, rName) +} + +func testAccAWSServiceCatalogTagOptionResourceAssociationConfig_basic(rName string) string { + return composeConfig(testAccAWSServiceCatalogTagOptionResourceAssociationConfig_base(rName), ` +resource "aws_servicecatalog_tag_option_resource_association" "test" { + resource_id = aws_servicecatalog_portfolio.test.id + tag_option_id = aws_servicecatalog_tag_option.test.id +} +`) +} From c116566094664cf4ccf64a473b8df8d4c2410d1b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 20:28:54 -0400 Subject: [PATCH 068/398] docs/r/servicecat_tag_option_resource_assoc: New resource --- ..._option_resource_association.html.markdown | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 website/docs/r/servicecatalog_tag_option_resource_association.html.markdown diff --git a/website/docs/r/servicecatalog_tag_option_resource_association.html.markdown b/website/docs/r/servicecatalog_tag_option_resource_association.html.markdown new file mode 100644 index 00000000000..076f525d4f3 --- /dev/null +++ b/website/docs/r/servicecatalog_tag_option_resource_association.html.markdown @@ -0,0 +1,49 @@ +--- +subcategory: "Service Catalog" +layout: "aws" +page_title: "AWS: aws_servicecatalog_tag_option_resource_association" +description: |- + Manages a Service Catalog Tag Option Resource Association +--- + +# Resource: aws_servicecatalog_tag_option_resource_association + +Manages a Service Catalog Tag Option Resource Association. + +-> A "resource" is either a Service Catalog portfolio or product. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_servicecatalog_tag_option_resource_association" "example" { + resource_id = "prod-dnigbtea24ste" + tag_option_id = "tag-pjtvyakdlyo3m" +} +``` + +## Argument Reference + +The following arguments are required: + +* `resource_id` - (Required) Resource identifier. +* `tag_option_id` - (Required) Tag Option identifier. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - Identifier of the association. +* `resource_arn` - ARN of the resource. +* `resource_created_time` - Creation time of the resource. +* `resource_description` - Description of the resource. +* `resource_name` - Description of the resource. + +## Import + +`aws_servicecatalog_tag_option_resource_association` can be imported using the tag option ID and resource ID, e.g. + +``` +$ terraform import aws_servicecatalog_tag_option_resource_association.example tag-pjtvyakdlyo3m:prod-dnigbtea24ste +``` From 80227905a4afeec2c433c4d7d049f5a8b1212e07 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 12:31:21 -0400 Subject: [PATCH 069/398] r/servicecatalog_tag_opt_res_assoc: Add changelog --- .changelog/19448.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19448.txt diff --git a/.changelog/19448.txt b/.changelog/19448.txt new file mode 100644 index 00000000000..6b7ca150797 --- /dev/null +++ b/.changelog/19448.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_servicecatalog_tag_option_resource_association +``` \ No newline at end of file From 4637efefff49354940658185ebf1ad8ef2d68e60 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 12:31:41 -0400 Subject: [PATCH 070/398] docs/r/servicecatalog_tag_opt_res_assoc: Update --- ...servicecatalog_tag_option_resource_association.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/servicecatalog_tag_option_resource_association.html.markdown b/website/docs/r/servicecatalog_tag_option_resource_association.html.markdown index 076f525d4f3..bb9f001d426 100644 --- a/website/docs/r/servicecatalog_tag_option_resource_association.html.markdown +++ b/website/docs/r/servicecatalog_tag_option_resource_association.html.markdown @@ -10,7 +10,7 @@ description: |- Manages a Service Catalog Tag Option Resource Association. --> A "resource" is either a Service Catalog portfolio or product. +-> **Tip:** A "resource" is either a Service Catalog portfolio or product. ## Example Usage From 32a7484ec62768d71a68243d543ecfcc0b6114b6 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 20 May 2021 18:31:07 +0000 Subject: [PATCH 071/398] Update CHANGELOG.md for #19448 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60f47f683e3..d1e6a0d77fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ FEATURES: * **New Resource:** `aws_servicecatalog_budget_resource_association` ([#19452](https://github.com/hashicorp/terraform-provider-aws/issues/19452)) +* **New Resource:** `aws_servicecatalog_tag_option_resource_association` ([#19448](https://github.com/hashicorp/terraform-provider-aws/issues/19448)) BUG FIXES: From 8c61e25e0a496fabffde86bf33ba6669474c8687 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 11 May 2021 12:46:53 -0400 Subject: [PATCH 072/398] docs/r/servicecatalog_provisioning_artifact: Add docs --- ...atalog_provisioning_artifact.html.markdown | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 website/docs/r/servicecatalog_provisioning_artifact.html.markdown diff --git a/website/docs/r/servicecatalog_provisioning_artifact.html.markdown b/website/docs/r/servicecatalog_provisioning_artifact.html.markdown new file mode 100644 index 00000000000..35f168dd665 --- /dev/null +++ b/website/docs/r/servicecatalog_provisioning_artifact.html.markdown @@ -0,0 +1,64 @@ +--- +subcategory: "Service Catalog" +layout: "aws" +page_title: "AWS: aws_servicecatalog_provisioning_artifact" +description: |- + Manages a Service Catalog Provisioning Artifact +--- + +# Resource: aws_servicecatalog_provisioning_artifact + +Manages a Service Catalog Provisioning Artifact for a specified product. + +-> A "provisioning artifact" is also referred to as a "version." + +~> **NOTE:** You cannot create a provisioning artifact for a product that was shared with you. + +~> **NOTE:** The user or role that use this resource must have the `cloudformation:GetTemplate` IAM policy permission. This policy permission is required when using the `template_physical_id` argument. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_servicecatalog_provisioning_artifact" "example" { + name = "example" + product_id = aws_servicecatalog_product.example.id + type = "CLOUD_FORMATION_TEMPLATE" + template_url = "https://s3.amazonaws.com/cf-templates-ozkq9d3hgiq2-us-east-1/temp1.json" +} +``` + +## Argument Reference + +The following arguments are required: + +* `product_id` - (Required) Identifier of the product. +* `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. + +The following arguments are optional: + +* `accept_language` - (Optional) Language code. Valid values: `en` (English), `jp` (Japanese), `zh` (Chinese). The default value is `en`. +* `active` - (Optional) Whether the product version is active. Inactive provisioning artifacts are invisible to end users. End users cannot launch or update a provisioned product from an inactive provisioning artifact. Default is `true`. +* `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. +* `guidance` - (Optional) Information set by the administrator to provide guidance to end users about which provisioning artifacts to use. Valid values are `DEFAULT` and `DEPRECATED`. The default is `DEFAULT`. Users are able to make updates to a provisioned product of a deprecated version but cannot launch new provisioned products using a deprecated version. +* `name` - (Optional) Name of the provisioning artifact (for example, `v1`, `v2beta`). No spaces are allowed. +* `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: + +* `created_time` - Time when the provisioning artifact was created. +* `id` - Provisioning Artifact identifier. +* `status` - Status of the provisioning artifact. + +## Import + +`aws_servicecatalog_provisioning_artifact` can be imported using the provisioning artifact ID, e.g. + +``` +$ terraform import aws_servicecatalog_provisioning_artifact.example pa-ij2b6lusy6dec +``` From 6476f1be38a54636c57e9ca7f4e9aa9bbc31f45f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 11 May 2021 12:47:41 -0400 Subject: [PATCH 073/398] tests/r/servicecatalog_provisioning_artifact: Add tests --- ...rvicecatalog_provisioning_artifact_test.go | 443 ++++++++++++++++++ 1 file changed, 443 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_provisioning_artifact_test.go diff --git a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go new file mode 100644 index 00000000000..7feb9c6b2f1 --- /dev/null +++ b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go @@ -0,0 +1,443 @@ +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" +) + +// add sweeper to delete known test servicecat provisioning artifacts +func init() { + resource.AddTestSweepers("aws_servicecatalog_provisioning_artifact", &resource.Sweeper{ + Name: "aws_servicecatalog_provisioning_artifact", + Dependencies: []string{}, + F: testSweepServiceCatalogProvisioningArtifacts, + }) +} + +func testSweepServiceCatalogProvisioningArtifacts(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 || pvd.ProductViewSummary.ProductId == nil { + continue + } + + productID := aws.StringValue(pvd.ProductViewSummary.ProductId) + + artInput := &servicecatalog.ListProvisioningArtifactsInput{ + ProductId: aws.String(productID), + } + + // there's no paginator for ListProvisioningArtifacts + for { + output, err := conn.ListProvisioningArtifacts(artInput) + + if err != nil { + err := fmt.Errorf("error listing Service Catalog Provisioning Artifacts for product (%s): %w", productID, err) + log.Printf("[ERROR] %s", err) + errs = multierror.Append(errs, err) + break + } + + for _, pad := range output.ProvisioningArtifactDetails { + r := resourceAwsServiceCatalogProvisioningArtifact() + d := r.Data(nil) + + d.SetId(aws.StringValue(pad.Id)) + d.Set("product_id", productID) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } + + /* + // Currently, the API has no token field on input (AWS oops) + if aws.StringValue(output.NextPageToken) == "" { + break + } + + artInput.NextPageToken = output.NextPageToken + */ + break + } + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error describing Service Catalog Provisioning Artifacts for %s: %w", region, err)) + } + + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping Service Catalog Provisioning Artifacts for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping Service Catalog Provisioning Artifacts sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() +} + +func TestAccAWSServiceCatalogProvisioningArtifact_basic(t *testing.T) { + resourceName := "aws_servicecatalog_provisioning_artifact.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProvisioningArtifactDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName, "beskrivning"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProvisioningArtifactExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "active", "true"), + resource.TestCheckResourceAttr(resourceName, "description", "beskrivning"), + resource.TestCheckResourceAttr(resourceName, "disable_template_validation", "true"), + resource.TestCheckResourceAttr(resourceName, "guidance", "DEFAULT"), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("%s-2", rName)), + resource.TestCheckResourceAttrPair(resourceName, "product_id", "aws_servicecatalog_product.test", "id"), + resource.TestCheckResourceAttrSet(resourceName, "template_url"), + resource.TestCheckResourceAttr(resourceName, "type", servicecatalog.ProductTypeCloudFormationTemplate), + testAccCheckResourceAttrRfc3339(resourceName, "created_time"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "accept_language", + "disable_template_validation", + "template_url", + }, + }, + }, + }) +} + +func TestAccAWSServiceCatalogProvisioningArtifact_disappears(t *testing.T) { + resourceName := "aws_servicecatalog_provisioning_artifact.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProvisioningArtifactDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProvisioningArtifactExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsServiceCatalogProvisioningArtifact(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSServiceCatalogProvisioningArtifact_update(t *testing.T) { + resourceName := "aws_servicecatalog_provisioning_artifact.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProvisioningArtifactDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName, "beskrivning"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProvisioningArtifactExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "description", "beskrivning"), + resource.TestCheckResourceAttr(resourceName, "support_description", "supportbeskrivning"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + ), + }, + { + Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName, "ny beskrivning"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProvisioningArtifactExists(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 TestAccAWSServiceCatalogProvisioningArtifact_physicalID(t *testing.T) { + resourceName := "aws_servicecatalog_provisioning_artifact.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProvisioningArtifactDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProvisioningArtifactConfig_physicalID(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProvisioningArtifactExists(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 testAccCheckAwsServiceCatalogProvisioningArtifactDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).scconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_servicecatalog_provisioning_artifact" { + continue + } + + artifactID, productID, err := parseServiceCatalogProvisioningArtifactID(rs.Primary.ID) + + if err != nil { + return fmt.Errorf("error parsing Service Catalog Provisioning Artifact ID (%s): %w", rs.Primary.ID, err) + } + + input := &servicecatalog.DescribeProvisioningArtifactInput{ + ProductId: aws.String(productID), + ProvisioningArtifactId: aws.String(artifactID), + } + + output, err := conn.DescribeProvisioningArtifact(input) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + continue + } + + if err != nil { + return fmt.Errorf("error getting Service Catalog Provisioning Artifact (%s): %w", rs.Primary.ID, err) + } + + if output != nil { + return fmt.Errorf("Service Catalog Provisioning Artifact (%s) still exists", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckAwsServiceCatalogProvisioningArtifactExists(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 + + artifactID, productID, err := parseServiceCatalogProvisioningArtifactID(rs.Primary.ID) + + if err != nil { + return fmt.Errorf("error parsing Service Catalog Provisioning Artifact ID (%s): %w", rs.Primary.ID, err) + } + + input := &servicecatalog.DescribeProvisioningArtifactInput{ + ProductId: aws.String(productID), + ProvisioningArtifactId: aws.String(artifactID), + } + + _, err = conn.DescribeProvisioningArtifact(input) + + if err != nil { + return fmt.Errorf("error describing Service Catalog Provisioning Artifact (%s): %w", rs.Primary.ID, err) + } + + return nil + } +} + +func testAccAWSServiceCatalogProvisioningArtifactConfigTemplateURLBase(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: Tue, 11 May 2021 12:48:16 -0400 Subject: [PATCH 074/398] r/servicecatalog_provisioning_artifact: New resource --- ...ws_servicecatalog_provisioning_artifact.go | 313 ++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_provisioning_artifact.go diff --git a/aws/resource_aws_servicecatalog_provisioning_artifact.go b/aws/resource_aws_servicecatalog_provisioning_artifact.go new file mode 100644 index 00000000000..42ca5d8cce5 --- /dev/null +++ b/aws/resource_aws_servicecatalog_provisioning_artifact.go @@ -0,0 +1,313 @@ +package aws + +import ( + "fmt" + "log" + "strings" + "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" + 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 resourceAwsServiceCatalogProvisioningArtifact() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsServiceCatalogProvisioningArtifactCreate, + Read: resourceAwsServiceCatalogProvisioningArtifactRead, + Update: resourceAwsServiceCatalogProvisioningArtifactUpdate, + Delete: resourceAwsServiceCatalogProvisioningArtifactDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "accept_language": { + Type: schema.TypeString, + Optional: true, + Default: "en", + ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), + }, + "active": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "disable_template_validation": { + Type: schema.TypeBool, + Optional: true, + Default: false, + ForceNew: true, + }, + "guidance": { + Type: schema.TypeString, + Optional: true, + Default: servicecatalog.ProvisioningArtifactGuidanceDefault, + ValidateFunc: validation.StringInSlice(servicecatalog.ProvisioningArtifactGuidance_Values(), false), + }, + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "product_id": { + Type: schema.TypeString, + Required: true, + }, + "template_physical_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ExactlyOneOf: []string{ + "template_url", + "template_physical_id", + }, + }, + "template_url": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ExactlyOneOf: []string{ + "template_url", + "template_physical_id", + }, + }, + "type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(servicecatalog.ProvisioningArtifactType_Values(), false), + }, + }, + } +} + +func resourceAwsServiceCatalogProvisioningArtifactCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + parameters := make(map[string]interface{}) + parameters["description"] = d.Get("description") + parameters["disable_template_validation"] = d.Get("disable_template_validation") + parameters["name"] = d.Get("name") + parameters["template_physical_id"] = d.Get("template_physical_id") + parameters["template_url"] = d.Get("template_url") + parameters["type"] = d.Get("type") + + input := &servicecatalog.CreateProvisioningArtifactInput{ + IdempotencyToken: aws.String(resource.UniqueId()), + Parameters: expandProvisioningArtifactParameters(parameters), + ProductId: aws.String(d.Get("product_id").(string)), + } + + if v, ok := d.GetOk("accept_language"); ok { + input.AcceptLanguage = aws.String(v.(string)) + } + + var output *servicecatalog.CreateProvisioningArtifactOutput + err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + var err error + + output, err = conn.CreateProvisioningArtifact(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.CreateProvisioningArtifact(input) + } + + if err != nil { + return fmt.Errorf("error creating Service Catalog Provisioning Artifact: %w", err) + } + + if output == nil || output.ProvisioningArtifactDetail == nil || output.ProvisioningArtifactDetail.Id == nil { + return fmt.Errorf("error creating Service Catalog Provisioning Artifact: empty response") + } + + d.SetId(serviceCatalogProvisioningArtifactID(aws.StringValue(output.ProvisioningArtifactDetail.Id), d.Get("product_id").(string))) + + // Active and Guidance are not fields of CreateProvisioningArtifact but are fields of UpdateProvisioningArtifact. + // In order to set these to non-default values, you must create and then update. + + return resourceAwsServiceCatalogProvisioningArtifactUpdate(d, meta) +} + +func resourceAwsServiceCatalogProvisioningArtifactRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + artifactID, productID, err := parseServiceCatalogProvisioningArtifactID(d.Id()) + + if err != nil { + return fmt.Errorf("error parsing Service Catalog Provisioning Artifact ID (%s): %w", d.Id(), err) + } + + output, err := waiter.ProvisioningArtifactReady(conn, artifactID, productID) + + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + log.Printf("[WARN] Service Catalog Provisioning Artifact (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error describing Service Catalog Provisioning Artifact (%s): %w", d.Id(), err) + } + + if output == nil || output.ProvisioningArtifactDetail == nil { + return fmt.Errorf("error getting Service Catalog Provisioning Artifact (%s): empty response", d.Id()) + } + + if v, ok := output.Info["ImportFromPhysicalId"]; ok { + d.Set("template_physical_id", v) + } + + if v, ok := output.Info["LoadTemplateFromURL"]; ok { + d.Set("template_url", v) + } + + pad := output.ProvisioningArtifactDetail + + d.Set("active", pad.Active) + if pad.CreatedTime != nil { + d.Set("created_time", pad.CreatedTime.Format(time.RFC3339)) + } + d.Set("description", pad.Description) + d.Set("guidance", pad.Guidance) + d.Set("name", pad.Name) + d.Set("product_id", productID) + d.Set("type", pad.Type) + + return nil +} + +func resourceAwsServiceCatalogProvisioningArtifactUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + if d.HasChanges("accept_language", "active", "description", "guidance", "name", "product_id") { + artifactID, productID, err := parseServiceCatalogProvisioningArtifactID(d.Id()) + + if err != nil { + return fmt.Errorf("error parsing Service Catalog Provisioning Artifact ID (%s): %w", d.Id(), err) + } + + input := &servicecatalog.UpdateProvisioningArtifactInput{ + ProductId: aws.String(productID), + ProvisioningArtifactId: aws.String(artifactID), + } + + if v, ok := d.GetOk("accept_language"); ok { + input.AcceptLanguage = aws.String(v.(string)) + } + + if v, ok := d.GetOk("active"); ok { + input.Active = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("guidance"); ok { + input.Guidance = aws.String(v.(string)) + } + + if v, ok := d.GetOk("name"); ok { + input.Name = aws.String(v.(string)) + } + + err = resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + _, err := conn.UpdateProvisioningArtifact(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.UpdateProvisioningArtifact(input) + } + + if err != nil { + return fmt.Errorf("error updating Service Catalog Provisioning Artifact (%s): %w", d.Id(), err) + } + } + + return resourceAwsServiceCatalogProvisioningArtifactRead(d, meta) +} + +func resourceAwsServiceCatalogProvisioningArtifactDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + artifactID, productID, err := parseServiceCatalogProvisioningArtifactID(d.Id()) + + if err != nil { + return fmt.Errorf("error parsing Service Catalog Provisioning Artifact ID (%s): %w", d.Id(), err) + } + + input := &servicecatalog.DeleteProvisioningArtifactInput{ + ProductId: aws.String(productID), + ProvisioningArtifactId: aws.String(artifactID), + } + + if v, ok := d.GetOk("accept_language"); ok { + input.AcceptLanguage = aws.String(v.(string)) + } + + _, err = conn.DeleteProvisioningArtifact(input) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Service Catalog Provisioning Artifact (%s): %w", d.Id(), err) + } + + if err := waiter.ProvisioningArtifactDeleted(conn, artifactID, productID); err != nil { + return fmt.Errorf("error waiting for Service Catalog Provisioning Artifact (%s) to be deleted: %w", d.Id(), err) + } + + return nil +} + +func serviceCatalogProvisioningArtifactID(artifactID, productID string) string { + return strings.Join([]string{artifactID, productID}, ":") +} + +func parseServiceCatalogProvisioningArtifactID(id string) (string, string, error) { + parts := strings.Split(id, ":") + if len(parts) != 2 { + return "", "", fmt.Errorf("Please make sure the ID is in the form artifact_id:product_id (i.e. pa-r2d2slrtcob:prod-c3pohcrhmisy") + } + return parts[0], parts[1], nil +} From 2eb06922080d124f11c06079b832f20c0f5477a5 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 11 May 2021 12:48:44 -0400 Subject: [PATCH 075/398] provider: Add new resource --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index ffb54b872c7..b0cc423bedc 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1031,6 +1031,7 @@ func Provider() *schema.Provider { "aws_servicecatalog_tag_option": resourceAwsServiceCatalogTagOption(), "aws_servicecatalog_tag_option_resource_association": resourceAwsServiceCatalogTagOptionResourceAssociation(), "aws_servicecatalog_product_portfolio_association": resourceAwsServiceCatalogProductPortfolioAssociation(), + "aws_servicecatalog_provisioning_artifact": resourceAwsServiceCatalogProvisioningArtifact(), "aws_service_discovery_http_namespace": resourceAwsServiceDiscoveryHttpNamespace(), "aws_service_discovery_private_dns_namespace": resourceAwsServiceDiscoveryPrivateDnsNamespace(), "aws_service_discovery_public_dns_namespace": resourceAwsServiceDiscoveryPublicDnsNamespace(), From cdd7742eb87786a1563cd148e1f8f73863b49562 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 11 May 2021 12:49:38 -0400 Subject: [PATCH 076/398] tests/r/servicecatalog_product: Refactor const --- .../service/servicecatalog/waiter/status.go | 25 ++++++++++ .../service/servicecatalog/waiter/waiter.go | 46 ++++++++++++++++++- ...esource_aws_servicecatalog_product_test.go | 10 ++-- 3 files changed, 75 insertions(+), 6 deletions(-) diff --git a/aws/internal/service/servicecatalog/waiter/status.go b/aws/internal/service/servicecatalog/waiter/status.go index 2ea72602cc7..91f11d79c33 100644 --- a/aws/internal/service/servicecatalog/waiter/status.go +++ b/aws/internal/service/servicecatalog/waiter/status.go @@ -274,3 +274,28 @@ func TagOptionResourceAssociationStatus(conn *servicecatalog.ServiceCatalog, tag return output, servicecatalog.StatusAvailable, err } } + +func ProvisioningArtifactStatus(conn *servicecatalog.ServiceCatalog, id, productID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &servicecatalog.DescribeProvisioningArtifactInput{ + ProvisioningArtifactId: aws.String(id), + ProductId: aws.String(productID), + } + + output, err := conn.DescribeProvisioningArtifact(input) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil, StatusNotFound, err + } + + if err != nil { + return nil, servicecatalog.StatusFailed, fmt.Errorf("error describing Service Catalog Provisioning Artifact (%s): %w", id, err) + } + + if output == nil || output.ProvisioningArtifactDetail == nil { + return nil, StatusUnavailable, fmt.Errorf("error describing Service Catalog Provisioning Artifact (%s): empty response", id) + } + + return output, aws.StringValue(output.Status), err + } +} diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index 3d8b4293b7c..d3339569ee2 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -35,6 +35,9 @@ const ( TagOptionResourceAssociationReadyTimeout = 3 * time.Minute TagOptionResourceAssociationDeleteTimeout = 3 * time.Minute + ProvisioningArtifactReadyTimeout = 3 * time.Minute + ProvisioningArtifactDeletedTimeout = 3 * time.Minute + StatusNotFound = "NOT_FOUND" StatusUnavailable = "UNAVAILABLE" @@ -42,12 +45,13 @@ const ( ProductStatusCreated = "CREATED" OrganizationAccessStatusError = "ERROR" + StatusCreated = "CREATED" ) func ProductReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID string) (*servicecatalog.DescribeProductAsAdminOutput, error) { stateConf := &resource.StateChangeConf{ Pending: []string{servicecatalog.StatusCreating, StatusNotFound, StatusUnavailable}, - Target: []string{servicecatalog.StatusAvailable, ProductStatusCreated}, + Target: []string{servicecatalog.StatusAvailable, StatusCreated}, Refresh: ProductStatus(conn, acceptLanguage, productID), Timeout: ProductReadyTimeout, } @@ -63,7 +67,7 @@ func ProductReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID func ProductDeleted(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID string) (*servicecatalog.DescribeProductAsAdminOutput, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{servicecatalog.StatusCreating, servicecatalog.StatusAvailable, ProductStatusCreated, StatusUnavailable}, + Pending: []string{servicecatalog.StatusCreating, servicecatalog.StatusAvailable, StatusCreated, StatusUnavailable}, Target: []string{StatusNotFound}, Refresh: ProductStatus(conn, acceptLanguage, productID), Timeout: ProductDeleteTimeout, @@ -366,3 +370,41 @@ func TagOptionResourceAssociationDeleted(conn *servicecatalog.ServiceCatalog, ta return err } + +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, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*servicecatalog.DescribeProvisioningArtifactOutput); ok { + return output, err + } + + return nil, err +} + +func ProvisioningArtifactDeleted(conn *servicecatalog.ServiceCatalog, id, productID string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{servicecatalog.StatusCreating, servicecatalog.StatusAvailable, StatusCreated, StatusUnavailable}, + Target: []string{StatusNotFound}, + Refresh: ProvisioningArtifactStatus(conn, id, productID), + Timeout: ProvisioningArtifactDeletedTimeout, + } + + _, err := stateConf.WaitForState() + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { + return err + } + + return nil +} diff --git a/aws/resource_aws_servicecatalog_product_test.go b/aws/resource_aws_servicecatalog_product_test.go index ff7c8a237cd..1d584c497c6 100644 --- a/aws/resource_aws_servicecatalog_product_test.go +++ b/aws/resource_aws_servicecatalog_product_test.go @@ -19,9 +19,11 @@ import ( // 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, + Name: "aws_servicecatalog_product", + Dependencies: []string{ + "aws_servicecatalog_provisioning_artifact", + }, + F: testSweepServiceCatalogProducts, }) } @@ -104,7 +106,7 @@ func TestAccAWSServiceCatalogProduct_basic(t *testing.T) { 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, "status", waiter.StatusCreated), resource.TestCheckResourceAttr(resourceName, "support_description", "supportbeskrivning"), resource.TestCheckResourceAttr(resourceName, "support_email", "support@example.com"), resource.TestCheckResourceAttr(resourceName, "support_url", "http://example.com"), From 69fb63f710ba65453dd6a703ed17310a64827451 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 11 May 2021 12:53:32 -0400 Subject: [PATCH 077/398] r/servicecatalog_provisioning_artifact: Add changelog --- .changelog/19316.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19316.txt diff --git a/.changelog/19316.txt b/.changelog/19316.txt new file mode 100644 index 00000000000..e29d6221bf7 --- /dev/null +++ b/.changelog/19316.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_servicecatalog_provisioning_artifact +``` From 1ae618b85fb62bb2afd74e2ffb037377948acb96 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 10:05:59 -0400 Subject: [PATCH 078/398] i/r/servicecat: Add provisioning artifact ID --- aws/internal/service/servicecatalog/id.go | 12 ++++++++++++ aws/internal/service/servicecatalog/waiter/waiter.go | 3 +-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/aws/internal/service/servicecatalog/id.go b/aws/internal/service/servicecatalog/id.go index 14bfac365e6..194b515dd48 100644 --- a/aws/internal/service/servicecatalog/id.go +++ b/aws/internal/service/servicecatalog/id.go @@ -60,3 +60,15 @@ func TagOptionResourceAssociationParseID(id string) (string, string, error) { func TagOptionResourceAssociationID(tagOptionID, resourceID string) string { return strings.Join([]string{tagOptionID, resourceID}, ":") } + +func ProvisioningArtifactID(artifactID, productID string) string { + return strings.Join([]string{artifactID, productID}, ":") +} + +func ProvisioningArtifactParseID(id string) (string, string, error) { + parts := strings.Split(id, ":") + if len(parts) != 2 { + return "", "", fmt.Errorf("Please make sure the ID is in the form artifact_id:product_id (i.e. pa-r2d2slrtcob:prod-c3pohcrhmisy") + } + return parts[0], parts[1], nil +} diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index d3339569ee2..8374a859dbd 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -42,10 +42,9 @@ const ( StatusUnavailable = "UNAVAILABLE" // AWS documentation is wrong, says that status will be "AVAILABLE" but it is actually "CREATED" - ProductStatusCreated = "CREATED" + StatusCreated = "CREATED" OrganizationAccessStatusError = "ERROR" - StatusCreated = "CREATED" ) func ProductReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID string) (*servicecatalog.DescribeProductAsAdminOutput, error) { From b88fe24c3f6436c8c3ece1ed693f27ba78a2cd89 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 10:06:41 -0400 Subject: [PATCH 079/398] r/servicecatalog_provisioning_artifact: Move ID funcs --- ...ws_servicecatalog_provisioning_artifact.go | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioning_artifact.go b/aws/resource_aws_servicecatalog_provisioning_artifact.go index 42ca5d8cce5..045a15e0958 100644 --- a/aws/resource_aws_servicecatalog_provisioning_artifact.go +++ b/aws/resource_aws_servicecatalog_provisioning_artifact.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "log" - "strings" "time" "github.com/aws/aws-sdk-go/aws" @@ -148,7 +147,7 @@ func resourceAwsServiceCatalogProvisioningArtifactCreate(d *schema.ResourceData, return fmt.Errorf("error creating Service Catalog Provisioning Artifact: empty response") } - d.SetId(serviceCatalogProvisioningArtifactID(aws.StringValue(output.ProvisioningArtifactDetail.Id), d.Get("product_id").(string))) + d.SetId(tfservicecatalog.ProvisioningArtifactID(aws.StringValue(output.ProvisioningArtifactDetail.Id), d.Get("product_id").(string))) // Active and Guidance are not fields of CreateProvisioningArtifact but are fields of UpdateProvisioningArtifact. // In order to set these to non-default values, you must create and then update. @@ -159,7 +158,7 @@ func resourceAwsServiceCatalogProvisioningArtifactCreate(d *schema.ResourceData, func resourceAwsServiceCatalogProvisioningArtifactRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).scconn - artifactID, productID, err := parseServiceCatalogProvisioningArtifactID(d.Id()) + artifactID, productID, err := tfservicecatalog.ProvisioningArtifactParseID(d.Id()) if err != nil { return fmt.Errorf("error parsing Service Catalog Provisioning Artifact ID (%s): %w", d.Id(), err) @@ -208,7 +207,7 @@ func resourceAwsServiceCatalogProvisioningArtifactUpdate(d *schema.ResourceData, conn := meta.(*AWSClient).scconn if d.HasChanges("accept_language", "active", "description", "guidance", "name", "product_id") { - artifactID, productID, err := parseServiceCatalogProvisioningArtifactID(d.Id()) + artifactID, productID, err := tfservicecatalog.ProvisioningArtifactParseID(d.Id()) if err != nil { return fmt.Errorf("error parsing Service Catalog Provisioning Artifact ID (%s): %w", d.Id(), err) @@ -268,7 +267,7 @@ func resourceAwsServiceCatalogProvisioningArtifactUpdate(d *schema.ResourceData, func resourceAwsServiceCatalogProvisioningArtifactDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).scconn - artifactID, productID, err := parseServiceCatalogProvisioningArtifactID(d.Id()) + artifactID, productID, err := tfservicecatalog.ProvisioningArtifactParseID(d.Id()) if err != nil { return fmt.Errorf("error parsing Service Catalog Provisioning Artifact ID (%s): %w", d.Id(), err) @@ -299,15 +298,3 @@ func resourceAwsServiceCatalogProvisioningArtifactDelete(d *schema.ResourceData, return nil } - -func serviceCatalogProvisioningArtifactID(artifactID, productID string) string { - return strings.Join([]string{artifactID, productID}, ":") -} - -func parseServiceCatalogProvisioningArtifactID(id string) (string, string, error) { - parts := strings.Split(id, ":") - if len(parts) != 2 { - return "", "", fmt.Errorf("Please make sure the ID is in the form artifact_id:product_id (i.e. pa-r2d2slrtcob:prod-c3pohcrhmisy") - } - return parts[0], parts[1], nil -} From 6f163349d98f8d95f847376fa4e19e57e4c4aa7b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 10:07:00 -0400 Subject: [PATCH 080/398] tests/r/servicecat_prov_art: Use ID funcs --- ...resource_aws_servicecatalog_provisioning_artifact_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go index 7feb9c6b2f1..d2e64509048 100644 --- a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go +++ b/aws/resource_aws_servicecatalog_provisioning_artifact_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" ) // add sweeper to delete known test servicecat provisioning artifacts @@ -250,7 +251,7 @@ func testAccCheckAwsServiceCatalogProvisioningArtifactDestroy(s *terraform.State continue } - artifactID, productID, err := parseServiceCatalogProvisioningArtifactID(rs.Primary.ID) + artifactID, productID, err := tfservicecatalog.ProvisioningArtifactParseID(rs.Primary.ID) if err != nil { return fmt.Errorf("error parsing Service Catalog Provisioning Artifact ID (%s): %w", rs.Primary.ID, err) @@ -289,7 +290,7 @@ func testAccCheckAwsServiceCatalogProvisioningArtifactExists(resourceName string conn := testAccProvider.Meta().(*AWSClient).scconn - artifactID, productID, err := parseServiceCatalogProvisioningArtifactID(rs.Primary.ID) + artifactID, productID, err := tfservicecatalog.ProvisioningArtifactParseID(rs.Primary.ID) if err != nil { return fmt.Errorf("error parsing Service Catalog Provisioning Artifact ID (%s): %w", rs.Primary.ID, err) From c023d00862e8ce97a10ff1b12f4935f2515cbf85 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 13:50:17 -0400 Subject: [PATCH 081/398] r/servicecat_prov_art: Minor fixes --- aws/resource_aws_servicecatalog_provisioning_artifact.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioning_artifact.go b/aws/resource_aws_servicecatalog_provisioning_artifact.go index 045a15e0958..b767586f25d 100644 --- a/aws/resource_aws_servicecatalog_provisioning_artifact.go +++ b/aws/resource_aws_servicecatalog_provisioning_artifact.go @@ -216,16 +216,13 @@ func resourceAwsServiceCatalogProvisioningArtifactUpdate(d *schema.ResourceData, input := &servicecatalog.UpdateProvisioningArtifactInput{ ProductId: aws.String(productID), ProvisioningArtifactId: aws.String(artifactID), + Active: aws.Bool(d.Get("active").(bool)), } if v, ok := d.GetOk("accept_language"); ok { input.AcceptLanguage = aws.String(v.(string)) } - if v, ok := d.GetOk("active"); ok { - input.Active = aws.Bool(v.(bool)) - } - if v, ok := d.GetOk("description"); ok { input.Description = aws.String(v.(string)) } From 309b021170335348a85ba5b6287c26f7c2424190 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 13:50:49 -0400 Subject: [PATCH 082/398] tests/r/servicecat_prov_art: Rework tests --- ...rvicecatalog_provisioning_artifact_test.go | 235 ++++++++++-------- 1 file changed, 135 insertions(+), 100 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go index d2e64509048..516e7986a19 100644 --- a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go +++ b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "log" - "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -117,14 +116,14 @@ func TestAccAWSServiceCatalogProvisioningArtifact_basic(t *testing.T) { CheckDestroy: testAccCheckAwsServiceCatalogProvisioningArtifactDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName, "beskrivning"), + Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogProvisioningArtifactExists(resourceName), resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), resource.TestCheckResourceAttr(resourceName, "active", "true"), - resource.TestCheckResourceAttr(resourceName, "description", "beskrivning"), + resource.TestCheckResourceAttr(resourceName, "description", rName), resource.TestCheckResourceAttr(resourceName, "disable_template_validation", "true"), - resource.TestCheckResourceAttr(resourceName, "guidance", "DEFAULT"), + resource.TestCheckResourceAttr(resourceName, "guidance", servicecatalog.ProvisioningArtifactGuidanceDefault), resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("%s-2", rName)), resource.TestCheckResourceAttrPair(resourceName, "product_id", "aws_servicecatalog_product.test", "id"), resource.TestCheckResourceAttrSet(resourceName, "template_url"), @@ -157,7 +156,7 @@ func TestAccAWSServiceCatalogProvisioningArtifact_disappears(t *testing.T) { CheckDestroy: testAccCheckAwsServiceCatalogProvisioningArtifactDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName, rName), + Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogProvisioningArtifactExists(resourceName), testAccCheckResourceDisappears(testAccProvider, resourceAwsServiceCatalogProvisioningArtifact(), resourceName), @@ -168,6 +167,28 @@ func TestAccAWSServiceCatalogProvisioningArtifact_disappears(t *testing.T) { }) } +/* + if v, ok := d.GetOk("accept_language"); ok { + input.AcceptLanguage = aws.String(v.(string)) + } + + if v, ok := d.GetOk("active"); ok { + input.Active = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("guidance"); ok { + input.Guidance = aws.String(v.(string)) + } + + if v, ok := d.GetOk("name"); ok { + input.Name = aws.String(v.(string)) + } +*/ + func TestAccAWSServiceCatalogProvisioningArtifact_update(t *testing.T) { resourceName := "aws_servicecatalog_provisioning_artifact.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -179,23 +200,24 @@ func TestAccAWSServiceCatalogProvisioningArtifact_update(t *testing.T) { CheckDestroy: testAccCheckAwsServiceCatalogProvisioningArtifactDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName, "beskrivning"), + Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogProvisioningArtifactExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "description", "beskrivning"), - resource.TestCheckResourceAttr(resourceName, "support_description", "supportbeskrivning"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "active", "true"), + resource.TestCheckResourceAttr(resourceName, "description", rName), + resource.TestCheckResourceAttr(resourceName, "guidance", servicecatalog.ProvisioningArtifactGuidanceDefault), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("%s-2", rName)), ), }, { - Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName, "ny beskrivning"), + Config: testAccAWSServiceCatalogProvisioningArtifactConfig_update(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsServiceCatalogProvisioningArtifactExists(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), + resource.TestCheckResourceAttr(resourceName, "accept_language", "jp"), + resource.TestCheckResourceAttr(resourceName, "active", "false"), + resource.TestCheckResourceAttr(resourceName, "description", fmt.Sprintf("%s-3", rName)), + resource.TestCheckResourceAttr(resourceName, "guidance", servicecatalog.ProvisioningArtifactGuidanceDeprecated), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("%s-3", rName)), ), }, }, @@ -216,29 +238,18 @@ func TestAccAWSServiceCatalogProvisioningArtifact_physicalID(t *testing.T) { Config: testAccAWSServiceCatalogProvisioningArtifactConfig_physicalID(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogProvisioningArtifactExists(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), + resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "active", "true"), + resource.TestCheckResourceAttr(resourceName, "description", rName), + resource.TestCheckResourceAttr(resourceName, "disable_template_validation", "false"), + resource.TestCheckResourceAttr(resourceName, "guidance", servicecatalog.ProvisioningArtifactGuidanceDefault), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("%s-2", rName)), + resource.TestCheckResourceAttrPair(resourceName, "product_id", "aws_servicecatalog_product.test", "id"), + resource.TestCheckResourceAttrSet(resourceName, "template_physical_id"), + resource.TestCheckResourceAttr(resourceName, "type", servicecatalog.ProductTypeCloudFormationTemplate), + testAccCheckResourceAttrRfc3339(resourceName, "created_time"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "accept_language", - "provisioning_artifact_parameters", - }, - }, }, }) } @@ -323,51 +334,44 @@ resource "aws_s3_bucket_object" "test" { bucket = aws_s3_bucket.test.id key = "%[1]s.json" - content = < Date: Wed, 19 May 2021 13:54:46 -0400 Subject: [PATCH 083/398] tests/r/servicecat_prov_art: Lint --- aws/resource_aws_servicecatalog_provisioning_artifact_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go index 516e7986a19..0a7c8caf1bf 100644 --- a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go +++ b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go @@ -349,8 +349,8 @@ resource "aws_s3_bucket_object" "test" { Outputs = { VpcID = { Description = "VPC ID" - Value = { - Ref = "MyVPC" + Value = { + Ref = "MyVPC" } } } From e31e403a36ef3a48a087272b789e4cada57e9d1a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 14:13:17 -0400 Subject: [PATCH 084/398] tests/r/servicecat_constraint: Clean up test config --- ...urce_aws_servicecatalog_constraint_test.go | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/aws/resource_aws_servicecatalog_constraint_test.go b/aws/resource_aws_servicecatalog_constraint_test.go index 84237028eaa..7d4d4179999 100644 --- a/aws/resource_aws_servicecatalog_constraint_test.go +++ b/aws/resource_aws_servicecatalog_constraint_test.go @@ -240,31 +240,27 @@ resource "aws_s3_bucket_object" "test" { bucket = aws_s3_bucket.test.id key = "%[1]s.json" - content = < Date: Wed, 19 May 2021 14:13:48 -0400 Subject: [PATCH 085/398] tests/r/servicecat_prod_port_assoc: Clean up test config --- ...alog_product_portfolio_association_test.go | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/aws/resource_aws_servicecatalog_product_portfolio_association_test.go b/aws/resource_aws_servicecatalog_product_portfolio_association_test.go index 48dd6bda47b..f81472914ae 100644 --- a/aws/resource_aws_servicecatalog_product_portfolio_association_test.go +++ b/aws/resource_aws_servicecatalog_product_portfolio_association_test.go @@ -227,31 +227,27 @@ func testAccAWSServiceCatalogProductPortfolioAssociationConfig_base(rName string resource "aws_cloudformation_stack" "test" { name = %[1]q - template_body = < Date: Wed, 19 May 2021 14:14:17 -0400 Subject: [PATCH 086/398] tests/r/servicecat_product: Clean up test config --- ...esource_aws_servicecatalog_product_test.go | 84 +++++++++---------- 1 file changed, 38 insertions(+), 46 deletions(-) diff --git a/aws/resource_aws_servicecatalog_product_test.go b/aws/resource_aws_servicecatalog_product_test.go index 1d584c497c6..bd7d153e6b1 100644 --- a/aws/resource_aws_servicecatalog_product_test.go +++ b/aws/resource_aws_servicecatalog_product_test.go @@ -322,31 +322,27 @@ resource "aws_s3_bucket_object" "test" { bucket = aws_s3_bucket.test.id key = "%[1]s.json" - content = < Date: Wed, 19 May 2021 14:14:46 -0400 Subject: [PATCH 087/398] tests/r/servicecat_prov_art: Clean up test config --- ...rvicecatalog_provisioning_artifact_test.go | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go index 0a7c8caf1bf..778b64584fc 100644 --- a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go +++ b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go @@ -167,28 +167,6 @@ func TestAccAWSServiceCatalogProvisioningArtifact_disappears(t *testing.T) { }) } -/* - if v, ok := d.GetOk("accept_language"); ok { - input.AcceptLanguage = aws.String(v.(string)) - } - - if v, ok := d.GetOk("active"); ok { - input.Active = aws.Bool(v.(bool)) - } - - if v, ok := d.GetOk("description"); ok { - input.Description = aws.String(v.(string)) - } - - if v, ok := d.GetOk("guidance"); ok { - input.Guidance = aws.String(v.(string)) - } - - if v, ok := d.GetOk("name"); ok { - input.Name = aws.String(v.(string)) - } -*/ - func TestAccAWSServiceCatalogProvisioningArtifact_update(t *testing.T) { resourceName := "aws_servicecatalog_provisioning_artifact.test" rName := acctest.RandomWithPrefix("tf-acc-test") From 936964eb58c6b2b3ef6ac49cf0a21d61884b7c37 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 19 May 2021 14:15:10 -0400 Subject: [PATCH 088/398] docs/r/servicecat_prov_art: Clean up example config --- .../docs/r/servicecatalog_provisioning_artifact.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/servicecatalog_provisioning_artifact.html.markdown b/website/docs/r/servicecatalog_provisioning_artifact.html.markdown index 35f168dd665..84e871b185e 100644 --- a/website/docs/r/servicecatalog_provisioning_artifact.html.markdown +++ b/website/docs/r/servicecatalog_provisioning_artifact.html.markdown @@ -25,7 +25,7 @@ resource "aws_servicecatalog_provisioning_artifact" "example" { name = "example" product_id = aws_servicecatalog_product.example.id type = "CLOUD_FORMATION_TEMPLATE" - template_url = "https://s3.amazonaws.com/cf-templates-ozkq9d3hgiq2-us-east-1/temp1.json" + template_url = "https://${aws_s3_bucket.example.bucket_regional_domain_name}/${aws_s3_bucket_object.example.key}" } ``` From 2f1ac32a3ca819ee6988565d80d599b505b4d848 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:29:36 -0400 Subject: [PATCH 089/398] i/r/servicecat_prov_art: Clean up ID --- aws/internal/service/servicecatalog/id.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/aws/internal/service/servicecatalog/id.go b/aws/internal/service/servicecatalog/id.go index 194b515dd48..03a7f4ef7fe 100644 --- a/aws/internal/service/servicecatalog/id.go +++ b/aws/internal/service/servicecatalog/id.go @@ -66,9 +66,10 @@ func ProvisioningArtifactID(artifactID, productID string) string { } func ProvisioningArtifactParseID(id string) (string, string, error) { - parts := strings.Split(id, ":") - if len(parts) != 2 { - return "", "", fmt.Errorf("Please make sure the ID is in the form artifact_id:product_id (i.e. pa-r2d2slrtcob:prod-c3pohcrhmisy") + parts := strings.SplitN(id, ":", 2) + + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("unexpected format of ID (%s), expected artifactID:productID", id) } return parts[0], parts[1], nil } From 7d19a8589d0c6d07d73474b09664b5b81925d4b1 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 10:13:22 -0400 Subject: [PATCH 090/398] i/r/servicecat_prov_art: Dial down error messages --- aws/internal/service/servicecatalog/waiter/status.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/internal/service/servicecatalog/waiter/status.go b/aws/internal/service/servicecatalog/waiter/status.go index 91f11d79c33..371aa8c8aa5 100644 --- a/aws/internal/service/servicecatalog/waiter/status.go +++ b/aws/internal/service/servicecatalog/waiter/status.go @@ -289,11 +289,11 @@ func ProvisioningArtifactStatus(conn *servicecatalog.ServiceCatalog, id, product } if err != nil { - return nil, servicecatalog.StatusFailed, fmt.Errorf("error describing Service Catalog Provisioning Artifact (%s): %w", id, err) + return nil, servicecatalog.StatusFailed, err } if output == nil || output.ProvisioningArtifactDetail == nil { - return nil, StatusUnavailable, fmt.Errorf("error describing Service Catalog Provisioning Artifact (%s): empty response", id) + return nil, StatusUnavailable, err } return output, aws.StringValue(output.Status), err From 91dabf7905356ea71e98707b74d0b365b985788b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 10:41:04 -0400 Subject: [PATCH 091/398] docs/r/servicecatalog_prov_art: Fix ID docs --- .../r/servicecatalog_provisioning_artifact.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/servicecatalog_provisioning_artifact.html.markdown b/website/docs/r/servicecatalog_provisioning_artifact.html.markdown index 84e871b185e..9e508da64e6 100644 --- a/website/docs/r/servicecatalog_provisioning_artifact.html.markdown +++ b/website/docs/r/servicecatalog_provisioning_artifact.html.markdown @@ -52,13 +52,13 @@ The following arguments are optional: In addition to all arguments above, the following attributes are exported: * `created_time` - Time when the provisioning artifact was created. -* `id` - Provisioning Artifact identifier. +* `id` - Provisioning Artifact identifier and product identifier separated by a colon. * `status` - Status of the provisioning artifact. ## Import -`aws_servicecatalog_provisioning_artifact` can be imported using the provisioning artifact ID, e.g. +`aws_servicecatalog_provisioning_artifact` can be imported using the provisioning artifact ID and product ID separated by a colon, e.g. ``` -$ terraform import aws_servicecatalog_provisioning_artifact.example pa-ij2b6lusy6dec +$ terraform import aws_servicecatalog_provisioning_artifact.example pa-ij2b6lusy6dec:prod-el3an0rma3 ``` From 9d153a04c6f7d5c0644a0af1bab1e4199eef0c44 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 10:41:44 -0400 Subject: [PATCH 092/398] tests/r/servicecat_prov_art: Verify import --- ...rvicecatalog_provisioning_artifact_test.go | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go index 778b64584fc..008ef7b58d3 100644 --- a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go +++ b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go @@ -198,6 +198,16 @@ func TestAccAWSServiceCatalogProvisioningArtifact_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("%s-3", rName)), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "accept_language", + "disable_template_validation", + "template_url", + }, + }, }, }) } @@ -228,6 +238,16 @@ func TestAccAWSServiceCatalogProvisioningArtifact_physicalID(t *testing.T) { testAccCheckResourceAttrRfc3339(resourceName, "created_time"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "accept_language", + "disable_template_validation", + "template_physical_id", + }, + }, }, }) } From 1edf6e45802bf04a552a951e9b2af90a3386ce20 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 20 May 2021 20:31:40 +0000 Subject: [PATCH 093/398] Update CHANGELOG.md for #19316 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1e6a0d77fc..45ab3142f9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ FEATURES: * **New Resource:** `aws_servicecatalog_budget_resource_association` ([#19452](https://github.com/hashicorp/terraform-provider-aws/issues/19452)) +* **New Resource:** `aws_servicecatalog_provisioning_artifact` ([#19316](https://github.com/hashicorp/terraform-provider-aws/issues/19316)) * **New Resource:** `aws_servicecatalog_tag_option_resource_association` ([#19448](https://github.com/hashicorp/terraform-provider-aws/issues/19448)) BUG FIXES: From b418fe78648866eeb8c2846e112596a58d4e989a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 20 May 2021 15:45:34 -0400 Subject: [PATCH 094/398] r/aws_amplify_app: Get branch auto-creation working. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplifyApp_AutoBranchCreationConfig' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplifyApp_AutoBranchCreationConfig -timeout 180m === RUN TestAccAWSAmplifyApp_AutoBranchCreationConfig === PAUSE TestAccAWSAmplifyApp_AutoBranchCreationConfig === CONT TestAccAWSAmplifyApp_AutoBranchCreationConfig --- PASS: TestAccAWSAmplifyApp_AutoBranchCreationConfig (35.19s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 38.286s --- aws/internal/service/amplify/consts.go | 5 + aws/resource_aws_amplify_app.go | 116 +++----- aws/resource_aws_amplify_app_test.go | 369 +++++++++++++++---------- 3 files changed, 271 insertions(+), 219 deletions(-) create mode 100644 aws/internal/service/amplify/consts.go diff --git a/aws/internal/service/amplify/consts.go b/aws/internal/service/amplify/consts.go new file mode 100644 index 00000000000..3049f2bcfc2 --- /dev/null +++ b/aws/internal/service/amplify/consts.go @@ -0,0 +1,5 @@ +package amplify + +const ( + StageNone = "NONE" +) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index 43c1de024b5..1b5d72698c3 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.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" + 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" ) @@ -55,6 +56,7 @@ func resourceAwsAmplifyApp() *schema.Resource { "auto_branch_creation_config": { Type: schema.TypeList, Optional: true, + Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -63,11 +65,20 @@ func resourceAwsAmplifyApp() *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("auto_branch_creation_config.0.enable_basic_auth").(bool) { + return old == new + } + + return true + }, }, "build_spec": { Type: schema.TypeString, Optional: true, + Computed: true, ValidateFunc: validation.StringLenBetween(1, 25000), }, @@ -110,17 +121,17 @@ func resourceAwsAmplifyApp() *schema.Resource { }, "stage": { - Type: schema.TypeString, - Optional: true, - //TODO - // DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - // // stage is "NONE" by default - // if old == "NONE" && new == "" { - // return true - // } - // return old == new - // }, + 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 + }, }, }, }, @@ -130,6 +141,14 @@ func resourceAwsAmplifyApp() *schema.Resource { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // These patterns are ignored if branch auto-creation is not enabled. + if d.Get("enable_auto_branch_creation").(bool) { + return old == new + } + + return true + }, }, "basic_auth_credentials": { @@ -148,10 +167,8 @@ func resourceAwsAmplifyApp() *schema.Resource { }, "build_spec": { - Type: schema.TypeString, - Optional: true, - //TODO - //Computed: true, + Type: schema.TypeString, + Optional: true, ValidateFunc: validation.StringLenBetween(1, 25000), }, @@ -383,61 +400,6 @@ func resourceAwsAmplifyAppCreate(d *schema.ResourceData, meta interface{}) error input.Repository = aws.String(v.(string)) } - /* - if v, ok := d.GetOk("auto_branch_creation_config"); ok { - config, patterns, enable := expandAmplifyAutoBranchCreationConfig(v.([]interface{})) - params.AutoBranchCreationConfig = config - params.AutoBranchCreationPatterns = patterns - params.EnableAutoBranchCreation = enable - } - - 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("custom_rules"); ok { - params.CustomRules = expandAmplifyCustomRules(v.([]interface{})) - } - - if v, ok := d.GetOk("description"); ok { - params.Description = aws.String(v.(string)) - } - - if v, ok := d.GetOk("enable_branch_auto_build"); ok { - params.EnableBranchAutoBuild = aws.Bool(v.(bool)) - } - - if v, ok := d.GetOk("environment_variables"); ok { - params.EnvironmentVariables = stringMapToPointers(v.(map[string]interface{})) - } - - if v, ok := d.GetOk("iam_service_role_arn"); ok { - params.IamServiceRoleArn = aws.String(v.(string)) - } - - if v, ok := d.GetOk("platform"); ok { - params.Platform = aws.String(v.(string)) - } - - if v, ok := d.GetOk("repository"); ok { - params.Repository = aws.String(v.(string)) - } - - if v, ok := d.GetOk("access_token"); ok { - params.AccessToken = aws.String(v.(string)) - } - - if v, ok := d.GetOk("oauth_token"); ok { - params.OauthToken = aws.String(v.(string)) - } - */ - if len(tags) > 0 { input.Tags = tags.IgnoreAws().AmplifyTags() } @@ -532,6 +494,12 @@ func resourceAwsAmplifyAppUpdate(d *schema.ResourceData, meta interface{}) error if d.HasChange("auto_branch_creation_config") { input.AutoBranchCreationConfig = expandAmplifyAutoBranchCreationConfig(d.Get("auto_branch_creation_config").([]interface{})[0].(map[string]interface{})) + + if d.HasChange("auto_branch_creation_config.0.environment_variables") { + if v := d.Get("auto_branch_creation_config.0.environment_variables").(map[string]interface{}); len(v) == 0 { + input.AutoBranchCreationConfig.EnvironmentVariables = aws.StringMap(map[string]string{"": ""}) + } + } } if d.HasChange("auto_branch_creation_patterns") { @@ -657,19 +625,19 @@ func expandAmplifyAutoBranchCreationConfig(tfMap map[string]interface{}) *amplif apiObject.BuildSpec = aws.String(v) } - if v, ok := tfMap["enable_auto_build"].(bool); ok && v { + if v, ok := tfMap["enable_auto_build"].(bool); ok { apiObject.EnableAutoBuild = aws.Bool(v) } - if v, ok := tfMap["enable_basic_auth"].(bool); ok && v { + if v, ok := tfMap["enable_basic_auth"].(bool); ok { apiObject.EnableBasicAuth = aws.Bool(v) } - if v, ok := tfMap["enable_performance_mode"].(bool); ok && v { + if v, ok := tfMap["enable_performance_mode"].(bool); ok { apiObject.EnablePerformanceMode = aws.Bool(v) } - if v, ok := tfMap["enable_pull_request_preview"].(bool); ok && v { + if v, ok := tfMap["enable_pull_request_preview"].(bool); ok { apiObject.EnablePullRequestPreview = aws.Bool(v) } @@ -685,7 +653,7 @@ func expandAmplifyAutoBranchCreationConfig(tfMap map[string]interface{}) *amplif apiObject.PullRequestEnvironmentName = aws.String(v) } - if v, ok := tfMap["stage"].(string); ok && v != "" { + if v, ok := tfMap["stage"].(string); ok && v != "" && v != tfamplify.StageNone { apiObject.Stage = aws.String(v) } diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index cb3d82c7ce6..51c64428b9d 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -184,6 +184,101 @@ func TestAccAWSAmplifyApp_Tags(t *testing.T) { }) } +func TestAccAWSAmplifyApp_AutoBranchCreationConfig(t *testing.T) { + var app amplify.App + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_app.test" + + credentials := base64.StdEncoding.EncodeToString([]byte("username1:password1")) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyAppConfigAutoBranchCreationConfigNoAutoBranchCreationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_credentials", ""), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.build_spec", ""), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_build", "false"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_basic_auth", "false"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_performance_mode", "false"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_pull_request_preview", "false"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.%", "0"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.framework", ""), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.pull_request_environment_name", ""), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.stage", "NONE"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_patterns.#", "2"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_patterns.0", "*"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_patterns.1", "*/**"), + resource.TestCheckResourceAttr(resourceName, "enable_auto_branch_creation", "true"), + ), + }, + { + Config: testAccAWSAmplifyAppConfigAutoBranchCreationConfigAutoBranchCreationConfig(rName, credentials), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_credentials", credentials), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.build_spec", "version: 0.1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_build", "true"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_basic_auth", "true"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_performance_mode", "false"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_pull_request_preview", "true"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.%", "1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.ENVVAR1", "1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.framework", "React"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.pull_request_environment_name", "test1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.stage", "DEVELOPMENT"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_patterns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_patterns.0", "feature/*"), + resource.TestCheckResourceAttr(resourceName, "enable_auto_branch_creation", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyAppConfigAutoBranchCreationConfigAutoBranchCreationConfigUpdated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.#", "1"), + // Clearing basic_auth_credentials not reflected in API. + // resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_credentials", ""), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.build_spec", "version: 0.2"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_build", "false"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_basic_auth", "false"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_performance_mode", "false"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_pull_request_preview", "false"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.%", "0"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.framework", "React"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.pull_request_environment_name", "test2"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.stage", "EXPERIMENTAL"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_patterns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_patterns.0", "feature/*"), + resource.TestCheckResourceAttr(resourceName, "enable_auto_branch_creation", "true"), + ), + }, + { + Config: testAccAWSAmplifyAppConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + // No change is reflected in API. + // resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.#", "0"), + // resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_patterns.#", "0"), + resource.TestCheckResourceAttr(resourceName, "enable_auto_branch_creation", "false"), + ), + }, + }, + }) +} + func TestAccAWSAmplifyApp_BasicAuthCredentials(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") @@ -275,11 +370,15 @@ func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { }) } -func TestAccAWSAmplifyApp_CustomRules(t *testing.T) { +/* +func TestAccAWSAmplifyApp_CustomHeaders(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" + customHeaders1 := `{"customHeaders":[{"pattern":"*.json","headers":[{"key":"custom-header-name-1","value":"custom-header-value-1"}]}]}` + customHeaders2 := `{"customHeaders":[{"pattern":"*.json","headers":[{"key":"custom-header-name-2","value":"custom-header-value-2"}]},{"pattern":"/path/*","headers":[{"key":"custom-header-name-1","value":"custom-header-value-1"}]}]}` + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), @@ -287,13 +386,10 @@ func TestAccAWSAmplifyApp_CustomRules(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigCustomRules(rName), + Config: testAccAWSAmplifyAppConfigCustomHeaders(rName, customHeaders1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "custom_rule.#", "1"), - resource.TestCheckResourceAttr(resourceName, "custom_rule.0.source", "/<*>"), - resource.TestCheckResourceAttr(resourceName, "custom_rule.0.status", "404"), - resource.TestCheckResourceAttr(resourceName, "custom_rule.0.target", "/index.html"), + resource.TestCheckResourceAttr(resourceName, "custom_headers", customHeaders1), ), }, { @@ -302,30 +398,25 @@ func TestAccAWSAmplifyApp_CustomRules(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigCustomRulesUpdated(rName), + Config: testAccAWSAmplifyAppConfigCustomHeaders(rName, ""), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "custom_rule.#", "2"), - resource.TestCheckResourceAttr(resourceName, "custom_rule.0.condition", ""), - resource.TestCheckResourceAttr(resourceName, "custom_rule.0.source", "/documents"), - resource.TestCheckResourceAttr(resourceName, "custom_rule.0.status", "302"), - resource.TestCheckResourceAttr(resourceName, "custom_rule.0.target", "/documents/us"), - resource.TestCheckResourceAttr(resourceName, "custom_rule.1.source", "/<*>"), - resource.TestCheckResourceAttr(resourceName, "custom_rule.1.status", "200"), - resource.TestCheckResourceAttr(resourceName, "custom_rule.1.target", "/index.html"), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "custom_headers", customHeaders2), ), }, { Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "custom_rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "custom_headers", ""), ), }, }, }) } +*/ -func TestAccAWSAmplifyApp_EnvironmentVariables(t *testing.T) { +func TestAccAWSAmplifyApp_CustomRules(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -337,11 +428,13 @@ func TestAccAWSAmplifyApp_EnvironmentVariables(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigEnvironmentVariables(rName), + Config: testAccAWSAmplifyAppConfigCustomRules(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "1"), - resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "1"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.source", "/<*>"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.status", "404"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.target", "/index.html"), ), }, { @@ -350,29 +443,32 @@ func TestAccAWSAmplifyApp_EnvironmentVariables(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigEnvironmentVariablesUpdated(rName), + Config: testAccAWSAmplifyAppConfigCustomRulesUpdated(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "2"), - resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "2"), - resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR2", "2"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.#", "2"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.condition", ""), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.source", "/documents"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.status", "302"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.0.target", "/documents/us"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.1.source", "/<*>"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.1.status", "200"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.1.target", "/index.html"), ), }, { Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), + resource.TestCheckResourceAttr(resourceName, "custom_rule.#", "0"), ), }, }, }) } -func TestAccAWSAmplifyApp_Name(t *testing.T) { - var app amplify.App - rName1 := acctest.RandomWithPrefix("tf-acc-test") - rName2 := acctest.RandomWithPrefix("tf-acc-test") +func TestAccAWSAmplifyApp_Description(t *testing.T) { + var app1, app2, app3 amplify.App + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ @@ -382,10 +478,10 @@ func TestAccAWSAmplifyApp_Name(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigName(rName1), + Config: testAccAWSAmplifyAppConfigDescription(rName, "description 1"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "name", rName1), + testAccCheckAWSAmplifyAppExists(resourceName, &app1), + resource.TestCheckResourceAttr(resourceName, "description", "description 1"), ), }, { @@ -394,17 +490,27 @@ func TestAccAWSAmplifyApp_Name(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigName(rName2), + Config: testAccAWSAmplifyAppConfigDescription(rName, "description 2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "name", rName2), + testAccCheckAWSAmplifyAppExists(resourceName, &app2), + testAccCheckAWSAmplifyAppNotRecreated(&app1, &app2), + resource.TestCheckResourceAttr(resourceName, "description", "description 2"), + ), + }, + { + Config: testAccAWSAmplifyAppConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app3), + testAccCheckAWSAmplifyAppRecreated(&app2, &app3), + resource.TestCheckResourceAttr(resourceName, "description", ""), ), }, }, }) } -func TestAccAWSAmplifyApp_repository(t *testing.T) { +func TestAccAWSAmplifyApp_EnvironmentVariables(t *testing.T) { + var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -415,25 +521,42 @@ func TestAccAWSAmplifyApp_repository(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigRepository(rName), + Config: testAccAWSAmplifyAppConfigEnvironmentVariables(rName), Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr(resourceName, "repository", regexp.MustCompile("^https://github.com")), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "1"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "1"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - // access_token is ignored because AWS does not store access_token and oauth_token - // See https://docs.aws.amazon.com/sdk-for-go/api/service/amplify/#CreateAppInput - ImportStateVerifyIgnore: []string{"access_token"}, + }, + { + Config: testAccAWSAmplifyAppConfigEnvironmentVariablesUpdated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "2"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "2"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR2", "2"), + ), + }, + { + Config: testAccAWSAmplifyAppConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), + ), }, }, }) } -func TestAccAWSAmplifyApp_autoBranchCreationConfig(t *testing.T) { - rName := acctest.RandomWithPrefix("tf-acc-test") +func TestAccAWSAmplifyApp_Name(t *testing.T) { + var app amplify.App + rName1 := acctest.RandomWithPrefix("tf-acc-test") + rName2 := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ @@ -443,20 +566,10 @@ func TestAccAWSAmplifyApp_autoBranchCreationConfig(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigAutoBranchCreationConfig(rName), + Config: testAccAWSAmplifyAppConfigName(rName1), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_branch_creation", "true"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.auto_branch_creation_patterns.#", "2"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.auto_branch_creation_patterns.0", "*"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.auto_branch_creation_patterns.1", "*/**"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.build_spec", ""), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.framework", ""), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.stage", "NONE"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.#", "0"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_build", "false"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_pull_request_preview", "false"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.pull_request_environment_name", ""), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.%", "0"), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "name", rName1), ), }, { @@ -465,44 +578,17 @@ func TestAccAWSAmplifyApp_autoBranchCreationConfig(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigAutoBranchCreationConfigModified(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_branch_creation", "true"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.auto_branch_creation_patterns.#", "1"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.auto_branch_creation_patterns.0", "feature/*"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.build_spec", "version: 0.1"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.framework", "React"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.stage", "DEVELOPMENT"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.0.enable_basic_auth", "true"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.0.username", "username"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.0.password", "password"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_build", "true"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_pull_request_preview", "true"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.pull_request_environment_name", "env"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.%", "1"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.ENVVAR1", "1"), - ), - }, - { - Config: testAccAWSAmplifyAppConfigAutoBranchCreationConfigModified2(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.enable_auto_branch_creation", "true"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.basic_auth_config.#", "0"), - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.0.environment_variables.%", "0"), - ), - }, - { - Config: testAccAWSAmplifyAppConfigName(rName), + Config: testAccAWSAmplifyAppConfigName(rName2), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_config.#", "0"), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "name", rName2), ), }, }, }) } -func TestAccAWSAmplifyApp_enableBranchAutoBuild(t *testing.T) { +func TestAccAWSAmplifyApp_repository(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -513,21 +599,18 @@ func TestAccAWSAmplifyApp_enableBranchAutoBuild(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigEnableBranchAutoBuild(rName), + Config: testAccAWSAmplifyAppConfigRepository(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "enable_branch_auto_build", "true"), + resource.TestMatchResourceAttr(resourceName, "repository", regexp.MustCompile("^https://github.com")), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyAppConfigName(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "enable_branch_auto_build", "false"), - ), + // access_token is ignored because AWS does not store access_token and oauth_token + // See https://docs.aws.amazon.com/sdk-for-go/api/service/amplify/#CreateAppInput + ImportStateVerifyIgnore: []string{"access_token"}, }, }, }) @@ -684,6 +767,16 @@ resource "aws_amplify_app" "test" { `, rName, buildSpec) } +func testAccAWSAmplifyAppConfigCustomHeaders(rName, customHeaders string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q + + custom_headers = %[2]q +} +`, rName, customHeaders) +} + func testAccAWSAmplifyAppConfigCustomRules(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { @@ -744,49 +837,43 @@ resource "aws_amplify_app" "test" { `, rName) } -func testAccAWSAmplifyAppConfigAutoBranchCreationConfig(rName string) string { +func testAccAWSAmplifyAppConfigAutoBranchCreationConfigNoAutoBranchCreationConfig(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q - auto_branch_creation_config { - enable_auto_branch_creation = true + enable_auto_branch_creation = true - auto_branch_creation_patterns = [ - "*", - "*/**", - ] - } + auto_branch_creation_patterns = [ + "*", + "*/**", + ] } `, rName) } -func testAccAWSAmplifyAppConfigAutoBranchCreationConfigModified(rName string) string { +func testAccAWSAmplifyAppConfigAutoBranchCreationConfigAutoBranchCreationConfig(rName, basicAuthCredentials string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" - - auto_branch_creation_config { - enable_auto_branch_creation = true + name = %[1]q - auto_branch_creation_patterns = [ - "feature/*", - ] + enable_auto_branch_creation = true + + auto_branch_creation_patterns = [ + "feature/*", + ] + auto_branch_creation_config { build_spec = "version: 0.1" framework = "React" stage = "DEVELOPMENT" - basic_auth_config { - enable_basic_auth = true - username = "username" - password = "password" - } - - enable_auto_build = true + enable_basic_auth = true + basic_auth_credentials = %[2]q + enable_auto_build = true enable_pull_request_preview = true - pull_request_environment_name = "env" + pull_request_environment_name = "test1" environment_variables = { ENVVAR1 = "1" @@ -794,29 +881,31 @@ resource "aws_amplify_app" "test" { } } -`, rName) +`, rName, basicAuthCredentials) } -func testAccAWSAmplifyAppConfigAutoBranchCreationConfigModified2(rName string) string { +func testAccAWSAmplifyAppConfigAutoBranchCreationConfigAutoBranchCreationConfigUpdated(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" - - auto_branch_creation_config { - enable_auto_branch_creation = true + name = %[1]q - auto_branch_creation_patterns = [ - "feature/*", - ] + enable_auto_branch_creation = true + + auto_branch_creation_patterns = [ + "feature/*", + ] - build_spec = "version: 0.1" + auto_branch_creation_config { + build_spec = "version: 0.2" framework = "React" - stage = "DEVELOPMENT" + stage = "EXPERIMENTAL" - enable_auto_build = false + enable_basic_auth = false - enable_pull_request_preview = false - pull_request_environment_name = "env" + enable_auto_build = false + enable_pull_request_preview = false + + pull_request_environment_name = "test2" } } `, rName) @@ -833,16 +922,6 @@ resource "aws_amplify_app" "test" { `, rName, basicAuthCredentials) } -func testAccAWSAmplifyAppConfigEnableBranchAutoBuild(rName string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = "%s" - - enable_branch_auto_build = true -} -`, rName) -} - func testAccAWSAmplifyAppConfigIAMServiceRoleArn(rName string, roleName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { From 76e401e3f882bdf0341b74effdd2aecff608fb05 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 20 May 2021 16:56:54 -0400 Subject: [PATCH 095/398] r/aws_amplify_app: ForceNew if 'iam_service_role_arn' changes to "". Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplifyApp_IamServiceRole' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplifyApp_IamServiceRole -timeout 180m === RUN TestAccAWSAmplifyApp_IamServiceRole === PAUSE TestAccAWSAmplifyApp_IamServiceRole === CONT TestAccAWSAmplifyApp_IamServiceRole --- PASS: TestAccAWSAmplifyApp_IamServiceRole (32.33s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 35.813s --- aws/resource_aws_amplify_app.go | 6 +- aws/resource_aws_amplify_app_test.go | 132 +++++++++++++++++---------- 2 files changed, 90 insertions(+), 48 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index 1b5d72698c3..65c19bf06b1 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -38,6 +38,10 @@ func resourceAwsAmplifyApp() *schema.Resource { // Any existing value cannot be cleared. return new.(string) == "" }), + customdiff.ForceNewIfChange("iam_service_role_arn", func(_ context.Context, old, new, meta interface{}) bool { + // Any existing value cannot be cleared. + return new.(string) == "" + }), ), Schema: map[string]*schema.Schema{ @@ -78,7 +82,6 @@ func resourceAwsAmplifyApp() *schema.Resource { "build_spec": { Type: schema.TypeString, Optional: true, - Computed: true, ValidateFunc: validation.StringLenBetween(1, 25000), }, @@ -169,6 +172,7 @@ func resourceAwsAmplifyApp() *schema.Resource { "build_spec": { Type: schema.TypeString, Optional: true, + Computed: true, ValidateFunc: validation.StringLenBetween(1, 25000), }, diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 51c64428b9d..7db18775b5b 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -553,11 +553,12 @@ func TestAccAWSAmplifyApp_EnvironmentVariables(t *testing.T) { }) } -func TestAccAWSAmplifyApp_Name(t *testing.T) { - var app amplify.App - rName1 := acctest.RandomWithPrefix("tf-acc-test") - rName2 := acctest.RandomWithPrefix("tf-acc-test") +func TestAccAWSAmplifyApp_IamServiceRole(t *testing.T) { + var app1, app2, app3 amplify.App + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" + iamRole1ResourceName := "aws_iam_role.test1" + iamRole2ResourceName := "aws_iam_role.test2" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, @@ -566,11 +567,10 @@ func TestAccAWSAmplifyApp_Name(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigName(rName1), + Config: testAccAWSAmplifyAppConfigIAMServiceRoleArn(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "name", rName1), - ), + testAccCheckAWSAmplifyAppExists(resourceName, &app1), + resource.TestCheckResourceAttrPair(resourceName, "iam_service_role_arn", iamRole1ResourceName, "arn")), }, { ResourceName: resourceName, @@ -578,18 +578,29 @@ func TestAccAWSAmplifyApp_Name(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyAppConfigName(rName2), + Config: testAccAWSAmplifyAppConfigIAMServiceRoleArnUpdated(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "name", rName2), + testAccCheckAWSAmplifyAppExists(resourceName, &app2), + testAccCheckAWSAmplifyAppNotRecreated(&app1, &app2), + resource.TestCheckResourceAttrPair(resourceName, "iam_service_role_arn", iamRole2ResourceName, "arn"), + ), + }, + { + Config: testAccAWSAmplifyAppConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app3), + testAccCheckAWSAmplifyAppRecreated(&app2, &app3), + resource.TestCheckResourceAttr(resourceName, "iam_service_role_arn", ""), ), }, }, }) } -func TestAccAWSAmplifyApp_repository(t *testing.T) { - rName := acctest.RandomWithPrefix("tf-acc-test") +func TestAccAWSAmplifyApp_Name(t *testing.T) { + var app amplify.App + rName1 := acctest.RandomWithPrefix("tf-acc-test") + rName2 := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" resource.ParallelTest(t, resource.TestCase{ @@ -599,30 +610,32 @@ func TestAccAWSAmplifyApp_repository(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigRepository(rName), + Config: testAccAWSAmplifyAppConfigName(rName1), Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr(resourceName, "repository", regexp.MustCompile("^https://github.com")), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "name", rName1), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - // access_token is ignored because AWS does not store access_token and oauth_token - // See https://docs.aws.amazon.com/sdk-for-go/api/service/amplify/#CreateAppInput - ImportStateVerifyIgnore: []string{"access_token"}, + }, + { + Config: testAccAWSAmplifyAppConfigName(rName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "name", rName2), + ), }, }, }) } -func TestAccAWSAmplifyApp_iamServiceRoleArn(t *testing.T) { +func TestAccAWSAmplifyApp_repository(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" - roleName1 := acctest.RandomWithPrefix("tf-acc-test") - roleName2 := acctest.RandomWithPrefix("tf-acc-test") - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), @@ -630,21 +643,18 @@ func TestAccAWSAmplifyApp_iamServiceRoleArn(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigIAMServiceRoleArn(rName, roleName1), + Config: testAccAWSAmplifyAppConfigRepository(rName), Check: resource.ComposeTestCheckFunc( - testAccMatchResourceAttrGlobalARN(resourceName, "iam_service_role_arn", "iam", regexp.MustCompile("role/"+roleName1)), + resource.TestMatchResourceAttr(resourceName, "repository", regexp.MustCompile("^https://github.com")), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyAppConfigIAMServiceRoleArn(rName, roleName2), - Check: resource.ComposeTestCheckFunc( - testAccMatchResourceAttrGlobalARN(resourceName, "iam_service_role_arn", "iam", regexp.MustCompile("role/"+roleName2)), - ), + // access_token is ignored because AWS does not store access_token and oauth_token + // See https://docs.aws.amazon.com/sdk-for-go/api/service/amplify/#CreateAppInput + ImportStateVerifyIgnore: []string{"access_token"}, }, }, }) @@ -922,34 +932,62 @@ resource "aws_amplify_app" "test" { `, rName, basicAuthCredentials) } -func testAccAWSAmplifyAppConfigIAMServiceRoleArn(rName string, roleName string) string { +func testAccAWSAmplifyAppConfigIAMServiceRoleBase(rName string) string { return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = "%s" +resource "aws_iam_role" "test1" { + name = "%[1]s-1" - iam_service_role_arn = aws_iam_role.role.arn + assume_role_policy = < Date: Thu, 20 May 2021 17:03:43 -0400 Subject: [PATCH 096/398] r/aws_amplify_app: Remove 'custom_headers' - Not amenable to IaC. --- aws/resource_aws_amplify_app.go | 15 -------- aws/resource_aws_amplify_app_test.go | 57 ---------------------------- 2 files changed, 72 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index 65c19bf06b1..8435abd0a95 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -176,12 +176,6 @@ func resourceAwsAmplifyApp() *schema.Resource { ValidateFunc: validation.StringLenBetween(1, 25000), }, - "custom_headers": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 25000), - }, - "custom_rule": { Type: schema.TypeList, Optional: true, @@ -356,10 +350,6 @@ func resourceAwsAmplifyAppCreate(d *schema.ResourceData, meta interface{}) error input.BuildSpec = aws.String(v.(string)) } - if v, ok := d.GetOk("custom_headers"); ok { - input.CustomHeaders = aws.String(v.(string)) - } - if v, ok := d.GetOk("custom_rule"); ok && len(v.([]interface{})) > 0 { input.CustomRules = expandAmplifyCustomRules(v.([]interface{})) } @@ -448,7 +438,6 @@ func resourceAwsAmplifyAppRead(d *schema.ResourceData, meta interface{}) error { d.Set("auto_branch_creation_patterns", aws.StringValueSlice(app.AutoBranchCreationPatterns)) d.Set("basic_auth_credentials", app.BasicAuthCredentials) d.Set("build_spec", app.BuildSpec) - d.Set("custom_headers", app.CustomHeaders) if err := d.Set("custom_rule", flattenAmplifyCustomRules(app.CustomRules)); err != nil { return fmt.Errorf("error setting custom_rule: %w", err) } @@ -518,10 +507,6 @@ func resourceAwsAmplifyAppUpdate(d *schema.ResourceData, meta interface{}) error input.BuildSpec = aws.String(d.Get("build_spec").(string)) } - if d.HasChange("custom_headers") { - input.CustomHeaders = aws.String(d.Get("custom_headers").(string)) - } - if d.HasChange("custom_rule") { if v := d.Get("custom_rule").([]interface{}); len(v) > 0 { input.CustomRules = expandAmplifyCustomRules(v) diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 7db18775b5b..f5b6a8afe2b 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -89,7 +89,6 @@ func TestAccAWSAmplifyApp_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "auto_branch_creation_patterns.#", "0"), resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", ""), resource.TestCheckResourceAttr(resourceName, "build_spec", ""), - resource.TestCheckResourceAttr(resourceName, "custom_headers", ""), resource.TestCheckResourceAttr(resourceName, "custom_rule.#", "0"), resource.TestMatchResourceAttr(resourceName, "default_domain", regexp.MustCompile(`\.amplifyapp\.com$`)), resource.TestCheckResourceAttr(resourceName, "description", ""), @@ -370,52 +369,6 @@ func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { }) } -/* -func TestAccAWSAmplifyApp_CustomHeaders(t *testing.T) { - var app amplify.App - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_amplify_app.test" - - customHeaders1 := `{"customHeaders":[{"pattern":"*.json","headers":[{"key":"custom-header-name-1","value":"custom-header-value-1"}]}]}` - customHeaders2 := `{"customHeaders":[{"pattern":"*.json","headers":[{"key":"custom-header-name-2","value":"custom-header-value-2"}]},{"pattern":"/path/*","headers":[{"key":"custom-header-name-1","value":"custom-header-value-1"}]}]}` - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, - ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAmplifyAppDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAmplifyAppConfigCustomHeaders(rName, customHeaders1), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "custom_headers", customHeaders1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyAppConfigCustomHeaders(rName, ""), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "custom_headers", customHeaders2), - ), - }, - { - Config: testAccAWSAmplifyAppConfigName(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app), - resource.TestCheckResourceAttr(resourceName, "custom_headers", ""), - ), - }, - }, - }) -} -*/ - func TestAccAWSAmplifyApp_CustomRules(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") @@ -777,16 +730,6 @@ resource "aws_amplify_app" "test" { `, rName, buildSpec) } -func testAccAWSAmplifyAppConfigCustomHeaders(rName, customHeaders string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = %[1]q - - custom_headers = %[2]q -} -`, rName, customHeaders) -} - func testAccAWSAmplifyAppConfigCustomRules(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { From 02ecfed46a700995696d77b0b4f5d3be311b50ab Mon Sep 17 00:00:00 2001 From: Satoshi Tanaka Date: Fri, 21 May 2021 12:02:38 +0900 Subject: [PATCH 097/398] fixed import parameter in aws_dms_certificate --- website/docs/r/dms_certificate.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/dms_certificate.html.markdown b/website/docs/r/dms_certificate.html.markdown index 51774c19e3e..51f9cd71453 100644 --- a/website/docs/r/dms_certificate.html.markdown +++ b/website/docs/r/dms_certificate.html.markdown @@ -42,8 +42,8 @@ In addition to all arguments above, the following attributes are exported: ## Import -Certificates can be imported using the `certificate_arn`, e.g. +Certificates can be imported using the `certificate_id`, e.g. ``` -$ terraform import aws_dms_certificate.test arn:aws:dms:us-west-2:123456789:cert:xxxxxxxxxx +$ terraform import aws_dms_certificate.test test-dms-certificate-tf ``` From 96f76cb7602a0c9336822669b00e3924b03e3a2e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 09:06:22 -0400 Subject: [PATCH 098/398] r/aws_amplify_app: Environment variables for 'TestAccAWSAmplifyApp_Repository'. Acceptance test output: AMPLIFY_GITHUB_ACCESS_TOKEN="..." AMPLIFY_GITHUB_REPOSITORY="https://github.com/ewbankkit/terraform-aws-provider-testing" make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplifyApp_Repository' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplifyApp_Repository -timeout 180m === RUN TestAccAWSAmplifyApp_Repository === PAUSE TestAccAWSAmplifyApp_Repository === CONT TestAccAWSAmplifyApp_Repository --- PASS: TestAccAWSAmplifyApp_Repository (15.63s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 18.557s --- aws/resource_aws_amplify_app.go | 7 +++--- aws/resource_aws_amplify_app_test.go | 32 +++++++++++++++++++--------- docs/MAINTAINING.md | 2 ++ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index 8435abd0a95..ae93286513a 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -306,10 +306,9 @@ func resourceAwsAmplifyApp() *schema.Resource { }, "repository": { - Type: schema.TypeString, - Optional: true, - //TODO - //ForceNew: true, + Type: schema.TypeString, + Optional: true, + ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 1000), }, diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index f5b6a8afe2b..89fb5297a64 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -585,7 +585,20 @@ func TestAccAWSAmplifyApp_Name(t *testing.T) { }) } -func TestAccAWSAmplifyApp_repository(t *testing.T) { +func TestAccAWSAmplifyApp_Repository(t *testing.T) { + key := "AMPLIFY_GITHUB_ACCESS_TOKEN" + accessToken := os.Getenv(key) + if accessToken == "" { + t.Skipf("Environment variable %s is not set", key) + } + + key = "AMPLIFY_GITHUB_REPOSITORY" + repository := os.Getenv(key) + if repository == "" { + t.Skipf("Environment variable %s is not set", key) + } + + var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -596,9 +609,11 @@ func TestAccAWSAmplifyApp_repository(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyAppDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyAppConfigRepository(rName), + Config: testAccAWSAmplifyAppConfigRepository(rName, repository, accessToken), Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr(resourceName, "repository", regexp.MustCompile("^https://github.com")), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "access_token", accessToken), + resource.TestCheckResourceAttr(resourceName, "repository", repository), ), }, { @@ -706,16 +721,13 @@ resource "aws_amplify_app" "test" { `, rName, description) } -func testAccAWSAmplifyAppConfigRepository(rName string) string { - repository := os.Getenv("AMPLIFY_GITHUB_REPOSITORY") - accessToken := os.Getenv("AMPLIFY_GITHUB_ACCESS_TOKEN") - +func testAccAWSAmplifyAppConfigRepository(rName, repository, accessToken string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q - repository = "%s" - access_token = "%s" + repository = %[2]q + access_token = %[3]q } `, rName, repository, accessToken) } diff --git a/docs/MAINTAINING.md b/docs/MAINTAINING.md index 1685b5f90d8..2a8d9b3c474 100644 --- a/docs/MAINTAINING.md +++ b/docs/MAINTAINING.md @@ -342,6 +342,8 @@ 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_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. | | `APNS_BUNDLE_ID` | Identifier for Apple Push Notification Service Bundle in Pinpoint testing. | | `APNS_CERTIFICATE` | Certificate (PEM format) for Apple Push Notification Service in Pinpoint testing. | From b964ecfae3a91fdf441dba19c5a5f478a53bf5a6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 09:44:58 -0400 Subject: [PATCH 099/398] r/aws_amplify_app: Get all acceptance tests passing. --- aws/resource_aws_amplify_app.go | 199 +-------------------------- aws/resource_aws_amplify_app_test.go | 199 +++++++++++++-------------- 2 files changed, 100 insertions(+), 298 deletions(-) diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index ae93286513a..963fffb1269 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -30,10 +30,6 @@ func resourceAwsAmplifyApp() *schema.Resource { CustomizeDiff: customdiff.Sequence( SetTagsDiff, - customdiff.ForceNewIfChange("build_spec", func(_ context.Context, old, new, meta interface{}) bool { - // Any existing value cannot be cleared. - return new.(string) == "" - }), customdiff.ForceNewIfChange("description", func(_ context.Context, old, new, meta interface{}) bool { // Any existing value cannot be cleared. return new.(string) == "" @@ -259,7 +255,7 @@ func resourceAwsAmplifyApp() *schema.Resource { "name": { Type: schema.TypeString, - Optional: true, + Required: true, ValidateFunc: validation.StringLenBetween(1, 255), }, @@ -819,196 +815,3 @@ func flattenAmplifyProductionBranch(apiObject *amplify.ProductionBranch) map[str return tfMap } - -/* -func expandAmplifyEnvironmentVariables(envs map[string]interface{}) map[string]*string { - if len(envs) == 0 { - empty := "" - return map[string]*string{"": &empty} - } else { - return stringMapToPointers(envs) - } -} - -func expandAmplifyAutoBranchCreationConfig(v []interface{}) (*amplify.AutoBranchCreationConfig, []*string, *bool) { - config := &lify.AutoBranchCreationConfig{} - patterns := make([]*string, 0) - enable := aws.Bool(false) - - if len(v) == 0 { - return config, patterns, enable - } - - e := v[0].(map[string]interface{}) - - if ev, ok := e["auto_branch_creation_patterns"]; ok && len(ev.([]interface{})) > 0 { - patterns = expandStringList(ev.([]interface{})) - } - - if ev, ok := e["basic_auth_config"]; ok { - enable, credentials := expandAmplifyBasicAuthConfig(ev.([]interface{})) - config.EnableBasicAuth = enable - config.BasicAuthCredentials = credentials - } - - if ev, ok := e["build_spec"].(string); ok && ev != "" { - config.BuildSpec = aws.String(ev) - } - - if ev, ok := e["enable_auto_branch_creation"].(bool); ok { - enable = aws.Bool(ev) - } - - if ev, ok := e["enable_auto_build"].(bool); ok { - config.EnableAutoBuild = aws.Bool(ev) - } - - if ev, ok := e["enable_pull_request_preview"].(bool); ok { - config.EnablePullRequestPreview = aws.Bool(ev) - } - - if ev, ok := e["environment_variables"].(map[string]interface{}); ok { - config.EnvironmentVariables = expandAmplifyEnvironmentVariables(ev) - } - - if ev, ok := e["framework"].(string); ok { - config.Framework = aws.String(ev) - } - - if ev, ok := e["pull_request_environment_name"].(string); ok { - config.PullRequestEnvironmentName = aws.String(ev) - } - - if ev, ok := e["stage"].(string); ok { - config.Stage = aws.String(ev) - } - - return config, patterns, enable -} - -func flattenAmplifyAutoBranchCreationConfig(config *amplify.AutoBranchCreationConfig, patterns []*string, enable *bool) []map[string]interface{} { - value := make(map[string]interface{}) - - if !aws.BoolValue(enable) { - return nil - } - - value["enable_auto_branch_creation"] = aws.BoolValue(enable) - value["auto_branch_creation_patterns"] = patterns - - if config != nil { - value["basic_auth_config"] = flattenAmplifyBasicAuthConfig(config.EnableBasicAuth, config.BasicAuthCredentials) - value["build_spec"] = aws.StringValue(config.BuildSpec) - value["enable_auto_build"] = aws.BoolValue(config.EnableAutoBuild) - value["enable_pull_request_preview"] = aws.BoolValue(config.EnablePullRequestPreview) - value["environment_variables"] = aws.StringValueMap(config.EnvironmentVariables) - value["framework"] = aws.StringValue(config.Framework) - value["pull_request_environment_name"] = aws.StringValue(config.PullRequestEnvironmentName) - value["stage"] = aws.StringValue(config.Stage) - } - - return []map[string]interface{}{value} -} - -func expandAmplifyBasicAuthConfig(v []interface{}) (*bool, *string) { - enable := false - credentials := "" - - if len(v) == 0 { - return aws.Bool(enable), aws.String(credentials) - } - - config := v[0].(map[string]interface{}) - - if ev, ok := config["enable_basic_auth"].(bool); ok { - enable = ev - } - - // build basic_auth_credentials from raw username and password - username, ok1 := config["username"].(string) - password, ok2 := config["password"].(string) - if ok1 && ok2 { - credentials = encodeAmplifyBasicAuthCredentials(username, password) - } - - return aws.Bool(enable), aws.String(credentials) -} - -func flattenAmplifyBasicAuthConfig(enableBasicAuth *bool, basicAuthCredentials *string) []map[string]interface{} { - value := make(map[string]interface{}) - - if !aws.BoolValue(enableBasicAuth) { - return nil - } - - value["enable_basic_auth"] = aws.BoolValue(enableBasicAuth) - - if basicAuthCredentials != nil { - // Decode BasicAuthCredentials to username and password - username, password, _ := decodeAmplifyBasicAuthCredentials(aws.StringValue(basicAuthCredentials)) - value["username"] = username - value["password"] = password - } - - return []map[string]interface{}{value} -} - -func encodeAmplifyBasicAuthCredentials(username string, password string) string { - data := fmt.Sprintf("%s:%s", username, password) - return base64.StdEncoding.EncodeToString([]byte(data)) -} - -func decodeAmplifyBasicAuthCredentials(encoded string) (string, string, error) { - data, err := base64.StdEncoding.DecodeString(encoded) - if err != nil { - return "", "", err - } - s := strings.SplitN(string(data), ":", 2) - return s[0], s[1], nil -} - -func expandAmplifyCustomRules(l []interface{}) []*amplify.CustomRule { - rules := make([]*amplify.CustomRule, 0) - - for _, v := range l { - e := v.(map[string]interface{}) - - rule := &lify.CustomRule{} - - if ev, ok := e["condition"].(string); ok && ev != "" { - rule.Condition = aws.String(ev) - } - - if ev, ok := e["source"].(string); ok { - rule.Source = aws.String(ev) - } - - if ev, ok := e["status"].(string); ok && ev != "" { - rule.Status = aws.String(ev) - } - - if ev, ok := e["target"].(string); ok { - rule.Target = aws.String(ev) - } - - rules = append(rules, rule) - } - - return rules -} - -func flattenAmplifyCustomRules(rules []*amplify.CustomRule) []map[string]interface{} { - values := make([]map[string]interface{}, 0) - - for _, rule := range rules { - value := make(map[string]interface{}) - value["condition"] = aws.StringValue(rule.Condition) - value["source"] = aws.StringValue(rule.Source) - value["status"] = aws.StringValue(rule.Status) - value["target"] = aws.StringValue(rule.Target) - values = append(values, value) - } - - return values -} -*/ diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 89fb5297a64..c68bb844424 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -327,7 +327,7 @@ func TestAccAWSAmplifyApp_BasicAuthCredentials(t *testing.T) { } func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { - var app1, app2, app3 amplify.App + var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -340,7 +340,7 @@ func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { { Config: testAccAWSAmplifyAppConfigBuildSpec(rName, "version: 0.1"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app1), + testAccCheckAWSAmplifyAppExists(resourceName, &app), resource.TestCheckResourceAttr(resourceName, "build_spec", "version: 0.1"), ), }, @@ -352,17 +352,16 @@ func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { { Config: testAccAWSAmplifyAppConfigBuildSpec(rName, "version: 0.2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app2), - testAccCheckAWSAmplifyAppNotRecreated(&app1, &app2), + testAccCheckAWSAmplifyAppExists(resourceName, &app), resource.TestCheckResourceAttr(resourceName, "build_spec", "version: 0.2"), ), }, { Config: testAccAWSAmplifyAppConfigName(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyAppExists(resourceName, &app3), - testAccCheckAWSAmplifyAppRecreated(&app2, &app3), - resource.TestCheckResourceAttr(resourceName, "build_spec", ""), + testAccCheckAWSAmplifyAppExists(resourceName, &app), + // build_spec is Computed. + resource.TestCheckResourceAttr(resourceName, "build_spec", "version: 0.2"), ), }, }, @@ -711,95 +710,29 @@ resource "aws_amplify_app" "test" { `, rName) } -func testAccAWSAmplifyAppConfigDescription(rName, description string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = %[1]q - - description = %[2]q -} -`, rName, description) -} - -func testAccAWSAmplifyAppConfigRepository(rName, repository, accessToken string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = %[1]q - - repository = %[2]q - access_token = %[3]q -} -`, rName, repository, accessToken) -} - -func testAccAWSAmplifyAppConfigBuildSpec(rName, buildSpec string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = %[1]q - - build_spec = %[2]q -} -`, rName, buildSpec) -} - -func testAccAWSAmplifyAppConfigCustomRules(rName string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = %[1]q - - custom_rule { - source = "/<*>" - status = "404" - target = "/index.html" - } -} -`, rName) -} - -func testAccAWSAmplifyAppConfigCustomRulesUpdated(rName string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = %[1]q - - custom_rule { - condition = "" - source = "/documents" - status = "302" - target = "/documents/us" - } - - custom_rule { - source = "/<*>" - status = "200" - target = "/index.html" - } -} -`, rName) -} - -func testAccAWSAmplifyAppConfigEnvironmentVariables(rName string) string { +func testAccAWSAmplifyAppConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { name = %[1]q - environment_variables = { - ENVVAR1 = "1" + tags = { + %[2]q = %[3]q } } -`, rName) +`, rName, tagKey1, tagValue1) } -func testAccAWSAmplifyAppConfigEnvironmentVariablesUpdated(rName string) string { +func testAccAWSAmplifyAppConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { name = %[1]q - environment_variables = { - ENVVAR1 = "2", - ENVVAR2 = "2" + tags = { + %[2]q = %[3]q + %[4]q = %[5]q } } -`, rName) +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) } func testAccAWSAmplifyAppConfigAutoBranchCreationConfigNoAutoBranchCreationConfig(rName string) string { @@ -887,6 +820,86 @@ resource "aws_amplify_app" "test" { `, rName, basicAuthCredentials) } +func testAccAWSAmplifyAppConfigBuildSpec(rName, buildSpec string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q + + build_spec = %[2]q +} +`, rName, buildSpec) +} + +func testAccAWSAmplifyAppConfigCustomRules(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q + + custom_rule { + source = "/<*>" + status = "404" + target = "/index.html" + } +} +`, rName) +} + +func testAccAWSAmplifyAppConfigCustomRulesUpdated(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q + + custom_rule { + condition = "" + source = "/documents" + status = "302" + target = "/documents/us" + } + + custom_rule { + source = "/<*>" + status = "200" + target = "/index.html" + } +} +`, rName) +} + +func testAccAWSAmplifyAppConfigDescription(rName, description string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q + + description = %[2]q +} +`, rName, description) +} + +func testAccAWSAmplifyAppConfigEnvironmentVariables(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q + + environment_variables = { + ENVVAR1 = "1" + } +} +`, rName) +} + +func testAccAWSAmplifyAppConfigEnvironmentVariablesUpdated(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q + + environment_variables = { + ENVVAR1 = "2", + ENVVAR2 = "2" + } +} +`, rName) +} + func testAccAWSAmplifyAppConfigIAMServiceRoleBase(rName string) string { return fmt.Sprintf(` resource "aws_iam_role" "test1" { @@ -945,27 +958,13 @@ resource "aws_amplify_app" "test" { `, rName)) } -func testAccAWSAmplifyAppConfigTags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = %[1]q - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1) -} - -func testAccAWSAmplifyAppConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { +func testAccAWSAmplifyAppConfigRepository(rName, repository, accessToken string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { name = %[1]q - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } + repository = %[2]q + access_token = %[3]q } -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +`, rName, repository, accessToken) } From 1643971750a143d18caf409cbd277ba7ab44f989 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 09:54:53 -0400 Subject: [PATCH 100/398] r/aws_amplify_app: Serialize acceptance tests to limit API rate-limit exceeded errors. --- aws/resource_aws_amplify_app_test.go | 59 ++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index c68bb844424..f928d6b78a4 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -7,6 +7,7 @@ import ( "os" "regexp" "testing" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" @@ -68,7 +69,41 @@ func testSweepAmplifyApps(region string) error { return sweeperErrs.ErrorOrNil() } -func TestAccAWSAmplifyApp_basic(t *testing.T) { +// Serialize to limit API rate-limit exceeded errors. +func TestAccAWSAmplify_serial(t *testing.T) { + testCases := map[string]map[string]func(t *testing.T){ + "App": { + "basic": testAccAWSAmplifyApp_basic, + "disappears": testAccAWSAmplifyApp_disappears, + "Tags": testAccAWSAmplifyApp_Tags, + "AutoBranchCreationConfig": testAccAWSAmplifyApp_AutoBranchCreationConfig, + "BasicAuthCredentials": testAccAWSAmplifyApp_BasicAuthCredentials, + "BuildSpec": testAccAWSAmplifyApp_BuildSpec, + "CustomRules": testAccAWSAmplifyApp_CustomRules, + "Description": testAccAWSAmplifyApp_Description, + "EnvironmentVariables": testAccAWSAmplifyApp_EnvironmentVariables, + "IamServiceRole": testAccAWSAmplifyApp_IamServiceRole, + "Name": testAccAWSAmplifyApp_Name, + "Repository": testAccAWSAmplifyApp_Repository, + }, + } + + 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) + }) + } + }) + } +} + +func testAccAWSAmplifyApp_basic(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -115,7 +150,7 @@ func TestAccAWSAmplifyApp_basic(t *testing.T) { }) } -func TestAccAWSAmplifyApp_disappears(t *testing.T) { +func testAccAWSAmplifyApp_disappears(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -138,7 +173,7 @@ func TestAccAWSAmplifyApp_disappears(t *testing.T) { }) } -func TestAccAWSAmplifyApp_Tags(t *testing.T) { +func testAccAWSAmplifyApp_Tags(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -183,7 +218,7 @@ func TestAccAWSAmplifyApp_Tags(t *testing.T) { }) } -func TestAccAWSAmplifyApp_AutoBranchCreationConfig(t *testing.T) { +func testAccAWSAmplifyApp_AutoBranchCreationConfig(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -278,7 +313,7 @@ func TestAccAWSAmplifyApp_AutoBranchCreationConfig(t *testing.T) { }) } -func TestAccAWSAmplifyApp_BasicAuthCredentials(t *testing.T) { +func testAccAWSAmplifyApp_BasicAuthCredentials(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -326,7 +361,7 @@ func TestAccAWSAmplifyApp_BasicAuthCredentials(t *testing.T) { }) } -func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { +func testAccAWSAmplifyApp_BuildSpec(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -368,7 +403,7 @@ func TestAccAWSAmplifyApp_BuildSpec(t *testing.T) { }) } -func TestAccAWSAmplifyApp_CustomRules(t *testing.T) { +func testAccAWSAmplifyApp_CustomRules(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -418,7 +453,7 @@ func TestAccAWSAmplifyApp_CustomRules(t *testing.T) { }) } -func TestAccAWSAmplifyApp_Description(t *testing.T) { +func testAccAWSAmplifyApp_Description(t *testing.T) { var app1, app2, app3 amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -461,7 +496,7 @@ func TestAccAWSAmplifyApp_Description(t *testing.T) { }) } -func TestAccAWSAmplifyApp_EnvironmentVariables(t *testing.T) { +func testAccAWSAmplifyApp_EnvironmentVariables(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -505,7 +540,7 @@ func TestAccAWSAmplifyApp_EnvironmentVariables(t *testing.T) { }) } -func TestAccAWSAmplifyApp_IamServiceRole(t *testing.T) { +func testAccAWSAmplifyApp_IamServiceRole(t *testing.T) { var app1, app2, app3 amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_app.test" @@ -549,7 +584,7 @@ func TestAccAWSAmplifyApp_IamServiceRole(t *testing.T) { }) } -func TestAccAWSAmplifyApp_Name(t *testing.T) { +func testAccAWSAmplifyApp_Name(t *testing.T) { var app amplify.App rName1 := acctest.RandomWithPrefix("tf-acc-test") rName2 := acctest.RandomWithPrefix("tf-acc-test") @@ -584,7 +619,7 @@ func TestAccAWSAmplifyApp_Name(t *testing.T) { }) } -func TestAccAWSAmplifyApp_Repository(t *testing.T) { +func testAccAWSAmplifyApp_Repository(t *testing.T) { key := "AMPLIFY_GITHUB_ACCESS_TOKEN" accessToken := os.Getenv(key) if accessToken == "" { From dc8b24e35c034b949e18732eb995db5635ed14ea Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 10:34:12 -0400 Subject: [PATCH 101/398] r/aws_amplify_app: Update documentation. --- website/docs/r/amplify_app.html.markdown | 131 ++++++++++++----------- 1 file changed, 67 insertions(+), 64 deletions(-) diff --git a/website/docs/r/amplify_app.html.markdown b/website/docs/r/amplify_app.html.markdown index 65f85c63bf8..d7e6b81fcce 100644 --- a/website/docs/r/amplify_app.html.markdown +++ b/website/docs/r/amplify_app.html.markdown @@ -15,8 +15,8 @@ Provides an Amplify App resource, a fullstack serverless app hosted on the [AWS ## Example Usage ```hcl -resource "aws_amplify_app" "app" { - name = "app" +resource "aws_amplify_app" "example" { + name = "example" repository = "https://github.com/example/app" # The default build_spec added by the Amplify Console for React. @@ -39,12 +39,16 @@ resource "aws_amplify_app" "app" { - node_modules/**/* EOT - # The default custom_rules added by the Amplify Console. - custom_rules { + # The default rewrites and redirects added by the Amplify Console. + custom_rule { source = "/<*>" status = "404" target = "/index.html" } + + environment_variables = { + ENV = "test" + } } ``` @@ -53,8 +57,8 @@ resource "aws_amplify_app" "app" { If you create a new Amplify App with the `repository` argument, you also need to set `oauth_token` or `access_token` for authentication. For GitHub, get a [personal access token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) and set `access_token` as follows: ```hcl -resource "aws_amplify_app" "app" { - name = "app" +resource "aws_amplify_app" "example" { + name = "example" repository = "https://github.com/example/app" # GitHub personal access token @@ -67,19 +71,18 @@ You can omit `access_token` if you import an existing Amplify App created by the ### Auto Branch Creation ```hcl -resource "aws_amplify_app" "app" { - name = "app" +resource "aws_amplify_app" "example" { + name = "example" - auto_branch_creation_config { - # Enable auto branch creation. - enable_auto_branch_creation = true + enable_auto_branch_creation = true - # The default patterns added by the Amplify Console. - auto_branch_creation_patterns = [ - "*", - "*/**", - ] + # The default patterns added by the Amplify Console. + auto_branch_creation_patterns = [ + "*", + "*/**", + ] + auto_branch_creation_config { # Enable auto build for the created branch. enable_auto_build = true } @@ -89,28 +92,23 @@ resource "aws_amplify_app" "app" { ### Basic Authentication ```hcl -resource "aws_amplify_app" "app" { - name = "app" - - basic_auth_config { - # Enable basic authentication. - enable_basic_auth = true +resource "aws_amplify_app" "example" { + name = "example" - username = "username" - password = "password" - } + enable_basic_auth = true + basic_auth_credentials = base64encode("username1:password1") } ``` ### Rewrites and redirects ```hcl -resource "aws_amplify_app" "app" { - name = "app" +resource "aws_amplify_app" "example" { + name = "example" # Reverse Proxy Rewrite for API requests # https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html#reverse-proxy-rewrite - custom_rules { + custom_rule { source = "/api/<*>" status = "200" target = "https://api.example.com/api/<*>" @@ -118,7 +116,7 @@ resource "aws_amplify_app" "app" { # Redirects for Single Page Web Apps (SPA) # https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html#redirects-for-single-page-web-apps-spa - custom_rules { + custom_rule { source = "" status = "200" target = "/index.html" @@ -130,58 +128,63 @@ resource "aws_amplify_app" "app" { The following arguments are supported: -* `name` - (Required) Name of the Amplify App. - -* `access_token` - (Optional) Personal Access token for 3rd party source control system for an Amplify App, used to create webhook and read-only deploy key. Token is not stored. -* `auto_branch_creation_config` - (Optional) Automated branch creation config for the Amplify App. An `auto_branch_creation_config` block is documented below. -* `basic_auth_config` - (Optional) Basic Authentication config for the Amplify App. A `basic_auth_config` block is documented below. -* `build_spec` - (Optional) BuildSpec content for Amplify App. -* `custom_rules` - (Optional) Custom redirect / rewrite rules for the Amplify App. A `custom_rules` block is documented below. -* `description` - (Optional) Description for the Amplify App. +* `name` - (Required) The name for an Amplify app. +* `access_token` - (Optional) The personal access token for a third-party source control system for an Amplify app. The personal access token is used to create a webhook and a read-only deploy key. The token is not stored. +* `auto_branch_creation_config` - (Optional) The automated branch creation configuration for an Amplify app. An `auto_branch_creation_config` block is documented below. +* `auto_branch_creation_patterns` - (Optional) The automated branch creation glob patterns for an Amplify app. +* `basic_auth_credentials` - (Optional) The credentials for basic authorization for an Amplify app. +* `build_spec` - (Optional) The [build specification](https://docs.aws.amazon.com/amplify/latest/userguide/build-settings.html) (build spec) for an Amplify app. +* `custom_rule` - (Optional) The custom rewrite and redirect rules for an Amplify app. A `custom_rule` block is documented below. +* `description` - (Optional) The description for an Amplify app. +* `enable_auto_branch_creation` - (Optional) Enables automated branch creation for an Amplify app. +* `enable_basic_auth` - (Optional) Enables basic authorization for an Amplify app. This will apply to all branches that are part of this app. * `enable_branch_auto_build` - (Optional) Enables auto-building of branches for the Amplify App. -* `environment_variables` - (Optional) Environment Variables for the Amplify App. -* `iam_service_role_arn` - (Optional) IAM service role ARN for the Amplify App. -* `oauth_token` - (Optional) OAuth token for 3rd party source control system for an Amplify App, used to create webhook and read-only deploy key. OAuth token is not stored. -* `platform` - (Optional) Platform for the Amplify App. -* `repository` - (Optional) Repository for the Amplify App. +* `enable_branch_auto_deletion` - (Optional) Automatically disconnects a branch in the Amplify Console when you delete a branch from your Git repository. +* `environment_variables` - (Optional) The environment variables map for an Amplify app. +* `iam_service_role_arn` - (Optional) The AWS Identity and Access Management (IAM) service role for an Amplify app. +* `oauth_token` - (Optional) The OAuth token for a third-party source control system for an Amplify app. The OAuth token is used to create a webhook and a read-only deploy key. The OAuth token is not stored. +* `platform` - (Optional) The platform or framework for an Amplify app. Valid values: `WEB`. +* `repository` - (Optional) The repository for an Amplify app. * `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. An `auto_branch_creation_config` block supports the following arguments: -* `enable_auto_branch_creation` - (Optional) Enables automated branch creation for the Amplify App. -* `auto_branch_creation_patterns` - (Optional) Automated branch creation glob patterns for the Amplify App. -* `basic_auth_config` - (Optional) Basic Authentication config for the auto created branch. A `basic_auth_config` block is documented below. -* `build_spec` - (Optional) BuildSpec for the auto created branch. -* `enable_auto_build` - (Optional) Enables auto building for the auto created branch. -* `enable_basic_auth` - (Optional) Enables Basic Auth for the auto created branch. -* `enable_pull_request_preview` - (Optional) Enables Pull Request Preview for auto created branch. -* `environment_variables` - (Optional) Environment Variables for the auto created branch. -* `framework` - (Optional) Framework for the auto created 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". - -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. +* `basic_auth_credentials` - (Optional) The basic authorization credentials for the autocreated branch. +* `build_spec` - (Optional) The build specification (build spec) for the autocreated branch. +* `enable_auto_build` - (Optional) Enables auto building for the autocreated branch. +* `enable_basic_auth` - (Optional) Enables basic authorization for the autocreated branch. +* `enable_performance_mode` - (Optional) Enables performance mode for the branch. +* `enable_pull_request_preview` - (Optional) Enables pull request previews for the autocreated branch. +* `environment_variables` - (Optional) The environment variables for the autocreated branch. +* `framework` - (Optional) The framework for the autocreated branch. +* `pull_request_environment_name` - (Optional) The Amplify environment name for the pull request. +* `stage` - (Optional) Describes the current stage for the autocreated branch. Valid values: `PRODUCTION`, `BETA`, `DEVELOPMENT`, `EXPERIMENTAL`, `PULL_REQUEST`. -A `custom_rules` block supports the following arguments: +A `custom_rule` block supports the following arguments: +* `condition` - (Optional) The condition for a URL rewrite or redirect rule, such as a country code. * `source` - (Required) The source pattern for a URL rewrite or redirect rule. +* `status` - (Optional) The status code for a URL rewrite or redirect rule. Valid values: `200`, `301`, `302`, `404`, `404-200`. * `target` - (Required) The target pattern for a URL rewrite or redirect rule. -* `condition` - (Optional) The condition for a URL rewrite or redirect rule, e.g. country code. -* `status` - (Optional) The status code for a URL rewrite or redirect rule. ## Attribute Reference The following attributes are exported: -* `arn` - ARN for the Amplify App. -* `default_domain` - Default domain for the Amplify App. +* `arn` - The Amazon Resource Name (ARN) of the Amplify app. +* `default_domain` - The default domain for the Amplify app. +* `id` - The unique ID of the Amplify app. +* `production_branch` - Describes the information about a production branch for an Amplify app. A `production_branch` block is documented below. * `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). +A `production_branch` block supports the following attributes: + +* `branch_name` - The branch name for the production branch. +* `last_deploy_time` - The last deploy time of the production branch. +* `status` - The status of the production branch. +* `thumbnail_url` - The thumbnail URL for the production branch. + ## Import Amplify App can be imported using Amplify App ID (appId), e.g. From 769b5ce934f4dc43e016cf835ce76ee14fe8a5ff Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 10:38:50 -0400 Subject: [PATCH 102/398] Add 'resource_aws_amplify_test.go'. --- aws/resource_aws_amplify_app_test.go | 35 ------------------------ aws/resource_aws_amplify_test.go | 40 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 35 deletions(-) create mode 100644 aws/resource_aws_amplify_test.go diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index f928d6b78a4..9c1dc8c0d18 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -7,7 +7,6 @@ import ( "os" "regexp" "testing" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" @@ -69,40 +68,6 @@ func testSweepAmplifyApps(region string) error { return sweeperErrs.ErrorOrNil() } -// Serialize to limit API rate-limit exceeded errors. -func TestAccAWSAmplify_serial(t *testing.T) { - testCases := map[string]map[string]func(t *testing.T){ - "App": { - "basic": testAccAWSAmplifyApp_basic, - "disappears": testAccAWSAmplifyApp_disappears, - "Tags": testAccAWSAmplifyApp_Tags, - "AutoBranchCreationConfig": testAccAWSAmplifyApp_AutoBranchCreationConfig, - "BasicAuthCredentials": testAccAWSAmplifyApp_BasicAuthCredentials, - "BuildSpec": testAccAWSAmplifyApp_BuildSpec, - "CustomRules": testAccAWSAmplifyApp_CustomRules, - "Description": testAccAWSAmplifyApp_Description, - "EnvironmentVariables": testAccAWSAmplifyApp_EnvironmentVariables, - "IamServiceRole": testAccAWSAmplifyApp_IamServiceRole, - "Name": testAccAWSAmplifyApp_Name, - "Repository": testAccAWSAmplifyApp_Repository, - }, - } - - 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) - }) - } - }) - } -} - func testAccAWSAmplifyApp_basic(t *testing.T) { var app amplify.App rName := acctest.RandomWithPrefix("tf-acc-test") diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go new file mode 100644 index 00000000000..4907084c10e --- /dev/null +++ b/aws/resource_aws_amplify_test.go @@ -0,0 +1,40 @@ +package aws + +import ( + "testing" + "time" +) + +// Serialize to limit API rate-limit exceeded errors. +func TestAccAWSAmplify_serial(t *testing.T) { + testCases := map[string]map[string]func(t *testing.T){ + "App": { + "basic": testAccAWSAmplifyApp_basic, + "disappears": testAccAWSAmplifyApp_disappears, + "Tags": testAccAWSAmplifyApp_Tags, + "AutoBranchCreationConfig": testAccAWSAmplifyApp_AutoBranchCreationConfig, + "BasicAuthCredentials": testAccAWSAmplifyApp_BasicAuthCredentials, + "BuildSpec": testAccAWSAmplifyApp_BuildSpec, + "CustomRules": testAccAWSAmplifyApp_CustomRules, + "Description": testAccAWSAmplifyApp_Description, + "EnvironmentVariables": testAccAWSAmplifyApp_EnvironmentVariables, + "IamServiceRole": testAccAWSAmplifyApp_IamServiceRole, + "Name": testAccAWSAmplifyApp_Name, + "Repository": testAccAWSAmplifyApp_Repository, + }, + } + + 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 ee538b0d7818d994262b98fc68c887a7561634f9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 11:03:12 -0400 Subject: [PATCH 103/398] Fix 'terrafmt' errors. --- aws/resource_aws_amplify_app_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_amplify_app_test.go b/aws/resource_aws_amplify_app_test.go index 9c1dc8c0d18..94b49a37ee8 100644 --- a/aws/resource_aws_amplify_app_test.go +++ b/aws/resource_aws_amplify_app_test.go @@ -743,8 +743,8 @@ resource "aws_amplify_app" "test" { enable_auto_branch_creation = true auto_branch_creation_patterns = [ - "*", - "*/**", + "*", + "*/**", ] } `, rName) @@ -756,7 +756,7 @@ resource "aws_amplify_app" "test" { name = %[1]q enable_auto_branch_creation = true - + auto_branch_creation_patterns = [ "feature/*", ] @@ -766,8 +766,8 @@ resource "aws_amplify_app" "test" { framework = "React" stage = "DEVELOPMENT" - enable_basic_auth = true - basic_auth_credentials = %[2]q + enable_basic_auth = true + basic_auth_credentials = %[2]q enable_auto_build = true enable_pull_request_preview = true @@ -788,7 +788,7 @@ resource "aws_amplify_app" "test" { name = %[1]q enable_auto_branch_creation = true - + auto_branch_creation_patterns = [ "feature/*", ] @@ -798,7 +798,7 @@ resource "aws_amplify_app" "test" { framework = "React" stage = "EXPERIMENTAL" - enable_basic_auth = false + enable_basic_auth = false enable_auto_build = false enable_pull_request_preview = false From ad4df307d7d7869db51bdaa413264e322c47b522 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 11:05:45 -0400 Subject: [PATCH 104/398] Fix 'tfproviderdocs' errors. --- website/docs/r/amplify_app.html.markdown | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/website/docs/r/amplify_app.html.markdown b/website/docs/r/amplify_app.html.markdown index d7e6b81fcce..891f2431a67 100644 --- a/website/docs/r/amplify_app.html.markdown +++ b/website/docs/r/amplify_app.html.markdown @@ -14,7 +14,7 @@ Provides an Amplify App resource, a fullstack serverless app hosted on the [AWS ## Example Usage -```hcl +```terraform resource "aws_amplify_app" "example" { name = "example" repository = "https://github.com/example/app" @@ -56,7 +56,7 @@ resource "aws_amplify_app" "example" { If you create a new Amplify App with the `repository` argument, you also need to set `oauth_token` or `access_token` for authentication. For GitHub, get a [personal access token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) and set `access_token` as follows: -```hcl +```terraform resource "aws_amplify_app" "example" { name = "example" repository = "https://github.com/example/app" @@ -70,7 +70,7 @@ You can omit `access_token` if you import an existing Amplify App created by the ### Auto Branch Creation -```hcl +```terraform resource "aws_amplify_app" "example" { name = "example" @@ -89,9 +89,9 @@ resource "aws_amplify_app" "example" { } ``` -### Basic Authentication +### Basic Authorization -```hcl +```terraform resource "aws_amplify_app" "example" { name = "example" @@ -100,9 +100,9 @@ resource "aws_amplify_app" "example" { } ``` -### Rewrites and redirects +### Rewrites and Redirects -```hcl +```terraform resource "aws_amplify_app" "example" { name = "example" From 70526bfe796452b674cfc120c17493163202b85d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 11:13:24 -0400 Subject: [PATCH 105/398] Fix 'tfproviderdocs' errors. --- website/docs/r/amplify_app.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/amplify_app.html.markdown b/website/docs/r/amplify_app.html.markdown index 891f2431a67..3da86a70893 100644 --- a/website/docs/r/amplify_app.html.markdown +++ b/website/docs/r/amplify_app.html.markdown @@ -168,7 +168,7 @@ A `custom_rule` block supports the following arguments: * `status` - (Optional) The status code for a URL rewrite or redirect rule. Valid values: `200`, `301`, `302`, `404`, `404-200`. * `target` - (Required) The target pattern for a URL rewrite or redirect rule. -## Attribute Reference +## Attributes Reference The following attributes are exported: From 509f70a2cd7a882611b1fb8bcacd055e2fc0551d Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Fri, 21 May 2021 11:43:14 -0400 Subject: [PATCH 106/398] add missing arguments in expansion methods --- aws/resource_aws_apprunner_service.go | 16 +++++++ aws/resource_aws_apprunner_service_test.go | 52 ++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/aws/resource_aws_apprunner_service.go b/aws/resource_aws_apprunner_service.go index e953e03f08f..9ae873b4c24 100644 --- a/aws/resource_aws_apprunner_service.go +++ b/aws/resource_aws_apprunner_service.go @@ -680,6 +680,10 @@ func expandAppRunnerServiceAuthenticationConfiguration(l []interface{}) *apprunn result.AccessRoleArn = aws.String(v) } + if v, ok := tfMap["connection_arn"].(string); ok && v != "" { + result.ConnectionArn = aws.String(v) + } + return result } @@ -700,6 +704,14 @@ func expandAppRunnerServiceImageConfiguration(l []interface{}) *apprunner.ImageC result.Port = aws.String(v) } + if v, ok := tfMap["runtime_environment_variables"].(map[string]interface{}); ok && len(v) > 0 { + result.RuntimeEnvironmentVariables = expandStringMap(v) + } + + if v, ok := tfMap["start_command"].(string); ok && v != "" { + result.StartCommand = aws.String(v) + } + return result } @@ -808,6 +820,10 @@ func expandAppRunnerServiceCodeConfigurationValues(l []interface{}) *apprunner.C result.Runtime = aws.String(v) } + if v, ok := tfMap["runtime_environment_variables"].(map[string]interface{}); ok && len(v) > 0 { + result.RuntimeEnvironmentVariables = expandStringMap(v) + } + if v, ok := tfMap["start_command"].(string); ok && v != "" { result.StartCommand = aws.String(v) } diff --git a/aws/resource_aws_apprunner_service_test.go b/aws/resource_aws_apprunner_service_test.go index 434c3692655..973d06c3941 100644 --- a/aws/resource_aws_apprunner_service_test.go +++ b/aws/resource_aws_apprunner_service_test.go @@ -281,6 +281,37 @@ func TestAccAwsAppRunnerService_ImageRepository_InstanceConfiguration(t *testing }) } +// Reference: https://github.com/hashicorp/terraform-provider-aws/issues/19469 +func TestAccAwsAppRunnerService_ImageRepository_RuntimeEnvironmentVars(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_apprunner_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAppRunner(t) }, + ErrorCheck: testAccErrorCheck(t, apprunner.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsAppRunnerServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppRunnerService_imageRepository_runtimeEnvVars(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAppRunnerServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "source_configuration.#", "1"), + 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.runtime_environment_variables.%", "1"), + resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.0.image_configuration.0.runtime_environment_variables.APP_NAME", rName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAwsAppRunnerService_disappears(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_apprunner_service.test" @@ -443,6 +474,27 @@ resource "aws_apprunner_service" "test" { `, rName) } +func testAccAppRunnerService_imageRepository_runtimeEnvVars(rName string) string { + return fmt.Sprintf(` +resource "aws_apprunner_service" "test" { + service_name = %[1]q + source_configuration { + auto_deployments_enabled = false + image_repository { + image_configuration { + port = "8000" + runtime_environment_variables = { + APP_NAME = %[1]q + } + } + image_identifier = "public.ecr.aws/jg/hello:latest" + image_repository_type = "ECR_PUBLIC" + } + } +} +`, rName) +} + func testAccAppRunnerService_imageRepository_autoScalingConfiguration(rName string) string { return fmt.Sprintf(` resource "aws_apprunner_auto_scaling_configuration_version" "test" { From 16a1342a3b907a997b199f1e3ce79aa4227e89f4 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Fri, 21 May 2021 11:51:41 -0400 Subject: [PATCH 107/398] Update CHANGELOG for #19471 --- .changelog/19471.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19471.txt diff --git a/.changelog/19471.txt b/.changelog/19471.txt new file mode 100644 index 00000000000..820b41723fc --- /dev/null +++ b/.changelog/19471.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_apprunner_service: Correctly configure `authentication_configuration`, `code_configuration`, and `image_configuration` nested arguments in API requests +``` From 062070df19cca22d853216246d48bc43c0c60ce4 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 21 May 2021 17:13:04 +0100 Subject: [PATCH 108/398] Added secret_arn output value --- aws/resource_aws_cloudwatch_event_connection.go | 5 +++++ website/docs/r/cloudwatch_event_connection.html.markdown | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudwatch_event_connection.go b/aws/resource_aws_cloudwatch_event_connection.go index dcc1069f815..49f48e016c7 100644 --- a/aws/resource_aws_cloudwatch_event_connection.go +++ b/aws/resource_aws_cloudwatch_event_connection.go @@ -225,6 +225,10 @@ func resourceAwsCloudWatchEventConnection() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "secret_arn": { + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -282,6 +286,7 @@ func resourceAwsCloudWatchEventConnectionRead(d *schema.ResourceData, meta inter log.Printf("[DEBUG] Found CloudWatchEvent connection: %#v", *output) d.Set("arn", output.ConnectionArn) + d.Set("secret_arn", output.SecretArn) d.Set("name", output.Name) d.Set("description", output.Description) d.Set("authorization_type", output.AuthorizationType) diff --git a/website/docs/r/cloudwatch_event_connection.html.markdown b/website/docs/r/cloudwatch_event_connection.html.markdown index 0bfc02384a3..c4c79455737 100644 --- a/website/docs/r/cloudwatch_event_connection.html.markdown +++ b/website/docs/r/cloudwatch_event_connection.html.markdown @@ -188,7 +188,8 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: -* `arn` - The Amazon Resource Name (ARN) of the event bus. +* `arn` - The Amazon Resource Name (ARN) of the connection. +* `secret_arn` - The Amazon Resource Name (ARN) of the secret created from the authorization parameters specified for the connection. ## Import From 6138602cbfd18ec537071e593c7d4f715167450a Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 21 May 2021 17:54:56 +0100 Subject: [PATCH 109/398] Add Cloudwatch Event Connection Data Source --- .changelog/18905.txt | 4 ++ ..._source_aws_cloudwatch_event_connection.go | 62 +++++++++++++++++++ ...ce_aws_cloudwatch_event_connection_test.go | 52 ++++++++++++++++ aws/provider.go | 1 + ...cloudwatch_events_connection.html.markdown | 38 ++++++++++++ .../cloudwatch_event_connection.html.markdown | 4 +- 6 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 aws/data_source_aws_cloudwatch_event_connection.go create mode 100644 aws/data_source_aws_cloudwatch_event_connection_test.go create mode 100644 website/docs/d/cloudwatch_events_connection.html.markdown diff --git a/.changelog/18905.txt b/.changelog/18905.txt index a2b9c9de84e..69e0051652b 100644 --- a/.changelog/18905.txt +++ b/.changelog/18905.txt @@ -4,4 +4,8 @@ aws_cloudwatch_event_connection ```release-note:new-resource aws_cloudwatch_event_api_destination +``` + +```release-note:new-data-source +aws_cloudwatch_event_connection ``` \ No newline at end of file diff --git a/aws/data_source_aws_cloudwatch_event_connection.go b/aws/data_source_aws_cloudwatch_event_connection.go new file mode 100644 index 00000000000..4c46028e192 --- /dev/null +++ b/aws/data_source_aws_cloudwatch_event_connection.go @@ -0,0 +1,62 @@ +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/schema" +) + +func dataSourceAwsCloudwatchEventConnection() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsCloudwatchEventConnectionRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "authorization_type": { + Type: schema.TypeString, + Computed: true, + }, + "secret_arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceAwsCloudwatchEventConnectionRead(d *schema.ResourceData, meta interface{}) error { + d.SetId(d.Get("name").(string)) + + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.DescribeConnectionInput{ + Name: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Reading CloudWatchEvent connection (%s)", d.Id()) + output, err := conn.DescribeConnection(input) + if err != nil { + return fmt.Errorf("error getting CloudWatchEvent connection (%s): %w", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting CloudWatchEvent connection (%s): empty response", d.Id()) + } + + log.Printf("[DEBUG] Found CloudWatchEvent connection: %#v", *output) + d.Set("arn", output.ConnectionArn) + d.Set("secret_arn", output.SecretArn) + d.Set("name", output.Name) + d.Set("authorization_type", output.AuthorizationType) + return nil +} diff --git a/aws/data_source_aws_cloudwatch_event_connection_test.go b/aws/data_source_aws_cloudwatch_event_connection_test.go new file mode 100644 index 00000000000..c148d19bc25 --- /dev/null +++ b/aws/data_source_aws_cloudwatch_event_connection_test.go @@ -0,0 +1,52 @@ +package aws + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAWSDataSourceCloudwatch_Event_Connection_basic(t *testing.T) { + dataSourceName := "data.aws_cloudwatch_event_connection.test" + resourceName := "aws_cloudwatch_event_connection.api_key" + + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "API_KEY" + description := acctest.RandomWithPrefix("tf-acc-test") + key := acctest.RandomWithPrefix("tf-acc-test") + value := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudwatch_Event_ConnectionDataConfig( + name, + description, + authorizationType, + key, + value, + ), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "secret_arn", resourceName, "secret_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "authorization_type", resourceName, "authorization_type"), + ), + }, + }, + }) +} + +func testAccAWSCloudwatch_Event_ConnectionDataConfig(name, description, authorizationType, key, value string) string { + return composeConfig( + testAccAWSCloudWatchEventConnectionConfig_apiKey(name, description, authorizationType, key, value), + ` +data "aws_cloudwatch_event_connection" "test" { + name = aws_cloudwatch_event_connection.api_key.name +} +`) +} diff --git a/aws/provider.go b/aws/provider.go index 70b1c2b888c..7cf0805b6ca 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -216,6 +216,7 @@ func Provider() *schema.Provider { "aws_cloudfront_origin_request_policy": dataSourceAwsCloudFrontOriginRequestPolicy(), "aws_cloudhsm_v2_cluster": dataSourceCloudHsmV2Cluster(), "aws_cloudtrail_service_account": dataSourceAwsCloudTrailServiceAccount(), + "aws_cloudwatch_event_connection": dataSourceAwsCloudwatchEventConnection(), "aws_cloudwatch_log_group": dataSourceAwsCloudwatchLogGroup(), "aws_codeartifact_authorization_token": dataSourceAwsCodeArtifactAuthorizationToken(), "aws_codeartifact_repository_endpoint": dataSourceAwsCodeArtifactRepositoryEndpoint(), diff --git a/website/docs/d/cloudwatch_events_connection.html.markdown b/website/docs/d/cloudwatch_events_connection.html.markdown new file mode 100644 index 00000000000..0b6bfeba1fe --- /dev/null +++ b/website/docs/d/cloudwatch_events_connection.html.markdown @@ -0,0 +1,38 @@ +--- +subcategory: "EventBridge (CloudWatch Events)" +layout: "aws" +page_title: "AWS: aws_cloudwatch_event_connection" +description: |- + Provides an EventBridge connection data source. +--- + +# Data source: aws_cloudfront_distribution + +Use this data source to retrieve information about a EventBridge connection. + +~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. + + +## Example Usage + +```terraform +data "aws_cloudwatch_event_connection" "test" { + name = "test" +} +``` + +## Argument Reference + +* `name` - The name of the connection. + +## Attributes Reference + +The following attributes are exported: + +* `name` - The name of the connection. + +* `arn` - The ARN (Amazon Resource Name) for the connection. + +* `secret_arn` - The ARN (Amazon Resource Name) for the secret created from the authorization parameters specified for the connection. + +* `authorization_type` - The type of authorization to use to connect. One of `API_KEY`,`BASIC`,`OAUTH_CLIENT_CREDENTIALS`. diff --git a/website/docs/r/cloudwatch_event_connection.html.markdown b/website/docs/r/cloudwatch_event_connection.html.markdown index c4c79455737..972e6893e4b 100644 --- a/website/docs/r/cloudwatch_event_connection.html.markdown +++ b/website/docs/r/cloudwatch_event_connection.html.markdown @@ -137,8 +137,8 @@ resource "aws_cloudwatch_event_connection" "test" { The following arguments are supported: * `name` - (Required) The name of the new connection. Maximum of 64 characters consisting of numbers, lower/upper case letters, .,-,_. -* `description` - (Optional) Enter a description for the connection. Maximum of 512 characters. -* `authorization_type` - (Required) Choose the type of authorization to use to access the API destination. One of `API_KEY`,`BASIC`,`OAUTH_CLIENT_CREDENTIALS`. A secret for the connection is created and stored in AWS Secrets Manager. +* `description` - (Optional) Enter a description for the connection. Maximum of 512 characters. +* `authorization_type` - (Required) Choose the type of authorization to use for the connection. One of `API_KEY`,`BASIC`,`OAUTH_CLIENT_CREDENTIALS`. * `auth_parameters` - (Required) Parameters used for authorization. A maximum of 1 are allowed. Documented below. * `invocation_http_parameters` - (Optional) Invocation Http Parameters are additional credentials used to sign each Invocation of the ApiDestination created from this Connection. If the ApiDestination Rule Target has additional HttpParameters, the values will be merged together, with the Connection Invocation Http Parameters taking precedence. Secret values are stored and managed by AWS Secrets Manager. A maximum of 1 are allowed. Documented below. From d4916da68691302e0539d613c6cd71c28531345d Mon Sep 17 00:00:00 2001 From: changelogbot Date: Fri, 21 May 2021 18:15:35 +0000 Subject: [PATCH 110/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45ab3142f9c..8cdfaadf4cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ FEATURES: +* **New Resource:** `aws_amplify_app` ([#15966](https://github.com/hashicorp/terraform-provider-aws/issues/15966)) * **New Resource:** `aws_servicecatalog_budget_resource_association` ([#19452](https://github.com/hashicorp/terraform-provider-aws/issues/19452)) * **New Resource:** `aws_servicecatalog_provisioning_artifact` ([#19316](https://github.com/hashicorp/terraform-provider-aws/issues/19316)) * **New Resource:** `aws_servicecatalog_tag_option_resource_association` ([#19448](https://github.com/hashicorp/terraform-provider-aws/issues/19448)) From d7cc6d9ed81d10574ff86fbd7a13a0d62b61bfc6 Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Fri, 7 Feb 2020 01:12:23 +0900 Subject: [PATCH 111/398] Add aws_amplify_backend_environment resource --- aws/provider.go | 1 + ...esource_aws_amplify_backend_environment.go | 145 ++++++++++++++++ ...ce_aws_amplify_backend_environment_test.go | 156 ++++++++++++++++++ .../amplify_backend_environment.html.markdown | 50 ++++++ 4 files changed, 352 insertions(+) create mode 100644 aws/resource_aws_amplify_backend_environment.go create mode 100644 aws/resource_aws_amplify_backend_environment_test.go create mode 100644 website/docs/r/amplify_backend_environment.html.markdown diff --git a/aws/provider.go b/aws/provider.go index a66754c0123..847612d67a5 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -451,6 +451,7 @@ func Provider() *schema.Provider { "aws_ami_from_instance": resourceAwsAmiFromInstance(), "aws_ami_launch_permission": resourceAwsAmiLaunchPermission(), "aws_amplify_app": resourceAwsAmplifyApp(), + "aws_amplify_backend_environment": resourceAwsAmplifyBackendEnvironment(), "aws_api_gateway_account": resourceAwsApiGatewayAccount(), "aws_api_gateway_api_key": resourceAwsApiGatewayApiKey(), "aws_api_gateway_authorizer": resourceAwsApiGatewayAuthorizer(), diff --git a/aws/resource_aws_amplify_backend_environment.go b/aws/resource_aws_amplify_backend_environment.go new file mode 100644 index 00000000000..c4cca6f4a33 --- /dev/null +++ b/aws/resource_aws_amplify_backend_environment.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 resourceAwsAmplifyBackendEnvironment() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAmplifyBackendEnvironmentCreate, + Read: resourceAwsAmplifyBackendEnvironmentRead, + Delete: resourceAwsAmplifyBackendEnvironmentDelete, + 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, + }, + "deployment_artifacts": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 100), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9-]+$`), "should not contain special characters"), + ), + }, + "environment_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(2, 10), + validation.StringMatch(regexp.MustCompile(`^[a-z]+$`), "should only contain lowercase alphabets"), + ), + }, + "stack_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 100), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9-]+$`), "should not contain special characters"), + ), + }, + }, + } +} + +func resourceAwsAmplifyBackendEnvironmentCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Print("[DEBUG] Creating Amplify BackendEnvironment") + + params := &lify.CreateBackendEnvironmentInput{ + AppId: aws.String(d.Get("app_id").(string)), + EnvironmentName: aws.String(d.Get("environment_name").(string)), + } + + if v, ok := d.GetOk("deployment_artifacts"); ok { + params.DeploymentArtifacts = aws.String(v.(string)) + } + + if v, ok := d.GetOk("stack_name"); ok { + params.StackName = aws.String(v.(string)) + } + + resp, err := conn.CreateBackendEnvironment(params) + if err != nil { + return fmt.Errorf("Error creating Amplify BackendEnvironment: %s", err) + } + + arn := *resp.BackendEnvironment.BackendEnvironmentArn + d.SetId(arn[strings.Index(arn, ":apps/")+len(":apps/"):]) + + return resourceAwsAmplifyBackendEnvironmentRead(d, meta) +} + +func resourceAwsAmplifyBackendEnvironmentRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Reading Amplify BackendEnvironment: %s", d.Id()) + + s := strings.Split(d.Id(), "/") + app_id := s[0] + environment_name := s[2] + + resp, err := conn.GetBackendEnvironment(&lify.GetBackendEnvironmentInput{ + AppId: aws.String(app_id), + EnvironmentName: aws.String(environment_name), + }) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == amplify.ErrCodeNotFoundException { + log.Printf("[WARN] Amplify BackendEnvironment (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + return err + } + + d.Set("app_id", app_id) + d.Set("arn", resp.BackendEnvironment.BackendEnvironmentArn) + d.Set("deployment_artifacts", resp.BackendEnvironment.DeploymentArtifacts) + d.Set("environment_name", resp.BackendEnvironment.EnvironmentName) + d.Set("stack_name", resp.BackendEnvironment.StackName) + + return nil +} + +func resourceAwsAmplifyBackendEnvironmentDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Deleting Amplify BackendEnvironment: %s", d.Id()) + + s := strings.Split(d.Id(), "/") + app_id := s[0] + environment_name := s[2] + + params := &lify.DeleteBackendEnvironmentInput{ + AppId: aws.String(app_id), + EnvironmentName: aws.String(environment_name), + } + + _, err := conn.DeleteBackendEnvironment(params) + if err != nil { + return fmt.Errorf("Error deleting Amplify BackendEnvironment: %s", err) + } + + return nil +} diff --git a/aws/resource_aws_amplify_backend_environment_test.go b/aws/resource_aws_amplify_backend_environment_test.go new file mode 100644 index 00000000000..902eda55b15 --- /dev/null +++ b/aws/resource_aws_amplify_backend_environment_test.go @@ -0,0 +1,156 @@ +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" +) + +func TestAccAWSAmplifyBackendEnvironment_basic(t *testing.T) { + var env1, env2 amplify.BackendEnvironment + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_backend_environment.test" + + envName := "backend" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBackendEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBackendEnvironmentConfig_Required(rName, envName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName, &env1), + resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/backendenvironments/"+envName)), + resource.TestCheckResourceAttr(resourceName, "environment_name", envName), + resource.TestMatchResourceAttr(resourceName, "deployment_artifacts", regexp.MustCompile(fmt.Sprintf("^tf-acc-test-.*-%s-.*-deployment$", envName))), + resource.TestMatchResourceAttr(resourceName, "stack_name", regexp.MustCompile(fmt.Sprintf("^amplify-tf-acc-test-.*-%s-.*$", envName))), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyBackendEnvironmentConfigAll(rName, envName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName, &env2), + testAccCheckAWSAmplifyBackendEnvironmentRecreated(&env1, &env2), + resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/backendenvironments/"+envName)), + resource.TestCheckResourceAttr(resourceName, "environment_name", envName), + resource.TestCheckResourceAttr(resourceName, "deployment_artifacts", rName), + resource.TestCheckResourceAttr(resourceName, "stack_name", rName), + ), + }, + }, + }) +} + +func testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName string, v *amplify.BackendEnvironment) 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] + environment_name := id[2] + + output, err := conn.GetBackendEnvironment(&lify.GetBackendEnvironmentInput{ + AppId: aws.String(app_id), + EnvironmentName: aws.String(environment_name), + }) + if err != nil { + return err + } + + if output == nil || output.BackendEnvironment == nil { + return fmt.Errorf("Amplify BackendEnvironment (%s) not found", rs.Primary.ID) + } + + *v = *output.BackendEnvironment + + return nil + } +} + +func testAccCheckAWSAmplifyBackendEnvironmentDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_amplify_backend_environment" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + + id := strings.Split(rs.Primary.ID, "/") + app_id := id[0] + environment_name := id[2] + + _, err := conn.GetBackendEnvironment(&lify.GetBackendEnvironmentInput{ + AppId: aws.String(app_id), + EnvironmentName: aws.String(environment_name), + }) + + if isAWSErr(err, amplify.ErrCodeNotFoundException, "") { + continue + } + + if err != nil { + return err + } + } + + return nil +} + +func testAccCheckAWSAmplifyBackendEnvironmentRecreated(i, j *amplify.BackendEnvironment) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.TimeValue(i.CreateTime) == aws.TimeValue(j.CreateTime) { + return errors.New("Amplify BackendEnvironment was not recreated") + } + + return nil + } +} + +func testAccAWSAmplifyBackendEnvironmentConfig_Required(rName string, envName 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 = "%s" +} +`, rName, envName) +} + +func testAccAWSAmplifyBackendEnvironmentConfigAll(rName string, envName 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 = "%s" + + deployment_artifacts = "%s" + stack_name = "%s" +} +`, rName, envName, rName, rName) +} diff --git a/website/docs/r/amplify_backend_environment.html.markdown b/website/docs/r/amplify_backend_environment.html.markdown new file mode 100644 index 00000000000..bf8a1782673 --- /dev/null +++ b/website/docs/r/amplify_backend_environment.html.markdown @@ -0,0 +1,50 @@ +--- +subcategory: "Amplify" +layout: "aws" +page_title: "AWS: aws_amplify_backend_environment" +description: |- + Provides an Amplify backend environment resource. +--- + +# Resource: aws_amplify_backend_environment + +Provides an Amplify backend environment resource. + +## Example Usage + +```hcl +resource "aws_amplify_app" "app" { + name = "app" +} + +resource "aws_amplify_backend_environment" "prod" { + app_id = aws_amplify_app.app.id + environment_name = "prod" + + deployment_artifacts = "app-prod-deployment" + stack_name = "amplify-app-prod" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `app_id` - (Required) Unique Id for an Amplify App. +* `environment_name` - (Required) Name for the backend environment. +* `deployment_artifacts` - (Optional) Name of deployment artifacts. +* `stack_name` - (Optional) CloudFormation stack name of backend environment. + +## Attribute Reference + +The following attributes are exported: + +* `arn` - Arn for the backend environment. + +## Import + +Amplify backend environment can be imported using `app_id` and `environment_name`, e.g. + +``` +$ terraform import aws_amplify_backend_environment.prod d2ypk4k47z8u6/backendenvironments/prod +``` From 0bc8527bdcf879d256d087b67f01aafb3d601a0f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 15:05:29 -0400 Subject: [PATCH 112/398] r/aws_amplify_backend_environment: First compiling version. --- aws/internal/service/amplify/finder/finder.go | 29 ++++ aws/internal/service/amplify/id.go | 25 +++ ...esource_aws_amplify_backend_environment.go | 143 +++++++++--------- ...ce_aws_amplify_backend_environment_test.go | 72 ++++----- aws/resource_aws_amplify_test.go | 3 + website/docs/r/amplify_app.html.markdown | 2 +- .../amplify_backend_environment.html.markdown | 37 ++--- 7 files changed, 182 insertions(+), 129 deletions(-) create mode 100644 aws/internal/service/amplify/id.go diff --git a/aws/internal/service/amplify/finder/finder.go b/aws/internal/service/amplify/finder/finder.go index 8f67fbb18f1..46c91eac887 100644 --- a/aws/internal/service/amplify/finder/finder.go +++ b/aws/internal/service/amplify/finder/finder.go @@ -34,3 +34,32 @@ func AppByID(conn *amplify.Amplify, id string) (*amplify.App, error) { return output.App, nil } + +func BackendEnvironmentByAppIDAndEnvironmentName(conn *amplify.Amplify, appID, environmentName string) (*amplify.BackendEnvironment, error) { + input := &lify.GetBackendEnvironmentInput{ + AppId: aws.String(appID), + EnvironmentName: aws.String(environmentName), + } + + output, err := conn.GetBackendEnvironment(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.BackendEnvironment == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.BackendEnvironment, nil +} diff --git a/aws/internal/service/amplify/id.go b/aws/internal/service/amplify/id.go new file mode 100644 index 00000000000..a6c3210b0f2 --- /dev/null +++ b/aws/internal/service/amplify/id.go @@ -0,0 +1,25 @@ +package amplify + +import ( + "fmt" + "strings" +) + +const backendEnvironmentResourceIDSeparator = "/" + +func BackendEnvironmentCreateResourceID(appID, environmentName string) string { + parts := []string{appID, environmentName} + id := strings.Join(parts, backendEnvironmentResourceIDSeparator) + + return id +} + +func BackendEnvironmentParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, backendEnvironmentResourceIDSeparator) + + 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]sENVIRONMENTNAME", id, backendEnvironmentResourceIDSeparator) +} diff --git a/aws/resource_aws_amplify_backend_environment.go b/aws/resource_aws_amplify_backend_environment.go index c4cca6f4a33..e1221b0bb27 100644 --- a/aws/resource_aws_amplify_backend_environment.go +++ b/aws/resource_aws_amplify_backend_environment.go @@ -3,14 +3,15 @@ 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/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/tfresource" ) func resourceAwsAmplifyBackendEnvironment() *schema.Resource { @@ -23,43 +24,38 @@ func resourceAwsAmplifyBackendEnvironment() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "arn": { - Type: schema.TypeString, - Computed: true, - }, "app_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "deployment_artifacts": { + + "arn": { Type: schema.TypeString, - Optional: true, Computed: true, - ForceNew: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 100), - validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9-]+$`), "should not contain special characters"), - ), }, + + "deployment_artifacts": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 1000), + }, + "environment_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.All( - validation.StringLenBetween(2, 10), - validation.StringMatch(regexp.MustCompile(`^[a-z]+$`), "should only contain lowercase alphabets"), - ), + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, + "stack_name": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 100), - validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9-]+$`), "should not contain special characters"), - ), + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, } @@ -67,78 +63,87 @@ func resourceAwsAmplifyBackendEnvironment() *schema.Resource { func resourceAwsAmplifyBackendEnvironmentCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Print("[DEBUG] Creating Amplify BackendEnvironment") - params := &lify.CreateBackendEnvironmentInput{ - AppId: aws.String(d.Get("app_id").(string)), - EnvironmentName: aws.String(d.Get("environment_name").(string)), + appID := d.Get("app_id").(string) + environmentName := d.Get("environment_name").(string) + id := tfamplify.BackendEnvironmentCreateResourceID(appID, environmentName) + + input := &lify.CreateBackendEnvironmentInput{ + AppId: aws.String(appID), + EnvironmentName: aws.String(environmentName), } if v, ok := d.GetOk("deployment_artifacts"); ok { - params.DeploymentArtifacts = aws.String(v.(string)) + input.DeploymentArtifacts = aws.String(v.(string)) } if v, ok := d.GetOk("stack_name"); ok { - params.StackName = aws.String(v.(string)) + input.StackName = aws.String(v.(string)) } - resp, err := conn.CreateBackendEnvironment(params) + log.Printf("[DEBUG] Creating Amplify Backend Environment: %s", input) + _, err := conn.CreateBackendEnvironment(input) + if err != nil { - return fmt.Errorf("Error creating Amplify BackendEnvironment: %s", err) + return fmt.Errorf("error creating Amplify Backend Environment (%s): %w", id, err) } - arn := *resp.BackendEnvironment.BackendEnvironmentArn - d.SetId(arn[strings.Index(arn, ":apps/")+len(":apps/"):]) + d.SetId(id) return resourceAwsAmplifyBackendEnvironmentRead(d, meta) } func resourceAwsAmplifyBackendEnvironmentRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Reading Amplify BackendEnvironment: %s", d.Id()) - s := strings.Split(d.Id(), "/") - app_id := s[0] - environment_name := s[2] + appID, environmentName, err := tfamplify.BackendEnvironmentParseResourceID(d.Id()) + + if err != nil { + return fmt.Errorf("error parsing Amplify Backend Environment ID: %w", err) + } + + backendEnvironment, err := finder.BackendEnvironmentByAppIDAndEnvironmentName(conn, appID, environmentName) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Amplify Backend Environment (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } - resp, err := conn.GetBackendEnvironment(&lify.GetBackendEnvironmentInput{ - AppId: aws.String(app_id), - EnvironmentName: aws.String(environment_name), - }) if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == amplify.ErrCodeNotFoundException { - log.Printf("[WARN] Amplify BackendEnvironment (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - return err + return fmt.Errorf("error reading Amplify Backend Environment (%s): %w", d.Id(), err) } - d.Set("app_id", app_id) - d.Set("arn", resp.BackendEnvironment.BackendEnvironmentArn) - d.Set("deployment_artifacts", resp.BackendEnvironment.DeploymentArtifacts) - d.Set("environment_name", resp.BackendEnvironment.EnvironmentName) - d.Set("stack_name", resp.BackendEnvironment.StackName) + d.Set("app_id", appID) + d.Set("arn", backendEnvironment.BackendEnvironmentArn) + d.Set("deployment_artifacts", backendEnvironment.DeploymentArtifacts) + d.Set("environment_name", backendEnvironment.EnvironmentName) + d.Set("stack_name", backendEnvironment.StackName) return nil } func resourceAwsAmplifyBackendEnvironmentDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Deleting Amplify BackendEnvironment: %s", d.Id()) - s := strings.Split(d.Id(), "/") - app_id := s[0] - environment_name := s[2] + appID, environmentName, err := tfamplify.BackendEnvironmentParseResourceID(d.Id()) + + if err != nil { + return fmt.Errorf("error parsing Amplify Backend Environment ID: %w", err) + } + + log.Printf("[DEBUG] Deleting Amplify Backend Environment: %s", d.Id()) + _, err = conn.DeleteBackendEnvironment(&lify.DeleteBackendEnvironmentInput{ + AppId: aws.String(appID), + EnvironmentName: aws.String(environmentName), + }) - params := &lify.DeleteBackendEnvironmentInput{ - AppId: aws.String(app_id), - EnvironmentName: aws.String(environment_name), + if tfawserr.ErrCodeEquals(err, amplify.ErrCodeNotFoundException) { + return nil } - _, err := conn.DeleteBackendEnvironment(params) if err != nil { - return fmt.Errorf("Error deleting Amplify BackendEnvironment: %s", err) + return fmt.Errorf("error deleting Amplify Backend Environment (%s): %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_amplify_backend_environment_test.go b/aws/resource_aws_amplify_backend_environment_test.go index 902eda55b15..d2c194c5004 100644 --- a/aws/resource_aws_amplify_backend_environment_test.go +++ b/aws/resource_aws_amplify_backend_environment_test.go @@ -1,20 +1,20 @@ 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" + "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 TestAccAWSAmplifyBackendEnvironment_basic(t *testing.T) { +func testAccAWSAmplifyBackendEnvironment_basic(t *testing.T) { var env1, env2 amplify.BackendEnvironment rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_backend_environment.test" @@ -22,7 +22,8 @@ func TestAccAWSAmplifyBackendEnvironment_basic(t *testing.T) { envName := "backend" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyBackendEnvironmentDestroy, Steps: []resource.TestStep{ @@ -30,7 +31,7 @@ func TestAccAWSAmplifyBackendEnvironment_basic(t *testing.T) { Config: testAccAWSAmplifyBackendEnvironmentConfig_Required(rName, envName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName, &env1), - resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/backendenvironments/"+envName)), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/[^/]+/backendenvironments/.+`)), resource.TestCheckResourceAttr(resourceName, "environment_name", envName), resource.TestMatchResourceAttr(resourceName, "deployment_artifacts", regexp.MustCompile(fmt.Sprintf("^tf-acc-test-.*-%s-.*-deployment$", envName))), resource.TestMatchResourceAttr(resourceName, "stack_name", regexp.MustCompile(fmt.Sprintf("^amplify-tf-acc-test-.*-%s-.*$", envName))), @@ -45,8 +46,6 @@ func TestAccAWSAmplifyBackendEnvironment_basic(t *testing.T) { Config: testAccAWSAmplifyBackendEnvironmentConfigAll(rName, envName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName, &env2), - testAccCheckAWSAmplifyBackendEnvironmentRecreated(&env1, &env2), - resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/backendenvironments/"+envName)), resource.TestCheckResourceAttr(resourceName, "environment_name", envName), resource.TestCheckResourceAttr(resourceName, "deployment_artifacts", rName), resource.TestCheckResourceAttr(resourceName, "stack_name", rName), @@ -63,69 +62,60 @@ func testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName string, v *ampl return fmt.Errorf("Not found: %s", resourceName) } - conn := testAccProvider.Meta().(*AWSClient).amplifyconn + if rs.Primary.ID == "" { + return fmt.Errorf("No Amplify Backend Environment ID is set") + } - id := strings.Split(rs.Primary.ID, "/") - app_id := id[0] - environment_name := id[2] + appID, environmentName, err := tfamplify.BackendEnvironmentParseResourceID(rs.Primary.ID) - output, err := conn.GetBackendEnvironment(&lify.GetBackendEnvironmentInput{ - AppId: aws.String(app_id), - EnvironmentName: aws.String(environment_name), - }) if err != nil { return err } - if output == nil || output.BackendEnvironment == nil { - return fmt.Errorf("Amplify BackendEnvironment (%s) not found", rs.Primary.ID) + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + + backendEnvironment, err := finder.BackendEnvironmentByAppIDAndEnvironmentName(conn, appID, environmentName) + + if err != nil { + return err } - *v = *output.BackendEnvironment + *v = *backendEnvironment return nil } } func testAccCheckAWSAmplifyBackendEnvironmentDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_amplify_backend_environment" { continue } - conn := testAccProvider.Meta().(*AWSClient).amplifyconn + appID, environmentName, err := tfamplify.BackendEnvironmentParseResourceID(rs.Primary.ID) - id := strings.Split(rs.Primary.ID, "/") - app_id := id[0] - environment_name := id[2] + if err != nil { + return err + } - _, err := conn.GetBackendEnvironment(&lify.GetBackendEnvironmentInput{ - AppId: aws.String(app_id), - EnvironmentName: aws.String(environment_name), - }) + _, err = finder.BackendEnvironmentByAppIDAndEnvironmentName(conn, appID, environmentName) - if isAWSErr(err, amplify.ErrCodeNotFoundException, "") { + if tfresource.NotFound(err) { continue } if err != nil { return err } + + return fmt.Errorf("Amplify BackendEnvironment %s still exists", rs.Primary.ID) } return nil } -func testAccCheckAWSAmplifyBackendEnvironmentRecreated(i, j *amplify.BackendEnvironment) resource.TestCheckFunc { - return func(s *terraform.State) error { - if aws.TimeValue(i.CreateTime) == aws.TimeValue(j.CreateTime) { - return errors.New("Amplify BackendEnvironment was not recreated") - } - - return nil - } -} - func testAccAWSAmplifyBackendEnvironmentConfig_Required(rName string, envName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go index 4907084c10e..1ff9c18bcf5 100644 --- a/aws/resource_aws_amplify_test.go +++ b/aws/resource_aws_amplify_test.go @@ -22,6 +22,9 @@ func TestAccAWSAmplify_serial(t *testing.T) { "Name": testAccAWSAmplifyApp_Name, "Repository": testAccAWSAmplifyApp_Repository, }, + "BackendEnvironment": { + "basic": testAccAWSAmplifyBackendEnvironment_basic, + }, } for group, m := range testCases { diff --git a/website/docs/r/amplify_app.html.markdown b/website/docs/r/amplify_app.html.markdown index 3da86a70893..a6012598850 100644 --- a/website/docs/r/amplify_app.html.markdown +++ b/website/docs/r/amplify_app.html.markdown @@ -190,7 +190,7 @@ A `production_branch` block supports the following attributes: Amplify App can be imported using Amplify App ID (appId), e.g. ``` -$ terraform import aws_amplify_app.app d2ypk4k47z8u6 +$ terraform import aws_amplify_app.example d2ypk4k47z8u6 ``` App ID can be obtained from App ARN (e.g. `arn:aws:amplify:us-east-1:12345678:apps/d2ypk4k47z8u6`). diff --git a/website/docs/r/amplify_backend_environment.html.markdown b/website/docs/r/amplify_backend_environment.html.markdown index bf8a1782673..6ba43271abb 100644 --- a/website/docs/r/amplify_backend_environment.html.markdown +++ b/website/docs/r/amplify_backend_environment.html.markdown @@ -1,28 +1,28 @@ --- -subcategory: "Amplify" +subcategory: "Amplify Console" layout: "aws" page_title: "AWS: aws_amplify_backend_environment" description: |- - Provides an Amplify backend environment resource. + Provides an Amplify Backend Environment resource. --- # Resource: aws_amplify_backend_environment -Provides an Amplify backend environment resource. +Provides an Amplify Backend Environment resource. ## Example Usage -```hcl -resource "aws_amplify_app" "app" { - name = "app" +```terraform +resource "aws_amplify_app" "example" { + name = "example" } -resource "aws_amplify_backend_environment" "prod" { - app_id = aws_amplify_app.app.id - environment_name = "prod" +resource "aws_amplify_backend_environment" "example" { + app_id = aws_amplify_app.example.id + environment_name = "example" - deployment_artifacts = "app-prod-deployment" - stack_name = "amplify-app-prod" + deployment_artifacts = "app-example-deployment" + stack_name = "amplify-app-example" } ``` @@ -30,21 +30,22 @@ resource "aws_amplify_backend_environment" "prod" { The following arguments are supported: -* `app_id` - (Required) Unique Id for an Amplify App. -* `environment_name` - (Required) Name for the backend environment. -* `deployment_artifacts` - (Optional) Name of deployment artifacts. -* `stack_name` - (Optional) CloudFormation stack name of backend environment. +* `app_id` - (Required) The unique ID for an Amplify app. +* `environment_name` - (Required) The name for the backend environment. +* `deployment_artifacts` - (Optional) The name of deployment artifacts. +* `stack_name` - (Optional) The AWS CloudFormation stack name of a backend environment. -## Attribute Reference +## Attributes Reference The following attributes are exported: -* `arn` - Arn for the backend environment. +* `arn` - The Amazon Resource Name (ARN) for a backend environment that is part of an Amplify app. +* `id` - The unique ID of the Amplify backend environment. ## Import Amplify backend environment can be imported using `app_id` and `environment_name`, e.g. ``` -$ terraform import aws_amplify_backend_environment.prod d2ypk4k47z8u6/backendenvironments/prod +$ terraform import aws_amplify_backend_environment.example d2ypk4k47z8u6/example ``` From 55c2161185ecf4d1a487d896ced97a12c1f893c8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 15:49:14 -0400 Subject: [PATCH 113/398] r/aws_amplify_backend_environment: Fix 'tfproviderdocs' errors. --- website/docs/r/amplify_app.html.markdown | 2 +- website/docs/r/amplify_backend_environment.html.markdown | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/amplify_app.html.markdown b/website/docs/r/amplify_app.html.markdown index a6012598850..5847a16116c 100644 --- a/website/docs/r/amplify_app.html.markdown +++ b/website/docs/r/amplify_app.html.markdown @@ -170,7 +170,7 @@ A `custom_rule` block supports the following arguments: ## Attributes Reference -The following attributes are exported: +In addition to all arguments above, the following attributes are exported: * `arn` - The Amazon Resource Name (ARN) of the Amplify app. * `default_domain` - The default domain for the Amplify app. diff --git a/website/docs/r/amplify_backend_environment.html.markdown b/website/docs/r/amplify_backend_environment.html.markdown index 6ba43271abb..83a7c1f1d68 100644 --- a/website/docs/r/amplify_backend_environment.html.markdown +++ b/website/docs/r/amplify_backend_environment.html.markdown @@ -37,7 +37,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 a backend environment that is part of an Amplify app. * `id` - The unique ID of the Amplify backend environment. From fbd0424f1433b0d3888c4129a9cbc6406b46f54e Mon Sep 17 00:00:00 2001 From: Will May Date: Sat, 15 May 2021 16:37:05 +0100 Subject: [PATCH 114/398] Expose the default tags configured on a provider as a data source Allow the provider `default_tags` to be exposed as a data source so that the tags can be added to other areas where they are not automatically applied, like the `volume_tags` of a `aws_instance` or the `tag_specifications` of a `aws_launch_template`. Closes #19370 --- aws/data_source_aws_default_tags.go | 23 +++++++++++ aws/data_source_aws_default_tags_test.go | 38 +++++++++++++++++ aws/provider.go | 1 + website/docs/d/default_tags.markdown | 52 ++++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 aws/data_source_aws_default_tags.go create mode 100644 aws/data_source_aws_default_tags_test.go create mode 100644 website/docs/d/default_tags.markdown diff --git a/aws/data_source_aws_default_tags.go b/aws/data_source_aws_default_tags.go new file mode 100644 index 00000000000..3c851879230 --- /dev/null +++ b/aws/data_source_aws_default_tags.go @@ -0,0 +1,23 @@ +package aws + +import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + +func dataSourceAwsDefaultTags() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsDefaultTagsRead, + + Schema: map[string]*schema.Schema{ + "tags": tagsSchemaComputed(), + }, + } +} + +func dataSourceAwsDefaultTagsRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).DefaultTagsConfig + if err := d.Set("tags", conn.Tags.Map()); err != nil { + return err + } + d.SetId(meta.(*AWSClient).partition) + + return nil +} diff --git a/aws/data_source_aws_default_tags_test.go b/aws/data_source_aws_default_tags_test.go new file mode 100644 index 00000000000..cb8b6ddb930 --- /dev/null +++ b/aws/data_source_aws_default_tags_test.go @@ -0,0 +1,38 @@ +package aws + +import ( + "testing" + + "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" +) + +func TestAWSDefaultTagsDataSource_basic(t *testing.T) { + var providers []*schema.Provider + + dataSourceName := "data.aws_default_tags.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + ProviderFactories: testAccProviderFactoriesInternal(&providers), + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAWSProviderConfigDefaultTags_Tags1("first", "value"), + testAccAWSDefaultTagsDataSource(), + ), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(dataSourceName, "tags.first", "value"), + ), + }, + }, + }) +} + +func testAccAWSDefaultTagsDataSource() string { + return `data "aws_default_tags" "test" {}` +} diff --git a/aws/provider.go b/aws/provider.go index b0cc423bedc..c58c5523273 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -226,6 +226,7 @@ func Provider() *schema.Provider { "aws_codecommit_repository": dataSourceAwsCodeCommitRepository(), "aws_codestarconnections_connection": dataSourceAwsCodeStarConnectionsConnection(), "aws_cur_report_definition": dataSourceAwsCurReportDefinition(), + "aws_default_tags": dataSourceAwsDefaultTags(), "aws_db_cluster_snapshot": dataSourceAwsDbClusterSnapshot(), "aws_db_event_categories": dataSourceAwsDbEventCategories(), "aws_db_instance": dataSourceAwsDbInstance(), diff --git a/website/docs/d/default_tags.markdown b/website/docs/d/default_tags.markdown new file mode 100644 index 00000000000..e92f80d1c57 --- /dev/null +++ b/website/docs/d/default_tags.markdown @@ -0,0 +1,52 @@ +--- +subcategory: "" +layout: "aws" +page_title: "AWS: aws_default_tags" +description: |- +Expose the default tags configured on the provider. +--- + +# Data Source: aws_default_Tags + +Use this data source to get the default tags configured on the provider. + +It is intended to be used to optionally add the default tags to resources not _directly_ managed by the Terraform +resource - such as the instances underneath an autoscaling group or the volumes created for an instance. + +## Example Usage + +```terraform +provider "aws" { + default_tags { + tags = { + Environment = "Test" + Name = "Provider Tag" + } + } +} +data "aws_default_tags" "tags" {} + +resource "aws_autoscaling_group" "group" { + # ... + dynamic "tag" { + for_each = data.aws_default_tags.tags.tags + content { + key = tag.key + value = tag.value + propagate_at_launch = true + } + } +} +``` + +## Argument Reference + +There are no arguments available for this data source. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `tags` - Any default tags set on the provider. + * `tags.#.key` - The key name of the tag. + * `tags.#.value` - The value of the tag. From b0098e52d8ba09584fc6fea58be6619c150ba392 Mon Sep 17 00:00:00 2001 From: Will May Date: Sat, 15 May 2021 16:46:33 +0100 Subject: [PATCH 115/398] Add CHANGELOG --- .changelog/19391.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19391.txt diff --git a/.changelog/19391.txt b/.changelog/19391.txt new file mode 100644 index 00000000000..d6ba5a475fd --- /dev/null +++ b/.changelog/19391.txt @@ -0,0 +1,3 @@ +```release-notes:enhancement +data-source/aws_default_tags: Add `aws_default_tags` data source to expose the `default_tags` configured on the provider +``` \ No newline at end of file From faa36ad5ff2cd68aa203fe4e6a91ec5fbb73f04c Mon Sep 17 00:00:00 2001 From: Will May Date: Sat, 15 May 2021 16:54:18 +0100 Subject: [PATCH 116/398] Changes from automated code review * Fix documentation indentation * Fix test naming * Include `IgnoreConfig` in tags --- aws/data_source_aws_default_tags.go | 3 ++- aws/data_source_aws_default_tags_test.go | 2 +- website/docs/d/default_tags.markdown | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/aws/data_source_aws_default_tags.go b/aws/data_source_aws_default_tags.go index 3c851879230..1d7a5271b03 100644 --- a/aws/data_source_aws_default_tags.go +++ b/aws/data_source_aws_default_tags.go @@ -14,7 +14,8 @@ func dataSourceAwsDefaultTags() *schema.Resource { func dataSourceAwsDefaultTagsRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).DefaultTagsConfig - if err := d.Set("tags", conn.Tags.Map()); err != nil { + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + if err := d.Set("tags", conn.Tags.IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return err } d.SetId(meta.(*AWSClient).partition) diff --git a/aws/data_source_aws_default_tags_test.go b/aws/data_source_aws_default_tags_test.go index cb8b6ddb930..3e6a96fb156 100644 --- a/aws/data_source_aws_default_tags_test.go +++ b/aws/data_source_aws_default_tags_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func TestAWSDefaultTagsDataSource_basic(t *testing.T) { +func TestAccAWSDefaultTagsDataSource_basic(t *testing.T) { var providers []*schema.Provider dataSourceName := "data.aws_default_tags.test" diff --git a/website/docs/d/default_tags.markdown b/website/docs/d/default_tags.markdown index e92f80d1c57..17893879240 100644 --- a/website/docs/d/default_tags.markdown +++ b/website/docs/d/default_tags.markdown @@ -3,7 +3,7 @@ subcategory: "" layout: "aws" page_title: "AWS: aws_default_tags" description: |- -Expose the default tags configured on the provider. + Expose the default tags configured on the provider. --- # Data Source: aws_default_Tags @@ -20,7 +20,7 @@ provider "aws" { default_tags { tags = { Environment = "Test" - Name = "Provider Tag" + Name = "Provider Tag" } } } @@ -31,8 +31,8 @@ resource "aws_autoscaling_group" "group" { dynamic "tag" { for_each = data.aws_default_tags.tags.tags content { - key = tag.key - value = tag.value + key = tag.key + value = tag.value propagate_at_launch = true } } From 1aaf9875dccff42316f669fd4cea4089ccddd738 Mon Sep 17 00:00:00 2001 From: Will May Date: Sat, 15 May 2021 17:02:19 +0100 Subject: [PATCH 117/398] Placate semgrep Ignore AWS tags that may have been set in the providers default tags --- aws/data_source_aws_default_tags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/data_source_aws_default_tags.go b/aws/data_source_aws_default_tags.go index 1d7a5271b03..86d4c842b09 100644 --- a/aws/data_source_aws_default_tags.go +++ b/aws/data_source_aws_default_tags.go @@ -15,7 +15,7 @@ func dataSourceAwsDefaultTags() *schema.Resource { func dataSourceAwsDefaultTagsRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - if err := d.Set("tags", conn.Tags.IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + if err := d.Set("tags", conn.Tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return err } d.SetId(meta.(*AWSClient).partition) From 31730091a05172681dfbcdc61dee8f3994e22fec Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 12:58:49 -0400 Subject: [PATCH 118/398] docs/ds/default_tags: Minor tweaks --- website/docs/d/default_tags.markdown | 31 +++++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/website/docs/d/default_tags.markdown b/website/docs/d/default_tags.markdown index 17893879240..c6fd19de038 100644 --- a/website/docs/d/default_tags.markdown +++ b/website/docs/d/default_tags.markdown @@ -3,18 +3,25 @@ subcategory: "" layout: "aws" page_title: "AWS: aws_default_tags" description: |- - Expose the default tags configured on the provider. + Access the default tags configured on the provider. --- # Data Source: aws_default_Tags Use this data source to get the default tags configured on the provider. -It is intended to be used to optionally add the default tags to resources not _directly_ managed by the Terraform -resource - such as the instances underneath an autoscaling group or the volumes created for an instance. +With this data source, you can apply default tags to resources not _directly_ managed by a Terraform resource, such as the instances underneath an Auto Scaling group or the volumes created for an instance. ## Example Usage +### Basic Usage + +```terraform +data "aws_default_tags" "example" {} +``` + +### Dynamically Apply Default Tags to Auto Scaling Group + ```terraform provider "aws" { default_tags { @@ -24,12 +31,13 @@ provider "aws" { } } } -data "aws_default_tags" "tags" {} -resource "aws_autoscaling_group" "group" { +data "aws_default_tags" "example" {} + +resource "aws_autoscaling_group" "example" { # ... dynamic "tag" { - for_each = data.aws_default_tags.tags.tags + for_each = data.aws_default_tags.example.tags content { key = tag.key value = tag.value @@ -41,12 +49,15 @@ resource "aws_autoscaling_group" "group" { ## Argument Reference -There are no arguments available for this data source. +This data source has no arguments. ## Attributes Reference In addition to all arguments above, the following attributes are exported: -* `tags` - Any default tags set on the provider. - * `tags.#.key` - The key name of the tag. - * `tags.#.value` - The value of the tag. +* `tags` - Blocks of default tags set on the provider. See details below. + +### tags + +* `key` - Key name of the tag (i.e., `tags.#.key`). +* `value` - Value of the tag (i.e., `tags.#.value`). From f7bef0baf3e7b8ce958740f39d7a4019b8b01509 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 12:59:52 -0400 Subject: [PATCH 119/398] docs/ds/default_tags: Minor tweak --- website/docs/d/default_tags.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/default_tags.markdown b/website/docs/d/default_tags.markdown index c6fd19de038..ea38cfcafaf 100644 --- a/website/docs/d/default_tags.markdown +++ b/website/docs/d/default_tags.markdown @@ -10,7 +10,7 @@ description: |- Use this data source to get the default tags configured on the provider. -With this data source, you can apply default tags to resources not _directly_ managed by a Terraform resource, such as the instances underneath an Auto Scaling group or the volumes created for an instance. +With this data source, you can apply default tags to resources not _directly_ managed by a Terraform resource, such as the instances underneath an Auto Scaling group or the volumes created for an EC2 instance. ## Example Usage From d11ef97f44c704ebc7b8208680ffbda2d33d99c6 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 13:02:36 -0400 Subject: [PATCH 120/398] ds/default_tags: Clean up changelog --- .changelog/19391.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changelog/19391.txt b/.changelog/19391.txt index d6ba5a475fd..113f81bf3fc 100644 --- a/.changelog/19391.txt +++ b/.changelog/19391.txt @@ -1,3 +1,3 @@ -```release-notes:enhancement -data-source/aws_default_tags: Add `aws_default_tags` data source to expose the `default_tags` configured on the provider +```release-notes:new-data-source +aws_default_tags ``` \ No newline at end of file From 49b4ca9d2566ff1c06f298825f08b108fe17ff7e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 13:27:01 -0400 Subject: [PATCH 121/398] ds/default_tags: Fix nil pointer panic --- aws/data_source_aws_default_tags.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/aws/data_source_aws_default_tags.go b/aws/data_source_aws_default_tags.go index 86d4c842b09..7f8cbf81087 100644 --- a/aws/data_source_aws_default_tags.go +++ b/aws/data_source_aws_default_tags.go @@ -13,12 +13,18 @@ func dataSourceAwsDefaultTags() *schema.Resource { } func dataSourceAwsDefaultTagsRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).DefaultTagsConfig + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - if err := d.Set("tags", conn.Tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + + d.SetId(meta.(*AWSClient).partition) + + if defaultTagsConfig == nil || defaultTagsConfig.Tags == nil { + return nil + } + + if err := d.Set("tags", defaultTagsConfig.Tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return err } - d.SetId(meta.(*AWSClient).partition) return nil } From a7f8304c13305e699c00b27011212a705aa89d9a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 13:27:22 -0400 Subject: [PATCH 122/398] tests/ds/default_tags: Test a bit more --- aws/data_source_aws_default_tags_test.go | 50 ++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/aws/data_source_aws_default_tags_test.go b/aws/data_source_aws_default_tags_test.go index 3e6a96fb156..7f14c7a4e7a 100644 --- a/aws/data_source_aws_default_tags_test.go +++ b/aws/data_source_aws_default_tags_test.go @@ -33,6 +33,56 @@ func TestAccAWSDefaultTagsDataSource_basic(t *testing.T) { }) } +func TestAccAWSDefaultTagsDataSource_empty(t *testing.T) { + var providers []*schema.Provider + + dataSourceName := "data.aws_default_tags.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + ProviderFactories: testAccProviderFactoriesInternal(&providers), + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAWSProviderConfigDefaultTags_Tags0(), + testAccAWSDefaultTagsDataSource(), + ), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "0"), + ), + }, + }, + }) +} + +func TestAccAWSDefaultTagsDataSource_multiple(t *testing.T) { + var providers []*schema.Provider + + dataSourceName := "data.aws_default_tags.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + ProviderFactories: testAccProviderFactoriesInternal(&providers), + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAWSProviderConfigDefaultTags_Tags2("nuera", "hijo", "escalofrios", "calambres"), + testAccAWSDefaultTagsDataSource(), + ), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(dataSourceName, "tags.nuera", "hijo"), + resource.TestCheckResourceAttr(dataSourceName, "tags.escalofrios", "calambres"), + ), + }, + }, + }) +} + func testAccAWSDefaultTagsDataSource() string { return `data "aws_default_tags" "test" {}` } From 53f65ffb6d4ea1c1434c8799a5468247baf74732 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 16:36:39 -0400 Subject: [PATCH 123/398] ds/default_tags: Refine empty logic --- aws/data_source_aws_default_tags.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/data_source_aws_default_tags.go b/aws/data_source_aws_default_tags.go index 7f8cbf81087..f4f96f0e8cd 100644 --- a/aws/data_source_aws_default_tags.go +++ b/aws/data_source_aws_default_tags.go @@ -18,12 +18,12 @@ func dataSourceAwsDefaultTagsRead(d *schema.ResourceData, meta interface{}) erro d.SetId(meta.(*AWSClient).partition) - if defaultTagsConfig == nil || defaultTagsConfig.Tags == nil { - return nil - } - - if err := d.Set("tags", defaultTagsConfig.Tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return err + if defaultTagsConfig != nil && defaultTagsConfig.Tags != nil { + if err := d.Set("tags", defaultTagsConfig.Tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return err + } + } else { + d.Set("tags", nil) } return nil From 390dcadd951bc37488cbd05b6a189208697cd80e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 17:02:33 -0400 Subject: [PATCH 124/398] ds/default_tags: Clean up logic, add test --- aws/data_source_aws_default_tags.go | 20 +++++++++----- aws/data_source_aws_default_tags_test.go | 34 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/aws/data_source_aws_default_tags.go b/aws/data_source_aws_default_tags.go index f4f96f0e8cd..2b2f9e323c6 100644 --- a/aws/data_source_aws_default_tags.go +++ b/aws/data_source_aws_default_tags.go @@ -1,6 +1,10 @@ package aws -import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) func dataSourceAwsDefaultTags() *schema.Resource { return &schema.Resource{ @@ -18,12 +22,14 @@ func dataSourceAwsDefaultTagsRead(d *schema.ResourceData, meta interface{}) erro d.SetId(meta.(*AWSClient).partition) - if defaultTagsConfig != nil && defaultTagsConfig.Tags != nil { - if err := d.Set("tags", defaultTagsConfig.Tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return err - } - } else { - d.Set("tags", nil) + tags := defaultTagsConfig.GetTags() + + if len(tags) > 0 { + tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) + } + + if err := d.Set("tags", tags.Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) } return nil diff --git a/aws/data_source_aws_default_tags_test.go b/aws/data_source_aws_default_tags_test.go index 7f14c7a4e7a..f7d1a0625b3 100644 --- a/aws/data_source_aws_default_tags_test.go +++ b/aws/data_source_aws_default_tags_test.go @@ -83,6 +83,40 @@ func TestAccAWSDefaultTagsDataSource_multiple(t *testing.T) { }) } +func TestAccAWSDefaultTagsDataSource_ignore(t *testing.T) { + var providers []*schema.Provider + + dataSourceName := "data.aws_default_tags.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + ProviderFactories: testAccProviderFactoriesInternal(&providers), + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAWSProviderConfigDefaultTags_Tags1("Tabac", "Louis Chiron"), + testAccAWSDefaultTagsDataSource(), + ), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(dataSourceName, "tags.Tabac", "Louis Chiron"), + ), + }, + { + Config: composeConfig( + testAccProviderConfigDefaultAndIgnoreTagsKeys1("Tabac", "Louis Chiron"), + testAccAWSDefaultTagsDataSource(), + ), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "0"), + ), + }, + }, + }) +} + func testAccAWSDefaultTagsDataSource() string { return `data "aws_default_tags" "test" {}` } From 0051a610b230cfa85ea1a6cd983ee640a2578527 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 17:12:38 -0400 Subject: [PATCH 125/398] ds/default_tags: Placate semgrep --- aws/data_source_aws_default_tags.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/data_source_aws_default_tags.go b/aws/data_source_aws_default_tags.go index 2b2f9e323c6..750359f41ed 100644 --- a/aws/data_source_aws_default_tags.go +++ b/aws/data_source_aws_default_tags.go @@ -24,12 +24,12 @@ func dataSourceAwsDefaultTagsRead(d *schema.ResourceData, meta interface{}) erro tags := defaultTagsConfig.GetTags() - if len(tags) > 0 { - tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) - } - - if err := d.Set("tags", tags.Map()); err != nil { - return fmt.Errorf("error setting tags: %w", err) + if tags != nil { + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + } else { + d.Set("tags", nil) } return nil From 7ae70e4536dce3d2aae9f642e22a5398ce4cfaef Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 17:28:16 -0400 Subject: [PATCH 126/398] Add CHANGELOG entry. --- .changelog/11936.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/11936.txt diff --git a/.changelog/11936.txt b/.changelog/11936.txt new file mode 100644 index 00000000000..0657ce4442c --- /dev/null +++ b/.changelog/11936.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_amplify_backend_environment +``` \ No newline at end of file From f14bb422f0daa22d122e190e1a67ba01d4cf9396 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 21 May 2021 17:29:02 -0400 Subject: [PATCH 127/398] r/aws_amplify_backend_environment: Get all tests passing. --- ...esource_aws_amplify_backend_environment.go | 7 +- ...ce_aws_amplify_backend_environment_test.go | 90 ++++++++++++++----- aws/resource_aws_amplify_test.go | 4 +- 3 files changed, 77 insertions(+), 24 deletions(-) diff --git a/aws/resource_aws_amplify_backend_environment.go b/aws/resource_aws_amplify_backend_environment.go index e1221b0bb27..d6bbc90950f 100644 --- a/aws/resource_aws_amplify_backend_environment.go +++ b/aws/resource_aws_amplify_backend_environment.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" @@ -40,14 +41,14 @@ func resourceAwsAmplifyBackendEnvironment() *schema.Resource { Optional: true, Computed: true, ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 1000), + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[0-9A-Za-z-]{1,100}$`), "should be not be more than 100 alphanumeric or hyphen characters"), }, "environment_name": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 255), + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[a-z]{2,10}$`), "should be between 2 and 10 characters (only lowercase alphabetic)"), }, "stack_name": { @@ -55,7 +56,7 @@ func resourceAwsAmplifyBackendEnvironment() *schema.Resource { Optional: true, Computed: true, ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 255), + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[0-9A-Za-z-]{1,100}$`), "should be not be more than 100 alphanumeric or hyphen characters"), }, }, } diff --git a/aws/resource_aws_amplify_backend_environment_test.go b/aws/resource_aws_amplify_backend_environment_test.go index d2c194c5004..8d3b590463b 100644 --- a/aws/resource_aws_amplify_backend_environment_test.go +++ b/aws/resource_aws_amplify_backend_environment_test.go @@ -15,11 +15,11 @@ import ( ) func testAccAWSAmplifyBackendEnvironment_basic(t *testing.T) { - var env1, env2 amplify.BackendEnvironment + var env amplify.BackendEnvironment rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_backend_environment.test" - envName := "backend" + environmentName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, @@ -28,13 +28,13 @@ func testAccAWSAmplifyBackendEnvironment_basic(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyBackendEnvironmentDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyBackendEnvironmentConfig_Required(rName, envName), + Config: testAccAWSAmplifyBackendEnvironmentConfigBasic(rName, environmentName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName, &env1), + testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName, &env), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/[^/]+/backendenvironments/.+`)), - resource.TestCheckResourceAttr(resourceName, "environment_name", envName), - resource.TestMatchResourceAttr(resourceName, "deployment_artifacts", regexp.MustCompile(fmt.Sprintf("^tf-acc-test-.*-%s-.*-deployment$", envName))), - resource.TestMatchResourceAttr(resourceName, "stack_name", regexp.MustCompile(fmt.Sprintf("^amplify-tf-acc-test-.*-%s-.*$", envName))), + resource.TestCheckResourceAttrSet(resourceName, "deployment_artifacts"), + resource.TestCheckResourceAttr(resourceName, "environment_name", environmentName), + resource.TestCheckResourceAttrSet(resourceName, "stack_name"), ), }, { @@ -42,19 +42,69 @@ func testAccAWSAmplifyBackendEnvironment_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + }, + }) +} + +func testAccAWSAmplifyBackendEnvironment_disappears(t *testing.T) { + var env amplify.BackendEnvironment + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_backend_environment.test" + + environmentName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBackendEnvironmentDestroy, + Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyBackendEnvironmentConfigAll(rName, envName), + Config: testAccAWSAmplifyBackendEnvironmentConfigBasic(rName, environmentName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName, &env2), - resource.TestCheckResourceAttr(resourceName, "environment_name", envName), + testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName, &env), + testAccCheckResourceDisappears(testAccProvider, resourceAwsAmplifyBackendEnvironment(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccAWSAmplifyBackendEnvironment_DeploymentArtifacts_StackName(t *testing.T) { + var env amplify.BackendEnvironment + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_backend_environment.test" + + environmentName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBackendEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBackendEnvironmentConfigDeploymentArtifactsAndStackName(rName, environmentName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName, &env), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/[^/]+/backendenvironments/.+`)), resource.TestCheckResourceAttr(resourceName, "deployment_artifacts", rName), + resource.TestCheckResourceAttr(resourceName, "environment_name", environmentName), resource.TestCheckResourceAttr(resourceName, "stack_name", rName), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } +// testAccAWSAmplifyBackendEnvironmentConfigDeploymentArtifactsAndStackName(rname, environmentName) + func testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName string, v *amplify.BackendEnvironment) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -116,31 +166,31 @@ func testAccCheckAWSAmplifyBackendEnvironmentDestroy(s *terraform.State) error { return nil } -func testAccAWSAmplifyBackendEnvironmentConfig_Required(rName string, envName string) string { +func testAccAWSAmplifyBackendEnvironmentConfigBasic(rName string, environmentName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q } resource "aws_amplify_backend_environment" "test" { app_id = aws_amplify_app.test.id - environment_name = "%s" + environment_name = %[2]q } -`, rName, envName) +`, rName, environmentName) } -func testAccAWSAmplifyBackendEnvironmentConfigAll(rName string, envName string) string { +func testAccAWSAmplifyBackendEnvironmentConfigDeploymentArtifactsAndStackName(rName string, environmentName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q } resource "aws_amplify_backend_environment" "test" { app_id = aws_amplify_app.test.id - environment_name = "%s" + environment_name = %[2]q - deployment_artifacts = "%s" - stack_name = "%s" + deployment_artifacts = %[1]q + stack_name = %[1]q } -`, rName, envName, rName, rName) +`, rName, environmentName) } diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go index 1ff9c18bcf5..46f5fab6279 100644 --- a/aws/resource_aws_amplify_test.go +++ b/aws/resource_aws_amplify_test.go @@ -23,7 +23,9 @@ func TestAccAWSAmplify_serial(t *testing.T) { "Repository": testAccAWSAmplifyApp_Repository, }, "BackendEnvironment": { - "basic": testAccAWSAmplifyBackendEnvironment_basic, + "basic": testAccAWSAmplifyBackendEnvironment_basic, + "disappears": testAccAWSAmplifyBackendEnvironment_disappears, + "DeploymentArtifacts_StackName": testAccAWSAmplifyBackendEnvironment_DeploymentArtifacts_StackName, }, } From 1c840ba2ab9ff2a5a14c0d5fd93e2d2e5ed78ada Mon Sep 17 00:00:00 2001 From: changelogbot Date: Fri, 21 May 2021 21:48:12 +0000 Subject: [PATCH 128/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cdfaadf4cd..0c5080d3ff6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ FEATURES: * **New Resource:** `aws_amplify_app` ([#15966](https://github.com/hashicorp/terraform-provider-aws/issues/15966)) +* **New Resource:** `aws_amplify_backend_environment` ([#11936](https://github.com/hashicorp/terraform-provider-aws/issues/11936)) * **New Resource:** `aws_servicecatalog_budget_resource_association` ([#19452](https://github.com/hashicorp/terraform-provider-aws/issues/19452)) * **New Resource:** `aws_servicecatalog_provisioning_artifact` ([#19316](https://github.com/hashicorp/terraform-provider-aws/issues/19316)) * **New Resource:** `aws_servicecatalog_tag_option_resource_association` ([#19448](https://github.com/hashicorp/terraform-provider-aws/issues/19448)) From 0b7a1cd1665e21d037c8304de273377778bb5172 Mon Sep 17 00:00:00 2001 From: david7482 Date: Mon, 24 May 2021 03:50:03 +0800 Subject: [PATCH 129/398] resource/aws_eks_node_group: added support for taints --- aws/resource_aws_eks_node_group.go | 162 +++++++++++++++++++- aws/resource_aws_eks_node_group_test.go | 128 ++++++++++++++++ website/docs/r/eks_node_group.html.markdown | 7 + 3 files changed, 296 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_eks_node_group.go b/aws/resource_aws_eks_node_group.go index 7f4f9b7c62f..80f8a5353b9 100644 --- a/aws/resource_aws_eks_node_group.go +++ b/aws/resource_aws_eks_node_group.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "reflect" "strings" "time" @@ -219,6 +220,30 @@ func resourceAwsEksNodeGroup() *schema.Resource { }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), + "taints": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 50, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 63), + }, + "value": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 63), + }, + "effect": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(eks.TaintEffect_Values(), false), + }, + }, + }, + }, "version": { Type: schema.TypeString, Optional: true, @@ -283,6 +308,10 @@ func resourceAwsEksNodeGroupCreate(d *schema.ResourceData, meta interface{}) err input.Tags = tags.IgnoreAws().EksTags() } + if v, ok := d.GetOk("taints"); ok && v.(*schema.Set).Len() > 0 { + input.Taints = expandEksTaints(v.(*schema.Set).List()) + } + if v, ok := d.GetOk("version"); ok { input.Version = aws.String(v.(string)) } @@ -396,6 +425,10 @@ func resourceAwsEksNodeGroupRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error setting tags_all: %w", err) } + if err := d.Set("taints", flattenEksTaints(nodeGroup.Taints)); err != nil { + return fmt.Errorf("error setting taints: %w", err) + } + d.Set("version", nodeGroup.Version) return nil @@ -410,7 +443,7 @@ func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) err return err } - if d.HasChanges("labels", "scaling_config") { + if d.HasChanges("labels", "scaling_config", "taints") { oldLabelsRaw, newLabelsRaw := d.GetChange("labels") input := &eks.UpdateNodegroupConfigInput{ @@ -424,6 +457,9 @@ func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) err input.ScalingConfig = expandEksNodegroupScalingConfig(v) } + oldTaintsRaw, newTaintsRaw := d.GetChange("taints") + input.Taints = expandEksUpdateTaintsPayload(oldTaintsRaw.(*schema.Set).List(), newTaintsRaw.(*schema.Set).List()) + output, err := conn.UpdateNodegroupConfig(input) if err != nil { @@ -585,6 +621,108 @@ func expandEksNodegroupScalingConfig(l []interface{}) *eks.NodegroupScalingConfi return config } +func expandEksTaints(l []interface{}) []*eks.Taint { + if len(l) == 0 { + return nil + } + + var taints []*eks.Taint + + for _, raw := range l { + t, ok := raw.(map[string]interface{}) + + if !ok { + continue + } + + taint := &eks.Taint{} + + if k, ok := t["key"].(string); ok { + taint.Key = aws.String(k) + } + + if v, ok := t["value"].(string); ok { + taint.Value = aws.String(v) + } + + if e, ok := t["effect"].(string); ok { + taint.Effect = aws.String(e) + } + + taints = append(taints, taint) + } + + return taints +} + +func expandEksUpdateTaintsPayload(oldTaintsRaw, newTaintsRaw []interface{}) *eks.UpdateTaintsPayload { + oldTaints := expandEksTaints(oldTaintsRaw) + newTaints := expandEksTaints(newTaintsRaw) + + var removedTaints []*eks.Taint + for _, ot := range oldTaints { + if ot == nil { + continue + } + + removed := true + for _, nt := range newTaints { + if nt == nil { + continue + } + + // if both taint.key and taint.effect are the same, we don't need to remove it. + if aws.StringValue(nt.Key) == aws.StringValue(ot.Key) && + aws.StringValue(nt.Effect) == aws.StringValue(ot.Effect) { + removed = false + break + } + } + + if removed { + removedTaints = append(removedTaints, ot) + } + } + + var updatedTaints []*eks.Taint + for _, nt := range newTaints { + if nt == nil { + continue + } + + updated := true + for _, ot := range oldTaints { + if nt == nil { + continue + } + + if reflect.DeepEqual(nt, ot) { + updated = false + break + } + } + if updated { + updatedTaints = append(updatedTaints, nt) + } + } + + if len(removedTaints) == 0 && len(updatedTaints) == 0 { + return nil + } + + updateTaintsPayload := &eks.UpdateTaintsPayload{} + + if len(removedTaints) > 0 { + updateTaintsPayload.RemoveTaints = removedTaints + } + + if len(updatedTaints) > 0 { + updateTaintsPayload.AddOrUpdateTaints = updatedTaints + } + + return updateTaintsPayload +} + func expandEksRemoteAccessConfig(l []interface{}) *eks.RemoteAccessConfig { if len(l) == 0 || l[0] == nil { return nil @@ -710,6 +848,28 @@ func flattenEksRemoteAccessConfig(config *eks.RemoteAccessConfig) []map[string]i return []map[string]interface{}{m} } +func flattenEksTaints(taints []*eks.Taint) []interface{} { + if len(taints) == 0 { + return nil + } + + var results []interface{} + + for _, taint := range taints { + if taint == nil { + continue + } + + t := make(map[string]interface{}) + t["key"] = aws.StringValue(taint.Key) + t["value"] = aws.StringValue(taint.Value) + t["effect"] = aws.StringValue(taint.Effect) + + results = append(results, t) + } + return results +} + func refreshEksNodeGroupStatus(conn *eks.EKS, clusterName string, nodeGroupName string) resource.StateRefreshFunc { return func() (interface{}, string, error) { input := &eks.DescribeNodegroupInput{ diff --git a/aws/resource_aws_eks_node_group_test.go b/aws/resource_aws_eks_node_group_test.go index b381cba9598..8dc80d6e5a3 100644 --- a/aws/resource_aws_eks_node_group_test.go +++ b/aws/resource_aws_eks_node_group_test.go @@ -126,6 +126,7 @@ func TestAccAWSEksNodeGroup_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "status", eks.NodegroupStatusActive), resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "2"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "taints.#", "0"), resource.TestCheckResourceAttrPair(resourceName, "version", eksClusterResourceName, "version"), ), }, @@ -818,6 +819,69 @@ func TestAccAWSEksNodeGroup_Tags(t *testing.T) { }) } +func TestAccAWSEksNodeGroup_Taints(t *testing.T) { + var nodeGroup1 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: testAccAWSEksNodeGroupConfigTaints1(rName, "key1", "value1", "NO_SCHEDULE"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup1), + resource.TestCheckResourceAttr(resourceName, "taints.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taints.*", map[string]string{ + "key": "key1", + "value": "value1", + "effect": "NO_SCHEDULE", + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSEksNodeGroupConfigTaints2(rName, + "key1", "value1updated", "NO_EXECUTE", + "key2", "value2", "NO_SCHEDULE"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup1), + resource.TestCheckResourceAttr(resourceName, "taints.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taints.*", map[string]string{ + "key": "key1", + "value": "value1updated", + "effect": "NO_EXECUTE", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taints.*", map[string]string{ + "key": "key2", + "value": "value2", + "effect": "NO_SCHEDULE", + }), + ), + }, + { + Config: testAccAWSEksNodeGroupConfigTaints1(rName, "key2", "value2", "NO_SCHEDULE"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup1), + resource.TestCheckResourceAttr(resourceName, "taints.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taints.*", map[string]string{ + "key": "key2", + "value": "value2", + "effect": "NO_SCHEDULE", + }), + ), + }, + }, + }) +} + func TestAccAWSEksNodeGroup_Version(t *testing.T) { var nodeGroup1, nodeGroup2 eks.Nodegroup rName := acctest.RandomWithPrefix("tf-acc-test") @@ -1900,6 +1964,70 @@ resource "aws_eks_node_group" "test" { `, rName, tagKey1, tagValue1, tagKey2, tagValue2)) } +func testAccAWSEksNodeGroupConfigTaints1(rName, taintKey1, taintValue1, taintEffect1 string) string { + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` +resource "aws_eks_node_group" "test" { + cluster_name = aws_eks_cluster.test.name + node_group_name = %[1]q + node_role_arn = aws_iam_role.node.arn + subnet_ids = aws_subnet.test[*].id + + taints { + key = %[2]q + value = %[3]q + effect = %[4]q + } + + scaling_config { + desired_size = 1 + max_size = 1 + min_size = 1 + } + + depends_on = [ + aws_iam_role_policy_attachment.node-AmazonEKSWorkerNodePolicy, + aws_iam_role_policy_attachment.node-AmazonEKS_CNI_Policy, + aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, + ] +} +`, rName, taintKey1, taintValue1, taintEffect1)) +} + +func testAccAWSEksNodeGroupConfigTaints2(rName, taintKey1, taintValue1, taintEffect1, taintKey2, taintValue2, taintEffect2 string) string { + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` +resource "aws_eks_node_group" "test" { + cluster_name = aws_eks_cluster.test.name + node_group_name = %[1]q + node_role_arn = aws_iam_role.node.arn + subnet_ids = aws_subnet.test[*].id + + taints { + key = %[2]q + value = %[3]q + effect = %[4]q + } + + taints { + key = %[5]q + value = %[6]q + effect = %[7]q + } + + scaling_config { + desired_size = 1 + max_size = 1 + min_size = 1 + } + + depends_on = [ + aws_iam_role_policy_attachment.node-AmazonEKSWorkerNodePolicy, + aws_iam_role_policy_attachment.node-AmazonEKS_CNI_Policy, + aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, + ] +} +`, rName, taintKey1, taintValue1, taintEffect1, taintKey2, taintValue2, taintEffect2)) +} + func testAccAWSEksNodeGroupConfigVersion(rName, version string) string { return composeConfig(testAccAWSEksNodeGroupConfigBaseVersion(rName, version), fmt.Sprintf(` resource "aws_eks_node_group" "test" { diff --git a/website/docs/r/eks_node_group.html.markdown b/website/docs/r/eks_node_group.html.markdown index e021880b5c8..5e7c676ceaf 100644 --- a/website/docs/r/eks_node_group.html.markdown +++ b/website/docs/r/eks_node_group.html.markdown @@ -134,6 +134,7 @@ The following arguments are optional: * `release_version` – (Optional) AMI version of the EKS Node Group. Defaults to latest version for Kubernetes version. * `remote_access` - (Optional) Configuration block with remote access settings. 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. +* `taints` - (Optional) The Kubernetes taints to be applied to the nodes in the node group. Maximum of 50 taints per node group. Detailed below. * `version` – (Optional) Kubernetes version. Defaults to EKS Cluster Kubernetes version. Terraform will only perform drift detection if a configuration value is provided. ### launch_template Configuration Block @@ -155,6 +156,12 @@ The following arguments are optional: * `max_size` - (Required) Maximum number of worker nodes. * `min_size` - (Required) Minimum number of worker nodes. +### taints Configuration Block + +* `key` - (Required) The key of the taint. Maximum length of 63. +* `value` - (Optional) The value of the taint. Maximum length of 63. +* `effect` - (Required) The effect of the taint. Valid values: `NO_SCHEDULE`, `NO_EXECUTE`, `PREFER_NO_SCHEDULE`. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From 463d39bdca19d17b91a882b7bd7588bfdbf7def7 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Sun, 23 May 2021 16:37:13 -0400 Subject: [PATCH 130/398] fix resource creation with instance role and instance_configuration --- .changelog/19483.txt | 7 +++ aws/resource_aws_apprunner_service.go | 32 ++++++++++- aws/resource_aws_apprunner_service_test.go | 67 +++++++++------------- 3 files changed, 64 insertions(+), 42 deletions(-) create mode 100644 .changelog/19483.txt diff --git a/.changelog/19483.txt b/.changelog/19483.txt new file mode 100644 index 00000000000..be4cf576068 --- /dev/null +++ b/.changelog/19483.txt @@ -0,0 +1,7 @@ +```release-note:bug +resource/aws_apprunner_service: Handle asynchronous IAM eventual consistency error on creation +``` + +```release-note:bug +resource/aws_apprunner_service: Suppress `instance_configuration` `cpu` and `memory` differences +``` diff --git a/aws/resource_aws_apprunner_service.go b/aws/resource_aws_apprunner_service.go index e953e03f08f..7021e786e4c 100644 --- a/aws/resource_aws_apprunner_service.go +++ b/aws/resource_aws_apprunner_service.go @@ -10,10 +10,13 @@ import ( "github.com/aws/aws-sdk-go/service/apprunner" "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" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apprunner/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 resourceAwsAppRunnerService() *schema.Resource { @@ -123,6 +126,10 @@ func resourceAwsAppRunnerService() *schema.Resource { Optional: true, Default: "1024", ValidateFunc: validation.StringMatch(regexp.MustCompile(`1024|2048|(1|2) vCPU`), ""), + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // App Runner API always returns the amount in multiples of 1024 units + return (old == "1024" && new == "1 vCPU") || (old == "2048" && new == "2 vCPU") + }, }, "instance_role_arn": { Type: schema.TypeString, @@ -134,6 +141,10 @@ func resourceAwsAppRunnerService() *schema.Resource { Optional: true, Default: "2048", ValidateFunc: validation.StringMatch(regexp.MustCompile(`2048|3072|4096|(2|3|4) GB`), ""), + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // App Runner API always returns the amount in MB + return (old == "2048" && new == "2 GB") || (old == "3072" && new == "3 GB") || (old == "4096" && new == "4 GB") + }, }, }, }, @@ -366,7 +377,26 @@ func resourceAwsAppRunnerServiceCreate(ctx context.Context, d *schema.ResourceDa input.InstanceConfiguration = expandAppRunnerServiceInstanceConfiguration(v.([]interface{})) } - output, err := conn.CreateServiceWithContext(ctx, input) + var output *apprunner.CreateServiceOutput + + err := resource.RetryContext(ctx, iamwaiter.PropagationTimeout, func() *resource.RetryError { + var err error + output, err = conn.CreateServiceWithContext(ctx, input) + + if tfawserr.ErrMessageContains(err, apprunner.ErrCodeInvalidRequestException, "Error in assuming instance role") { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + output, err = conn.CreateServiceWithContext(ctx, input) + } if err != nil { return diag.FromErr(fmt.Errorf("error creating App Runner Service (%s): %w", serviceName, err)) diff --git a/aws/resource_aws_apprunner_service_test.go b/aws/resource_aws_apprunner_service_test.go index 434c3692655..aaa707882aa 100644 --- a/aws/resource_aws_apprunner_service_test.go +++ b/aws/resource_aws_apprunner_service_test.go @@ -93,6 +93,21 @@ func TestAccAwsAppRunnerService_ImageRepository_basic(t *testing.T) { testAccCheckAwsAppRunnerServiceExists(resourceName), resource.TestCheckResourceAttr(resourceName, "service_name", rName), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "apprunner", regexp.MustCompile(fmt.Sprintf(`service/%s/.+`, rName))), + testAccMatchResourceAttrRegionalARN(resourceName, "auto_scaling_configuration_arn", "apprunner", regexp.MustCompile(`autoscalingconfiguration/DefaultConfiguration/1/.+`)), + resource.TestCheckResourceAttr(resourceName, "health_check_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "health_check_configuration.0.protocol", apprunner.HealthCheckProtocolTcp), + resource.TestCheckResourceAttr(resourceName, "health_check_configuration.0.path", "/"), + // Only check the following attribute values for health_check and instance configurations + // are set as their defaults differ in the API documentation and API itself + resource.TestCheckResourceAttrSet(resourceName, "health_check_configuration.0.interval"), + resource.TestCheckResourceAttrSet(resourceName, "health_check_configuration.0.timeout"), + resource.TestCheckResourceAttrSet(resourceName, "health_check_configuration.0.healthy_threshold"), + resource.TestCheckResourceAttrSet(resourceName, "health_check_configuration.0.unhealthy_threshold"), + resource.TestCheckResourceAttr(resourceName, "instance_configuration.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "instance_configuration.0.cpu"), + resource.TestCheckResourceAttrSet(resourceName, "instance_configuration.0.memory"), + resource.TestCheckResourceAttrSet(resourceName, "service_id"), + resource.TestCheckResourceAttrSet(resourceName, "service_url"), resource.TestCheckResourceAttr(resourceName, "source_configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "source_configuration.0.auto_deployments_enabled", "false"), resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.#", "1"), @@ -100,6 +115,8 @@ func TestAccAwsAppRunnerService_ImageRepository_basic(t *testing.T) { 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_repository_type", apprunner.ImageRepositoryTypeEcrPublic), + resource.TestCheckResourceAttr(resourceName, "status", apprunner.ServiceStatusRunning), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -245,9 +262,9 @@ func TestAccAwsAppRunnerService_ImageRepository_InstanceConfiguration(t *testing Check: resource.ComposeTestCheckFunc( testAccCheckAwsAppRunnerServiceExists(resourceName), resource.TestCheckResourceAttr(resourceName, "instance_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.cpu", "1 vCPU"), + resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.cpu", "1024"), resource.TestCheckResourceAttrPair(resourceName, "instance_configuration.0.instance_role_arn", roleResourceName, "arn"), - resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.memory", "3 GB"), + resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.memory", "3072"), ), }, { @@ -260,7 +277,7 @@ func TestAccAwsAppRunnerService_ImageRepository_InstanceConfiguration(t *testing Check: resource.ComposeTestCheckFunc( testAccCheckAwsAppRunnerServiceExists(resourceName), resource.TestCheckResourceAttr(resourceName, "instance_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.cpu", "2 vCPU"), + resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.cpu", "2048"), resource.TestCheckResourceAttrPair(resourceName, "instance_configuration.0.instance_role_arn", roleResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.memory", "4096"), ), @@ -274,7 +291,9 @@ func TestAccAwsAppRunnerService_ImageRepository_InstanceConfiguration(t *testing Config: testAccAppRunnerService_imageRepository(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAppRunnerServiceExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "instance_configuration.#", "0"), + resource.TestCheckResourceAttr(resourceName, "instance_configuration.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "instance_configuration.0.cpu"), + resource.TestCheckResourceAttrSet(resourceName, "instance_configuration.0.memory"), ), }, }, @@ -560,48 +579,14 @@ resource "aws_iam_role" "test" { "Sid": "", "Effect": "Allow", "Principal": { - "Service": [ - "apprunner.${data.aws_partition.current.dns_suffix}" - ] + "Service": "tasks.apprunner.${data.aws_partition.current.dns_suffix}" }, - "Action": [ - "sts:AssumeRole" - ] + "Action": "sts:AssumeRole" } ] } EOF } - -resource "aws_iam_policy" "test" { - name = %[1]q - path = "/" - description = "App Runner PassRole Policy" - - policy = < Date: Mon, 24 May 2021 06:36:05 +0000 Subject: [PATCH 131/398] build(deps): bump hashicorp/github in /infrastructure/repository Bumps [hashicorp/github](https://github.com/hashicorp/terraform-provider-github) from 4.9.4 to 4.10.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) 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 0f72141b88d..2cb5ab673fa 100644 --- a/infrastructure/repository/main.tf +++ b/infrastructure/repository/main.tf @@ -10,7 +10,7 @@ terraform { required_providers { github = { source = "hashicorp/github" - version = "4.9.4" + version = "4.10.0" } } From 8678068aa899b814b5339ee792ba62e08cb554e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 06:43:37 +0000 Subject: [PATCH 132/398] build(deps): bump github.com/aws/aws-sdk-go from 1.38.43 to 1.38.45 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.43 to 1.38.45. - [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.43...v1.38.45) 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 c83c116f129..26ef4188b60 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.43 + github.com/aws/aws-sdk-go v1.38.45 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 1116bb7e0f3..005c8328e2b 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.43 h1:OKe9+Cdmrkhe0KXgpKhrDqidPhXQ4bv1FzzKnrmTJ5g= -github.com/aws/aws-sdk-go v1.38.43/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.45 h1:pQmv1vT/voRAjENnPsT4WobFBgLwnODDFogrt2kXc7M= +github.com/aws/aws-sdk-go v1.38.45/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 72f0d982ccf894f2eff33eac3e59d02d938bddca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 06:44:45 +0000 Subject: [PATCH 133/398] 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.43 to 1.38.45. - [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.43...v1.38.45) Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 +- .../aws/aws-sdk-go/aws/endpoints/defaults.go | 12 + .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- .../aws/aws-sdk-go/service/s3/api.go | 238 +++++++++--------- awsproviderlint/vendor/modules.txt | 2 +- 6 files changed, 140 insertions(+), 120 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 18aae82fc02..3d8806a94e3 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.43 + github.com/aws/aws-sdk-go v1.38.45 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 ee93f351187..83d9a8da77a 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.43 h1:OKe9+Cdmrkhe0KXgpKhrDqidPhXQ4bv1FzzKnrmTJ5g= -github.com/aws/aws-sdk-go v1.38.43/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.45 h1:pQmv1vT/voRAjENnPsT4WobFBgLwnODDFogrt2kXc7M= +github.com/aws/aws-sdk-go v1.38.45/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 b927bd350a6..961d40f8b32 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 @@ -837,6 +837,16 @@ var awsPartition = partition{ "us-west-2": endpoint{}, }, }, + "apprunner": service{ + + Endpoints: endpoints{ + "ap-northeast-1": endpoint{}, + "eu-west-1": endpoint{}, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-2": endpoint{}, + }, + }, "appstream2": service{ Defaults: endpoint{ Protocols: []string{"https"}, @@ -2857,6 +2867,7 @@ var awsPartition = partition{ "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, "eu-west-3": endpoint{}, + "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, "us-west-1": endpoint{}, @@ -4084,6 +4095,7 @@ var awsPartition = partition{ "ap-southeast-2": endpoint{}, "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, + "eu-north-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, "eu-west-3": 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 a29d39b7cda..7f71a54fa81 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.43" +const SDKVersion = "1.38.45" 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 6d15bad28f7..ebdd5f616e9 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 @@ -356,9 +356,8 @@ func (c *S3) CopyObjectRequest(input *CopyObjectInput) (req *request.Request, ou // use the s3:x-amz-metadata-directive condition key to enforce certain metadata // behavior when objects are uploaded. For more information, see Specifying // Conditions in a Policy (https://docs.aws.amazon.com/AmazonS3/latest/dev/amazon-s3-policy-keys.html) -// in the Amazon S3 Developer Guide. For a complete list of Amazon S3-specific -// condition keys, see Actions, Resources, and Condition Keys for Amazon S3 -// (https://docs.aws.amazon.com/AmazonS3/latest/dev/list_amazons3.html). +// in the Amazon S3 User Guide. For a complete list of Amazon S3-specific condition +// keys, see Actions, Resources, and Condition Keys for Amazon S3 (https://docs.aws.amazon.com/AmazonS3/latest/dev/list_amazons3.html). // // x-amz-copy-source-if Headers // @@ -422,7 +421,7 @@ func (c *S3) CopyObjectRequest(input *CopyObjectInput) (req *request.Request, ou // You can use the CopyObject action to change the storage class of an object // that is already stored in Amazon S3 using the StorageClass parameter. For // more information, see Storage Classes (https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html) -// in the Amazon S3 Service Developer Guide. +// in the Amazon S3 User Guide. // // Versioning // @@ -535,7 +534,7 @@ func (c *S3) CreateBucketRequest(input *CreateBucketInput) (req *request.Request // become the bucket owner. // // Not every string is an acceptable bucket name. For information about bucket -// naming restrictions, see Working with Amazon S3 buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html). +// naming restrictions, see Bucket naming rules (https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html). // // If you want to create an Amazon S3 on Outposts bucket, see Create Bucket // (https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_CreateBucket.html). @@ -723,10 +722,11 @@ func (c *S3) CreateMultipartUploadRequest(input *CreateMultipartUploadInput) (re // by using CreateMultipartUpload. // // To perform a multipart upload with encryption using an AWS KMS CMK, the requester -// must have permission to the kms:Encrypt, kms:Decrypt, kms:ReEncrypt*, kms:GenerateDataKey*, -// and kms:DescribeKey actions on the key. These permissions are required because -// Amazon S3 must decrypt and read data from the encrypted file parts before -// it completes the multipart upload. +// must have permission to the kms:Decrypt and kms:GenerateDataKey* actions +// on the key. These permissions are required because Amazon S3 must decrypt +// and read data from the encrypted file parts before it completes the multipart +// upload. For more information, see Multipart upload API and permissions (https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html#mpuAndPermissions) +// in the Amazon S3 User Guide. // // If your AWS Identity and Access Management (IAM) user or role is in the same // AWS account as the AWS KMS CMK, then you must have these permissions on the @@ -1835,7 +1835,7 @@ func (c *S3) DeleteBucketReplicationRequest(input *DeleteBucketReplicationInput) // propagate. // // For information about replication configuration, see Replication (https://docs.aws.amazon.com/AmazonS3/latest/dev/replication.html) -// in the Amazon S3 Developer Guide. +// in the Amazon S3 User Guide. // // The following operations are related to DeleteBucketReplication: // @@ -6497,12 +6497,13 @@ func (c *S3) ListObjectsV2Request(input *ListObjectsV2Input) (req *request.Reque // ListObjectsV2 API operation for Amazon Simple Storage Service. // -// Returns some or all (up to 1,000) of the objects in a bucket. You can use -// the request parameters as selection criteria to return a subset of the objects -// in a bucket. A 200 OK response can contain valid or invalid XML. Make sure -// to design your application to parse the contents of the response and handle -// it appropriately. Objects are returned sorted in an ascending order of the -// respective key names in the list. +// Returns some or all (up to 1,000) of the objects in a bucket with each request. +// You can use the request parameters as selection criteria to return a subset +// of the objects in a bucket. A 200 OK response can contain valid or invalid +// XML. Make sure to design your application to parse the contents of the response +// and handle it appropriately. Objects are returned sorted in an ascending +// order of the respective key names in the list. For more information about +// listing objects, see Listing object keys programmatically (https://docs.aws.amazon.com/AmazonS3/latest/userguide/ListingKeysUsingAPIs.html) // // To use this operation, you must have READ access to the bucket. // @@ -7816,7 +7817,7 @@ func (c *S3) PutBucketLifecycleConfigurationRequest(input *PutBucketLifecycleCon // // Creates a new lifecycle configuration for the bucket or replaces an existing // lifecycle configuration. For information about lifecycle configuration, see -// Managing Access Permissions to Your Amazon S3 Resources (https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html). +// Managing your storage lifecycle (https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html). // // Bucket lifecycle configuration now supports specifying a lifecycle rule using // an object key name prefix, one or more object tags, or a combination of both. @@ -8587,7 +8588,7 @@ func (c *S3) PutBucketReplicationRequest(input *PutBucketReplicationInput) (req // // Creates a replication configuration or replaces an existing one. For more // information, see Replication (https://docs.aws.amazon.com/AmazonS3/latest/dev/replication.html) -// in the Amazon S3 Developer Guide. +// in the Amazon S3 User Guide. // // To perform this operation, the user or role performing the action must have // the iam:PassRole (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_passrole.html) @@ -9229,7 +9230,7 @@ func (c *S3) PutObjectRequest(input *PutObjectInput) (req *request.Request, outp // Depending on performance needs, you can specify a different Storage Class. // Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, // see Storage Classes (https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html) -// in the Amazon S3 Service Developer Guide. +// in the Amazon S3 User Guide. // // Versioning // @@ -9339,7 +9340,7 @@ func (c *S3) PutObjectAclRequest(input *PutObjectAclInput) (req *request.Request // have an existing application that updates a bucket ACL using the request // body, you can continue to use that approach. For more information, see Access // Control List (ACL) Overview (https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html) -// in the Amazon S3 Developer Guide. +// in the Amazon S3 User Guide. // // Access Permissions // @@ -10997,7 +10998,7 @@ type AbortMultipartUploadInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -11025,7 +11026,7 @@ type AbortMultipartUploadInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // Upload ID that identifies the multipart upload. @@ -11242,7 +11243,7 @@ type AccessControlTranslation struct { // Specifies the replica ownership. For default and valid values, see PUT bucket // replication (https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTreplication.html) - // in the Amazon Simple Storage Service API Reference. + // in the Amazon S3 API Reference. // // Owner is a required field Owner *string `type:"string" required:"true" enum:"OwnerOverride"` @@ -11693,7 +11694,7 @@ type BucketLoggingStatus struct { // Describes where logs are stored and the prefix that Amazon S3 assigns to // all log object keys for a bucket. For more information, see PUT Bucket logging // (https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTlogging.html) - // in the Amazon Simple Storage Service API Reference. + // in the Amazon S3 API Reference. LoggingEnabled *LoggingEnabled `type:"structure"` } @@ -12168,7 +12169,7 @@ type CompleteMultipartUploadInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // ID for the initiated multipart upload. @@ -12291,7 +12292,7 @@ type CompleteMultipartUploadOutput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -12577,7 +12578,7 @@ type CopyObjectInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -12735,7 +12736,7 @@ type CopyObjectInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // Specifies the algorithm to use to when encrypting the object (for example, @@ -12764,7 +12765,7 @@ type CopyObjectInput struct { // or using SigV4. For information about configuring using any of the officially // supported AWS SDKs and AWS CLI, see Specifying the Signature Version in Request // Authentication (https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingAWSSDK.html#specify-signature-version) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` // The server-side encryption algorithm used when storing this object in Amazon @@ -12776,7 +12777,7 @@ type CopyObjectInput struct { // Depending on performance needs, you can specify a different Storage Class. // Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, // see Storage Classes (https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html) - // in the Amazon S3 Service Developer Guide. + // in the Amazon S3 User Guide. StorageClass *string `location:"header" locationName:"x-amz-storage-class" type:"string" enum:"StorageClass"` // The tag-set for the object destination object this value must be used in @@ -13358,7 +13359,10 @@ type CreateBucketInput struct { // Allows grantee to read the bucket ACL. GrantReadACP *string `location:"header" locationName:"x-amz-grant-read-acp" type:"string"` - // Allows grantee to create, overwrite, and delete any object in the bucket. + // Allows grantee to create new objects in the bucket. + // + // For the bucket and object owners of existing objects, also allows deletions + // and overwrites of those objects. GrantWrite *string `location:"header" locationName:"x-amz-grant-write" type:"string"` // Allows grantee to write the ACL for the applicable bucket. @@ -13494,7 +13498,7 @@ type CreateMultipartUploadInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -13583,7 +13587,7 @@ type CreateMultipartUploadInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // Specifies the algorithm to use to when encrypting the object (for example, @@ -13612,7 +13616,7 @@ type CreateMultipartUploadInput struct { // KMS will fail if not made via SSL or using SigV4. For information about configuring // using any of the officially supported AWS SDKs and AWS CLI, see Specifying // the Signature Version in Request Authentication (https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingAWSSDK.html#specify-signature-version) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` // The server-side encryption algorithm used when storing this object in Amazon @@ -13624,7 +13628,7 @@ type CreateMultipartUploadInput struct { // Depending on performance needs, you can specify a different Storage Class. // Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, // see Storage Classes (https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html) - // in the Amazon S3 Service Developer Guide. + // in the Amazon S3 User Guide. StorageClass *string `location:"header" locationName:"x-amz-storage-class" type:"string" enum:"StorageClass"` // The tag-set for the object. The tag-set must be encoded as URL Query parameters. @@ -13908,7 +13912,7 @@ type CreateMultipartUploadOutput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -15613,7 +15617,7 @@ type DeleteObjectInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -15651,7 +15655,7 @@ type DeleteObjectInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // VersionId used to reference a specific version of the object. @@ -15819,7 +15823,7 @@ type DeleteObjectTaggingInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -15970,7 +15974,7 @@ type DeleteObjectsInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -16009,7 +16013,7 @@ type DeleteObjectsInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` } @@ -16333,7 +16337,7 @@ type Destination struct { // the destination bucket by specifying the AccessControlTranslation property, // this is the account ID of the destination bucket owner. For more information, // see Replication Additional Configuration: Changing the Replica Owner (https://docs.aws.amazon.com/AmazonS3/latest/dev/replication-change-owner.html) - // in the Amazon Simple Storage Service Developer Guide. + // in the Amazon S3 User Guide. Account *string `type:"string"` // The Amazon Resource Name (ARN) of the bucket where you want Amazon S3 to @@ -16361,7 +16365,7 @@ type Destination struct { // // For valid values, see the StorageClass element of the PUT Bucket replication // (https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTreplication.html) - // action in the Amazon Simple Storage Service API Reference. + // action in the Amazon S3 API Reference. StorageClass *string `type:"string" enum:"StorageClass"` } @@ -16468,8 +16472,8 @@ type Encryption struct { // If the encryption type is aws:kms, this optional value specifies the ID of // the symmetric customer managed AWS KMS CMK to use for encryption of job results. - // Amazon S3 only supports symmetric CMKs. For more information, see Using Symmetric - // and Asymmetric Keys (https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html) + // Amazon S3 only supports symmetric CMKs. For more information, see Using symmetric + // and asymmetric keys (https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html) // in the AWS Key Management Service Developer Guide. KMSKeyId *string `type:"string" sensitive:"true"` } @@ -16520,11 +16524,11 @@ func (s *Encryption) SetKMSKeyId(v string) *Encryption { type EncryptionConfiguration struct { _ struct{} `type:"structure"` - // Specifies the ID (Key ARN or Alias ARN) of the customer managed customer - // master key (CMK) stored in AWS Key Management Service (KMS) for the destination - // bucket. Amazon S3 uses this key to encrypt replica objects. Amazon S3 only - // supports symmetric customer managed CMKs. For more information, see Using - // Symmetric and Asymmetric Keys (https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html) + // Specifies the ID (Key ARN or Alias ARN) of the customer managed AWS KMS key + // stored in AWS Key Management Service (KMS) for the destination bucket. Amazon + // S3 uses this key to encrypt replica objects. Amazon S3 only supports symmetric, + // customer managed KMS keys. For more information, see Using symmetric and + // asymmetric keys (https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html) // in the AWS Key Management Service Developer Guide. ReplicaKmsKeyID *string `type:"string"` } @@ -17035,7 +17039,7 @@ func (s *ErrorDocument) SetKey(v string) *ErrorDocument { // Optional configuration to replicate existing source bucket objects. For more // information, see Replicating Existing Objects (https://docs.aws.amazon.com/AmazonS3/latest/dev/replication-what-is-isnot-replicated.html#existing-object-replication) -// in the Amazon S3 Developer Guide. +// in the Amazon S3 User Guide. type ExistingObjectReplication struct { _ struct{} `type:"structure"` @@ -18337,7 +18341,7 @@ type GetBucketLoggingOutput struct { // Describes where logs are stored and the prefix that Amazon S3 assigns to // all log object keys for a bucket. For more information, see PUT Bucket logging // (https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTlogging.html) - // in the Amazon Simple Storage Service API Reference. + // in the Amazon S3 API Reference. LoggingEnabled *LoggingEnabled `type:"structure"` } @@ -19490,7 +19494,7 @@ type GetObjectAclInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // Bucket is a required field @@ -19510,7 +19514,7 @@ type GetObjectAclInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // VersionId used to reference a specific version of the object. @@ -19664,7 +19668,7 @@ type GetObjectInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -19720,7 +19724,7 @@ type GetObjectInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // Sets the Cache-Control header of the response. @@ -19964,7 +19968,7 @@ type GetObjectLegalHoldInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // Bucket is a required field @@ -19984,7 +19988,7 @@ type GetObjectLegalHoldInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // The version ID of the object whose Legal Hold status you want to retrieve. @@ -20119,7 +20123,7 @@ type GetObjectLockConfigurationInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // Bucket is a required field @@ -20567,7 +20571,7 @@ type GetObjectRetentionInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // Bucket is a required field @@ -20587,7 +20591,7 @@ type GetObjectRetentionInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // The version ID for the object whose retention settings you want to retrieve. @@ -20722,7 +20726,7 @@ type GetObjectTaggingInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -20750,7 +20754,7 @@ type GetObjectTaggingInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // The versionId of the object for which to get the tagging information. @@ -20910,7 +20914,7 @@ type GetObjectTorrentInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` } @@ -21342,7 +21346,7 @@ type HeadBucketInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -21457,7 +21461,7 @@ type HeadObjectInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -21514,7 +21518,7 @@ type HeadObjectInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // Specifies the algorithm to use to when encrypting the object (for example, @@ -22417,7 +22421,7 @@ func (s *IntelligentTieringFilter) SetTag(v *Tag) *IntelligentTieringFilter { // Specifies the inventory configuration for an Amazon S3 bucket. For more information, // see GET Bucket inventory (https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETInventoryConfig.html) -// in the Amazon Simple Storage Service API Reference. +// in the Amazon S3 API Reference. type InventoryConfiguration struct { _ struct{} `type:"structure"` @@ -23987,7 +23991,7 @@ type ListMultipartUploadsInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -24627,7 +24631,7 @@ type ListObjectsInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -24921,7 +24925,7 @@ type ListObjectsV2Input struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -25157,7 +25161,7 @@ type ListObjectsV2Output struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -25273,7 +25277,7 @@ type ListPartsInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -25308,7 +25312,7 @@ type ListPartsInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // Upload ID identifying the multipart upload whose parts are being listed. @@ -25730,7 +25734,7 @@ func (s *Location) SetUserMetadata(v []*MetadataEntry) *Location { // Describes where logs are stored and the prefix that Amazon S3 assigns to // all log object keys for a bucket. For more information, see PUT Bucket logging // (https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTlogging.html) -// in the Amazon Simple Storage Service API Reference. +// in the Amazon S3 API Reference. type LoggingEnabled struct { _ struct{} `type:"structure"` @@ -25953,7 +25957,7 @@ func (s *MetricsAndOperator) SetTags(v []*Tag) *MetricsAndOperator { // the existing metrics configuration. If you don't include the elements you // want to keep, they are erased. For more information, see PUT Bucket metrics // (https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTMetricConfiguration.html) -// in the Amazon Simple Storage Service API Reference. +// in the Amazon S3 API Reference. type MetricsConfiguration struct { _ struct{} `type:"structure"` @@ -26155,7 +26159,7 @@ type NoncurrentVersionExpiration struct { // perform the associated action. For information about the noncurrent days // calculations, see How Amazon S3 Calculates When an Object Became Noncurrent // (https://docs.aws.amazon.com/AmazonS3/latest/dev/intro-lifecycle-rules.html#non-current-days-calculations) - // in the Amazon Simple Storage Service Developer Guide. + // in the Amazon S3 User Guide. NoncurrentDays *int64 `type:"integer"` } @@ -27336,7 +27340,10 @@ type PutBucketAclInput struct { // Allows grantee to read the bucket ACL. GrantReadACP *string `location:"header" locationName:"x-amz-grant-read-acp" type:"string"` - // Allows grantee to create, overwrite, and delete any object in the bucket. + // Allows grantee to create new objects in the bucket. + // + // For the bucket and object owners of existing objects, also allows deletions + // and overwrites of those objects. GrantWrite *string `location:"header" locationName:"x-amz-grant-write" type:"string"` // Allows grantee to write the ACL for the applicable bucket. @@ -29693,7 +29700,7 @@ type PutObjectAclInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // Bucket is a required field @@ -29720,7 +29727,10 @@ type PutObjectAclInput struct { // This action is not supported by Amazon S3 on Outposts. GrantReadACP *string `location:"header" locationName:"x-amz-grant-read-acp" type:"string"` - // Allows grantee to create, overwrite, and delete any object in the bucket. + // Allows grantee to create new objects in the bucket. + // + // For the bucket and object owners of existing objects, also allows deletions + // and overwrites of those objects. GrantWrite *string `location:"header" locationName:"x-amz-grant-write" type:"string"` // Allows grantee to write the ACL for the applicable bucket. @@ -29734,7 +29744,7 @@ type PutObjectAclInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -29752,7 +29762,7 @@ type PutObjectAclInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // VersionId used to reference a specific version of the object. @@ -29944,7 +29954,7 @@ type PutObjectInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -30053,7 +30063,7 @@ type PutObjectInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // Specifies the algorithm to use to when encrypting the object (for example, @@ -30080,13 +30090,11 @@ type PutObjectInput struct { // If x-amz-server-side-encryption is present and has the value of aws:kms, // this header specifies the ID of the AWS Key Management Service (AWS KMS) // symmetrical customer managed customer master key (CMK) that was used for - // the object. - // - // If the value of x-amz-server-side-encryption is aws:kms, this header specifies - // the ID of the symmetric customer managed AWS KMS CMK that will be used for // the object. If you specify x-amz-server-side-encryption:aws:kms, but do not // providex-amz-server-side-encryption-aws-kms-key-id, Amazon S3 uses the AWS - // managed CMK in AWS to protect the data. + // managed CMK in AWS to protect the data. If the KMS key does not exist in + // the same account issuing the command, you must use the full ARN and not just + // the ID. SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` // The server-side encryption algorithm used when storing this object in Amazon @@ -30098,7 +30106,7 @@ type PutObjectInput struct { // Depending on performance needs, you can specify a different Storage Class. // Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, // see Storage Classes (https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html) - // in the Amazon S3 Service Developer Guide. + // in the Amazon S3 User Guide. StorageClass *string `location:"header" locationName:"x-amz-storage-class" type:"string" enum:"StorageClass"` // The tag-set for the object. The tag-set must be encoded as URL Query parameters. @@ -30401,7 +30409,7 @@ type PutObjectLegalHoldInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // Bucket is a required field @@ -30425,7 +30433,7 @@ type PutObjectLegalHoldInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // The version ID of the object that you want to place a Legal Hold on. @@ -30578,7 +30586,7 @@ type PutObjectLockConfigurationInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // A token to allow Object Lock to be enabled for an existing bucket. @@ -30831,7 +30839,7 @@ type PutObjectRetentionInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // Bucket is a required field @@ -30855,7 +30863,7 @@ type PutObjectRetentionInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // The container element for the Object Retention configuration. @@ -31007,7 +31015,7 @@ type PutObjectTaggingInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -31035,7 +31043,7 @@ type PutObjectTaggingInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // Container for the TagSet and Tag elements @@ -31752,7 +31760,7 @@ type ReplicationRule struct { // Optional configuration to replicate existing source bucket objects. For more // information, see Replicating Existing Objects (https://docs.aws.amazon.com/AmazonS3/latest/dev/replication-what-is-isnot-replicated.html#existing-object-replication) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. ExistingObjectReplication *ExistingObjectReplication `type:"structure"` // A filter that identifies the subset of objects to which the replication rule @@ -32195,7 +32203,7 @@ type RestoreObjectInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -32223,7 +32231,7 @@ type RestoreObjectInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // Container for restore job parameters. @@ -32540,8 +32548,8 @@ func (s *RoutingRule) SetRedirect(v *Redirect) *RoutingRule { // Specifies lifecycle rules for an Amazon S3 bucket. For more information, // see Put Bucket Lifecycle Configuration (https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTlifecycle.html) -// in the Amazon Simple Storage Service API Reference. For examples, see Put -// Bucket Lifecycle Configuration Examples (https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html#API_PutBucketLifecycleConfiguration_Examples). +// in the Amazon S3 API Reference. For examples, see Put Bucket Lifecycle Configuration +// Examples (https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html#API_PutBucketLifecycleConfiguration_Examples). type Rule struct { _ struct{} `type:"structure"` @@ -33287,17 +33295,17 @@ func (s *SelectParameters) SetOutputSerialization(v *OutputSerialization) *Selec // bucket. If a PUT Object request doesn't specify any server-side encryption, // this default encryption will be applied. For more information, see PUT Bucket // encryption (https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTencryption.html) -// in the Amazon Simple Storage Service API Reference. +// in the Amazon S3 API Reference. type ServerSideEncryptionByDefault struct { _ struct{} `type:"structure"` - // AWS Key Management Service (KMS) customer master key ID to use for the default + // AWS Key Management Service (KMS) customer AWS KMS key ID to use for the default // encryption. This parameter is allowed if and only if SSEAlgorithm is set // to aws:kms. // - // You can specify the key ID or the Amazon Resource Name (ARN) of the CMK. + // You can specify the key ID or the Amazon Resource Name (ARN) of the KMS key. // However, if you are using encryption with cross-account operations, you must - // use a fully qualified CMK ARN. For more information, see Using encryption + // use a fully qualified KMS key ARN. For more information, see Using encryption // for cross-account operations (https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html#bucket-encryption-update-bucket-policy). // // For example: @@ -33306,8 +33314,8 @@ type ServerSideEncryptionByDefault struct { // // * Key ARN: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab // - // Amazon S3 only supports symmetric CMKs and not asymmetric CMKs. For more - // information, see Using Symmetric and Asymmetric Keys (https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html) + // Amazon S3 only supports symmetric KMS keys and not asymmetric KMS keys. For + // more information, see Using symmetric and asymmetric keys (https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html) // in the AWS Key Management Service Developer Guide. KMSMasterKeyID *string `type:"string" sensitive:"true"` @@ -33531,7 +33539,7 @@ type SseKmsEncryptedObjects struct { _ struct{} `type:"structure"` // Specifies whether Amazon S3 replicates objects created with server-side encryption - // using a customer master key (CMK) stored in AWS Key Management Service. + // using an AWS KMS key stored in AWS Key Management Service. // // Status is a required field Status *string `type:"string" required:"true" enum:"SseKmsEncryptedObjectsStatus"` @@ -34170,7 +34178,7 @@ type UploadPartCopyInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -34275,7 +34283,7 @@ type UploadPartCopyInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // Specifies the algorithm to use to when encrypting the object (for example, @@ -34612,7 +34620,7 @@ type UploadPartInput struct { // the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. // When using this action with an access point through the AWS SDKs, you provide // the access point ARN in place of the bucket name. For more information about - // access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // access point ARNs, see Using access points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) // in the Amazon S3 User Guide. // // When using this action with Amazon S3 on Outposts, you must direct requests @@ -34655,7 +34663,7 @@ type UploadPartInput struct { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) - // in the Amazon S3 Developer Guide. + // in the Amazon S3 User Guide. RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` // Specifies the algorithm to use to when encrypting the object (for example, @@ -34919,7 +34927,7 @@ func (s *UploadPartOutput) SetServerSideEncryption(v string) *UploadPartOutput { // Describes the versioning state of an Amazon S3 bucket. For more information, // see PUT Bucket versioning (https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTVersioningStatus.html) -// in the Amazon Simple Storage Service API Reference. +// in the Amazon S3 API Reference. type VersioningConfiguration struct { _ struct{} `type:"structure"` @@ -36477,7 +36485,7 @@ func RequestCharged_Values() []string { // Bucket owners need not specify this parameter in their requests. For information // about downloading objects from requester pays buckets, see Downloading Objects // in Requestor Pays Buckets (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) -// in the Amazon S3 Developer Guide. +// in the Amazon S3 User Guide. const ( // RequestPayerRequester is a RequestPayer enum value RequestPayerRequester = "requester" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index ff401fc6f4f..e10d7feb404 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.43 +# github.com/aws/aws-sdk-go v1.38.45 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 3b1900a8bfd91180ac1e4c011765e74daf05e3fe Mon Sep 17 00:00:00 2001 From: ghdiska <67001298+ghdiska@users.noreply.github.com> Date: Mon, 24 May 2021 09:29:20 +0200 Subject: [PATCH 134/398] add missing interface_type definition --- aws/data_source_aws_launch_template.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aws/data_source_aws_launch_template.go b/aws/data_source_aws_launch_template.go index 10b79878541..2906112ef22 100644 --- a/aws/data_source_aws_launch_template.go +++ b/aws/data_source_aws_launch_template.go @@ -10,6 +10,7 @@ import ( "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/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) @@ -315,6 +316,11 @@ func dataSourceAwsLaunchTemplate() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "interface_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"efa", "interface"}, false), + }, }, }, }, From 181497fb857d031443cff0bee19dd9b86e2fbe24 Mon Sep 17 00:00:00 2001 From: ghdiska <67001298+ghdiska@users.noreply.github.com> Date: Mon, 24 May 2021 09:43:13 +0200 Subject: [PATCH 135/398] add interface_type --- aws/data_source_aws_launch_template.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aws/data_source_aws_launch_template.go b/aws/data_source_aws_launch_template.go index 2906112ef22..335fbd6aeae 100644 --- a/aws/data_source_aws_launch_template.go +++ b/aws/data_source_aws_launch_template.go @@ -317,9 +317,8 @@ func dataSourceAwsLaunchTemplate() *schema.Resource { Computed: true, }, "interface_type": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{"efa", "interface"}, false), + Type: schema.TypeString, + Computed: true, }, }, }, From bfaa5b8d0e4c6fbcd7943071293e6a4932f79d15 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 24 May 2021 10:41:10 -0400 Subject: [PATCH 136/398] Add CHANGELOG entry. --- .changelog/19492.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19492.txt diff --git a/.changelog/19492.txt b/.changelog/19492.txt new file mode 100644 index 00000000000..5b3b001b89d --- /dev/null +++ b/.changelog/19492.txt @@ -0,0 +1,3 @@ +```release-note:bug +data-source/aws_launch_template: Add `interface_type` to `network_interfaces` attribute +``` \ No newline at end of file From b74be69acd7f711de390858bc405aadbe64265fe Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 24 May 2021 10:54:52 -0400 Subject: [PATCH 137/398] Fix compliation errors. --- aws/data_source_aws_launch_template.go | 1 - aws/data_source_aws_launch_template_test.go | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/aws/data_source_aws_launch_template.go b/aws/data_source_aws_launch_template.go index 335fbd6aeae..a4251784ce4 100644 --- a/aws/data_source_aws_launch_template.go +++ b/aws/data_source_aws_launch_template.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/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" ) diff --git a/aws/data_source_aws_launch_template_test.go b/aws/data_source_aws_launch_template_test.go index 84919d90e73..b98277cdfd8 100644 --- a/aws/data_source_aws_launch_template_test.go +++ b/aws/data_source_aws_launch_template_test.go @@ -303,7 +303,7 @@ func TestAccAWSLaunchTemplateDataSource_NonExistent(t *testing.T) { func testAccAWSLaunchTemplateDataSourceConfig_Basic(rName string) string { return fmt.Sprintf(` resource "aws_launch_template" "test" { - name = %q + name = %[1]q } data "aws_launch_template" "test" { @@ -315,7 +315,7 @@ data "aws_launch_template" "test" { func testAccAWSLaunchTemplateDataSourceConfig_BasicId(rName string) string { return fmt.Sprintf(` resource "aws_launch_template" "test" { - name = %q + name = %[1]q } data "aws_launch_template" "test" { From 6a3f3823f1e3a7cb9d47321fc981224d0655a79e Mon Sep 17 00:00:00 2001 From: changelogbot Date: Mon, 24 May 2021 15:11:48 +0000 Subject: [PATCH 138/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c5080d3ff6..ad1c9fcb15a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ FEATURES: BUG FIXES: +* data-source/aws_launch_template: Add `interface_type` to `network_interfaces` attribute ([#19492](https://github.com/hashicorp/terraform-provider-aws/issues/19492)) * 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 9b0f40aa22bd73672ad5d771cffd4026ac92a929 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 24 May 2021 11:22:25 -0400 Subject: [PATCH 139/398] r/aws_lb_listener_rule: Allow empty string for 'action.redirect.query'. --- aws/resource_aws_lb_listener_rule.go | 2 +- aws/resource_aws_lb_listener_rule_test.go | 62 +++++++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_lb_listener_rule.go b/aws/resource_aws_lb_listener_rule.go index 55154b80890..4945fa860e0 100644 --- a/aws/resource_aws_lb_listener_rule.go +++ b/aws/resource_aws_lb_listener_rule.go @@ -168,7 +168,7 @@ func resourceAwsLbbListenerRule() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "#{query}", - ValidateFunc: validation.StringLenBetween(1, 128), + ValidateFunc: validation.StringLenBetween(0, 128), }, "status_code": { diff --git a/aws/resource_aws_lb_listener_rule_test.go b/aws/resource_aws_lb_listener_rule_test.go index 5711ff6ac48..5be0c988090 100644 --- a/aws/resource_aws_lb_listener_rule_test.go +++ b/aws/resource_aws_lb_listener_rule_test.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "regexp" + "strconv" "testing" "github.com/aws/aws-sdk-go/aws" @@ -285,7 +286,7 @@ func TestAccAWSLBListenerRule_redirect(t *testing.T) { CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLBListenerRuleConfig_redirect(lbName), + Config: testAccAWSLBListenerRuleConfig_redirect(lbName, "null"), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSLBListenerRuleExists(resourceName, &conf), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexp.MustCompile(fmt.Sprintf(`listener-rule/app/%s/.+$`, lbName))), @@ -308,6 +309,54 @@ func TestAccAWSLBListenerRule_redirect(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "condition.#", "1"), ), }, + { + Config: testAccAWSLBListenerRuleConfig_redirect(lbName, "param1=value1"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists(resourceName, &conf), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexp.MustCompile(fmt.Sprintf(`listener-rule/app/%s/.+$`, lbName))), + resource.TestCheckResourceAttrPair(resourceName, "listener_arn", frontEndListenerResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "priority", "100"), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.order", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "redirect"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.host", "#{host}"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.path", "/#{path}"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.port", "443"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.query", "param1=value1"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.status_code", "HTTP_301"), + resource.TestCheckResourceAttr(resourceName, "action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.authenticate_cognito.#", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.authenticate_oidc.#", "0"), + resource.TestCheckResourceAttr(resourceName, "condition.#", "1"), + ), + }, + { + Config: testAccAWSLBListenerRuleConfig_redirect(lbName, ""), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists(resourceName, &conf), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexp.MustCompile(fmt.Sprintf(`listener-rule/app/%s/.+$`, lbName))), + resource.TestCheckResourceAttrPair(resourceName, "listener_arn", frontEndListenerResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "priority", "100"), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.order", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "redirect"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.host", "#{host}"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.path", "/#{path}"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.port", "443"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.query", ""), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.0.status_code", "HTTP_301"), + resource.TestCheckResourceAttr(resourceName, "action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.authenticate_cognito.#", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.authenticate_oidc.#", "0"), + resource.TestCheckResourceAttr(resourceName, "condition.#", "1"), + ), + }, }, }) } @@ -2016,7 +2065,11 @@ resource "aws_security_group" "alb_test" { `, lbName, targetGroupName) } -func testAccAWSLBListenerRuleConfig_redirect(lbName string) string { +func testAccAWSLBListenerRuleConfig_redirect(lbName, query string) string { + if query != "null" { + query = strconv.Quote(query) + } + return fmt.Sprintf(` resource "aws_lb_listener_rule" "static" { listener_arn = aws_lb_listener.front_end.arn @@ -2028,6 +2081,7 @@ resource "aws_lb_listener_rule" "static" { redirect { port = "443" protocol = "HTTPS" + query = %[2]s status_code = "HTTP_301" } } @@ -2056,7 +2110,7 @@ resource "aws_lb_listener" "front_end" { } resource "aws_lb" "alb_test" { - name = "%s" + name = %[1]q internal = true security_groups = [aws_security_group.alb_test.id] subnets = aws_subnet.alb_test[*].id @@ -2126,7 +2180,7 @@ resource "aws_security_group" "alb_test" { Name = "TestAccAWSALB_redirect" } } -`, lbName) +`, lbName, query) } func testAccAWSLBListenerRuleConfig_fixedResponse(lbName, response string) string { From 2313f6a3a62ee76ce65ff43bc0681a5fb25fb7e4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 24 May 2021 11:26:28 -0400 Subject: [PATCH 140/398] Add CHANGELOG entry. --- .changelog/19496.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19496.txt diff --git a/.changelog/19496.txt b/.changelog/19496.txt new file mode 100644 index 00000000000..5bbf54b65d5 --- /dev/null +++ b/.changelog/19496.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_lb_listener_rule: Allow blank string for `action.redirect.query` nested argument +``` \ No newline at end of file From da67222e09ed10cb27f1520dda701b42e97c0acf Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 11:55:51 -0400 Subject: [PATCH 141/398] provider: New data source --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index 347b1ad8177..6aece9c9ea0 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 142/398] 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 00000000000..98bf3aa8c12 --- /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 143/398] 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 00000000000..aa176fcce5e --- /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 144/398] 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 00000000000..6f1708c7915 --- /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 145/398] 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 00000000000..92a274598bb --- /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 146/398] 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 aa176fcce5e..025966ef59a 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 3b05635c2bb9486f5156576b3701746066aa92f8 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Mon, 24 May 2021 16:14:05 +0000 Subject: [PATCH 147/398] Update CHANGELOG.md for #19471 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad1c9fcb15a..5203dfb135e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ FEATURES: BUG FIXES: * data-source/aws_launch_template: Add `interface_type` to `network_interfaces` attribute ([#19492](https://github.com/hashicorp/terraform-provider-aws/issues/19492)) +* resource/aws_apprunner_service: Correctly configure `authentication_configuration`, `code_configuration`, and `image_configuration` nested arguments in API requests ([#19471](https://github.com/hashicorp/terraform-provider-aws/issues/19471)) +* 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_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 7ecd95175fccc16fb945ec2a9055a554a45cb187 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 13:01:47 -0400 Subject: [PATCH 148/398] 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 6f1708c7915..bf69c9b3067 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 149/398] 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 98bf3aa8c12..771b877ea36 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 94f15473d7dbdda3517ab203910e0366ac3f8a19 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 24 May 2021 13:12:37 -0400 Subject: [PATCH 150/398] d/aws_mq_broker: 'logs.audit' is of TypeString (NullableBool). --- aws/data_source_aws_mq_broker.go | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/aws/data_source_aws_mq_broker.go b/aws/data_source_aws_mq_broker.go index 7c9ad4d3a41..d7d8b9c4c60 100644 --- a/aws/data_source_aws_mq_broker.go +++ b/aws/data_source_aws_mq_broker.go @@ -6,6 +6,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/mq" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/experimental/nullable" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) @@ -162,15 +163,7 @@ func dataSourceAwsMqBroker() *schema.Resource { }, "logs": { Type: schema.TypeList, - Optional: true, - MaxItems: 1, - // Ignore missing configuration block - DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - if old == "1" && new == "0" { - return true - } - return false - }, + Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "general": { @@ -178,7 +171,7 @@ func dataSourceAwsMqBroker() *schema.Resource { Computed: true, }, "audit": { - Type: schema.TypeBool, + Type: nullable.TypeNullableBool, Computed: true, }, }, From 9d6c553d10944b55b08369d04637be498e0d8ad9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 24 May 2021 13:16:08 -0400 Subject: [PATCH 151/398] Add CHANGELOG entry. --- .changelog/19502.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19502.txt diff --git a/.changelog/19502.txt b/.changelog/19502.txt new file mode 100644 index 00000000000..2176316b46d --- /dev/null +++ b/.changelog/19502.txt @@ -0,0 +1,3 @@ +```release-note:bug +data-source/aws_mq_broker: Correct type for `logs.audit` attribute +``` \ No newline at end of file From 59c07b2e80eb981cc1f1d6c7287558dd26bff12d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 24 May 2021 13:22:50 -0400 Subject: [PATCH 152/398] Rename documentation page to match data source name. --- ...on.html.markdown => cloudwatch_event_connection.html.markdown} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename website/docs/d/{cloudwatch_events_connection.html.markdown => cloudwatch_event_connection.html.markdown} (100%) diff --git a/website/docs/d/cloudwatch_events_connection.html.markdown b/website/docs/d/cloudwatch_event_connection.html.markdown similarity index 100% rename from website/docs/d/cloudwatch_events_connection.html.markdown rename to website/docs/d/cloudwatch_event_connection.html.markdown From eaa2ae7e941203abed0c2cc7c42017e092757cfa Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Mon, 24 May 2021 10:28:46 -0700 Subject: [PATCH 153/398] Apply suggestions from code review Co-authored-by: angie pinilla --- aws/wafv2_helper.go | 89 +++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/aws/wafv2_helper.go b/aws/wafv2_helper.go index caa411ba1af..6b759cd6b6d 100644 --- a/aws/wafv2_helper.go +++ b/aws/wafv2_helper.go @@ -474,7 +474,7 @@ func wafv2CustomRequestHandlingSchema() *schema.Schema { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 64), - validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9._$-]+$`), "must contain only alphanumeric hyphen, underscore, dot and $ characters"), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9._$-]+$`), "must contain only alphanumeric, hyphen, underscore, dot and $ characters"), ), }, "value": { @@ -500,7 +500,7 @@ func wafv2CustomResponseSchema() *schema.Schema { "response_code": { Type: schema.TypeInt, Required: true, - ValidateFunc: validation.IntBetween(200, 599), + ValidateFunc: validation.IntBetween(200, 600), }, "response_header": { Type: schema.TypeSet, @@ -512,7 +512,7 @@ func wafv2CustomResponseSchema() *schema.Schema { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 64), - validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9._$-]+$`), "must contain only alphanumeric hyphen, underscore, dot and $ characters"), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9._$-]+$`), "must contain only alphanumeric, hyphen, underscore, dot and $ characters"), ), }, "value": { @@ -583,42 +583,57 @@ func expandWafv2RuleAction(l []interface{}) *wafv2.RuleAction { } func expandWafv2AllowAction(l []interface{}) *wafv2.AllowAction { - action := &wafv2.AllowAction{} if len(l) == 0 || l[0] == nil { - return action + return nil } - m := l[0].(map[string]interface{}) - if v, ok := m["custom_request_handling"]; ok && len(v.([]interface{})) > 0 { - action.CustomRequestHandling = expandWafv2CustomRequestHandling(v.([]interface{})) + m, ok := l[0].(map[string]interface{}) + if !ok { + return nil + } + + action := &wafv2.AllowAction{} + + if v, ok := m["custom_request_handling"].([]interface{}); ok && len(v) > 0 { + action.CustomRequestHandling = expandWafv2CustomRequestHandling(v) } return action } func expandWafv2CountAction(l []interface{}) *wafv2.CountAction { - action := &wafv2.CountAction{} if len(l) == 0 || l[0] == nil { - return action + return nil } - m := l[0].(map[string]interface{}) - if v, ok := m["custom_request_handling"]; ok && len(v.([]interface{})) > 0 { - action.CustomRequestHandling = expandWafv2CustomRequestHandling(v.([]interface{})) + m, ok := l[0].(map[string]interface{}) + if !ok { + return nil + } + + action := &wafv2.CountAction{} + + if v, ok := m["custom_request_handling"].([]interface{}); ok && len(v) > 0 { + action.CustomRequestHandling = expandWafv2CustomRequestHandling(v) } return action } func expandWafv2BlockAction(l []interface{}) *wafv2.BlockAction { - action := &wafv2.BlockAction{} if len(l) == 0 || l[0] == nil { - return action + return nil } - m := l[0].(map[string]interface{}) - if v, ok := m["custom_response"]; ok && len(v.([]interface{})) > 0 { - action.CustomResponse = expandWafv2CustomResponse(v.([]interface{})) + m, ok := l[0].(map[string]interface{}) + if !ok { + return nil + } + + action := &wafv2.BlockAction{} + + if v, ok := m["custom_response"].([]interface{}); ok && len(v) > 0 { + action.CustomResponse = expandWafv2CustomResponse(v) } return action @@ -629,14 +644,18 @@ func expandWafv2CustomResponse(l []interface{}) *wafv2.CustomResponse { return nil } - m := l[0].(map[string]interface{}) + m, ok := l[0].(map[string]interface{}) + if !ok { + return nil + } + customResponse := &wafv2.CustomResponse{} - if v, ok := m["response_code"]; ok && v.(int) > 0 { - customResponse.ResponseCode = aws.Int64(int64(v.(int))) + if v, ok := m["response_code"].(int); ok && v > 0 { + customResponse.ResponseCode = aws.Int64(int64(v)) } - if v, ok := m["response_header"]; ok && len(v.(*schema.Set).List()) > 0 { - customResponse.ResponseHeaders = expandWafv2CustomHeaders(v.(*schema.Set).List()) + if v, ok := m["response_header"].(*schema.Set); ok && len(v.List()) > 0 { + customResponse.ResponseHeaders = expandWafv2CustomHeaders(v.List()) } return customResponse @@ -650,8 +669,8 @@ func expandWafv2CustomRequestHandling(l []interface{}) *wafv2.CustomRequestHandl m := l[0].(map[string]interface{}) requestHandling := &wafv2.CustomRequestHandling{} - if v, ok := m["insert_header"]; ok && len(v.(*schema.Set).List()) > 0 { - requestHandling.InsertHeaders = expandWafv2CustomHeaders(v.(*schema.Set).List()) + if v, ok := m["insert_header"].(*schema.Set); ok && len(v.List()) > 0 { + requestHandling.InsertHeaders = expandWafv2CustomHeaders(v.List()) } return requestHandling @@ -1083,9 +1102,9 @@ func flattenWafv2RuleAction(a *wafv2.RuleAction) interface{} { return []interface{}{m} } -func flattenWafv2Allow(a *wafv2.AllowAction) interface{} { +func flattenWafv2Allow(a *wafv2.AllowAction) []interface{} { if a == nil { - return map[string]interface{}{} + return []interface{}{} } m := map[string]interface{}{} @@ -1096,9 +1115,9 @@ func flattenWafv2Allow(a *wafv2.AllowAction) interface{} { return []interface{}{m} } -func flattenWafv2Block(a *wafv2.BlockAction) interface{} { +func flattenWafv2Block(a *wafv2.BlockAction) []interface{} { if a == nil { - return map[string]interface{}{} + return []interface{}{} } m := map[string]interface{}{} @@ -1110,9 +1129,9 @@ func flattenWafv2Block(a *wafv2.BlockAction) interface{} { return []interface{}{m} } -func flattenWafv2Count(a *wafv2.CountAction) interface{} { +func flattenWafv2Count(a *wafv2.CountAction) []interface{} { if a == nil { - return map[string]interface{}{} + return []interface{}{} } m := map[string]interface{}{} @@ -1123,7 +1142,7 @@ func flattenWafv2Count(a *wafv2.CountAction) interface{} { return []interface{}{m} } -func flattenWafv2CustomRequestHandling(c *wafv2.CustomRequestHandling) interface{} { +func flattenWafv2CustomRequestHandling(c *wafv2.CustomRequestHandling) []interface{} { if c == nil { return []interface{}{} } @@ -1135,7 +1154,7 @@ func flattenWafv2CustomRequestHandling(c *wafv2.CustomRequestHandling) interface return []interface{}{m} } -func flattenWafv2CustomResponse(r *wafv2.CustomResponse) interface{} { +func flattenWafv2CustomResponse(r *wafv2.CustomResponse) []interface{} { if r == nil { return []interface{}{} } @@ -1148,7 +1167,7 @@ func flattenWafv2CustomResponse(r *wafv2.CustomResponse) interface{} { return []interface{}{m} } -func flattenWafv2CustomHeaders(h []*wafv2.CustomHTTPHeader) interface{} { +func flattenWafv2CustomHeaders(h []*wafv2.CustomHTTPHeader) []interface{} { out := make([]interface{}, len(h)) for i, header := range h { out[i] = flattenWafv2CustomHeader(header) @@ -1157,7 +1176,7 @@ func flattenWafv2CustomHeaders(h []*wafv2.CustomHTTPHeader) interface{} { return out } -func flattenWafv2CustomHeader(h *wafv2.CustomHTTPHeader) interface{} { +func flattenWafv2CustomHeader(h *wafv2.CustomHTTPHeader) map[string]interface{} { if h == nil { return map[string]interface{}{} } From 83f9d42337ea8b3c402efaf0aab64d8dcdace54b Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Mon, 24 May 2021 10:33:00 -0700 Subject: [PATCH 154/398] Added mention of `aws_wafv2_rule_group` changes to the release notes --- .changelog/19415.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.changelog/19415.txt b/.changelog/19415.txt index 483c7aa2360..fad6f4d0234 100644 --- a/.changelog/19415.txt +++ b/.changelog/19415.txt @@ -4,4 +4,8 @@ resource/aws_wafv2_web_acl: Add `custom_request_handling` to `allow` and `count` ```release-notes:enhancement resource/aws_wafv2_web_acl: Add `custom_response` to `block` actions. +``` + +```release-notes:enhancement +resource/aws_wafv2_rule_group: Included the above changes to `rule` `allow`, `count`, and `block` actions. ``` \ No newline at end of file From d1f899a3e7a2de6bba67aa8488ee6a2b572f6d25 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 24 May 2021 13:49:57 -0400 Subject: [PATCH 155/398] Skip aws_cloudwatch_event_connection tests in GovCloud. --- aws/resource_aws_cloudwatch_event_rule_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/aws/resource_aws_cloudwatch_event_rule_test.go b/aws/resource_aws_cloudwatch_event_rule_test.go index 9e0a64d8916..0b78f9ecf45 100644 --- a/aws/resource_aws_cloudwatch_event_rule_test.go +++ b/aws/resource_aws_cloudwatch_event_rule_test.go @@ -20,6 +20,8 @@ import ( ) func init() { + RegisterServiceErrorCheckFunc(events.EndpointsID, testAccErrorCheckSkipEvents) + resource.AddTestSweepers("aws_cloudwatch_event_rule", &resource.Sweeper{ Name: "aws_cloudwatch_event_rule", F: testSweepCloudWatchEventRules, @@ -78,6 +80,12 @@ func testSweepCloudWatchEventRules(region string) error { return sweeperErrs.ErrorOrNil() } +func testAccErrorCheckSkipEvents(t *testing.T) resource.ErrorCheckFunc { + return testAccErrorCheckSkipMessagesContaining(t, + "Operation is disabled in this region", + ) +} + func TestAccAWSCloudWatchEventRule_basic(t *testing.T) { var v1, v2, v3 events.DescribeRuleOutput rName := acctest.RandomWithPrefix("tf-acc-test") From 7542f4becace32178645a9488c33b9e5036ec541 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Mon, 24 May 2021 11:08:35 -0700 Subject: [PATCH 156/398] Don't allow custom_request_handling on allow actions in an `override_action` section. Per AWS docs, they are not supported. (https://docs.aws.amazon.com/waf/latest/developerguide/waf-custom-request-response.html) --- aws/resource_aws_wafv2_web_acl.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_wafv2_web_acl.go b/aws/resource_aws_wafv2_web_acl.go index 1f4c7894287..ee635a360c9 100644 --- a/aws/resource_aws_wafv2_web_acl.go +++ b/aws/resource_aws_wafv2_web_acl.go @@ -119,7 +119,7 @@ func resourceAwsWafv2WebACL() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "count": wafv2CountConfigSchema(), + "count": wafv2EmptySchema(), "none": wafv2EmptySchema(), }, }, @@ -519,7 +519,7 @@ func expandWafv2OverrideAction(l []interface{}) *wafv2.OverrideAction { action := &wafv2.OverrideAction{} if v, ok := m["count"]; ok && len(v.([]interface{})) > 0 { - action.Count = expandWafv2CountAction(v.([]interface{})) + action.Count = &wafv2.CountAction{} } if v, ok := m["none"]; ok && len(v.([]interface{})) > 0 { @@ -790,7 +790,7 @@ func flattenWafv2OverrideAction(a *wafv2.OverrideAction) interface{} { m := map[string]interface{}{} if a.Count != nil { - m["count"] = flattenWafv2Count(a.Count) + m["count"] = make([]map[string]interface{}, 1) } if a.None != nil { From 17f52ddf261d46f3b7af0b7eb9a6a133ef2de3cd Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Mon, 24 May 2021 11:11:02 -0700 Subject: [PATCH 157/398] Added `custom_request_handling` and `custom_response` sections to the docs for `wafv2_web_acl` and `wafv2_rule_group` resources. --- website/docs/r/wafv2_rule_group.html.markdown | 46 +++++++++++++++-- website/docs/r/wafv2_web_acl.html.markdown | 50 ++++++++++++++++--- 2 files changed, 86 insertions(+), 10 deletions(-) diff --git a/website/docs/r/wafv2_rule_group.html.markdown b/website/docs/r/wafv2_rule_group.html.markdown index ebc521a8021..a8432218bf1 100644 --- a/website/docs/r/wafv2_rule_group.html.markdown +++ b/website/docs/r/wafv2_rule_group.html.markdown @@ -307,11 +307,49 @@ Each `rule` supports the following arguments: The `action` block supports the following arguments: -~> **NOTE:** One of `allow`, `block`, or `count`, expressed as an empty configuration block `{}`, is required when specifying an `action` +~> **NOTE:** One of `allow`, `block`, or `count`, is required when specifying an `action`. -* `allow` - (Optional) Instructs AWS WAF to allow the web request. -* `block` - (Optional) Instructs AWS WAF to block the web request. -* `count` - (Optional) Instructs AWS WAF to count the web request and allow it. +* `allow` - (Optional) Instructs AWS WAF to allow the web request. See [Allow](#action) below for details. +* `block` - (Optional) Instructs AWS WAF to block the web request. See [Block](#block) below for details. +* `count` - (Optional) Instructs AWS WAF to count the web request and allow it. See [Count](#count) below for details. + +### Allow + +The `allow` block supports the following arguments: + +* `custom_request_handling` - (Optional) Defines custom handling for the web request. See [Custom Request Handling](#custom-request-handling) below for details. + +### Block + +The `block` block supports the following arguments: + +* `custom_response` - (Optional) Defines a custom response for the web request. See [Custom Response](#custom-response) below for details. + +### Count + +The `count` block supports the following arguments: + +* `custom_request_handling` - (Optional) Defines custom handling for the web request. See [Custom Request Handling](#custom-request-handling) below for details. + +### Custom Request Handling + +The `custom_request_handling` block supports the following arguments: + +* `insert_header` - (Required) The `insert_header` blocks used to define HTTP headers added to the request. See [Custom HTTP Header](#custom-http-header) below for details. + +### Custom Response + +The `custom_response` block supports the following arguments: + +* `response_code` - (Optional) The HTTP status code to return to the client. +* `response_header` - (Optional) The `response_header` blocks used to define the HTTP response headers added to the response. See [Custom HTTP Header](#custom-http-header) below for details. + +### Custom HTTP Header + +Each block supports the following arguments. Duplicate header names are not allowed: + +* `name` - The name of the custom header. For custom request header insertion, when AWS WAF inserts the header into the request, it prefixes this name `x-amzn-waf-`, to avoid confusion with the headers that are already in the request. For example, for the header name `sample`, AWS WAF inserts the header `x-amzn-waf-sample`. +* `value` - The value of the custom header. ### Statement diff --git a/website/docs/r/wafv2_web_acl.html.markdown b/website/docs/r/wafv2_web_acl.html.markdown index de0f98a1745..14640f4fc27 100644 --- a/website/docs/r/wafv2_web_acl.html.markdown +++ b/website/docs/r/wafv2_web_acl.html.markdown @@ -269,8 +269,8 @@ The `default_action` block supports the following arguments: ~> **NOTE:** One of `allow` or `block`, expressed as an empty configuration block `{}`, is required when specifying a `default_action` -* `allow` - (Optional) Specifies that AWS WAF should allow requests by default. -* `block` - (Optional) Specifies that AWS WAF should block requests by default. +* `allow` - (Optional) Specifies that AWS WAF should allow requests by default. See [Allow](#action) below for details. +* `block` - (Optional) Specifies that AWS WAF should block requests by default. See [Block](#block) below for details. ### Rules @@ -289,11 +289,11 @@ Each `rule` supports the following arguments: The `action` block supports the following arguments: -~> **NOTE:** One of `allow`, `block`, or `count`, expressed as an empty configuration block `{}`, is required when specifying an `action` +~> **NOTE:** One of `allow`, `block`, or `count`, is required when specifying an `action`. -* `allow` - (Optional) Instructs AWS WAF to allow the web request. Configure as an empty block `{}`. -* `block` - (Optional) Instructs AWS WAF to block the web request. Configure as an empty block `{}`. -* `count` - (Optional) Instructs AWS WAF to count the web request and allow it. Configure as an empty block `{}`. +* `allow` - (Optional) Instructs AWS WAF to allow the web request. See [Allow](#action) below for details. +* `block` - (Optional) Instructs AWS WAF to block the web request. See [Block](#block) below for details. +* `count` - (Optional) Instructs AWS WAF to count the web request and allow it. See [Count](#count) below for details. ### Override Action @@ -304,6 +304,44 @@ The `override_action` block supports the following arguments: * `count` - (Optional) Override the rule action setting to count (i.e. only count matches). Configured as an empty block `{}`. * `none` - (Optional) Don't override the rule action setting. Configured as an empty block `{}`. +### Allow + +The `allow` block supports the following arguments: + +* `custom_request_handling` - (Optional) Defines custom handling for the web request. See [Custom Request Handling](#custom-request-handling) below for details. + +### Block + +The `block` block supports the following arguments: + +* `custom_response` - (Optional) Defines a custom response for the web request. See [Custom Response](#custom-response) below for details. + +### Count + +The `count` block supports the following arguments: + +* `custom_request_handling` - (Optional) Defines custom handling for the web request. See [Custom Request Handling](#custom-request-handling) below for details. + +### Custom Request Handling + +The `custom_request_handling` block supports the following arguments: + +* `insert_header` - (Required) The `insert_header` blocks used to define HTTP headers added to the request. See [Custom HTTP Header](#custom-http-header) below for details. + +### Custom Response + +The `custom_response` block supports the following arguments: + +* `response_code` - (Optional) The HTTP status code to return to the client. +* `response_header` - (Optional) The `response_header` blocks used to define the HTTP response headers added to the response. See [Custom HTTP Header](#custom-http-header) below for details. + +### Custom HTTP Header + +Each block supports the following arguments. Duplicate header names are not allowed: + +* `name` - The name of the custom header. For custom request header insertion, when AWS WAF inserts the header into the request, it prefixes this name `x-amzn-waf-`, to avoid confusion with the headers that are already in the request. For example, for the header name `sample`, AWS WAF inserts the header `x-amzn-waf-sample`. +* `value` - The value of the custom header. + ### Statement The processing guidance for a Rule, used by AWS WAF to determine whether a web request matches the rule. See the [documentation](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statements-list.html) for more information. From 49f9b5d188781c9e893f8fe87fea5d5ef2e8e957 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Mon, 24 May 2021 11:38:35 -0700 Subject: [PATCH 158/398] Update the `expandWafv2` functions for the `Allow`, `Block`, and `Count` actions to always at least return an empty object. By the time these `expand` functions are called, we know we at least want an empty object to indicate which action we are to take. --- aws/wafv2_helper.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/aws/wafv2_helper.go b/aws/wafv2_helper.go index 6b759cd6b6d..28107047530 100644 --- a/aws/wafv2_helper.go +++ b/aws/wafv2_helper.go @@ -583,17 +583,17 @@ func expandWafv2RuleAction(l []interface{}) *wafv2.RuleAction { } func expandWafv2AllowAction(l []interface{}) *wafv2.AllowAction { + action := &wafv2.AllowAction{} + if len(l) == 0 || l[0] == nil { - return nil + return action } m, ok := l[0].(map[string]interface{}) if !ok { - return nil + return action } - action := &wafv2.AllowAction{} - if v, ok := m["custom_request_handling"].([]interface{}); ok && len(v) > 0 { action.CustomRequestHandling = expandWafv2CustomRequestHandling(v) } @@ -602,17 +602,17 @@ func expandWafv2AllowAction(l []interface{}) *wafv2.AllowAction { } func expandWafv2CountAction(l []interface{}) *wafv2.CountAction { + action := &wafv2.CountAction{} + if len(l) == 0 || l[0] == nil { - return nil + return action } m, ok := l[0].(map[string]interface{}) if !ok { - return nil + return action } - action := &wafv2.CountAction{} - if v, ok := m["custom_request_handling"].([]interface{}); ok && len(v) > 0 { action.CustomRequestHandling = expandWafv2CustomRequestHandling(v) } @@ -621,17 +621,17 @@ func expandWafv2CountAction(l []interface{}) *wafv2.CountAction { } func expandWafv2BlockAction(l []interface{}) *wafv2.BlockAction { + action := &wafv2.BlockAction{} + if len(l) == 0 || l[0] == nil { - return nil + return action } m, ok := l[0].(map[string]interface{}) if !ok { - return nil + return action } - action := &wafv2.BlockAction{} - if v, ok := m["custom_response"].([]interface{}); ok && len(v) > 0 { action.CustomResponse = expandWafv2CustomResponse(v) } From 9f4f6af0cb4dfd3be2c52ccb96ea3e5b2b9e9982 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 24 May 2021 15:25:53 -0400 Subject: [PATCH 159/398] r/aws_cloudwatch_event_connection: Add waiters for connection creation and update. --- .../service/cloudwatchevents/finder/finder.go | 30 +++++ .../service/cloudwatchevents/waiter/status.go | 25 ++++ .../service/cloudwatchevents/waiter/waiter.go | 54 ++++---- ...esource_aws_cloudwatch_event_connection.go | 115 +++++++++--------- ...ce_aws_cloudwatch_event_connection_test.go | 39 +++--- 5 files changed, 166 insertions(+), 97 deletions(-) create mode 100644 aws/internal/service/cloudwatchevents/waiter/status.go diff --git a/aws/internal/service/cloudwatchevents/finder/finder.go b/aws/internal/service/cloudwatchevents/finder/finder.go index 14b1829448c..408979e14e7 100644 --- a/aws/internal/service/cloudwatchevents/finder/finder.go +++ b/aws/internal/service/cloudwatchevents/finder/finder.go @@ -5,10 +5,40 @@ import ( "github.com/aws/aws-sdk-go/aws" events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" tfevents "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents/lister" ) +func ConnectionByName(conn *events.CloudWatchEvents, name string) (*events.DescribeConnectionOutput, error) { + input := &events.DescribeConnectionInput{ + Name: aws.String(name), + } + + output, err := conn.DescribeConnection(input) + + if tfawserr.ErrCodeEquals(err, events.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 Rule(conn *events.CloudWatchEvents, eventBusName, ruleName string) (*events.DescribeRuleOutput, error) { input := events.DescribeRuleInput{ Name: aws.String(ruleName), diff --git a/aws/internal/service/cloudwatchevents/waiter/status.go b/aws/internal/service/cloudwatchevents/waiter/status.go new file mode 100644 index 00000000000..7201c0fee79 --- /dev/null +++ b/aws/internal/service/cloudwatchevents/waiter/status.go @@ -0,0 +1,25 @@ +package waiter + +import ( + "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/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func ConnectionState(conn *events.CloudWatchEvents, name string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.ConnectionByName(conn, name) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.ConnectionState), nil + } +} diff --git a/aws/internal/service/cloudwatchevents/waiter/waiter.go b/aws/internal/service/cloudwatchevents/waiter/waiter.go index 62189935c68..834d746a5ea 100644 --- a/aws/internal/service/cloudwatchevents/waiter/waiter.go +++ b/aws/internal/service/cloudwatchevents/waiter/waiter.go @@ -3,23 +3,38 @@ package waiter import ( "time" - "github.com/aws/aws-sdk-go/aws" events "github.com/aws/aws-sdk-go/service/cloudwatchevents" - "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) const ( - // ConnectionDeletedTimeout is the maximum amount of time to wait for a CloudwatchEvent Connection to delete + ConnectionCreatedTimeout = 2 * time.Minute ConnectionDeletedTimeout = 2 * time.Minute + ConnectionUpdatedTimeout = 2 * time.Minute ) -// CloudWatchEventConnectionDeleted waits for a CloudwatchEvent Connection to return Deleted -func CloudWatchEventConnectionDeleted(conn *events.CloudWatchEvents, id string) (*events.DescribeConnectionOutput, error) { +func ConnectionCreated(conn *events.CloudWatchEvents, id string) (*events.DescribeConnectionOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{events.ConnectionStateCreating, events.ConnectionStateAuthorizing}, + Target: []string{events.ConnectionStateAuthorized, events.ConnectionStateDeauthorized}, + Refresh: ConnectionState(conn, id), + Timeout: ConnectionCreatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*events.DescribeConnectionOutput); ok { + return v, err + } + + return nil, err +} + +func ConnectionDeleted(conn *events.CloudWatchEvents, id string) (*events.DescribeConnectionOutput, error) { stateConf := &resource.StateChangeConf{ Pending: []string{events.ConnectionStateDeleting}, Target: []string{}, - Refresh: CloudWatchEventConnectionStatus(conn, id), + Refresh: ConnectionState(conn, id), Timeout: ConnectionDeletedTimeout, } @@ -32,22 +47,19 @@ func CloudWatchEventConnectionDeleted(conn *events.CloudWatchEvents, id string) return nil, err } -// CloudWatchEventConnectionStatus fetches the Connection and its Status -func CloudWatchEventConnectionStatus(conn *events.CloudWatchEvents, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - params := events.DescribeConnectionInput{ - Name: aws.String(id), - } - - output, err := conn.DescribeConnection(¶ms) - if tfawserr.ErrMessageContains(err, events.ErrCodeResourceNotFoundException, "") { - return nil, "", nil - } +func ConnectionUpdated(conn *events.CloudWatchEvents, id string) (*events.DescribeConnectionOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{events.ConnectionStateUpdating, events.ConnectionStateAuthorizing, events.ConnectionStateDeauthorizing}, + Target: []string{events.ConnectionStateAuthorized, events.ConnectionStateDeauthorized}, + Refresh: ConnectionState(conn, id), + Timeout: ConnectionUpdatedTimeout, + } - if err != nil { - return nil, "", err - } + outputRaw, err := stateConf.WaitForState() - return output, aws.StringValue(output.ConnectionState), nil + if v, ok := outputRaw.(*events.DescribeConnectionOutput); ok { + return v, err } + + return nil, err } diff --git a/aws/resource_aws_cloudwatch_event_connection.go b/aws/resource_aws_cloudwatch_event_connection.go index 49f48e016c7..7ca4ffcaabd 100644 --- a/aws/resource_aws_cloudwatch_event_connection.go +++ b/aws/resource_aws_cloudwatch_event_connection.go @@ -7,9 +7,12 @@ import ( "github.com/aws/aws-sdk-go/aws" events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "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/cloudwatchevents/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsCloudWatchEventConnection() *schema.Resource { @@ -236,31 +239,32 @@ func resourceAwsCloudWatchEventConnection() *schema.Resource { func resourceAwsCloudWatchEventConnectionCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).cloudwatcheventsconn - input := &events.CreateConnectionInput{} - - if name, ok := d.GetOk("name"); ok { - input.Name = aws.String(name.(string)) - } - if description, ok := d.GetOk("description"); ok { - input.Description = aws.String(description.(string)) - } - if authorizationType, ok := d.GetOk("authorization_type"); ok { - input.AuthorizationType = aws.String(authorizationType.(string)) + name := d.Get("name").(string) + input := &events.CreateConnectionInput{ + AuthorizationType: aws.String(d.Get("authorization_type").(string)), + AuthParameters: expandAwsCloudWatchEventCreateConnectionAuthRequestParameters(d.Get("auth_parameters").([]interface{})), + Name: aws.String(name), } - if authParameters, ok := d.GetOk("auth_parameters"); ok { - input.AuthParameters = expandAwsCloudWatchEventCreateConnectionAuthRequestParameters(authParameters.([]interface{})) + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) } - log.Printf("[DEBUG] Creating CloudWatchEvent connection: %v", input) + log.Printf("[DEBUG] Creating CloudWatch Events connection: %s", input) _, err := conn.CreateConnection(input) + if err != nil { - return fmt.Errorf("Creating CloudWatchEvent connection (%s) failed: %w", *input.Name, err) + return fmt.Errorf("error creating CloudWatch Events connection (%s): %w", name, err) } - d.SetId(aws.StringValue(input.Name)) + d.SetId(name) - log.Printf("[INFO] CloudWatchEvent connection (%s) created", d.Id()) + _, err = waiter.ConnectionCreated(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for CloudWatch Events connection (%s) to create: %w", d.Id(), err) + } return resourceAwsCloudWatchEventConnectionRead(d, meta) } @@ -268,33 +272,28 @@ func resourceAwsCloudWatchEventConnectionCreate(d *schema.ResourceData, meta int func resourceAwsCloudWatchEventConnectionRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).cloudwatcheventsconn - input := &events.DescribeConnectionInput{ - Name: aws.String(d.Id()), - } + output, err := finder.ConnectionByName(conn, d.Id()) - log.Printf("[DEBUG] Reading CloudWatchEvent connection (%s)", d.Id()) - output, err := conn.DescribeConnection(input) - if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] CloudWatchEvent connection (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] CloudWatch Events connection (%s) not found, removing from state", d.Id()) d.SetId("") return nil } + if err != nil { - return fmt.Errorf("error reading CloudWatchEvent connection: %w", err) + return fmt.Errorf("error reading CloudWatch Events connection (%s): %w", d.Id(), err) } - log.Printf("[DEBUG] Found CloudWatchEvent connection: %#v", *output) - d.Set("arn", output.ConnectionArn) - d.Set("secret_arn", output.SecretArn) - d.Set("name", output.Name) - d.Set("description", output.Description) d.Set("authorization_type", output.AuthorizationType) + d.Set("description", output.Description) + d.Set("name", output.Name) + d.Set("secret_arn", output.SecretArn) if output.AuthParameters != nil { authParameters := flattenAwsCloudWatchEventConnectionAuthParameters(output.AuthParameters, d) if err := d.Set("auth_parameters", authParameters); err != nil { - return fmt.Errorf("Error setting authParameters error: %w", err) + return fmt.Errorf("error setting auth_parameters error: %w", err) } } @@ -304,55 +303,59 @@ func resourceAwsCloudWatchEventConnectionRead(d *schema.ResourceData, meta inter func resourceAwsCloudWatchEventConnectionUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).cloudwatcheventsconn - input := &events.UpdateConnectionInput{} - - if name, ok := d.GetOk("name"); ok { - input.Name = aws.String(name.(string)) + input := &events.UpdateConnectionInput{ + Name: aws.String(d.Id()), } - if description, ok := d.GetOk("description"); ok { - input.Description = aws.String(description.(string)) + + if v, ok := d.GetOk("authorization_type"); ok { + input.AuthorizationType = aws.String(v.(string)) } - if authorizationType, ok := d.GetOk("authorization_type"); ok { - input.AuthorizationType = aws.String(authorizationType.(string)) + + if v, ok := d.GetOk("auth_parameters"); ok { + input.AuthParameters = expandAwsCloudWatchEventUpdateConnectionAuthRequestParameters(v.([]interface{})) } - if authParameters, ok := d.GetOk("auth_parameters"); ok { - input.AuthParameters = expandAwsCloudWatchEventUpdateConnectionAuthRequestParameters(authParameters.([]interface{})) + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) } - log.Printf("[DEBUG] Updating CloudWatchEvent connection: %s", input) + log.Printf("[DEBUG] Updating CloudWatch Events connection: %s", input) _, err := conn.UpdateConnection(input) + if err != nil { - return fmt.Errorf("error updating CloudWatchEvent connection (%s): %w", d.Id(), err) + return fmt.Errorf("error updating CloudWatch Events connection (%s): %w", d.Id(), err) } + + _, err = waiter.ConnectionUpdated(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for CloudWatch Events connection (%s) to update: %w", d.Id(), err) + } + return resourceAwsCloudWatchEventConnectionRead(d, meta) } func resourceAwsCloudWatchEventConnectionDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).cloudwatcheventsconn - log.Printf("[INFO] Deleting CloudWatchEvent connection (%s)", d.Id()) - input := &events.DeleteConnectionInput{ + log.Printf("[INFO] Deleting CloudWatch Events connection (%s)", d.Id()) + _, err := conn.DeleteConnection(&events.DeleteConnectionInput{ Name: aws.String(d.Id()), - } - _, err := conn.DeleteConnection(input) + }) - if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] CloudWatchEvent connection (%s) not found", d.Id()) + if tfawserr.ErrCodeEquals(err, events.ErrCodeResourceNotFoundException) { return nil } + if err != nil { - return fmt.Errorf("Error deleting CloudWatchEvent connection (%s): %w", d.Id(), err) + return fmt.Errorf("error deleting CloudWatch Events connection (%s): %w", d.Id(), err) } - _, err = waiter.CloudWatchEventConnectionDeleted(conn, d.Id()) - if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] CloudWatchEvent connection (%s) not found", d.Id()) - return nil - } + _, err = waiter.ConnectionDeleted(conn, d.Id()) + if err != nil { - return fmt.Errorf("error waiting for CloudWatchEvent connection (%s) deletion: %s", d.Id(), err) + return fmt.Errorf("error waiting for CloudWatch Events connection (%s) to delete: %w", d.Id(), err) } - log.Printf("[INFO] CloudWatchEvent connection (%s) deleted", d.Id()) return nil } diff --git a/aws/resource_aws_cloudwatch_event_connection_test.go b/aws/resource_aws_cloudwatch_event_connection_test.go index ead4d6f872d..79a968889a0 100644 --- a/aws/resource_aws_cloudwatch_event_connection_test.go +++ b/aws/resource_aws_cloudwatch_event_connection_test.go @@ -8,12 +8,13 @@ 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" "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/cloudwatchevents/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -81,7 +82,7 @@ func TestAccAWSCloudWatchEventConnection_apiKey(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: testAccCheckAWSCloudWatchEventConnectionDestroy, Steps: []resource.TestStep{ @@ -163,7 +164,7 @@ func TestAccAWSCloudWatchEventConnection_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: testAccCheckAWSCloudWatchEventConnectionDestroy, Steps: []resource.TestStep{ @@ -282,7 +283,7 @@ func TestAccAWSCloudWatchEventConnection_oAuth(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: testAccCheckAWSCloudWatchEventConnectionDestroy, Steps: []resource.TestStep{ @@ -447,7 +448,7 @@ func TestAccAWSCloudWatchEventConnection_invocationHttpParameters(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: testAccCheckAWSCloudWatchEventConnectionDestroy, Steps: []resource.TestStep{ @@ -593,7 +594,7 @@ func TestAccAWSCloudWatchEventConnection_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: testAccCheckAWSCloudWatchEventConnectionDestroy, Steps: []resource.TestStep{ @@ -623,15 +624,17 @@ func testAccCheckAWSCloudWatchEventConnectionDestroy(s *terraform.State) error { continue } - params := events.DescribeConnectionInput{ - Name: aws.String(rs.Primary.ID), - } + _, err := finder.ConnectionByName(conn, rs.Primary.ID) - resp, err := conn.DescribeConnection(¶ms) + if tfresource.NotFound(err) { + continue + } - if err == nil { - return fmt.Errorf("CloudWatch Events Connection (%s) still exists: %s", rs.Primary.ID, resp) + if err != nil { + return err } + + return fmt.Errorf("CloudWatch Events connection %s still exists", rs.Primary.ID) } return nil @@ -645,18 +648,14 @@ func testAccCheckCloudWatchEventConnectionExists(n string, v *events.DescribeCon } conn := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn - params := events.DescribeConnectionInput{ - Name: aws.String(rs.Primary.ID), - } - resp, err := conn.DescribeConnection(¶ms) + + output, err := finder.ConnectionByName(conn, rs.Primary.ID) + if err != nil { return err } - if resp == nil { - return fmt.Errorf("CloudWatch Events Connection (%s) not found", n) - } - *v = *resp + *v = *output return nil } From 5283e38ff9fa019c0d8aa3059a41a03cf431a2c2 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Mon, 24 May 2021 20:02:50 +0000 Subject: [PATCH 160/398] Update CHANGELOG.md for #19502 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5203dfb135e..dbeb03b3f17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,11 @@ FEATURES: +* **New Data Source:** `aws_cloudwatch_event_connection` ([#18905](https://github.com/hashicorp/terraform-provider-aws/issues/18905)) * **New Resource:** `aws_amplify_app` ([#15966](https://github.com/hashicorp/terraform-provider-aws/issues/15966)) * **New Resource:** `aws_amplify_backend_environment` ([#11936](https://github.com/hashicorp/terraform-provider-aws/issues/11936)) +* **New Resource:** `aws_cloudwatch_event_api_destination` ([#18905](https://github.com/hashicorp/terraform-provider-aws/issues/18905)) +* **New Resource:** `aws_cloudwatch_event_connection` ([#18905](https://github.com/hashicorp/terraform-provider-aws/issues/18905)) * **New Resource:** `aws_servicecatalog_budget_resource_association` ([#19452](https://github.com/hashicorp/terraform-provider-aws/issues/19452)) * **New Resource:** `aws_servicecatalog_provisioning_artifact` ([#19316](https://github.com/hashicorp/terraform-provider-aws/issues/19316)) * **New Resource:** `aws_servicecatalog_tag_option_resource_association` ([#19448](https://github.com/hashicorp/terraform-provider-aws/issues/19448)) @@ -11,6 +14,7 @@ FEATURES: BUG FIXES: * data-source/aws_launch_template: Add `interface_type` to `network_interfaces` attribute ([#19492](https://github.com/hashicorp/terraform-provider-aws/issues/19492)) +* data-source/aws_mq_broker: Correct type for `logs.audit` attribute ([#19502](https://github.com/hashicorp/terraform-provider-aws/issues/19502)) * resource/aws_apprunner_service: Correctly configure `authentication_configuration`, `code_configuration`, and `image_configuration` nested arguments in API requests ([#19471](https://github.com/hashicorp/terraform-provider-aws/issues/19471)) * 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)) From 2d963b6a1ac03d84b635f549f072e3f8622ca062 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 24 May 2021 16:29:51 -0400 Subject: [PATCH 161/398] r/aws_batch_job_definition: Don't crash when setting 'timeout.attempt_duration_seconds' to 'null'. --- aws/resource_aws_batch_job_definition.go | 45 +++++++++++++++--------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/aws/resource_aws_batch_job_definition.go b/aws/resource_aws_batch_job_definition.go index 8f583ad83de..47e2268edfd 100644 --- a/aws/resource_aws_batch_job_definition.go +++ b/aws/resource_aws_batch_job_definition.go @@ -210,8 +210,8 @@ func resourceAwsBatchJobDefinitionCreate(d *schema.ResourceData, meta interface{ input.Tags = tags.IgnoreAws().BatchTags() } - if v, ok := d.GetOk("timeout"); ok { - input.Timeout = expandJobDefinitionTimeout(v.([]interface{})) + if v, ok := d.GetOk("timeout"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.Timeout = expandBatchJobTimeout(v.([]interface{})[0].(map[string]interface{})) } output, err := conn.RegisterJobDefinition(input) @@ -278,8 +278,12 @@ func resourceAwsBatchJobDefinitionRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("error setting tags_all: %w", err) } - if err := d.Set("timeout", flattenBatchJobTimeout(jobDefinition.Timeout)); err != nil { - return fmt.Errorf("error setting timeout: %w", err) + if jobDefinition.Timeout != nil { + if err := d.Set("timeout", []interface{}{flattenBatchJobTimeout(jobDefinition.Timeout)}); err != nil { + return fmt.Errorf("error setting timeout: %w", err) + } + } else { + d.Set("timeout", nil) } d.Set("revision", jobDefinition.Revision) @@ -488,23 +492,30 @@ func flattenBatchEvaluateOnExits(apiObjects []*batch.EvaluateOnExit) []interface return tfList } -func expandJobDefinitionTimeout(item []interface{}) *batch.JobTimeout { - timeout := &batch.JobTimeout{} - data := item[0].(map[string]interface{}) +func expandBatchJobTimeout(tfMap map[string]interface{}) *batch.JobTimeout { + if tfMap == nil { + return nil + } + + apiObject := &batch.JobTimeout{} - if v, ok := data["attempt_duration_seconds"].(int); ok && v >= 60 { - timeout.AttemptDurationSeconds = aws.Int64(int64(v)) + if v, ok := tfMap["attempt_duration_seconds"].(int); ok && v != 0 { + apiObject.AttemptDurationSeconds = aws.Int64(int64(v)) } - return timeout + return apiObject } -func flattenBatchJobTimeout(item *batch.JobTimeout) []map[string]interface{} { - data := []map[string]interface{}{} - if item != nil && item.AttemptDurationSeconds != nil { - data = append(data, map[string]interface{}{ - "attempt_duration_seconds": int(aws.Int64Value(item.AttemptDurationSeconds)), - }) +func flattenBatchJobTimeout(apiObject *batch.JobTimeout) map[string]interface{} { + if apiObject == nil { + return nil } - return data + + tfMap := map[string]interface{}{} + + if v := apiObject.AttemptDurationSeconds; v != nil { + tfMap["attempt_duration_seconds"] = aws.Int64Value(v) + } + + return tfMap } From 7fb917ee0372e6cbd4077a3347f1ebd51ec7c576 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 24 May 2021 16:33:36 -0400 Subject: [PATCH 162/398] Add CHANGELOG entry. --- .changelog/19505.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19505.txt diff --git a/.changelog/19505.txt b/.changelog/19505.txt new file mode 100644 index 00000000000..89dbec57814 --- /dev/null +++ b/.changelog/19505.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_batch_job_definition: Don't crash when setting `timeout.attempt_duration_seconds` to `null` +``` \ No newline at end of file From 8fb408e36b4f030fae8a18bb10e8c54dfeec4b63 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 May 2021 05:51:40 +0000 Subject: [PATCH 163/398] build(deps): bump github.com/aws/aws-sdk-go from 1.38.45 to 1.38.46 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.45 to 1.38.46. - [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.45...v1.38.46) 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 26ef4188b60..f4e500001a8 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.45 + github.com/aws/aws-sdk-go v1.38.46 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 005c8328e2b..6e49a85218e 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.45 h1:pQmv1vT/voRAjENnPsT4WobFBgLwnODDFogrt2kXc7M= -github.com/aws/aws-sdk-go v1.38.45/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.46 h1:voiwaKmwU1K6Y0dfjqTSiy5xOG4LPyr5sHD92cj+g2c= +github.com/aws/aws-sdk-go v1.38.46/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 fc895a577979b507cdfcbeb0b00d9527b7631261 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 May 2021 05:52:51 +0000 Subject: [PATCH 164/398] 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.45 to 1.38.46. - [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.45...v1.38.46) Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../github.com/aws/aws-sdk-go/aws/endpoints/defaults.go | 1 + .../vendor/github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 3d8806a94e3..f830dfceec1 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.45 + github.com/aws/aws-sdk-go v1.38.46 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 83d9a8da77a..196a64067af 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.45 h1:pQmv1vT/voRAjENnPsT4WobFBgLwnODDFogrt2kXc7M= -github.com/aws/aws-sdk-go v1.38.45/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.46 h1:voiwaKmwU1K6Y0dfjqTSiy5xOG4LPyr5sHD92cj+g2c= +github.com/aws/aws-sdk-go v1.38.46/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 961d40f8b32..b493eadeb37 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 @@ -5435,6 +5435,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 7f71a54fa81..54804378787 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.45" +const SDKVersion = "1.38.46" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index e10d7feb404..b7b99744fa8 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.45 +# github.com/aws/aws-sdk-go v1.38.46 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 3ac57592330f694f3f8b8e150839bff79c03947c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 May 2021 11:20:48 -0400 Subject: [PATCH 165/398] r/aws_ec2_managed_prefix_list: Fix crash with multiple description-only changes. --- aws/resource_aws_ec2_managed_prefix_list.go | 36 ++++++++++++------- ...source_aws_ec2_managed_prefix_list_test.go | 17 +++++++-- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/aws/resource_aws_ec2_managed_prefix_list.go b/aws/resource_aws_ec2_managed_prefix_list.go index 1f437358d6f..af36e110f2b 100644 --- a/aws/resource_aws_ec2_managed_prefix_list.go +++ b/aws/resource_aws_ec2_managed_prefix_list.go @@ -242,22 +242,32 @@ func resourceAwsEc2ManagedPrefixListUpdate(d *schema.ResourceData, meta interfac // one with a collection of all description-only removals and the // second one will add them all back. if len(input.AddEntries) > 0 && len(input.RemoveEntries) > 0 { - removalInput := &ec2.ModifyManagedPrefixListInput{ - CurrentVersion: input.CurrentVersion, - PrefixListId: aws.String(d.Id()), - } + descriptionOnlyRemovals := []*ec2.RemovePrefixListEntry{} + removals := []*ec2.RemovePrefixListEntry{} + + for _, removeEntry := range input.RemoveEntries { + inAddAndRemove := false - for idx, removeEntry := range input.RemoveEntries { for _, addEntry := range input.AddEntries { if aws.StringValue(addEntry.Cidr) == aws.StringValue(removeEntry.Cidr) { - removalInput.RemoveEntries = append(removalInput.RemoveEntries, input.RemoveEntries[idx]) - input.RemoveEntries = append(input.RemoveEntries[:idx], input.RemoveEntries[idx+1:]...) + inAddAndRemove = true + break } } + + if inAddAndRemove { + descriptionOnlyRemovals = append(descriptionOnlyRemovals, removeEntry) + } else { + removals = append(removals, removeEntry) + } } - if len(removalInput.RemoveEntries) > 0 { - _, err := conn.ModifyManagedPrefixList(removalInput) + if len(descriptionOnlyRemovals) > 0 { + _, err := conn.ModifyManagedPrefixList(&ec2.ModifyManagedPrefixListInput{ + CurrentVersion: input.CurrentVersion, + PrefixListId: aws.String(d.Id()), + RemoveEntries: descriptionOnlyRemovals, + }) if err != nil { return fmt.Errorf("error updating EC2 Managed Prefix List (%s): %w", d.Id(), err) @@ -274,12 +284,14 @@ func resourceAwsEc2ManagedPrefixListUpdate(d *schema.ResourceData, meta interfac } input.CurrentVersion = managedPrefixList.Version + } + if len(removals) > 0 { + input.RemoveEntries = removals + } else { // Prevent this error if RemoveEntries is list with no elements after removals: // InvalidRequest: The request received was invalid. - if len(input.RemoveEntries) == 0 { - input.RemoveEntries = nil - } + input.RemoveEntries = nil } } diff --git a/aws/resource_aws_ec2_managed_prefix_list_test.go b/aws/resource_aws_ec2_managed_prefix_list_test.go index f9f03499794..6f32c9dec78 100644 --- a/aws/resource_aws_ec2_managed_prefix_list_test.go +++ b/aws/resource_aws_ec2_managed_prefix_list_test.go @@ -170,11 +170,15 @@ func TestAccAwsEc2ManagedPrefixList_Entry_Description(t *testing.T) { ResourceName: resourceName, Check: resource.ComposeAggregateTestCheckFunc( testAccAwsEc2ManagedPrefixListExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "entry.#", "1"), + resource.TestCheckResourceAttr(resourceName, "entry.#", "2"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "entry.*", map[string]string{ "cidr": "1.0.0.0/8", "description": "description1", }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "entry.*", map[string]string{ + "cidr": "2.0.0.0/8", + "description": "description1", + }), resource.TestCheckResourceAttr(resourceName, "version", "1"), ), }, @@ -188,11 +192,15 @@ func TestAccAwsEc2ManagedPrefixList_Entry_Description(t *testing.T) { ResourceName: resourceName, Check: resource.ComposeAggregateTestCheckFunc( testAccAwsEc2ManagedPrefixListExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "entry.#", "1"), + resource.TestCheckResourceAttr(resourceName, "entry.#", "2"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "entry.*", map[string]string{ "cidr": "1.0.0.0/8", "description": "description2", }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "entry.*", map[string]string{ + "cidr": "2.0.0.0/8", + "description": "description2", + }), resource.TestCheckResourceAttr(resourceName, "version", "3"), // description-only updates require two operations ), }, @@ -416,6 +424,11 @@ resource "aws_ec2_managed_prefix_list" "test" { cidr = "1.0.0.0/8" description = %[2]q } + + entry { + cidr = "2.0.0.0/8" + description = %[2]q + } } `, rName, description) } From 96daf279baf44add9778955553cf67422e1e2cba Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 May 2021 11:24:36 -0400 Subject: [PATCH 166/398] Add CHANGELOG entry. --- .changelog/19517.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19517.txt diff --git a/.changelog/19517.txt b/.changelog/19517.txt new file mode 100644 index 00000000000..21ad4c42fe8 --- /dev/null +++ b/.changelog/19517.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_ec2_managed_prefix_list: Fix crash with multiple description-only updates +``` \ No newline at end of file From d89aa814b8b8b8c7649831240f86087c52b680dc Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 May 2021 11:36:46 -0400 Subject: [PATCH 167/398] Add CHANGELOG entry. --- .changelog/19482.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19482.txt diff --git a/.changelog/19482.txt b/.changelog/19482.txt new file mode 100644 index 00000000000..f43aebc5884 --- /dev/null +++ b/.changelog/19482.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_eks_node_group: Add `taint` argument +``` \ No newline at end of file From 0027824491f3d442530c8c71d81ba57c006160a6 Mon Sep 17 00:00:00 2001 From: kostas Date: Tue, 25 May 2021 17:48:53 +0300 Subject: [PATCH 168/398] fix minimum timeout_in_seconds --- .changelog/19515.txt | 3 +++ aws/resource_aws_synthetics_canary.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 .changelog/19515.txt diff --git a/.changelog/19515.txt b/.changelog/19515.txt new file mode 100644 index 00000000000..f41d46513e5 --- /dev/null +++ b/.changelog/19515.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_synthetics_canary: Change minimum `timeout_in_seconds` in `run_config` from `60` to `3` +``` diff --git a/aws/resource_aws_synthetics_canary.go b/aws/resource_aws_synthetics_canary.go index f04e4919d02..99518674bcf 100644 --- a/aws/resource_aws_synthetics_canary.go +++ b/aws/resource_aws_synthetics_canary.go @@ -96,7 +96,7 @@ func resourceAwsSyntheticsCanary() *schema.Resource { "timeout_in_seconds": { Type: schema.TypeInt, Optional: true, - ValidateFunc: validation.IntBetween(60, 14*60), + ValidateFunc: validation.IntBetween(3, 14*60), Default: 840, }, }, From a64adbce64bd2852df610e4569cc8be0ed29b2fc Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 May 2021 13:02:19 -0400 Subject: [PATCH 169/398] r/aws_eks_node_group: Rename 'taints' to 'taint'. --- aws/resource_aws_eks_node_group.go | 12 +++++------ aws/resource_aws_eks_node_group_test.go | 22 ++++++++++----------- website/docs/r/eks_node_group.html.markdown | 4 ++-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/aws/resource_aws_eks_node_group.go b/aws/resource_aws_eks_node_group.go index 80f8a5353b9..17001047f7a 100644 --- a/aws/resource_aws_eks_node_group.go +++ b/aws/resource_aws_eks_node_group.go @@ -220,7 +220,7 @@ func resourceAwsEksNodeGroup() *schema.Resource { }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), - "taints": { + "taint": { Type: schema.TypeSet, Optional: true, MaxItems: 50, @@ -308,7 +308,7 @@ func resourceAwsEksNodeGroupCreate(d *schema.ResourceData, meta interface{}) err input.Tags = tags.IgnoreAws().EksTags() } - if v, ok := d.GetOk("taints"); ok && v.(*schema.Set).Len() > 0 { + if v, ok := d.GetOk("taint"); ok && v.(*schema.Set).Len() > 0 { input.Taints = expandEksTaints(v.(*schema.Set).List()) } @@ -425,8 +425,8 @@ func resourceAwsEksNodeGroupRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error setting tags_all: %w", err) } - if err := d.Set("taints", flattenEksTaints(nodeGroup.Taints)); err != nil { - return fmt.Errorf("error setting taints: %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) @@ -443,7 +443,7 @@ func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) err return err } - if d.HasChanges("labels", "scaling_config", "taints") { + if d.HasChanges("labels", "scaling_config", "taint") { oldLabelsRaw, newLabelsRaw := d.GetChange("labels") input := &eks.UpdateNodegroupConfigInput{ @@ -457,7 +457,7 @@ func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) err input.ScalingConfig = expandEksNodegroupScalingConfig(v) } - oldTaintsRaw, newTaintsRaw := d.GetChange("taints") + oldTaintsRaw, newTaintsRaw := d.GetChange("taint") input.Taints = expandEksUpdateTaintsPayload(oldTaintsRaw.(*schema.Set).List(), newTaintsRaw.(*schema.Set).List()) output, err := conn.UpdateNodegroupConfig(input) diff --git a/aws/resource_aws_eks_node_group_test.go b/aws/resource_aws_eks_node_group_test.go index 8dc80d6e5a3..55a1ad905c5 100644 --- a/aws/resource_aws_eks_node_group_test.go +++ b/aws/resource_aws_eks_node_group_test.go @@ -126,7 +126,7 @@ func TestAccAWSEksNodeGroup_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "status", eks.NodegroupStatusActive), resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "2"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - resource.TestCheckResourceAttr(resourceName, "taints.#", "0"), + resource.TestCheckResourceAttr(resourceName, "taint.#", "0"), resource.TestCheckResourceAttrPair(resourceName, "version", eksClusterResourceName, "version"), ), }, @@ -834,8 +834,8 @@ func TestAccAWSEksNodeGroup_Taints(t *testing.T) { Config: testAccAWSEksNodeGroupConfigTaints1(rName, "key1", "value1", "NO_SCHEDULE"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup1), - resource.TestCheckResourceAttr(resourceName, "taints.#", "1"), - resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taints.*", map[string]string{ + resource.TestCheckResourceAttr(resourceName, "taint.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taint.*", map[string]string{ "key": "key1", "value": "value1", "effect": "NO_SCHEDULE", @@ -853,13 +853,13 @@ func TestAccAWSEksNodeGroup_Taints(t *testing.T) { "key2", "value2", "NO_SCHEDULE"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup1), - resource.TestCheckResourceAttr(resourceName, "taints.#", "2"), - resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taints.*", map[string]string{ + resource.TestCheckResourceAttr(resourceName, "taint.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taint.*", map[string]string{ "key": "key1", "value": "value1updated", "effect": "NO_EXECUTE", }), - resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taints.*", map[string]string{ + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taint.*", map[string]string{ "key": "key2", "value": "value2", "effect": "NO_SCHEDULE", @@ -870,8 +870,8 @@ func TestAccAWSEksNodeGroup_Taints(t *testing.T) { Config: testAccAWSEksNodeGroupConfigTaints1(rName, "key2", "value2", "NO_SCHEDULE"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup1), - resource.TestCheckResourceAttr(resourceName, "taints.#", "1"), - resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taints.*", map[string]string{ + resource.TestCheckResourceAttr(resourceName, "taint.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "taint.*", map[string]string{ "key": "key2", "value": "value2", "effect": "NO_SCHEDULE", @@ -1972,7 +1972,7 @@ resource "aws_eks_node_group" "test" { node_role_arn = aws_iam_role.node.arn subnet_ids = aws_subnet.test[*].id - taints { + taint { key = %[2]q value = %[3]q effect = %[4]q @@ -2001,13 +2001,13 @@ resource "aws_eks_node_group" "test" { node_role_arn = aws_iam_role.node.arn subnet_ids = aws_subnet.test[*].id - taints { + taint { key = %[2]q value = %[3]q effect = %[4]q } - taints { + taint { key = %[5]q value = %[6]q effect = %[7]q diff --git a/website/docs/r/eks_node_group.html.markdown b/website/docs/r/eks_node_group.html.markdown index 5e7c676ceaf..f7d4f6490d4 100644 --- a/website/docs/r/eks_node_group.html.markdown +++ b/website/docs/r/eks_node_group.html.markdown @@ -134,7 +134,7 @@ The following arguments are optional: * `release_version` – (Optional) AMI version of the EKS Node Group. Defaults to latest version for Kubernetes version. * `remote_access` - (Optional) Configuration block with remote access settings. 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. -* `taints` - (Optional) The Kubernetes taints to be applied to the nodes in the node group. Maximum of 50 taints per node group. Detailed below. +* `taint` - (Optional) The Kubernetes taints to be applied to the nodes in the node group. Maximum of 50 taints per node group. Detailed below. * `version` – (Optional) Kubernetes version. Defaults to EKS Cluster Kubernetes version. Terraform will only perform drift detection if a configuration value is provided. ### launch_template Configuration Block @@ -156,7 +156,7 @@ The following arguments are optional: * `max_size` - (Required) Maximum number of worker nodes. * `min_size` - (Required) Minimum number of worker nodes. -### taints Configuration Block +### taint Configuration Block * `key` - (Required) The key of the taint. Maximum length of 63. * `value` - (Optional) The value of the taint. Maximum length of 63. From ce7f743b088b08c9a52b6fa3de1f0144b054e5e9 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 25 May 2021 17:55:47 +0000 Subject: [PATCH 170/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbeb03b3f17..0927cf490e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ FEATURES: * **New Resource:** `aws_servicecatalog_provisioning_artifact` ([#19316](https://github.com/hashicorp/terraform-provider-aws/issues/19316)) * **New Resource:** `aws_servicecatalog_tag_option_resource_association` ([#19448](https://github.com/hashicorp/terraform-provider-aws/issues/19448)) +ENHANCEMENTS: + +* resource/aws_eks_node_group: Add `taint` argument ([#19482](https://github.com/hashicorp/terraform-provider-aws/issues/19482)) + BUG FIXES: * data-source/aws_launch_template: Add `interface_type` to `network_interfaces` attribute ([#19492](https://github.com/hashicorp/terraform-provider-aws/issues/19492)) @@ -20,6 +24,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_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)) +* 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)) ## 3.42.0 (May 20, 2021) From 23aa3b67a82a2d15b78cd81bdab35631819b5ace Mon Sep 17 00:00:00 2001 From: Joe Atzberger Date: Tue, 25 May 2021 15:27:04 -0400 Subject: [PATCH 171/398] Trivial typo correction --- website/docs/r/ec2_traffic_mirror_target.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/ec2_traffic_mirror_target.html.markdown b/website/docs/r/ec2_traffic_mirror_target.html.markdown index b25f5b03312..af7c1619a58 100644 --- a/website/docs/r/ec2_traffic_mirror_target.html.markdown +++ b/website/docs/r/ec2_traffic_mirror_target.html.markdown @@ -8,7 +8,7 @@ description: |- # Resource: aws_ec2_traffic_mirror_target -Provides an Traffic mirror target. +Provides a Traffic mirror target. Read [limits and considerations](https://docs.aws.amazon.com/vpc/latest/mirroring/traffic-mirroring-considerations.html) for traffic mirroring ## Example Usage From a9347f2d32ac1191cfe5d361d1ada2b982676e72 Mon Sep 17 00:00:00 2001 From: Judith Malnick Date: Tue, 25 May 2021 16:50:52 -0700 Subject: [PATCH 172/398] change page description and opening to active voice --- website/docs/index.html.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index ca240bd9902..9eeb19f1d93 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -2,14 +2,14 @@ layout: "aws" page_title: "Provider: AWS" description: |- - The Amazon Web Services (AWS) provider is used to interact with the many resources supported by AWS. The provider needs to be configured with the proper credentials before it can be used. + Use the Amazon Web Services (AWS) provider to interact with the many resources supported by AWS. You must configure the provider with the proper credentials before you can use it. --- # AWS Provider -The Amazon Web Services (AWS) provider is used to interact with the -many resources supported by AWS. The provider needs to be configured -with the proper credentials before it can be used. +Use the Amazon Web Services (AWS) provider to interact with the +many resources supported by AWS. You must configure the provider +with the proper credentials before you can use it. Use the navigation to the left to read about the available resources. From 26ee7994dd7a1c4e0ad9e4ad529de3d756c9d28c Mon Sep 17 00:00:00 2001 From: Judith Malnick Date: Tue, 25 May 2021 16:51:58 -0700 Subject: [PATCH 173/398] add link out to learn from provider docs --- website/docs/index.html.markdown | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index 9eeb19f1d93..3de4a40822c 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -13,6 +13,11 @@ with the proper credentials before you can use it. Use the navigation to the left to read about the available resources. +To learn the basics of Terraform using this provider, follow the +hands-on [get started tutorials](https://learn.hashicorp.com/tutorials/terraform/infrastructure-as-code?in=terraform/aws-get-started&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) on HashiCorp's Learn platform. Interact with AWS services, +including Lambda, RDS, and IAM by following the [AWS services +tutorials](https://learn.hashicorp.com/collections/terraform/aws?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS). + ## Example Usage Terraform 0.13 and later: From 481b778b6c5c2fd0af92d1ebabf1db20f7229bef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 May 2021 05:27:33 +0000 Subject: [PATCH 174/398] build(deps): bump hashicorp/github in /infrastructure/repository Bumps [hashicorp/github](https://github.com/hashicorp/terraform-provider-github) from 4.10.0 to 4.10.1. - [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) 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 2cb5ab673fa..6e3714578d5 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.0" + version = "4.10.1" } } From 6d3b8c9241ee266d4e7b0e748267f271996166f8 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Wed, 26 May 2021 09:38:23 +0300 Subject: [PATCH 175/398] add firehose args --- aws/resource_aws_sns_topic.go | 110 ++++++++++++++++++++++++----- aws/resource_aws_sns_topic_test.go | 39 ++++++++++ 2 files changed, 133 insertions(+), 16 deletions(-) diff --git a/aws/resource_aws_sns_topic.go b/aws/resource_aws_sns_topic.go index ecf7cb15db3..8e2f0c28228 100644 --- a/aws/resource_aws_sns_topic.go +++ b/aws/resource_aws_sns_topic.go @@ -75,8 +75,9 @@ func resourceAwsSnsTopic() *schema.Resource { }, }, "application_success_feedback_role_arn": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, }, "application_success_feedback_sample_rate": { Type: schema.TypeInt, @@ -84,12 +85,14 @@ func resourceAwsSnsTopic() *schema.Resource { ValidateFunc: validation.IntBetween(0, 100), }, "application_failure_feedback_role_arn": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, }, "http_success_feedback_role_arn": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, }, "http_success_feedback_sample_rate": { Type: schema.TypeInt, @@ -97,8 +100,9 @@ func resourceAwsSnsTopic() *schema.Resource { ValidateFunc: validation.IntBetween(0, 100), }, "http_failure_feedback_role_arn": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, }, "kms_master_key_id": { Type: schema.TypeString, @@ -115,9 +119,25 @@ func resourceAwsSnsTopic() *schema.Resource { Optional: true, Default: false, }, + "firehose_success_feedback_role_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, + }, + "firehose_success_feedback_sample_rate": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 100), + }, + "firehose_failure_feedback_role_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, + }, "lambda_success_feedback_role_arn": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, }, "lambda_success_feedback_sample_rate": { Type: schema.TypeInt, @@ -125,12 +145,14 @@ func resourceAwsSnsTopic() *schema.Resource { ValidateFunc: validation.IntBetween(0, 100), }, "lambda_failure_feedback_role_arn": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, }, "sqs_success_feedback_role_arn": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, }, "sqs_success_feedback_sample_rate": { Type: schema.TypeInt, @@ -138,13 +160,18 @@ func resourceAwsSnsTopic() *schema.Resource { ValidateFunc: validation.IntBetween(0, 100), }, "sqs_failure_feedback_role_arn": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, }, "arn": { Type: schema.TypeString, Computed: true, }, + "owner": { + Type: schema.TypeString, + Computed: true, + }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), }, @@ -298,6 +325,24 @@ func resourceAwsSnsTopicCreate(d *schema.ResourceData, meta interface{}) error { return err } } + if d.HasChange("firehose_failure_feedback_role_arn") { + _, v := d.GetChange("firehose_failure_feedback_role_arn") + if err := updateAwsSnsTopicAttribute(d.Id(), "FirehoseFailureFeedbackRoleArn", v, snsconn); err != nil { + return err + } + } + if d.HasChange("firehose_success_feedback_role_arn") { + _, v := d.GetChange("firehose_success_feedback_role_arn") + if err := updateAwsSnsTopicAttribute(d.Id(), "FirehoseSuccessFeedbackRoleArn", v, snsconn); err != nil { + return err + } + } + if d.HasChange("firehose_success_feedback_sample_rate") { + _, v := d.GetChange("firehose_success_feedback_sample_rate") + if err := updateAwsSnsTopicAttribute(d.Id(), "FirehoseSuccessFeedbackSampleRate", v, snsconn); err != nil { + return err + } + } return resourceAwsSnsTopicRead(d, meta) } @@ -414,6 +459,24 @@ func resourceAwsSnsTopicUpdate(d *schema.ResourceData, meta interface{}) error { return err } } + if d.HasChange("firehose_failure_feedback_role_arn") { + _, v := d.GetChange("firehose_failure_feedback_role_arn") + if err := updateAwsSnsTopicAttribute(d.Id(), "FirehoseFailureFeedbackRoleArn", v, snsconn); err != nil { + return err + } + } + if d.HasChange("firehose_success_feedback_role_arn") { + _, v := d.GetChange("firehose_success_feedback_role_arn") + if err := updateAwsSnsTopicAttribute(d.Id(), "FirehoseSuccessFeedbackRoleArn", v, snsconn); err != nil { + return err + } + } + if d.HasChange("firehose_success_feedback_sample_rate") { + _, v := d.GetChange("firehose_success_feedback_sample_rate") + if err := updateAwsSnsTopicAttribute(d.Id(), "FirehoseSuccessFeedbackSampleRate", v, snsconn); err != nil { + return err + } + } if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") @@ -463,6 +526,9 @@ func resourceAwsSnsTopicRead(d *schema.ResourceData, meta interface{}) error { d.Set("policy", attributeOutput.Attributes["Policy"]) d.Set("sqs_failure_feedback_role_arn", attributeOutput.Attributes["SQSFailureFeedbackRoleArn"]) d.Set("sqs_success_feedback_role_arn", attributeOutput.Attributes["SQSSuccessFeedbackRoleArn"]) + d.Set("firehose_success_feedback_role_arn", attributeOutput.Attributes["FirehoseSuccessFeedbackRoleArn"]) + d.Set("firehose_failure_feedback_role_arn", attributeOutput.Attributes["FirehoseFailureFeedbackRoleArn"]) + d.Set("owner", attributeOutput.Attributes["Owner"]) // set the boolean values if v, ok := attributeOutput.Attributes["FifoTopic"]; ok && aws.StringValue(v) == "true" { @@ -513,6 +579,15 @@ func resourceAwsSnsTopicRead(d *schema.ResourceData, meta interface{}) error { } d.Set("sqs_success_feedback_sample_rate", v) } + + vStr = aws.StringValue(attributeOutput.Attributes["FirehoseSuccessFeedbackSampleRate"]) + if vStr != "" { + v, err = strconv.ParseInt(vStr, 10, 64) + if err != nil { + return fmt.Errorf("error parsing integer attribute 'FirehoseSuccessFeedbackSampleRate': %w", err) + } + d.Set("firehose_success_feedback_sample_rate", v) + } } d.Set("fifo_topic", fifoTopic) @@ -560,6 +635,9 @@ func resourceAwsSnsTopicDelete(d *schema.ResourceData, meta interface{}) error { }) if err != nil { + if isAWSErr(err, sns.ErrCodeNotFoundException, "") { + return nil + } return fmt.Errorf("error deleting SNS Topic (%s): %w", d.Id(), err) } diff --git a/aws/resource_aws_sns_topic_test.go b/aws/resource_aws_sns_topic_test.go index f0d9872a4c0..c9223e7cd03 100644 --- a/aws/resource_aws_sns_topic_test.go +++ b/aws/resource_aws_sns_topic_test.go @@ -114,6 +114,7 @@ func TestAccAWSSNSTopic_basic(t *testing.T) { naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), resource.TestCheckResourceAttr(resourceName, "fifo_topic", "false"), + testAccCheckResourceAttrAccountID(resourceName, "owner"), ), }, { @@ -227,6 +228,11 @@ func TestAccAWSSNSTopic_withIAMRole(t *testing.T) { testAccCheckAWSSNSTopicExists(resourceName, attributes), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -304,8 +310,16 @@ func TestAccAWSSNSTopic_deliveryStatus(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "sqs_success_feedback_role_arn", iamRoleResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "sqs_success_feedback_sample_rate", "70"), resource.TestCheckResourceAttrPair(resourceName, "sqs_failure_feedback_role_arn", iamRoleResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "firehose_failure_feedback_role_arn", iamRoleResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "firehose_success_feedback_role_arn", iamRoleResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "firehose_success_feedback_sample_rate", "60"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -526,6 +540,28 @@ func TestAccAWSSNSTopic_tags(t *testing.T) { }) } +func TestAccAWSSNSTopic_disappears(t *testing.T) { + attributes := make(map[string]string) + resourceName := "aws_sns_topic.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sns.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSNSTopicDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSNSTopicConfigNameGenerated, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSNSTopicExists(resourceName, attributes), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSnsTopic(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAWSNSTopicHasPolicy(n string, expectedPolicyText string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -871,6 +907,9 @@ resource "aws_sns_topic" "test" { sqs_success_feedback_role_arn = aws_iam_role.example.arn sqs_success_feedback_sample_rate = 70 sqs_failure_feedback_role_arn = aws_iam_role.example.arn + firehose_success_feedback_sample_rate = 60 + firehose_failure_feedback_role_arn = aws_iam_role.example.arn + firehose_success_feedback_role_arn = aws_iam_role.example.arn } data "aws_partition" "current" {} From 0991527780ef5038a9062a25d5daebe39cd354ed Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Wed, 26 May 2021 09:39:45 +0300 Subject: [PATCH 176/398] docs --- website/docs/r/sns_topic.html.markdown | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/docs/r/sns_topic.html.markdown b/website/docs/r/sns_topic.html.markdown index 3273f1e684e..785ef0b5e15 100644 --- a/website/docs/r/sns_topic.html.markdown +++ b/website/docs/r/sns_topic.html.markdown @@ -92,6 +92,9 @@ The following arguments are supported: * `sqs_success_feedback_role_arn` - (Optional) The IAM role permitted to receive success feedback for this topic * `sqs_success_feedback_sample_rate` - (Optional) Percentage of success to sample * `sqs_failure_feedback_role_arn` - (Optional) IAM role for failure feedback +* `firehose_success_feedback_role_arn` - (Optional) The IAM role permitted to receive success feedback for this topic +* `firehose_success_feedback_sample_rate` - (Optional) Percentage of success to sample +* `firehose_failure_feedback_role_arn` - (Optional) IAM role for failure feedback * `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. ## Attributes Reference @@ -100,6 +103,7 @@ In addition to all arguments above, the following attributes are exported: * `id` - The ARN of the SNS topic * `arn` - The ARN of the SNS topic, as a more obvious property (clone of id) +* `owner` - The AWS Account ID of the SNS topic owner * `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 ae720e565ddf87b630454419ec7be5f4fb368c9e Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Wed, 26 May 2021 09:43:56 +0300 Subject: [PATCH 177/398] changelog --- .changelog/19528.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changelog/19528.txt diff --git a/.changelog/19528.txt b/.changelog/19528.txt new file mode 100644 index 00000000000..95babeb7b16 --- /dev/null +++ b/.changelog/19528.txt @@ -0,0 +1,11 @@ +```release-note:enhancement +resource/aws_sns_topic: Add `firehose_success_feedback_role_arn`, `firehose_success_feedback_sample_rate` and `firehose_failure_feedback_role_arn` arguments. +``` + +```release-note:enhancement +resource/aws_sns_topic: Add plan time validation for `application_success_feedback_role_arn`, `application_failure_feedback_role_arn`, `http_success_feedback_role_arn`, `http_failure_feedback_role_arn`, `lambda_success_feedback_role_arn`, `lambda_failure_feedback_role_arn`, `sqs_success_feedback_role_arn`, `sqs_failure_feedback_role_arn`. +``` + +```release-note:enhancement +resource/aws_sns_topic: Add `owner` attribute. +``` \ No newline at end of file From dd112338350811665f79fb47d977b96cc3c46951 Mon Sep 17 00:00:00 2001 From: hcourse-nydig Date: Mon, 17 May 2021 12:22:14 +0100 Subject: [PATCH 178/398] Added support for MSK SASL/IAM client authentication --- aws/resource_aws_msk_cluster.go | 12 +++- aws/resource_aws_msk_cluster_test.go | 82 ++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_msk_cluster.go b/aws/resource_aws_msk_cluster.go index 27e3784bf7f..516a2880ea6 100644 --- a/aws/resource_aws_msk_cluster.go +++ b/aws/resource_aws_msk_cluster.go @@ -112,6 +112,11 @@ func resourceAwsMskCluster() *schema.Resource { Optional: true, ForceNew: true, }, + "iam": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + }, }, }, ConflictsWith: []string{"client_authentication.0.tls"}, @@ -713,7 +718,7 @@ func expandMskClusterClientAuthentication(l []interface{}) *kafka.ClientAuthenti m := l[0].(map[string]interface{}) ca := &kafka.ClientAuthentication{ - Sasl: expandMskClusterScram(m["sasl"].([]interface{})), + Sasl: expandMskClusterSasl(m["sasl"].([]interface{})), Tls: expandMskClusterTls(m["tls"].([]interface{})), } @@ -770,7 +775,7 @@ func expandMskClusterEncryptionInTransit(l []interface{}) *kafka.EncryptionInTra return eit } -func expandMskClusterScram(l []interface{}) *kafka.Sasl { +func expandMskClusterSasl(l []interface{}) *kafka.Sasl { if len(l) == 0 || l[0] == nil { return nil } @@ -784,6 +789,9 @@ func expandMskClusterScram(l []interface{}) *kafka.Sasl { Scram: &kafka.Scram{ Enabled: aws.Bool(tfMap["scram"].(bool)), }, + Iam: &kafka.Iam{ + Enabled: aws.Bool(tfMap["iam"].(bool)), + }, } return sasl diff --git a/aws/resource_aws_msk_cluster_test.go b/aws/resource_aws_msk_cluster_test.go index 2fb0a1080b0..2ecad776e2b 100644 --- a/aws/resource_aws_msk_cluster_test.go +++ b/aws/resource_aws_msk_cluster_test.go @@ -273,6 +273,65 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Scram(t *testing.T) { }) } +func TestAccAWSMskCluster_ClientAuthentication_Sasl_Iam(t *testing.T) { + var cluster1, cluster2 kafka.ClusterInfo + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_msk_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMsk(t) }, + ErrorCheck: testAccErrorCheck(t, kafka.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckMskClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccMskClusterConfigClientAuthenticationSaslIam(rName, true), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckMskClusterExists(resourceName, &cluster1), + resource.TestCheckResourceAttr(resourceName, "client_authentication.#", "1"), + resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.#", "1"), + resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.iam", "true"), + + resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), + resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", mskClusterBoostrapBrokersSaslRegexp), + resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_tls", ""), + + testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_sasl_scram"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, + }, + { + Config: testAccMskClusterConfigClientAuthenticationSaslIam(rName, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckMskClusterExists(resourceName, &cluster2), + testAccCheckMskClusterRecreated(&cluster1, &cluster2), + resource.TestCheckResourceAttr(resourceName, "client_authentication.#", "1"), + resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.#", "1"), + resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.iam", "false"), + + resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), + resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", ""), + resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_tls", mskClusterBoostrapBrokersTlsRegexp), + + testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_tls"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSMskCluster_ClientAuthentication_Tls_CertificateAuthorityArns(t *testing.T) { TestAccSkip(t, "Requires the aws_acmpca_certificate_authority resource to support importing the root CA certificate") @@ -1083,6 +1142,29 @@ resource "aws_msk_cluster" "test" { `, rName, enabled) } +func testAccMskClusterConfigClientAuthenticationSaslIam(rName string, enabled bool) string { + return testAccMskClusterBaseConfig() + fmt.Sprintf(` +resource "aws_msk_cluster" "test" { + cluster_name = %[1]q + kafka_version = "2.6.0" + number_of_broker_nodes = 3 + + broker_node_group_info { + client_subnets = [aws_subnet.example_subnet_az1.id, aws_subnet.example_subnet_az2.id, aws_subnet.example_subnet_az3.id] + ebs_volume_size = 10 + instance_type = "kafka.m5.large" + security_groups = [aws_security_group.example_sg.id] + } + + client_authentication { + sasl { + iam = %t + } + } +} +`, rName, enabled) +} + func testAccMskClusterConfigConfigurationInfoRevision1(rName string) string { return testAccMskClusterBaseConfig() + fmt.Sprintf(` resource "aws_msk_configuration" "test" { From 546090df8ac85305c085301f9763533e3a42513a Mon Sep 17 00:00:00 2001 From: hcourse-nydig Date: Mon, 17 May 2021 12:28:55 +0100 Subject: [PATCH 179/398] gofmt --- aws/resource_aws_msk_cluster.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_msk_cluster.go b/aws/resource_aws_msk_cluster.go index 516a2880ea6..f56880e7a68 100644 --- a/aws/resource_aws_msk_cluster.go +++ b/aws/resource_aws_msk_cluster.go @@ -113,9 +113,9 @@ func resourceAwsMskCluster() *schema.Resource { ForceNew: true, }, "iam": { - Type: schema.TypeBool, - Optional: true, - ForceNew: true, + Type: schema.TypeBool, + Optional: true, + ForceNew: true, }, }, }, From 91d0a5be31c250ea53a771ebf6099cf18aafe3a2 Mon Sep 17 00:00:00 2001 From: hcourse-nydig Date: Mon, 17 May 2021 13:50:13 +0100 Subject: [PATCH 180/398] Fixed acceptance test cases --- aws/resource_aws_msk_cluster_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_msk_cluster_test.go b/aws/resource_aws_msk_cluster_test.go index 2ecad776e2b..e75c74d4119 100644 --- a/aws/resource_aws_msk_cluster_test.go +++ b/aws/resource_aws_msk_cluster_test.go @@ -293,8 +293,8 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Iam(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.iam", "true"), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), - resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", mskClusterBoostrapBrokersSaslRegexp), - resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_tls", ""), + resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", ""), + resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_tls", mskClusterBoostrapBrokersTlsRegexp), testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_sasl_scram"), ), From c6576462b6150a94bc8b68b9b69fb82d886c6598 Mon Sep 17 00:00:00 2001 From: hcourse-nydig Date: Mon, 17 May 2021 14:51:37 +0100 Subject: [PATCH 181/398] Added support for the sasl iam bootstrap brokers output --- aws/data_source_aws_msk_cluster.go | 5 +++++ aws/resource_aws_msk_cluster.go | 5 +++++ aws/resource_aws_msk_cluster_test.go | 6 +++--- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/aws/data_source_aws_msk_cluster.go b/aws/data_source_aws_msk_cluster.go index c46c155e6a2..7b67cb904f1 100644 --- a/aws/data_source_aws_msk_cluster.go +++ b/aws/data_source_aws_msk_cluster.go @@ -27,6 +27,10 @@ func dataSourceAwsMskCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "bootstrap_brokers_sasl_iam": { + Type: schema.TypeString, + Computed: true, + }, "bootstrap_brokers_tls": { Type: schema.TypeString, Computed: true, @@ -105,6 +109,7 @@ func dataSourceAwsMskClusterRead(d *schema.ResourceData, meta interface{}) error d.Set("arn", cluster.ClusterArn) d.Set("bootstrap_brokers", sortMskClusterEndpoints(aws.StringValue(bootstrapBrokersOutput.BootstrapBrokerString))) d.Set("bootstrap_brokers_sasl_scram", sortMskClusterEndpoints(aws.StringValue(bootstrapBrokersOutput.BootstrapBrokerStringSaslScram))) + d.Set("bootstrap_brokers_sasl_iam", sortMskClusterEndpoints(aws.StringValue(bootstrapBrokersOutput.BootstrapBrokerStringSaslIam))) d.Set("bootstrap_brokers_tls", sortMskClusterEndpoints(aws.StringValue(bootstrapBrokersOutput.BootstrapBrokerStringTls))) d.Set("cluster_name", cluster.ClusterName) d.Set("kafka_version", cluster.CurrentBrokerSoftwareInfo.KafkaVersion) diff --git a/aws/resource_aws_msk_cluster.go b/aws/resource_aws_msk_cluster.go index f56880e7a68..29fc929f93d 100644 --- a/aws/resource_aws_msk_cluster.go +++ b/aws/resource_aws_msk_cluster.go @@ -45,6 +45,10 @@ func resourceAwsMskCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "bootstrap_brokers_sasl_iam": { + Type: schema.TypeString, + Computed: true, + }, "bootstrap_brokers_tls": { Type: schema.TypeString, Computed: true, @@ -468,6 +472,7 @@ func resourceAwsMskClusterRead(d *schema.ResourceData, meta interface{}) error { d.Set("arn", cluster.ClusterArn) d.Set("bootstrap_brokers", sortMskClusterEndpoints(aws.StringValue(brokerOut.BootstrapBrokerString))) d.Set("bootstrap_brokers_sasl_scram", sortMskClusterEndpoints(aws.StringValue(brokerOut.BootstrapBrokerStringSaslScram))) + d.Set("bootstrap_brokers_sasl_iam", sortMskClusterEndpoints(aws.StringValue(brokerOut.BootstrapBrokerStringSaslIam))) d.Set("bootstrap_brokers_tls", sortMskClusterEndpoints(aws.StringValue(brokerOut.BootstrapBrokerStringTls))) if err := d.Set("broker_node_group_info", flattenMskBrokerNodeGroupInfo(cluster.BrokerNodeGroupInfo)); err != nil { diff --git a/aws/resource_aws_msk_cluster_test.go b/aws/resource_aws_msk_cluster_test.go index e75c74d4119..218c4a9ea1f 100644 --- a/aws/resource_aws_msk_cluster_test.go +++ b/aws/resource_aws_msk_cluster_test.go @@ -293,10 +293,10 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Iam(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.iam", "true"), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), - resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", ""), - resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_tls", mskClusterBoostrapBrokersTlsRegexp), + resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_sasl_iam", mskClusterBoostrapBrokersSaslRegexp), + resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_tls", ""), - testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_sasl_scram"), + testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_sasl_iam"), ), }, { From 15305275b7ef695f02737ac95841ebe04aa375e5 Mon Sep 17 00:00:00 2001 From: hcourse-nydig Date: Mon, 17 May 2021 14:52:29 +0100 Subject: [PATCH 182/398] Typo in test case --- aws/resource_aws_msk_cluster_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_msk_cluster_test.go b/aws/resource_aws_msk_cluster_test.go index 218c4a9ea1f..c7b952ae9ca 100644 --- a/aws/resource_aws_msk_cluster_test.go +++ b/aws/resource_aws_msk_cluster_test.go @@ -317,7 +317,7 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Iam(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.iam", "false"), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), - resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", ""), + resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_iam", ""), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_tls", mskClusterBoostrapBrokersTlsRegexp), testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_tls"), From 394c47a83b8c44b2774af9658b73e696122d78c9 Mon Sep 17 00:00:00 2001 From: hcourse-nydig Date: Mon, 17 May 2021 16:19:46 +0100 Subject: [PATCH 183/398] Added regex for iam broker connection strings --- aws/resource_aws_msk_cluster_test.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_msk_cluster_test.go b/aws/resource_aws_msk_cluster_test.go index c7b952ae9ca..52dbde867d1 100644 --- a/aws/resource_aws_msk_cluster_test.go +++ b/aws/resource_aws_msk_cluster_test.go @@ -57,7 +57,8 @@ func testSweepMskClusters(region string) error { const ( mskClusterPortPlaintext = 9092 - mskClusterPortSasl = 9096 + mskClusterPortSaslScram = 9096 + mskClusterPortSaslIam = 9098 mskClusterPortTls = 9094 mskClusterPortZookeeper = 2181 @@ -68,9 +69,10 @@ const ( ) var ( - mskClusterBoostrapBrokersRegexp = regexp.MustCompile(fmt.Sprintf(mskClusterBrokerRegexpFormat, mskClusterPortPlaintext)) - mskClusterBoostrapBrokersSaslRegexp = regexp.MustCompile(fmt.Sprintf(mskClusterBrokerRegexpFormat, mskClusterPortSasl)) - mskClusterBoostrapBrokersTlsRegexp = regexp.MustCompile(fmt.Sprintf(mskClusterBrokerRegexpFormat, mskClusterPortTls)) + mskClusterBoostrapBrokersRegexp = regexp.MustCompile(fmt.Sprintf(mskClusterBrokerRegexpFormat, mskClusterPortPlaintext)) + mskClusterBoostrapBrokersSaslScramRegexp = regexp.MustCompile(fmt.Sprintf(mskClusterBrokerRegexpFormat, mskClusterPortSaslScram)) + mskClusterBoostrapBrokersSaslIamRegexp = regexp.MustCompile(fmt.Sprintf(mskClusterBrokerRegexpFormat, mskClusterPortSaslIam)) + mskClusterBoostrapBrokersTlsRegexp = regexp.MustCompile(fmt.Sprintf(mskClusterBrokerRegexpFormat, mskClusterPortTls)) mskClusterZookeeperConnectStringRegexp = regexp.MustCompile(fmt.Sprintf(mskClusterBrokerRegexpFormat, mskClusterPortZookeeper)) ) @@ -234,7 +236,7 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Scram(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.scram", "true"), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), - resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", mskClusterBoostrapBrokersSaslRegexp), + resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", mskClusterBoostrapBrokersSaslScramRegexp), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_tls", ""), testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_sasl_scram"), @@ -293,7 +295,7 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Iam(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.iam", "true"), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), - resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_sasl_iam", mskClusterBoostrapBrokersSaslRegexp), + resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_sasl_iam", mskClusterBoostrapBrokersSaslIamRegexp), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_tls", ""), testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_sasl_iam"), From 2bbf0ccc41ec648e12c949ab80b0f28fc713192f Mon Sep 17 00:00:00 2001 From: hcourse-nydig Date: Tue, 18 May 2021 13:45:33 +0100 Subject: [PATCH 184/398] All tests passing --- aws/resource_aws_msk_cluster.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_msk_cluster.go b/aws/resource_aws_msk_cluster.go index 29fc929f93d..9e5608d8dae 100644 --- a/aws/resource_aws_msk_cluster.go +++ b/aws/resource_aws_msk_cluster.go @@ -1027,13 +1027,14 @@ func flattenMskSasl(sasl *kafka.Sasl) []map[string]interface{} { } m := map[string]interface{}{ - "scram": flattenMskScram(sasl.Scram), + "scram": flattenMskSaslScram(sasl.Scram), + "iam": flattenMskSaslIam(sasl.Iam), } return []map[string]interface{}{m} } -func flattenMskScram(scram *kafka.Scram) bool { +func flattenMskSaslScram(scram *kafka.Scram) bool { if scram == nil { return false } @@ -1041,6 +1042,14 @@ func flattenMskScram(scram *kafka.Scram) bool { return aws.BoolValue(scram.Enabled) } +func flattenMskSaslIam(iam *kafka.Iam) bool { + if iam == nil { + return false + } + + return aws.BoolValue(iam.Enabled) +} + func flattenMskTls(tls *kafka.Tls) []map[string]interface{} { if tls == nil { return []map[string]interface{}{} From c6baf029554473268ec9a3e0fc519b2227671878 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 May 2021 11:03:00 -0400 Subject: [PATCH 185/398] msk_cluster: Add changelog --- .changelog/19404.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/19404.txt diff --git a/.changelog/19404.txt b/.changelog/19404.txt new file mode 100644 index 00000000000..e1ea47bec81 --- /dev/null +++ b/.changelog/19404.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +data-source/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` attribute +``` + +```release-note:enhancement +resource/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` argument +``` \ No newline at end of file From 25b4db6497c62629c02fa2d04f475f9cb0395d56 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 May 2021 11:49:25 -0400 Subject: [PATCH 186/398] ds/msk_cluster: Adjust arg order --- aws/data_source_aws_msk_cluster.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/data_source_aws_msk_cluster.go b/aws/data_source_aws_msk_cluster.go index 7b67cb904f1..d6cd65c89f8 100644 --- a/aws/data_source_aws_msk_cluster.go +++ b/aws/data_source_aws_msk_cluster.go @@ -23,11 +23,11 @@ func dataSourceAwsMskCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "bootstrap_brokers_sasl_scram": { + "bootstrap_brokers_sasl_iam": { Type: schema.TypeString, Computed: true, }, - "bootstrap_brokers_sasl_iam": { + "bootstrap_brokers_sasl_scram": { Type: schema.TypeString, Computed: true, }, @@ -108,8 +108,8 @@ func dataSourceAwsMskClusterRead(d *schema.ResourceData, meta interface{}) error d.Set("arn", cluster.ClusterArn) d.Set("bootstrap_brokers", sortMskClusterEndpoints(aws.StringValue(bootstrapBrokersOutput.BootstrapBrokerString))) - d.Set("bootstrap_brokers_sasl_scram", sortMskClusterEndpoints(aws.StringValue(bootstrapBrokersOutput.BootstrapBrokerStringSaslScram))) d.Set("bootstrap_brokers_sasl_iam", sortMskClusterEndpoints(aws.StringValue(bootstrapBrokersOutput.BootstrapBrokerStringSaslIam))) + d.Set("bootstrap_brokers_sasl_scram", sortMskClusterEndpoints(aws.StringValue(bootstrapBrokersOutput.BootstrapBrokerStringSaslScram))) d.Set("bootstrap_brokers_tls", sortMskClusterEndpoints(aws.StringValue(bootstrapBrokersOutput.BootstrapBrokerStringTls))) d.Set("cluster_name", cluster.ClusterName) d.Set("kafka_version", cluster.CurrentBrokerSoftwareInfo.KafkaVersion) From 943745621d7979eae2f6ab43163de3b064a70e6f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 May 2021 11:50:05 -0400 Subject: [PATCH 187/398] tests/ds/msk_cluster: Update func call --- aws/data_source_aws_msk_cluster_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/data_source_aws_msk_cluster_test.go b/aws/data_source_aws_msk_cluster_test.go index 4ddfe159bc2..594f721bc17 100644 --- a/aws/data_source_aws_msk_cluster_test.go +++ b/aws/data_source_aws_msk_cluster_test.go @@ -39,7 +39,7 @@ func TestAccAWSMskClusterDataSource_Name(t *testing.T) { } func testAccMskClusterDataSourceConfigName(rName string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.2.1" @@ -60,5 +60,5 @@ resource "aws_msk_cluster" "test" { data "aws_msk_cluster" "test" { cluster_name = aws_msk_cluster.test.cluster_name } -`, rName) +`, rName)) } From d3ee2b4068299a3feea96414ed4c84ad43a0d9f2 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 May 2021 11:50:32 -0400 Subject: [PATCH 188/398] r/msk_cluster: Adjust arg order --- aws/resource_aws_msk_cluster.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_msk_cluster.go b/aws/resource_aws_msk_cluster.go index 9e5608d8dae..fd81f1a4a0f 100644 --- a/aws/resource_aws_msk_cluster.go +++ b/aws/resource_aws_msk_cluster.go @@ -41,11 +41,11 @@ func resourceAwsMskCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "bootstrap_brokers_sasl_scram": { + "bootstrap_brokers_sasl_iam": { Type: schema.TypeString, Computed: true, }, - "bootstrap_brokers_sasl_iam": { + "bootstrap_brokers_sasl_scram": { Type: schema.TypeString, Computed: true, }, @@ -471,8 +471,8 @@ func resourceAwsMskClusterRead(d *schema.ResourceData, meta interface{}) error { d.Set("arn", cluster.ClusterArn) d.Set("bootstrap_brokers", sortMskClusterEndpoints(aws.StringValue(brokerOut.BootstrapBrokerString))) - d.Set("bootstrap_brokers_sasl_scram", sortMskClusterEndpoints(aws.StringValue(brokerOut.BootstrapBrokerStringSaslScram))) d.Set("bootstrap_brokers_sasl_iam", sortMskClusterEndpoints(aws.StringValue(brokerOut.BootstrapBrokerStringSaslIam))) + d.Set("bootstrap_brokers_sasl_scram", sortMskClusterEndpoints(aws.StringValue(brokerOut.BootstrapBrokerStringSaslScram))) d.Set("bootstrap_brokers_tls", sortMskClusterEndpoints(aws.StringValue(brokerOut.BootstrapBrokerStringTls))) if err := d.Set("broker_node_group_info", flattenMskBrokerNodeGroupInfo(cluster.BrokerNodeGroupInfo)); err != nil { From ccbdc954b1934cffde66c1db3fe6bfee6468562c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 May 2021 11:51:02 -0400 Subject: [PATCH 189/398] tests/r/msk_cluster: Clean up tests --- aws/resource_aws_msk_cluster_test.go | 141 +++++++++++---------------- 1 file changed, 57 insertions(+), 84 deletions(-) diff --git a/aws/resource_aws_msk_cluster_test.go b/aws/resource_aws_msk_cluster_test.go index 52dbde867d1..fe899f11f0e 100644 --- a/aws/resource_aws_msk_cluster_test.go +++ b/aws/resource_aws_msk_cluster_test.go @@ -116,11 +116,9 @@ func TestAccAWSMskCluster_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "number_of_broker_nodes", "3"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestMatchResourceAttr(resourceName, "zookeeper_connect_string", mskClusterZookeeperConnectStringRegexp), - resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", ""), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_tls", mskClusterBoostrapBrokersTlsRegexp), - testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_tls"), testCheckResourceAttrIsSortedCsv(resourceName, "zookeeper_connect_string"), ), @@ -234,11 +232,9 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Scram(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "client_authentication.#", "1"), resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.#", "1"), resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.scram", "true"), - resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", mskClusterBoostrapBrokersSaslScramRegexp), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_tls", ""), - testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_sasl_scram"), ), }, @@ -258,11 +254,9 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Scram(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "client_authentication.#", "1"), resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.#", "1"), resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.scram", "false"), - resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", ""), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_tls", mskClusterBoostrapBrokersTlsRegexp), - testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_tls"), ), }, @@ -293,11 +287,9 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Iam(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "client_authentication.#", "1"), resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.#", "1"), resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.iam", "true"), - resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_sasl_iam", mskClusterBoostrapBrokersSaslIamRegexp), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_tls", ""), - testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_sasl_iam"), ), }, @@ -317,11 +309,9 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Iam(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "client_authentication.#", "1"), resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.#", "1"), resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.iam", "false"), - resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers", ""), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_iam", ""), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_tls", mskClusterBoostrapBrokersTlsRegexp), - testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_tls"), ), }, @@ -455,11 +445,9 @@ func TestAccAWSMskCluster_EncryptionInfo_EncryptionInTransit_ClientBroker(t *tes resource.TestCheckResourceAttr(resourceName, "encryption_info.#", "1"), resource.TestCheckResourceAttr(resourceName, "encryption_info.0.encryption_in_transit.#", "1"), resource.TestCheckResourceAttr(resourceName, "encryption_info.0.encryption_in_transit.0.client_broker", "PLAINTEXT"), - resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers", mskClusterBoostrapBrokersRegexp), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", ""), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_tls", ""), - testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers"), ), }, @@ -560,7 +548,6 @@ func TestAccAWSMskCluster_NumberOfBrokerNodes(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "broker_node_group_info.0.client_subnets.1", "aws_subnet.example_subnet_az2", "id"), resource.TestCheckResourceAttrPair(resourceName, "broker_node_group_info.0.client_subnets.2", "aws_subnet.example_subnet_az3", "id"), resource.TestCheckResourceAttr(resourceName, "number_of_broker_nodes", "3"), - testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_tls"), ), }, @@ -586,7 +573,6 @@ func TestAccAWSMskCluster_NumberOfBrokerNodes(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "broker_node_group_info.0.client_subnets.1", "aws_subnet.example_subnet_az2", "id"), resource.TestCheckResourceAttrPair(resourceName, "broker_node_group_info.0.client_subnets.2", "aws_subnet.example_subnet_az3", "id"), resource.TestCheckResourceAttr(resourceName, "number_of_broker_nodes", "6"), - testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_tls"), ), }, @@ -742,11 +728,9 @@ func TestAccAWSMskCluster_KafkaVersionDowngrade(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( testAccCheckMskClusterExists(resourceName, &cluster1), resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.4.1.1"), - resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers", mskClusterBoostrapBrokersRegexp), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", ""), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_tls", mskClusterBoostrapBrokersTlsRegexp), - testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers"), testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_tls"), ), @@ -762,11 +746,9 @@ func TestAccAWSMskCluster_KafkaVersionDowngrade(t *testing.T) { testAccCheckMskClusterExists(resourceName, &cluster2), testAccCheckMskClusterRecreated(&cluster1, &cluster2), resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.2.1"), - resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers", mskClusterBoostrapBrokersRegexp), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", ""), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_tls", mskClusterBoostrapBrokersTlsRegexp), - testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers"), testCheckResourceAttrIsSortedCsv(resourceName, "bootstrap_brokers_tls"), ), @@ -975,22 +957,13 @@ func testAccPreCheckAWSMsk(t *testing.T) { } } -func testAccMskClusterBaseConfig() string { - return ` +func testAccMskClusterBaseConfig(rName string) string { + return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(` resource "aws_vpc" "example_vpc" { cidr_block = "192.168.0.0/22" tags = { - Name = "tf-testacc-msk-cluster-vpc" - } -} - -data "aws_availability_zones" "available" { - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] + Name = %[1]q } } @@ -1000,7 +973,7 @@ resource "aws_subnet" "example_subnet_az1" { availability_zone = data.aws_availability_zones.available.names[0] tags = { - Name = "tf-testacc-msk-cluster-subnet-az1" + Name = %[1]q } } @@ -1010,7 +983,7 @@ resource "aws_subnet" "example_subnet_az2" { availability_zone = data.aws_availability_zones.available.names[1] tags = { - Name = "tf-testacc-msk-cluster-subnet-az2" + Name = %[1]q } } @@ -1020,18 +993,18 @@ resource "aws_subnet" "example_subnet_az3" { availability_zone = data.aws_availability_zones.available.names[2] tags = { - Name = "tf-testacc-msk-cluster-subnet-az3" + Name = %[1]q } } resource "aws_security_group" "example_sg" { vpc_id = aws_vpc.example_vpc.id } -` +`, rName)) } func testAccMskClusterConfig_basic(rName string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.2.1" @@ -1044,11 +1017,11 @@ resource "aws_msk_cluster" "test" { security_groups = [aws_security_group.example_sg.id] } } -`, rName) +`, rName)) } func testAccMskClusterConfigBrokerNodeGroupInfoEbsVolumeSize(rName string, ebsVolumeSize int) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.2.1" @@ -1061,11 +1034,11 @@ resource "aws_msk_cluster" "test" { security_groups = [aws_security_group.example_sg.id] } } -`, rName, ebsVolumeSize) +`, rName, ebsVolumeSize)) } func testAccMskClusterConfigBrokerNodeGroupInfoInstanceType(rName string, t string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.2.1" @@ -1078,11 +1051,11 @@ resource "aws_msk_cluster" "test" { security_groups = [aws_security_group.example_sg.id] } } -`, rName, t) +`, rName, t)) } func testAccMskClusterConfigClientAuthenticationTlsCertificateAuthorityArns(rName string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "test" { certificate_authority_configuration { key_algorithm = "RSA_4096" @@ -1118,11 +1091,11 @@ resource "aws_msk_cluster" "test" { } } } -`, rName) +`, rName)) } func testAccMskClusterConfigClientAuthenticationSaslScram(rName string, enabled bool) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.6.0" @@ -1141,11 +1114,11 @@ resource "aws_msk_cluster" "test" { } } } -`, rName, enabled) +`, rName, enabled)) } func testAccMskClusterConfigClientAuthenticationSaslIam(rName string, enabled bool) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.6.0" @@ -1164,11 +1137,11 @@ resource "aws_msk_cluster" "test" { } } } -`, rName, enabled) +`, rName, enabled)) } func testAccMskClusterConfigConfigurationInfoRevision1(rName string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_configuration" "test" { kafka_versions = ["2.2.1"] name = "%[1]s-1" @@ -1195,11 +1168,11 @@ resource "aws_msk_cluster" "test" { revision = aws_msk_configuration.test.latest_revision } } -`, rName) +`, rName)) } func testAccMskClusterConfigConfigurationInfoRevision2(rName string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_configuration" "test" { kafka_versions = ["2.2.1"] name = "%[1]s-1" @@ -1235,16 +1208,16 @@ resource "aws_msk_cluster" "test" { revision = aws_msk_configuration.test2.latest_revision } } -`, rName) +`, rName)) } func testAccMskClusterConfigEncryptionInfoEncryptionAtRestKmsKeyArn(rName string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_kms_key" "example_key" { - description = "tf-testacc-msk-cluster-kms" + description = %[1]q tags = { - Name = "tf-testacc-msk-cluster-kms" + Name = %[1]q } } @@ -1264,12 +1237,12 @@ resource "aws_msk_cluster" "test" { encryption_at_rest_kms_key_arn = aws_kms_key.example_key.arn } } -`, rName) +`, rName)) } func testAccMskClusterConfigEncryptionInfoEncryptionInTransitClientBroker(rName, clientBroker string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.2.1" @@ -1288,11 +1261,11 @@ resource "aws_msk_cluster" "test" { } } } -`, rName, clientBroker) +`, rName, clientBroker)) } func testAccMskClusterConfigEncryptionInfoEncryptionInTransitInCluster(rName string, inCluster bool) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.2.1" @@ -1311,11 +1284,11 @@ resource "aws_msk_cluster" "test" { } } } -`, rName, inCluster) +`, rName, inCluster)) } func testAccMskClusterConfigEnhancedMonitoring(rName, enhancedMonitoring string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q enhanced_monitoring = %[2]q @@ -1329,12 +1302,12 @@ resource "aws_msk_cluster" "test" { security_groups = [aws_security_group.example_sg.id] } } -`, rName, enhancedMonitoring) +`, rName, enhancedMonitoring)) } func testAccMskClusterConfigNumberOfBrokerNodes(rName string, brokerCount int) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.2.1" @@ -1347,12 +1320,12 @@ resource "aws_msk_cluster" "test" { security_groups = [aws_security_group.example_sg.id] } } -`, rName, brokerCount) +`, rName, brokerCount)) } func testAccMskClusterConfigOpenMonitoring(rName string, jmxExporterEnabled bool, nodeExporterEnabled bool) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.2.1" @@ -1377,7 +1350,7 @@ resource "aws_msk_cluster" "test" { } } } -`, rName, jmxExporterEnabled, nodeExporterEnabled) +`, rName, jmxExporterEnabled, nodeExporterEnabled)) } func testAccMskClusterConfigLoggingInfo(rName string, cloudwatchLogsEnabled bool, firehoseEnabled bool, s3Enabled bool) string { @@ -1386,16 +1359,16 @@ func testAccMskClusterConfigLoggingInfo(rName string, cloudwatchLogsEnabled bool s3Bucket := "" if cloudwatchLogsEnabled { - cloudwatchLogsLogGroup = "${aws_cloudwatch_log_group.test.name}" + cloudwatchLogsLogGroup = "aws_cloudwatch_log_group.test.name" } if firehoseEnabled { - firehoseDeliveryStream = "${aws_kinesis_firehose_delivery_stream.test.name}" + firehoseDeliveryStream = "aws_kinesis_firehose_delivery_stream.test.name" } if s3Enabled { - s3Bucket = "${aws_s3_bucket.bucket.id}" + s3Bucket = "aws_s3_bucket.bucket.id" } - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_cloudwatch_log_group" "test" { name = %[1]q } @@ -1463,27 +1436,27 @@ resource "aws_msk_cluster" "test" { broker_logs { cloudwatch_logs { enabled = %[2]t - log_group = %[3]q + log_group = %[3]s } firehose { enabled = %[4]t - delivery_stream = %[5]q + delivery_stream = %[5]s } s3 { enabled = %[6]t - bucket = %[7]q + bucket = %[7]s prefix = "" } } } } -`, rName, cloudwatchLogsEnabled, cloudwatchLogsLogGroup, firehoseEnabled, firehoseDeliveryStream, s3Enabled, s3Bucket) +`, rName, cloudwatchLogsEnabled, cloudwatchLogsLogGroup, firehoseEnabled, firehoseDeliveryStream, s3Enabled, s3Bucket)) } func testAccMskClusterConfigKafkaVersion(rName string, kafkaVersion string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = %[2]q @@ -1496,17 +1469,17 @@ resource "aws_msk_cluster" "test" { } broker_node_group_info { - client_subnets = ["${aws_subnet.example_subnet_az1.id}", "${aws_subnet.example_subnet_az2.id}", "${aws_subnet.example_subnet_az3.id}"] + client_subnets = [aws_subnet.example_subnet_az1.id, aws_subnet.example_subnet_az2.id, aws_subnet.example_subnet_az3.id] ebs_volume_size = 10 instance_type = "kafka.m5.large" - security_groups = ["${aws_security_group.example_sg.id}"] + security_groups = [aws_security_group.example_sg.id] } } -`, rName, kafkaVersion) +`, rName, kafkaVersion)) } func testAccMskClusterConfigKafkaVersionWithConfigurationInfo(rName string, kafkaVersion string, configResourceName string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_configuration" "config1" { kafka_versions = ["2.2.1"] name = "%[1]s-1" @@ -1535,10 +1508,10 @@ resource "aws_msk_cluster" "test" { } broker_node_group_info { - client_subnets = ["${aws_subnet.example_subnet_az1.id}", "${aws_subnet.example_subnet_az2.id}", "${aws_subnet.example_subnet_az3.id}"] + client_subnets = [aws_subnet.example_subnet_az1.id, aws_subnet.example_subnet_az2.id, aws_subnet.example_subnet_az3.id] ebs_volume_size = 10 instance_type = "kafka.m5.large" - security_groups = ["${aws_security_group.example_sg.id}"] + security_groups = [aws_security_group.example_sg.id] } configuration_info { @@ -1546,11 +1519,11 @@ resource "aws_msk_cluster" "test" { revision = aws_msk_configuration.%[3]s.latest_revision } } -`, rName, kafkaVersion, configResourceName) +`, rName, kafkaVersion, configResourceName)) } func testAccMskClusterConfigTags1(rName string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.2.1" @@ -1567,11 +1540,11 @@ resource "aws_msk_cluster" "test" { foo = "bar" } } -`, rName) +`, rName)) } func testAccMskClusterConfigTags2(rName string) string { - return testAccMskClusterBaseConfig() + fmt.Sprintf(` + return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q kafka_version = "2.2.1" @@ -1589,7 +1562,7 @@ resource "aws_msk_cluster" "test" { new = "type" } } -`, rName) +`, rName)) } func TestSortMskClusterEndpoints(t *testing.T) { From 41b3536acc59647db31204f9592ef2ae7becadf2 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 May 2021 11:51:37 -0400 Subject: [PATCH 190/398] tests/r/msk_scram_secret_association: Update func call --- aws/resource_aws_msk_scram_secret_association_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_msk_scram_secret_association_test.go b/aws/resource_aws_msk_scram_secret_association_test.go index 6b5641a1edb..b070493be1c 100644 --- a/aws/resource_aws_msk_scram_secret_association_test.go +++ b/aws/resource_aws_msk_scram_secret_association_test.go @@ -240,7 +240,7 @@ POLICY func testAccMskScramSecretAssociation_basic(rName string, count int) string { return composeConfig( - testAccMskClusterBaseConfig(), + testAccMskClusterBaseConfig(rName), testAccMskScramSecretAssociationBaseConfig(rName, count), ` resource "aws_msk_scram_secret_association" "test" { cluster_arn = aws_msk_cluster.test.arn From 702efc0973287d65bf1a0c00eec9bd334f8ec93e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 May 2021 12:08:44 -0400 Subject: [PATCH 191/398] tests/r/msk_cluster: Fix empty condition --- aws/resource_aws_msk_cluster_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_msk_cluster_test.go b/aws/resource_aws_msk_cluster_test.go index fe899f11f0e..c3f08d4c008 100644 --- a/aws/resource_aws_msk_cluster_test.go +++ b/aws/resource_aws_msk_cluster_test.go @@ -1354,9 +1354,9 @@ resource "aws_msk_cluster" "test" { } func testAccMskClusterConfigLoggingInfo(rName string, cloudwatchLogsEnabled bool, firehoseEnabled bool, s3Enabled bool) string { - cloudwatchLogsLogGroup := "" - firehoseDeliveryStream := "" - s3Bucket := "" + cloudwatchLogsLogGroup := "\"\"" + firehoseDeliveryStream := "\"\"" + s3Bucket := "\"\"" if cloudwatchLogsEnabled { cloudwatchLogsLogGroup = "aws_cloudwatch_log_group.test.name" From e7225654be590c8977db8bab24d8622ca9a6f4aa Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 May 2021 14:56:23 -0400 Subject: [PATCH 192/398] docs/r/msk_cluster: Update docs --- website/docs/r/msk_cluster.html.markdown | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/website/docs/r/msk_cluster.html.markdown b/website/docs/r/msk_cluster.html.markdown index 378af634f0f..cb6a219ef02 100644 --- a/website/docs/r/msk_cluster.html.markdown +++ b/website/docs/r/msk_cluster.html.markdown @@ -191,6 +191,7 @@ The following arguments are supported: #### client_authentication sasl Argument Reference +* `iam` - (Optional) Enables IAM client authentication. Defaults to `false`. * `scram` - (Optional) Enables SCRAM client authentication via AWS Secrets Manager. Defaults to `false`. #### client_authentication tls Argument Reference @@ -254,9 +255,10 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `arn` - Amazon Resource Name (ARN) of the MSK cluster. -* `bootstrap_brokers` - A comma separated list of one or more hostname:port pairs of kafka brokers suitable to boostrap connectivity to the kafka cluster. Only contains value if `client_broker` encryption in transit is set to `PLAINTEXT` or `TLS_PLAINTEXT`. The returned values are sorted alphbetically. The AWS API may not return all endpoints, so this value is not guaranteed to be stable across applies. -* `bootstrap_brokers_sasl_scram` - A comma separated list of one or more DNS names (or IPs) and TLS port pairs kafka brokers suitable to boostrap connectivity using SASL/SCRAM to the kafka cluster. Only contains value if `client_broker` encryption in transit is set to `TLS_PLAINTEXT` or `TLS` and `client_authentication` is set to `sasl`. The returned values are sorted alphbetically. The AWS API may not return all endpoints, so this value is not guaranteed to be stable across applies. -* `bootstrap_brokers_tls` - A comma separated list of one or more DNS names (or IPs) and TLS port pairs kafka brokers suitable to boostrap connectivity to the kafka cluster. Only contains value if `client_broker` encryption in transit is set to `TLS_PLAINTEXT` or `TLS`. The returned values are sorted alphbetically. The AWS API may not return all endpoints, so this value is not guaranteed to be stable across applies. +* `bootstrap_brokers` - Comma separated list of one or more hostname:port pairs of kafka brokers suitable to bootstrap connectivity to the kafka cluster. Contains a value if `encryption_info.0.encryption_in_transit.0.client_broker` is set to `PLAINTEXT` or `TLS_PLAINTEXT`. The resource sorts values alphabetically. AWS may not always return all endpoints so this value is not guaranteed to be stable across applies. +* `bootstrap_brokers_sasl_iam` - One or more DNS names (or IP addresses) and SASL IAM port pairs. For example, `b-1.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9098,b-2.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9098,b-3.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9098`. This attribute will have a value if `encryption_info.0.encryption_in_transit.0.client_broker` is set to `TLS_PLAINTEXT` or `TLS` and `client_authentication.0.sasl.0.iam` is set to `true`. The resource sorts the list alphabetically. AWS may not always return all endpoints so the values may not be stable across applies. +* `bootstrap_brokers_sasl_scram` - One or more DNS names (or IP addresses) and SASL SCRAM port pairs. For example, `b-1.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9096,b-2.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9096,b-3.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9096`. This attribute will have a value if `encryption_info.0.encryption_in_transit.0.client_broker` is set to `TLS_PLAINTEXT` or `TLS` and `client_authentication.0.sasl.0.scram` is set to `true`. The resource sorts the list alphabetically. AWS may not always return all endpoints so the values may not be stable across applies. +* `bootstrap_brokers_tls` - One or more DNS names (or IP addresses) and TLS port pairs. For example, `b-1.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9094,b-2.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9094,b-3.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9094`. This attribute will have a value if `encryption_info.0.encryption_in_transit.0.client_broker` is set to `TLS_PLAINTEXT` or `TLS`. The resource sorts the list alphabetically. AWS may not always return all endpoints so the values may not be stable across applies. * `current_version` - Current version of the MSK Cluster used for updates, e.g. `K13V1IB3VIYZZH` * `encryption_info.0.encryption_at_rest_kms_key_arn` - The ARN of the KMS key used for encryption at rest of the broker data volumes. * `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 e56aaf17bb87ee3bc124e2a0e31edb9e77c16dd9 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 May 2021 14:56:39 -0400 Subject: [PATCH 193/398] docs/ds/msk_cluster: Update docs --- website/docs/d/msk_cluster.html.markdown | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/website/docs/d/msk_cluster.html.markdown b/website/docs/d/msk_cluster.html.markdown index a5ac3e56b3c..519f982fa31 100644 --- a/website/docs/d/msk_cluster.html.markdown +++ b/website/docs/d/msk_cluster.html.markdown @@ -29,9 +29,10 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `arn` - Amazon Resource Name (ARN) of the MSK cluster. -* `bootstrap_brokers` - A comma separated list of one or more hostname:port pairs of Kafka brokers suitable to boostrap connectivity to the Kafka cluster. Only contains value if `client_broker` encryption in transit is set to `PLAINTEXT` or `TLS_PLAINTEXT`. The returned values are sorted alphbetically. The AWS API may not return all endpoints, so this value is not guaranteed to be stable across applies. -* `bootstrap_brokers_sasl_scram` - A comma separated list of one or more DNS names (or IPs) and TLS port pairs kafka brokers suitable to boostrap connectivity using SASL/SCRAM to the kafka cluster. Only contains value if `client_broker` encryption in transit is set to `TLS_PLAINTEXT` or `TLS` and `client_authentication` is set to `sasl`. The returned values are sorted alphbetically. The AWS API may not return all endpoints, so this value is not guaranteed to be stable across applies. -* `bootstrap_brokers_tls` - A comma separated list of one or more DNS names (or IPs) and TLS port pairs kafka brokers suitable to boostrap connectivity to the kafka cluster. Only contains value if `client_broker` encryption in transit is set to `TLS_PLAINTEXT` or `TLS`. The returned values are sorted alphbetically. The AWS API may not return all endpoints, so this value is not guaranteed to be stable across applies. +* `bootstrap_brokers` - Comma separated list of one or more hostname:port pairs of kafka brokers suitable to bootstrap connectivity to the kafka cluster. Contains a value if `encryption_info.0.encryption_in_transit.0.client_broker` is set to `PLAINTEXT` or `TLS_PLAINTEXT`. The resource sorts values alphabetically. AWS may not always return all endpoints so this value is not guaranteed to be stable across applies. +* `bootstrap_brokers_sasl_iam` - One or more DNS names (or IP addresses) and SASL IAM port pairs. For example, `b-1.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9098,b-2.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9098,b-3.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9098`. This attribute will have a value if `encryption_info.0.encryption_in_transit.0.client_broker` is set to `TLS_PLAINTEXT` or `TLS` and `client_authentication.0.sasl.0.iam` is set to `true`. The resource sorts the list alphabetically. AWS may not always return all endpoints so the values may not be stable across applies. +* `bootstrap_brokers_sasl_scram` - One or more DNS names (or IP addresses) and SASL SCRAM port pairs. For example, `b-1.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9096,b-2.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9096,b-3.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9096`. This attribute will have a value if `encryption_info.0.encryption_in_transit.0.client_broker` is set to `TLS_PLAINTEXT` or `TLS` and `client_authentication.0.sasl.0.scram` is set to `true`. The resource sorts the list alphabetically. AWS may not always return all endpoints so the values may not be stable across applies. +* `bootstrap_brokers_tls` - One or more DNS names (or IP addresses) and TLS port pairs. For example, `b-1.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9094,b-2.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9094,b-3.exampleClusterName.abcde.c2.kafka.us-east-1.amazonaws.com:9094`. This attribute will have a value if `encryption_info.0.encryption_in_transit.0.client_broker` is set to `TLS_PLAINTEXT` or `TLS`. The resource sorts the list alphabetically. AWS may not always return all endpoints so the values may not be stable across applies. * `kafka_version` - Apache Kafka version. * `number_of_broker_nodes` - Number of broker nodes in the cluster. * `tags` - Map of key-value pairs assigned to the cluster. From 632ce3d2365e8fb2141c4e9b38e87f187d61ae3c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 09:53:26 -0400 Subject: [PATCH 194/398] Add CHANGELOG entry. --- .changelog/17571.txt | 3 +++ tools/go.sum | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 .changelog/17571.txt diff --git a/.changelog/17571.txt b/.changelog/17571.txt new file mode 100644 index 00000000000..af769263bcc --- /dev/null +++ b/.changelog/17571.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_msk_configuration: `kafka_versions` argument is optional +``` \ No newline at end of file diff --git a/tools/go.sum b/tools/go.sum index 8fd0508eca6..678e9fe5719 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -420,8 +420,6 @@ github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/S github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= github.com/hashicorp/go-getter v1.5.0/go.mod h1:a7z7NPPfNQpJWcn4rSWFtdrSldqLdLPEF3d8nFMsSLM= -github.com/hashicorp/go-getter v1.5.1 h1:lM9sM02nvEApQGFgkXxWbhfqtyN+AyhQmi+MaMdBDOI= -github.com/hashicorp/go-getter v1.5.1/go.mod h1:a7z7NPPfNQpJWcn4rSWFtdrSldqLdLPEF3d8nFMsSLM= github.com/hashicorp/go-getter v1.5.2 h1:XDo8LiAcDisiqZdv0TKgz+HtX3WN7zA2JD1R1tjsabE= github.com/hashicorp/go-getter v1.5.2/go.mod h1:orNH3BTYLu/fIxGIdLjLoAJHWMDQ/UKQr5O4m3iBuoo= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= From 7440f1fbd16ddbe1ce97bba5081b58f9b7a60aee Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 10:02:25 -0400 Subject: [PATCH 195/398] r/aws_msk_configuration: Tweak acceptance tests. --- aws/resource_aws_msk_configuration.go | 2 +- aws/resource_aws_msk_configuration_test.go | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_msk_configuration.go b/aws/resource_aws_msk_configuration.go index c644b789ee4..1fcc3fd2837 100644 --- a/aws/resource_aws_msk_configuration.go +++ b/aws/resource_aws_msk_configuration.go @@ -67,7 +67,7 @@ func resourceAwsMskConfigurationCreate(d *schema.ResourceData, meta interface{}) input.Description = aws.String(v.(string)) } - if v, ok := d.GetOk("kafka_versions"); ok { + if v, ok := d.GetOk("kafka_versions"); ok && v.(*schema.Set).Len() > 0 { input.KafkaVersions = expandStringSet(v.(*schema.Set)) } diff --git a/aws/resource_aws_msk_configuration_test.go b/aws/resource_aws_msk_configuration_test.go index a322b06f7bd..c3194e161e1 100644 --- a/aws/resource_aws_msk_configuration_test.go +++ b/aws/resource_aws_msk_configuration_test.go @@ -91,6 +91,7 @@ func TestAccAWSMskConfiguration_basic(t *testing.T) { testAccCheckMskConfigurationExists(resourceName, &configuration1), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "kafka", regexp.MustCompile(`configuration/.+`)), resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "kafka_versions.#", "0"), resource.TestCheckResourceAttr(resourceName, "latest_revision", "1"), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestMatchResourceAttr(resourceName, "server_properties", regexp.MustCompile(`auto.create.topics.enable = true`)), @@ -176,6 +177,8 @@ func TestAccAWSMskConfiguration_KafkaVersions(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckMskConfigurationExists(resourceName, &configuration1), resource.TestCheckResourceAttr(resourceName, "kafka_versions.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "kafka_versions.*", "2.6.0"), + resource.TestCheckTypeSetElemAttr(resourceName, "kafka_versions.*", "2.7.0"), ), }, { @@ -311,7 +314,7 @@ PROPERTIES func testAccMskConfigurationConfigKafkaVersions(rName string) string { return fmt.Sprintf(` resource "aws_msk_configuration" "test" { - kafka_versions = ["1.1.1", "2.1.0"] + kafka_versions = ["2.6.0", "2.7.0"] name = %[1]q server_properties = < Date: Wed, 26 May 2021 10:06:11 -0400 Subject: [PATCH 196/398] r/msk_cluster: Rearrange D in CRUD, tweak expand SASL --- aws/resource_aws_msk_cluster.go | 56 ++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/aws/resource_aws_msk_cluster.go b/aws/resource_aws_msk_cluster.go index fd81f1a4a0f..ee01552e569 100644 --- a/aws/resource_aws_msk_cluster.go +++ b/aws/resource_aws_msk_cluster.go @@ -690,7 +690,25 @@ func resourceAwsMskClusterUpdate(d *schema.ResourceData, meta interface{}) error } return resourceAwsMskClusterRead(d, meta) +} + +func resourceAwsMskClusterDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).kafkaconn + + log.Printf("[DEBUG] Deleting MSK cluster: %q", d.Id()) + _, err := conn.DeleteCluster(&kafka.DeleteClusterInput{ + ClusterArn: aws.String(d.Id()), + }) + if err != nil { + if isAWSErr(err, kafka.ErrCodeNotFoundException, "") { + return nil + } + return fmt.Errorf("failed deleting MSK cluster %q: %s", d.Id(), err) + } + + log.Printf("[DEBUG] Waiting for MSK cluster %q to be deleted", d.Id()) + return resourceAwsMskClusterDeleteWaiter(conn, d.Id()) } func expandMskClusterBrokerNodeGroupInfo(l []interface{}) *kafka.BrokerNodeGroupInfo { @@ -790,13 +808,18 @@ func expandMskClusterSasl(l []interface{}) *kafka.Sasl { return nil } - sasl := &kafka.Sasl{ - Scram: &kafka.Scram{ - Enabled: aws.Bool(tfMap["scram"].(bool)), - }, - Iam: &kafka.Iam{ - Enabled: aws.Bool(tfMap["iam"].(bool)), - }, + sasl := &kafka.Sasl{} + + if v, ok := tfMap["scram"].(bool); ok { + sasl.Scram = &kafka.Scram{ + Enabled: aws.Bool(v), + } + } + + if v, ok := tfMap["iam"].(bool); ok { + sasl.Iam = &kafka.Iam{ + Enabled: aws.Bool(v), + } } return sasl @@ -1177,25 +1200,6 @@ func flattenMskLoggingInfoBrokerLogsS3(e *kafka.S3) []map[string]interface{} { return []map[string]interface{}{m} } -func resourceAwsMskClusterDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).kafkaconn - - log.Printf("[DEBUG] Deleting MSK cluster: %q", d.Id()) - _, err := conn.DeleteCluster(&kafka.DeleteClusterInput{ - ClusterArn: aws.String(d.Id()), - }) - if err != nil { - if isAWSErr(err, kafka.ErrCodeNotFoundException, "") { - return nil - } - return fmt.Errorf("failed deleting MSK cluster %q: %s", d.Id(), err) - } - - log.Printf("[DEBUG] Waiting for MSK cluster %q to be deleted", d.Id()) - - return resourceAwsMskClusterDeleteWaiter(conn, d.Id()) -} - func resourceAwsMskClusterDeleteWaiter(conn *kafka.Kafka, arn string) error { input := &kafka.DescribeClusterInput{ ClusterArn: aws.String(arn), From 13b9e82cfbfacadaa1cd5fca57dd20439ac873eb Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 26 May 2021 10:06:41 -0400 Subject: [PATCH 197/398] tests/r/msk_cluster: Update versions --- aws/resource_aws_msk_cluster_test.go | 70 ++++++++++++++-------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/aws/resource_aws_msk_cluster_test.go b/aws/resource_aws_msk_cluster_test.go index c3f08d4c008..22c670f8cb3 100644 --- a/aws/resource_aws_msk_cluster_test.go +++ b/aws/resource_aws_msk_cluster_test.go @@ -112,7 +112,7 @@ func TestAccAWSMskCluster_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "encryption_info.0.encryption_in_transit.0.client_broker", "TLS"), resource.TestCheckResourceAttr(resourceName, "encryption_info.0.encryption_in_transit.0.in_cluster", "true"), resource.TestCheckResourceAttr(resourceName, "enhanced_monitoring", kafka.EnhancedMonitoringDefault), - resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.2.1"), + resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.7.1"), resource.TestCheckResourceAttr(resourceName, "number_of_broker_nodes", "3"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestMatchResourceAttr(resourceName, "zookeeper_connect_string", mskClusterZookeeperConnectStringRegexp), @@ -689,10 +689,10 @@ func TestAccAWSMskCluster_KafkaVersionUpgrade(t *testing.T) { CheckDestroy: testAccCheckMskClusterDestroy, Steps: []resource.TestStep{ { - Config: testAccMskClusterConfigKafkaVersion(rName, "2.2.1"), + Config: testAccMskClusterConfigKafkaVersion(rName, "2.7.1"), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckMskClusterExists(resourceName, &cluster1), - resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.2.1"), + resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.7.1"), ), }, { @@ -701,11 +701,11 @@ func TestAccAWSMskCluster_KafkaVersionUpgrade(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccMskClusterConfigKafkaVersion(rName, "2.4.1.1"), + Config: testAccMskClusterConfigKafkaVersion(rName, "2.8.0"), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckMskClusterExists(resourceName, &cluster2), testAccCheckMskClusterNotRecreated(&cluster1, &cluster2), - resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.4.1.1"), + resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.8.0"), ), }, }, @@ -724,10 +724,10 @@ func TestAccAWSMskCluster_KafkaVersionDowngrade(t *testing.T) { CheckDestroy: testAccCheckMskClusterDestroy, Steps: []resource.TestStep{ { - Config: testAccMskClusterConfigKafkaVersion(rName, "2.4.1.1"), + Config: testAccMskClusterConfigKafkaVersion(rName, "2.8.0"), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckMskClusterExists(resourceName, &cluster1), - resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.4.1.1"), + resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.8.0"), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers", mskClusterBoostrapBrokersRegexp), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", ""), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_tls", mskClusterBoostrapBrokersTlsRegexp), @@ -741,11 +741,11 @@ func TestAccAWSMskCluster_KafkaVersionDowngrade(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccMskClusterConfigKafkaVersion(rName, "2.2.1"), + Config: testAccMskClusterConfigKafkaVersion(rName, "2.7.1"), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckMskClusterExists(resourceName, &cluster2), testAccCheckMskClusterRecreated(&cluster1, &cluster2), - resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.2.1"), + resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.7.1"), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers", mskClusterBoostrapBrokersRegexp), resource.TestCheckResourceAttr(resourceName, "bootstrap_brokers_sasl_scram", ""), resource.TestMatchResourceAttr(resourceName, "bootstrap_brokers_tls", mskClusterBoostrapBrokersTlsRegexp), @@ -771,10 +771,10 @@ func TestAccAWSMskCluster_KafkaVersionUpgradeWithConfigurationInfo(t *testing.T) CheckDestroy: testAccCheckMskClusterDestroy, Steps: []resource.TestStep{ { - Config: testAccMskClusterConfigKafkaVersionWithConfigurationInfo(rName, "2.2.1", "config1"), + Config: testAccMskClusterConfigKafkaVersionWithConfigurationInfo(rName, "2.7.1", "config1"), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckMskClusterExists(resourceName, &cluster1), - resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.2.1"), + resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.7.1"), resource.TestCheckResourceAttr(resourceName, "configuration_info.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "configuration_info.0.arn", configurationResourceName1, "arn"), resource.TestCheckResourceAttrPair(resourceName, "configuration_info.0.revision", configurationResourceName1, "latest_revision"), @@ -786,11 +786,11 @@ func TestAccAWSMskCluster_KafkaVersionUpgradeWithConfigurationInfo(t *testing.T) ImportStateVerify: true, }, { - Config: testAccMskClusterConfigKafkaVersionWithConfigurationInfo(rName, "2.4.1.1", "config2"), + Config: testAccMskClusterConfigKafkaVersionWithConfigurationInfo(rName, "2.8.0", "config2"), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckMskClusterExists(resourceName, &cluster2), testAccCheckMskClusterNotRecreated(&cluster1, &cluster2), - resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.4.1.1"), + resource.TestCheckResourceAttr(resourceName, "kafka_version", "2.8.0"), resource.TestCheckResourceAttr(resourceName, "configuration_info.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "configuration_info.0.arn", configurationResourceName2, "arn"), resource.TestCheckResourceAttrPair(resourceName, "configuration_info.0.revision", configurationResourceName2, "latest_revision"), @@ -1007,7 +1007,7 @@ func testAccMskClusterConfig_basic(rName string) string { return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q - kafka_version = "2.2.1" + kafka_version = "2.7.1" number_of_broker_nodes = 3 broker_node_group_info { @@ -1024,7 +1024,7 @@ func testAccMskClusterConfigBrokerNodeGroupInfoEbsVolumeSize(rName string, ebsVo return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q - kafka_version = "2.2.1" + kafka_version = "2.7.1" number_of_broker_nodes = 3 broker_node_group_info { @@ -1041,7 +1041,7 @@ func testAccMskClusterConfigBrokerNodeGroupInfoInstanceType(rName string, t stri return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q - kafka_version = "2.2.1" + kafka_version = "2.7.1" number_of_broker_nodes = 3 broker_node_group_info { @@ -1069,7 +1069,7 @@ resource "aws_acmpca_certificate_authority" "test" { resource "aws_msk_cluster" "test" { cluster_name = %[1]q - kafka_version = "2.2.1" + kafka_version = "2.7.1" number_of_broker_nodes = 3 broker_node_group_info { @@ -1098,7 +1098,7 @@ func testAccMskClusterConfigClientAuthenticationSaslScram(rName string, enabled return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q - kafka_version = "2.6.0" + kafka_version = "2.7.1" number_of_broker_nodes = 3 broker_node_group_info { @@ -1121,7 +1121,7 @@ func testAccMskClusterConfigClientAuthenticationSaslIam(rName string, enabled bo return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_cluster" "test" { cluster_name = %[1]q - kafka_version = "2.6.0" + kafka_version = "2.7.1" number_of_broker_nodes = 3 broker_node_group_info { @@ -1143,7 +1143,7 @@ resource "aws_msk_cluster" "test" { func testAccMskClusterConfigConfigurationInfoRevision1(rName string) string { return composeConfig(testAccMskClusterBaseConfig(rName), fmt.Sprintf(` resource "aws_msk_configuration" "test" { - kafka_versions = ["2.2.1"] + kafka_versions = ["2.7.1"] name = "%[1]s-1" server_properties = < Date: Wed, 26 May 2021 10:14:21 -0400 Subject: [PATCH 198/398] r/msk_cluster: Tweak SASL expander --- aws/resource_aws_msk_cluster.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_msk_cluster.go b/aws/resource_aws_msk_cluster.go index ee01552e569..37e62bbca8e 100644 --- a/aws/resource_aws_msk_cluster.go +++ b/aws/resource_aws_msk_cluster.go @@ -740,9 +740,14 @@ func expandMskClusterClientAuthentication(l []interface{}) *kafka.ClientAuthenti m := l[0].(map[string]interface{}) - ca := &kafka.ClientAuthentication{ - Sasl: expandMskClusterSasl(m["sasl"].([]interface{})), - Tls: expandMskClusterTls(m["tls"].([]interface{})), + ca := &kafka.ClientAuthentication{} + + if v, ok := m["sasl"].([]interface{}); ok { + ca.Sasl = expandMskClusterSasl(v) + } + + if v, ok := m["tls"].([]interface{}); ok { + ca.Tls = expandMskClusterTls(v) } return ca From 9e7f5bbe0ae9a7bad2c619412567d9350322f431 Mon Sep 17 00:00:00 2001 From: Richard Jennings Date: Wed, 26 May 2021 16:47:03 +0100 Subject: [PATCH 199/398] Init support for outpost_arn. --- aws/resource_aws_ec2_capacity_reservation.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/aws/resource_aws_ec2_capacity_reservation.go b/aws/resource_aws_ec2_capacity_reservation.go index 57e491bebf6..d368bb77e3e 100644 --- a/aws/resource_aws_ec2_capacity_reservation.go +++ b/aws/resource_aws_ec2_capacity_reservation.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "time" "github.com/aws/aws-sdk-go/aws" @@ -98,6 +99,16 @@ func resourceAwsEc2CapacityReservation() *schema.Resource { Required: true, ForceNew: true, }, + "outpost_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringMatch( + regexp.MustCompile(`^arn:aws([a-z-]+)?:outposts:[a-z\d-]+:\d{12}:outpost/op-[a-f0-9]{17}$`), + "must match ^arn:aws([a-z-]+)?:outposts:[a-z\\d-]+:\\d{12}:outpost/op-[a-f0-9]{17}$", + ), + ), + }, "owner_id": { Type: schema.TypeString, Computed: true, @@ -156,6 +167,10 @@ func resourceAwsEc2CapacityReservationCreate(d *schema.ResourceData, meta interf opts.InstanceMatchCriteria = aws.String(v.(string)) } + if v, ok := d.GetOk("outpost_arn"); ok { + opts.OutpostArn = aws.String(v.(string)) + } + if v, ok := d.GetOk("tenancy"); ok { opts.Tenancy = aws.String(v.(string)) } @@ -214,6 +229,7 @@ func resourceAwsEc2CapacityReservationRead(d *schema.ResourceData, meta interfac d.Set("instance_match_criteria", reservation.InstanceMatchCriteria) d.Set("instance_platform", reservation.InstancePlatform) d.Set("instance_type", reservation.InstanceType) + d.Set("outpost_arn", reservation.OutpostArn) d.Set("owner_id", reservation.OwnerId) tags := keyvaluetags.Ec2KeyValueTags(reservation.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) From 8f441bcfd187921aedeecbeefbd55be4876f7958 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 26 May 2021 11:55:45 -0400 Subject: [PATCH 200/398] tests/r/msk_cluster: Ignore current_version on import --- aws/resource_aws_msk_cluster_test.go | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/aws/resource_aws_msk_cluster_test.go b/aws/resource_aws_msk_cluster_test.go index 22c670f8cb3..678167a2db3 100644 --- a/aws/resource_aws_msk_cluster_test.go +++ b/aws/resource_aws_msk_cluster_test.go @@ -158,6 +158,9 @@ func TestAccAWSMskCluster_BrokerNodeGroupInfo_EbsVolumeSize(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, { // BadRequestException: The minimum increase in storage size of the cluster should be atleast 100GB @@ -199,6 +202,7 @@ func TestAccAWSMskCluster_BrokerNodeGroupInfo_InstanceType(t *testing.T) { ImportStateVerifyIgnore: []string{ "bootstrap_brokers", // API may mutate ordering and selection of brokers to return "bootstrap_brokers_tls", // API may mutate ordering and selection of brokers to return + "current_version", }, }, { @@ -264,6 +268,9 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Scram(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, }, }) @@ -319,6 +326,9 @@ func TestAccAWSMskCluster_ClientAuthentication_Sasl_Iam(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, }, }) @@ -350,6 +360,9 @@ func TestAccAWSMskCluster_ClientAuthentication_Tls_CertificateAuthorityArns(t *t ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, }, }) @@ -382,6 +395,9 @@ func TestAccAWSMskCluster_ConfigurationInfo_Revision(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, { Config: testAccMskClusterConfigConfigurationInfoRevision2(rName), @@ -455,6 +471,9 @@ func TestAccAWSMskCluster_EncryptionInfo_EncryptionInTransit_ClientBroker(t *tes ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, }, }) @@ -484,6 +503,9 @@ func TestAccAWSMskCluster_EncryptionInfo_EncryptionInTransit_InCluster(t *testin ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, }, }) @@ -511,6 +533,9 @@ func TestAccAWSMskCluster_EnhancedMonitoring(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, { Config: testAccMskClusterConfigEnhancedMonitoring(rName, "PER_TOPIC_PER_BROKER"), @@ -657,6 +682,9 @@ func TestAccAWSMskCluster_LoggingInfo(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, { Config: testAccMskClusterConfigLoggingInfo(rName, true, true, true), @@ -699,6 +727,9 @@ func TestAccAWSMskCluster_KafkaVersionUpgrade(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, { Config: testAccMskClusterConfigKafkaVersion(rName, "2.8.0"), @@ -739,6 +770,9 @@ func TestAccAWSMskCluster_KafkaVersionDowngrade(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, { Config: testAccMskClusterConfigKafkaVersion(rName, "2.7.1"), @@ -784,6 +818,9 @@ func TestAccAWSMskCluster_KafkaVersionUpgradeWithConfigurationInfo(t *testing.T) ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, { Config: testAccMskClusterConfigKafkaVersionWithConfigurationInfo(rName, "2.8.0", "config2"), @@ -833,6 +870,9 @@ func TestAccAWSMskCluster_Tags(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "current_version", + }, }, }, }) From b6aceba4d8f4b493534ac278968e1aad014e6c84 Mon Sep 17 00:00:00 2001 From: Richard Jennings Date: Wed, 26 May 2021 17:04:09 +0100 Subject: [PATCH 201/398] add changelog release-note:enhancement resource/aws_ec2_capacity_reservation: Add support for outpost_arn attribute --- .changelog/19535.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19535.txt diff --git a/.changelog/19535.txt b/.changelog/19535.txt new file mode 100644 index 00000000000..4ee30055411 --- /dev/null +++ b/.changelog/19535.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_ec2_capacity_reservation: Add support for outpost_arn attribute +``` \ No newline at end of file From d3fb93dddd75946f84a6b98d47994449d9e42ff2 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 26 May 2021 12:08:15 -0400 Subject: [PATCH 202/398] r/msk_cluster: Increase create timeout --- aws/resource_aws_msk_cluster.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aws/resource_aws_msk_cluster.go b/aws/resource_aws_msk_cluster.go index 37e62bbca8e..8db75849e25 100644 --- a/aws/resource_aws_msk_cluster.go +++ b/aws/resource_aws_msk_cluster.go @@ -26,6 +26,11 @@ func resourceAwsMskCluster() *schema.Resource { Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(120 * time.Minute), + }, + CustomizeDiff: customdiff.Sequence( customdiff.ForceNewIfChange("kafka_version", func(_ context.Context, old, new, meta interface{}) bool { return new.(string) < old.(string) From 9b6a2e2979ad7746f8f4b4beba34ba3e5513b1ae Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 26 May 2021 12:22:57 -0400 Subject: [PATCH 203/398] r/msk_cluster: Use const for timeouts --- aws/internal/service/msk/waiter/waiter.go | 11 +++++++++++ aws/resource_aws_msk_cluster.go | 12 +++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 aws/internal/service/msk/waiter/waiter.go diff --git a/aws/internal/service/msk/waiter/waiter.go b/aws/internal/service/msk/waiter/waiter.go new file mode 100644 index 00000000000..55b8c8a6997 --- /dev/null +++ b/aws/internal/service/msk/waiter/waiter.go @@ -0,0 +1,11 @@ +package waiter + +import ( + "time" +) + +const ( + ClusterCreateTimeout = 120 * time.Minute + ClusterUpdateTimeout = 120 * time.Minute + ClusterDeleteTimeout = 120 * time.Minute +) diff --git a/aws/resource_aws_msk_cluster.go b/aws/resource_aws_msk_cluster.go index 8db75849e25..c36694446dc 100644 --- a/aws/resource_aws_msk_cluster.go +++ b/aws/resource_aws_msk_cluster.go @@ -6,7 +6,6 @@ import ( "log" "sort" "strings" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/kafka" @@ -15,6 +14,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/msk/waiter" ) func resourceAwsMskCluster() *schema.Resource { @@ -28,7 +28,9 @@ func resourceAwsMskCluster() *schema.Resource { }, Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(120 * time.Minute), + Create: schema.DefaultTimeout(waiter.ClusterCreateTimeout), + Update: schema.DefaultTimeout(waiter.ClusterUpdateTimeout), + Delete: schema.DefaultTimeout(waiter.ClusterDeleteTimeout), }, CustomizeDiff: customdiff.Sequence( @@ -413,7 +415,7 @@ func waitForMskClusterCreation(conn *kafka.Kafka, arn string) error { input := &kafka.DescribeClusterInput{ ClusterArn: aws.String(arn), } - err := resource.Retry(60*time.Minute, func() *resource.RetryError { + err := resource.Retry(waiter.ClusterCreateTimeout, func() *resource.RetryError { out, err := conn.DescribeCluster(input) if err != nil { return resource.NonRetryableError(err) @@ -1214,7 +1216,7 @@ func resourceAwsMskClusterDeleteWaiter(conn *kafka.Kafka, arn string) error { input := &kafka.DescribeClusterInput{ ClusterArn: aws.String(arn), } - err := resource.Retry(60*time.Minute, func() *resource.RetryError { + err := resource.Retry(waiter.ClusterDeleteTimeout, func() *resource.RetryError { _, err := conn.DescribeCluster(input) if err != nil { @@ -1271,7 +1273,7 @@ func waitForMskClusterOperation(conn *kafka.Kafka, clusterOperationARN string) e Pending: []string{"PENDING", "UPDATE_IN_PROGRESS"}, Target: []string{"UPDATE_COMPLETE"}, Refresh: mskClusterOperationRefreshFunc(conn, clusterOperationARN), - Timeout: 2 * time.Hour, + Timeout: waiter.ClusterUpdateTimeout, } log.Printf("[DEBUG] Waiting for MSK Cluster Operation (%s) completion", clusterOperationARN) From 203e17a977a7bf96a78974dc16be0414311a43af Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 26 May 2021 17:04:39 +0000 Subject: [PATCH 204/398] Update CHANGELOG.md for #19496 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0927cf490e6..ceab8dab628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ FEATURES: ENHANCEMENTS: * resource/aws_eks_node_group: Add `taint` argument ([#19482](https://github.com/hashicorp/terraform-provider-aws/issues/19482)) +* resource/aws_msk_configuration: `kafka_versions` argument is optional ([#17571](https://github.com/hashicorp/terraform-provider-aws/issues/17571)) +* resource/aws_sns_topic: Add `firehose_success_feedback_role_arn`, `firehose_success_feedback_sample_rate` and `firehose_failure_feedback_role_arn` arguments. ([#19528](https://github.com/hashicorp/terraform-provider-aws/issues/19528)) +* resource/aws_sns_topic: Add `owner` attribute. ([#19528](https://github.com/hashicorp/terraform-provider-aws/issues/19528)) +* resource/aws_sns_topic: Add plan time validation for `application_success_feedback_role_arn`, `application_failure_feedback_role_arn`, `http_success_feedback_role_arn`, `http_failure_feedback_role_arn`, `lambda_success_feedback_role_arn`, `lambda_failure_feedback_role_arn`, `sqs_success_feedback_role_arn`, `sqs_failure_feedback_role_arn`. ([#19528](https://github.com/hashicorp/terraform-provider-aws/issues/19528)) BUG FIXES: @@ -24,6 +28,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_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)) +* 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)) ## 3.42.0 (May 20, 2021) From 3f118725dbf3d0c5e484b692c93d4bb1e83e0c33 Mon Sep 17 00:00:00 2001 From: Richard Jennings Date: Wed, 26 May 2021 18:20:22 +0100 Subject: [PATCH 205/398] use validateArn instead of regex pattern --- aws/resource_aws_ec2_capacity_reservation.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_ec2_capacity_reservation.go b/aws/resource_aws_ec2_capacity_reservation.go index d368bb77e3e..9d20620db3f 100644 --- a/aws/resource_aws_ec2_capacity_reservation.go +++ b/aws/resource_aws_ec2_capacity_reservation.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "log" - "regexp" "time" "github.com/aws/aws-sdk-go/aws" @@ -100,14 +99,9 @@ func resourceAwsEc2CapacityReservation() *schema.Resource { ForceNew: true, }, "outpost_arn": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.All( - validation.StringMatch( - regexp.MustCompile(`^arn:aws([a-z-]+)?:outposts:[a-z\d-]+:\d{12}:outpost/op-[a-f0-9]{17}$`), - "must match ^arn:aws([a-z-]+)?:outposts:[a-z\\d-]+:\\d{12}:outpost/op-[a-f0-9]{17}$", - ), - ), + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, }, "owner_id": { Type: schema.TypeString, From 1e5be7a74a4692aa504f8b0817b7469ce8b9d423 Mon Sep 17 00:00:00 2001 From: Richard Jennings Date: Wed, 26 May 2021 18:21:26 +0100 Subject: [PATCH 206/398] add check that outpost_arn is empty string --- aws/resource_aws_ec2_capacity_reservation_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_ec2_capacity_reservation_test.go b/aws/resource_aws_ec2_capacity_reservation_test.go index 099a5840796..54b4e7e348d 100644 --- a/aws/resource_aws_ec2_capacity_reservation_test.go +++ b/aws/resource_aws_ec2_capacity_reservation_test.go @@ -89,6 +89,7 @@ func TestAccAWSEc2CapacityReservation_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "instance_match_criteria", "open"), resource.TestCheckResourceAttr(resourceName, "instance_platform", "Linux/UNIX"), resource.TestCheckResourceAttr(resourceName, "instance_type", "t2.micro"), + resource.TestCheckResourceAttr(resourceName, "outpost_arn", ""), testAccCheckResourceAttrAccountID(resourceName, "owner_id"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestCheckResourceAttr(resourceName, "tenancy", "default"), From cbb68fb91a2640dac47ef5a1c4495668e55cd359 Mon Sep 17 00:00:00 2001 From: Richard Jennings Date: Wed, 26 May 2021 18:25:04 +0100 Subject: [PATCH 207/398] add outpost_arn attribute to website documentation --- website/docs/r/ec2_capacity_reservation.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/ec2_capacity_reservation.html.markdown b/website/docs/r/ec2_capacity_reservation.html.markdown index fa70669e024..3d61d70f24d 100644 --- a/website/docs/r/ec2_capacity_reservation.html.markdown +++ b/website/docs/r/ec2_capacity_reservation.html.markdown @@ -34,6 +34,7 @@ The following arguments are supported: * `instance_match_criteria` - (Optional) Indicates the type of instance launches that the Capacity Reservation accepts. Specify either `open` or `targeted`. * `instance_platform` - (Required) The type of operating system for which to reserve capacity. Valid options are `Linux/UNIX`, `Red Hat Enterprise Linux`, `SUSE Linux`, `Windows`, `Windows with SQL Server`, `Windows with SQL Server Enterprise`, `Windows with SQL Server Standard` or `Windows with SQL Server Web`. * `instance_type` - (Required) The instance type for which to reserve capacity. +* `outpost_arn` - (Optional) The Amazon Resource Name (ARN) of the Outpost on which to create the Capacity Reservation. * `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. * `tenancy` - (Optional) Indicates the tenancy of the Capacity Reservation. Specify either `default` or `dedicated`. From e80ed5ee373c67fac088bd6e6232a93d3acac829 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 May 2021 18:36:56 +0000 Subject: [PATCH 208/398] 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.46 to 1.38.48. - [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.46...v1.38.48) Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../aws/aws-sdk-go/aws/endpoints/defaults.go | 24 ++++++++++++++++--- .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index f830dfceec1..022baef5eee 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.46 + github.com/aws/aws-sdk-go v1.38.48 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 196a64067af..e8551f7ba47 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.46 h1:voiwaKmwU1K6Y0dfjqTSiy5xOG4LPyr5sHD92cj+g2c= -github.com/aws/aws-sdk-go v1.38.46/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.48 h1:4kfX2KFjRaW0/p3rKBXA+QLOTH3gFUBg+ZoKMDkSSqk= +github.com/aws/aws-sdk-go v1.38.48/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 b493eadeb37..2de69cc5bc8 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 @@ -6205,9 +6205,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: "session.qldb-fips.us-east-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-1", + }, + }, + "fips-us-east-2": endpoint{ + Hostname: "session.qldb-fips.us-east-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-2", + }, + }, + "fips-us-west-2": endpoint{ + Hostname: "session.qldb-fips.us-west-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-west-2", + }, + }, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-2": endpoint{}, }, }, "shield": 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 54804378787..cca6a68d158 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.46" +const SDKVersion = "1.38.48" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index b7b99744fa8..445b2cdf3ef 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.46 +# github.com/aws/aws-sdk-go v1.38.48 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 4919d9eafbe042120b270eb096ae7d419438b1eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 May 2021 18:37:26 +0000 Subject: [PATCH 209/398] build(deps): bump github.com/aws/aws-sdk-go from 1.38.46 to 1.38.48 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.46 to 1.38.48. - [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.46...v1.38.48) 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 f4e500001a8..305c6c103a0 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.46 + github.com/aws/aws-sdk-go v1.38.48 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 6e49a85218e..673ab1271b1 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.46 h1:voiwaKmwU1K6Y0dfjqTSiy5xOG4LPyr5sHD92cj+g2c= -github.com/aws/aws-sdk-go v1.38.46/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.48 h1:4kfX2KFjRaW0/p3rKBXA+QLOTH3gFUBg+ZoKMDkSSqk= +github.com/aws/aws-sdk-go v1.38.48/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 6d6d248fcb1b22b5253ffc5b668252a31126a945 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 26 May 2021 18:41:10 +0000 Subject: [PATCH 210/398] Update CHANGELOG.md for #19517 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ceab8dab628..85ce5d25d8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,9 @@ 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_eks_node_group: Add `taint` argument ([#19482](https://github.com/hashicorp/terraform-provider-aws/issues/19482)) +* resource/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` argument ([#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)) * resource/aws_sns_topic: Add `firehose_success_feedback_role_arn`, `firehose_success_feedback_sample_rate` and `firehose_failure_feedback_role_arn` arguments. ([#19528](https://github.com/hashicorp/terraform-provider-aws/issues/19528)) * resource/aws_sns_topic: Add `owner` attribute. ([#19528](https://github.com/hashicorp/terraform-provider-aws/issues/19528)) @@ -26,6 +28,8 @@ BUG FIXES: * resource/aws_apprunner_service: Correctly configure `authentication_configuration`, `code_configuration`, and `image_configuration` nested arguments in API requests ([#19471](https://github.com/hashicorp/terraform-provider-aws/issues/19471)) * 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_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)) * resource/aws_lb_listener_rule: Allow blank string for `action.redirect.query` nested argument ([#19496](https://github.com/hashicorp/terraform-provider-aws/issues/19496)) From 6155bb31231e399525616b33606fddc807370a66 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Wed, 26 May 2021 11:49:09 -0700 Subject: [PATCH 211/398] Apply documentation suggestions from code review Co-authored-by: angie pinilla --- .changelog/19415.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.changelog/19415.txt b/.changelog/19415.txt index fad6f4d0234..4c0b25a85f4 100644 --- a/.changelog/19415.txt +++ b/.changelog/19415.txt @@ -1,11 +1,11 @@ ```release-notes:enhancement -resource/aws_wafv2_web_acl: Add `custom_request_handling` to `allow` and `count` actions. +resource/aws_wafv2_web_acl: Add `custom_request_handling` to `allow` and `count` default action and rule actions. ``` ```release-notes:enhancement -resource/aws_wafv2_web_acl: Add `custom_response` to `block` actions. +resource/aws_wafv2_web_acl: Add `custom_response` to `block` default action and rule actions. ``` ```release-notes:enhancement resource/aws_wafv2_rule_group: Included the above changes to `rule` `allow`, `count`, and `block` actions. -``` \ No newline at end of file +``` From 546b3b02296e0d193ce40f01c3f2c57e3e410e5e Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Wed, 26 May 2021 11:54:40 -0700 Subject: [PATCH 212/398] Clarified release notes for the aws_wafv2_rule_group changes --- .changelog/19415.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.changelog/19415.txt b/.changelog/19415.txt index 4c0b25a85f4..6ff2032e1a3 100644 --- a/.changelog/19415.txt +++ b/.changelog/19415.txt @@ -7,5 +7,9 @@ resource/aws_wafv2_web_acl: Add `custom_response` to `block` default action and ``` ```release-notes:enhancement -resource/aws_wafv2_rule_group: Included the above changes to `rule` `allow`, `count`, and `block` actions. +resource/aws_wafv2_rule_group: Add `custom_request_handling` to `allow` and `count` rule actions. +``` + +```release-notes:enhancement +resource/aws_wafv2_rule_group: Add `custom_response` to `block` rule actions. ``` From 98c6c25473a5a9a52f1584256ad37659f43e14bf Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 24 Apr 2021 21:40:51 +0100 Subject: [PATCH 213/398] Add support for Eventbridge Schema Registry, Discoverer and Schema resources --- .changelog/19100.txt | 11 + aws/config.go | 3 + .../keyvaluetags/generators/listtags/main.go | 1 + .../generators/servicetags/main.go | 1 + .../generators/updatetags/main.go | 1 + aws/internal/keyvaluetags/list_tags_gen.go | 18 + .../service_generation_customizations.go | 3 + aws/internal/keyvaluetags/service_tags_gen.go | 10 + aws/internal/keyvaluetags/update_tags_gen.go | 37 ++ aws/provider.go | 3 + aws/resource_aws_schemas_discoverer.go | 160 ++++++ aws/resource_aws_schemas_discoverer_test.go | 313 ++++++++++++ aws/resource_aws_schemas_registry.go | 161 ++++++ aws/resource_aws_schemas_registry_test.go | 300 +++++++++++ aws/resource_aws_schemas_schema.go | 235 +++++++++ aws/resource_aws_schemas_schema_test.go | 472 ++++++++++++++++++ .../docs/r/schemas_discoverer.html.markdown | 51 ++ website/docs/r/schemas_registry.html.markdown | 46 ++ website/docs/r/schemas_schema.html.markdown | 78 +++ 19 files changed, 1904 insertions(+) create mode 100644 .changelog/19100.txt create mode 100644 aws/resource_aws_schemas_discoverer.go create mode 100644 aws/resource_aws_schemas_discoverer_test.go create mode 100644 aws/resource_aws_schemas_registry.go create mode 100644 aws/resource_aws_schemas_registry_test.go create mode 100644 aws/resource_aws_schemas_schema.go create mode 100644 aws/resource_aws_schemas_schema_test.go create mode 100644 website/docs/r/schemas_discoverer.html.markdown create mode 100644 website/docs/r/schemas_registry.html.markdown create mode 100644 website/docs/r/schemas_schema.html.markdown diff --git a/.changelog/19100.txt b/.changelog/19100.txt new file mode 100644 index 00000000000..471cee52e86 --- /dev/null +++ b/.changelog/19100.txt @@ -0,0 +1,11 @@ +```release-note:new-resource +aws_schemas_discoverer +``` + +```release-note:new-resource +aws_schemas_registry +``` + +```release-note:new-resource +aws_schemas_schema +``` \ No newline at end of file diff --git a/aws/config.go b/aws/config.go index 4b47c42ced4..8eef7bed53c 100644 --- a/aws/config.go +++ b/aws/config.go @@ -140,6 +140,7 @@ import ( "github.com/aws/aws-sdk-go/service/s3control" "github.com/aws/aws-sdk-go/service/s3outposts" "github.com/aws/aws-sdk-go/service/sagemaker" + "github.com/aws/aws-sdk-go/service/schemas" "github.com/aws/aws-sdk-go/service/secretsmanager" "github.com/aws/aws-sdk-go/service/securityhub" "github.com/aws/aws-sdk-go/service/serverlessapplicationrepository" @@ -354,6 +355,7 @@ type AWSClient struct { s3outpostsconn *s3outposts.S3Outposts sagemakerconn *sagemaker.SageMaker scconn *servicecatalog.ServiceCatalog + schemasconn *schemas.Schemas sdconn *servicediscovery.ServiceDiscovery secretsmanagerconn *secretsmanager.SecretsManager securityhubconn *securityhub.SecurityHub @@ -598,6 +600,7 @@ func (c *Config) Client() (interface{}, error) { s3outpostsconn: s3outposts.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["s3outposts"])})), sagemakerconn: sagemaker.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["sagemaker"])})), scconn: servicecatalog.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["servicecatalog"])})), + schemasconn: schemas.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["schemas"])})), sdconn: servicediscovery.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["servicediscovery"])})), secretsmanagerconn: secretsmanager.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["secretsmanager"])})), securityhubconn: securityhub.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["securityhub"])})), diff --git a/aws/internal/keyvaluetags/generators/listtags/main.go b/aws/internal/keyvaluetags/generators/listtags/main.go index f7e35a5cd60..393ba549ef2 100644 --- a/aws/internal/keyvaluetags/generators/listtags/main.go +++ b/aws/internal/keyvaluetags/generators/listtags/main.go @@ -108,6 +108,7 @@ var serviceNames = []string{ "sagemaker", "securityhub", "servicediscovery", + "schemas", "sfn", "shield", "signer", diff --git a/aws/internal/keyvaluetags/generators/servicetags/main.go b/aws/internal/keyvaluetags/generators/servicetags/main.go index 39c30ad7baa..8775ca80700 100644 --- a/aws/internal/keyvaluetags/generators/servicetags/main.go +++ b/aws/internal/keyvaluetags/generators/servicetags/main.go @@ -144,6 +144,7 @@ var mapServiceNames = []string{ "pinpoint", "resourcegroups", "securityhub", + "schemas", "signer", "sqs", "synthetics", diff --git a/aws/internal/keyvaluetags/generators/updatetags/main.go b/aws/internal/keyvaluetags/generators/updatetags/main.go index d330cbdf48e..c302a3b7da1 100644 --- a/aws/internal/keyvaluetags/generators/updatetags/main.go +++ b/aws/internal/keyvaluetags/generators/updatetags/main.go @@ -115,6 +115,7 @@ var serviceNames = []string{ "secretsmanager", "securityhub", "servicediscovery", + "schemas", "sfn", "shield", "signer", diff --git a/aws/internal/keyvaluetags/list_tags_gen.go b/aws/internal/keyvaluetags/list_tags_gen.go index 4b2688e7c3f..0b527c833fa 100644 --- a/aws/internal/keyvaluetags/list_tags_gen.go +++ b/aws/internal/keyvaluetags/list_tags_gen.go @@ -93,6 +93,7 @@ import ( "github.com/aws/aws-sdk-go/service/route53" "github.com/aws/aws-sdk-go/service/route53resolver" "github.com/aws/aws-sdk-go/service/sagemaker" + "github.com/aws/aws-sdk-go/service/schemas" "github.com/aws/aws-sdk-go/service/securityhub" "github.com/aws/aws-sdk-go/service/servicediscovery" "github.com/aws/aws-sdk-go/service/sfn" @@ -1638,6 +1639,23 @@ func SagemakerListTags(conn *sagemaker.SageMaker, identifier string) (KeyValueTa return SagemakerKeyValueTags(output.Tags), nil } +// SchemasListTags lists schemas service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SchemasListTags(conn *schemas.Schemas, identifier string) (KeyValueTags, error) { + input := &schemas.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return SchemasKeyValueTags(output.Tags), nil +} + // SecurityhubListTags lists securityhub 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_generation_customizations.go b/aws/internal/keyvaluetags/service_generation_customizations.go index 34819c2b764..f1f03359a5a 100644 --- a/aws/internal/keyvaluetags/service_generation_customizations.go +++ b/aws/internal/keyvaluetags/service_generation_customizations.go @@ -103,6 +103,7 @@ import ( "github.com/aws/aws-sdk-go/service/route53" "github.com/aws/aws-sdk-go/service/route53resolver" "github.com/aws/aws-sdk-go/service/sagemaker" + "github.com/aws/aws-sdk-go/service/schemas" "github.com/aws/aws-sdk-go/service/secretsmanager" "github.com/aws/aws-sdk-go/service/securityhub" "github.com/aws/aws-sdk-go/service/servicediscovery" @@ -333,6 +334,8 @@ func ServiceClientType(serviceName string) string { funcType = reflect.TypeOf(securityhub.New) case "servicediscovery": funcType = reflect.TypeOf(servicediscovery.New) + case "schemas": + funcType = reflect.TypeOf(schemas.New) case "sfn": funcType = reflect.TypeOf(sfn.New) case "shield": diff --git a/aws/internal/keyvaluetags/service_tags_gen.go b/aws/internal/keyvaluetags/service_tags_gen.go index 2abcf13632a..7a2dad640d0 100644 --- a/aws/internal/keyvaluetags/service_tags_gen.go +++ b/aws/internal/keyvaluetags/service_tags_gen.go @@ -447,6 +447,16 @@ func ResourcegroupsKeyValueTags(tags map[string]*string) KeyValueTags { return New(tags) } +// SchemasTags returns schemas service tags. +func (tags KeyValueTags) SchemasTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// SchemasKeyValueTags creates KeyValueTags from schemas service tags. +func SchemasKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + // SecurityhubTags returns securityhub service tags. func (tags KeyValueTags) SecurityhubTags() 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 19f2c314012..6a2a9d37f19 100644 --- a/aws/internal/keyvaluetags/update_tags_gen.go +++ b/aws/internal/keyvaluetags/update_tags_gen.go @@ -101,6 +101,7 @@ import ( "github.com/aws/aws-sdk-go/service/route53" "github.com/aws/aws-sdk-go/service/route53resolver" "github.com/aws/aws-sdk-go/service/sagemaker" + "github.com/aws/aws-sdk-go/service/schemas" "github.com/aws/aws-sdk-go/service/secretsmanager" "github.com/aws/aws-sdk-go/service/securityhub" "github.com/aws/aws-sdk-go/service/servicediscovery" @@ -3545,6 +3546,42 @@ func SagemakerUpdateTags(conn *sagemaker.SageMaker, identifier string, oldTagsMa return nil } +// SchemasUpdateTags updates schemas service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SchemasUpdateTags(conn *schemas.Schemas, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &schemas.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 := &schemas.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().SchemasTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %w", identifier, err) + } + } + + return nil +} + // SecretsmanagerUpdateTags updates secretsmanager 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/provider.go b/aws/provider.go index 53fcd8be5e8..411f97f3e26 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -981,6 +981,9 @@ func Provider() *schema.Provider { "aws_sagemaker_notebook_instance_lifecycle_configuration": resourceAwsSagemakerNotebookInstanceLifeCycleConfiguration(), "aws_sagemaker_notebook_instance": resourceAwsSagemakerNotebookInstance(), "aws_sagemaker_user_profile": resourceAwsSagemakerUserProfile(), + "aws_schemas_discoverer": resourceAwsSchemasDiscoverer(), + "aws_schemas_registry": resourceAwsSchemasRegistry(), + "aws_schemas_schema": resourceAwsSchemasSchema(), "aws_secretsmanager_secret": resourceAwsSecretsManagerSecret(), "aws_secretsmanager_secret_policy": resourceAwsSecretsManagerSecretPolicy(), "aws_secretsmanager_secret_version": resourceAwsSecretsManagerSecretVersion(), diff --git a/aws/resource_aws_schemas_discoverer.go b/aws/resource_aws_schemas_discoverer.go new file mode 100644 index 00000000000..2864ab80c9b --- /dev/null +++ b/aws/resource_aws_schemas_discoverer.go @@ -0,0 +1,160 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + schemas "github.com/aws/aws-sdk-go/service/schemas" + "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 resourceAwsSchemasDiscoverer() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSchemasDiscovererCreate, + Read: resourceAwsSchemasDiscovererRead, + Update: resourceAwsSchemasDiscovererUpdate, + Delete: resourceAwsSchemasDiscovererDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "source_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateArn, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 256), + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "discoverer_id": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchema(), + }, + } +} + +func resourceAwsSchemasDiscovererCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + + input := &schemas.CreateDiscovererInput{} + if source, ok := d.GetOk("source_arn"); ok { + input.SourceArn = aws.String(source.(string)) + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + if v, ok := d.GetOk("tags"); ok { + input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().SchemasTags() + } + + log.Printf("[DEBUG] Creating Schemas Discoverer: %v", input) + + output, err := conn.CreateDiscoverer(input) + if err != nil { + return fmt.Errorf("Creating Schemas Discoverer (%s) failed: %w", *input.SourceArn, err) + } + + d.SetId(aws.StringValue(output.DiscovererId)) + + log.Printf("[INFO] Schemas Discoverer (%s) created", d.Id()) + + return resourceAwsSchemasDiscovererRead(d, meta) +} + +func resourceAwsSchemasDiscovererRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + input := &schemas.DescribeDiscovererInput{ + DiscovererId: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Reading Schemas Discoverer (%s)", d.Id()) + output, err := conn.DescribeDiscoverer(input) + if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { + log.Printf("[WARN] Schemas Discoverer (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("error reading Schemas Discoverer: %w", err) + } + + log.Printf("[DEBUG] Found CloudWatch Event bus: %#v", *output) + + d.Set("arn", output.DiscovererArn) + d.Set("source_arn", output.SourceArn) + d.Set("description", output.Description) + d.Set("discoverer_id", output.DiscovererId) + + tags, err := keyvaluetags.SchemasListTags(conn, *output.DiscovererArn) + if err != nil { + return fmt.Errorf("error listing tags for Schemas Discoverer (%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 +} + +func resourceAwsSchemasDiscovererUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + + if d.HasChange("description") { + input := &schemas.UpdateDiscovererInput{ + DiscovererId: aws.String(d.Id()), + Description: aws.String(""), + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + + log.Printf("[DEBUG] Updating Schemas Discoverer: %s", input) + _, err := conn.UpdateDiscoverer(input) + if err != nil { + return fmt.Errorf("error updating Schemas Discoverer (%s): %w", d.Id(), err) + } + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.SchemasUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } + } + + return resourceAwsSchemasDiscovererRead(d, meta) +} + +func resourceAwsSchemasDiscovererDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + + log.Printf("[INFO] Deleting Schemas Discoverer (%s)", d.Id()) + _, err := conn.DeleteDiscoverer(&schemas.DeleteDiscovererInput{ + DiscovererId: aws.String(d.Id()), + }) + if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { + log.Printf("[WARN] Schemas Discoverer (%s) not found", d.Id()) + return nil + } + if err != nil { + return fmt.Errorf("Error deleting Schemas Discoverer (%s): %w", d.Id(), err) + } + log.Printf("[INFO] Schemas Discoverer (%s) deleted", d.Id()) + + return nil +} diff --git a/aws/resource_aws_schemas_discoverer_test.go b/aws/resource_aws_schemas_discoverer_test.go new file mode 100644 index 00000000000..a648eca6128 --- /dev/null +++ b/aws/resource_aws_schemas_discoverer_test.go @@ -0,0 +1,313 @@ +package aws + +import ( + "fmt" + "log" + "testing" + + "github.com/aws/aws-sdk-go/aws" + schemas "github.com/aws/aws-sdk-go/service/schemas" + "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_schemas_discoverer", &resource.Sweeper{ + Name: "aws_schemas_discoverer", + F: testSweepSchemasDiscoverer, + Dependencies: []string{ + "aws_cloudwatch_event_bus", + }, + }) +} + +func testSweepSchemasDiscoverer(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("Error getting client: %w", err) + } + conn := client.(*AWSClient).schemasconn + + var sweeperErrs *multierror.Error + + input := &schemas.ListDiscoverersInput{ + Limit: aws.Int64(100), + } + var discoverers []*schemas.DiscovererSummary + for { + output, err := conn.ListDiscoverers(input) + if err != nil { + return err + } + discoverers = append(discoverers, output.Discoverers...) + + if aws.StringValue(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + for _, discoverer := range discoverers { + + input := &schemas.DeleteDiscovererInput{ + DiscovererId: discoverer.DiscovererId, + } + _, err := conn.DeleteDiscoverer(input) + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("Error deleting Schemas Discoverer (%s): %w", *discoverer.DiscovererId, err)) + continue + } + } + + log.Printf("[INFO] Deleted %d Schemas Discoverers", len(discoverers)) + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSSchemasDiscoverer_basic(t *testing.T) { + var v1, v2, v3 schemas.DescribeDiscovererOutput + eventbusName := acctest.RandomWithPrefix("tf-acc-test") + eventbusNameModified := acctest.RandomWithPrefix("tf-acc-test") + + description := acctest.RandomWithPrefix("tf-acc-test") + descriptionModified := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_schemas_discoverer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasDiscovererDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSchemasDiscovererConfig(eventbusName, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasDiscovererExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "description", description), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("discoverer/events-event-bus-%s", eventbusName)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSchemasDiscovererConfig(eventbusNameModified, descriptionModified), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasDiscovererExists(resourceName, &v2), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("discoverer/events-event-bus-%s", eventbusNameModified)), + testAccCheckSchemasDiscovererRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + Config: testAccAWSSchemasDiscovererConfig_Tags1(eventbusNameModified, "key", "value"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasDiscovererExists(resourceName, &v3), + testAccCheckSchemasDiscovererNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key", "value"), + ), + }, + }, + }) +} + +func TestAccAWSSchemasDiscoverer_tags(t *testing.T) { + var v1, v2, v3, v4 schemas.DescribeDiscovererOutput + eventbusName := acctest.RandomWithPrefix("tf-acc-test") + description := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_schemas_discoverer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasDiscovererDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSchemasDiscovererConfig_Tags1(eventbusName, "key1", "value"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasDiscovererExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSchemasDiscovererConfig_Tags2(eventbusName, "key1", "updated", "key2", "added"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasDiscovererExists(resourceName, &v2), + testAccCheckSchemasDiscovererNotRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), + ), + }, + { + Config: testAccAWSSchemasDiscovererConfig_Tags1(eventbusName, "key2", "added"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasDiscovererExists(resourceName, &v3), + testAccCheckSchemasDiscovererNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), + ), + }, + { + Config: testAccAWSSchemasDiscovererConfig(eventbusName, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasDiscovererExists(resourceName, &v4), + testAccCheckSchemasDiscovererNotRecreated(&v3, &v4), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + }, + }) +} + +func TestAccAWSSchemasDiscoverer_disappears(t *testing.T) { + var v schemas.DescribeDiscovererOutput + eventbusName := acctest.RandomWithPrefix("tf-acc-test") + description := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_schemas_discoverer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasDiscovererDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSchemasDiscovererConfig(eventbusName, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasDiscovererExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSchemasDiscoverer(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSSchemasDiscovererDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).schemasconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_schemas_discoverer" { + continue + } + + params := schemas.DescribeDiscovererInput{ + DiscovererId: aws.String(rs.Primary.ID), + } + + resp, err := conn.DescribeDiscoverer(¶ms) + + if err == nil { + return fmt.Errorf("Schemas Discoverer (%s) still exists: %s", rs.Primary.ID, resp) + } + } + + return nil +} + +func testAccCheckSchemasDiscovererExists(n string, v *schemas.DescribeDiscovererOutput) 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).schemasconn + params := schemas.DescribeDiscovererInput{ + DiscovererId: aws.String(rs.Primary.ID), + } + resp, err := conn.DescribeDiscoverer(¶ms) + if err != nil { + return err + } + if resp == nil { + return fmt.Errorf("Schemas Discoverer (%s) not found", n) + } + + *v = *resp + + return nil + } +} + +func testAccCheckSchemasDiscovererRecreated(i, j *schemas.DescribeDiscovererOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.DiscovererArn) == aws.StringValue(j.DiscovererArn) { + return fmt.Errorf("Schemas Discoverer not recreated") + } + return nil + } +} + +func testAccCheckSchemasDiscovererNotRecreated(i, j *schemas.DescribeDiscovererOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.DiscovererArn) != aws.StringValue(j.DiscovererArn) { + return fmt.Errorf("Schemas Discoverer was recreated") + } + return nil + } +} + +func testAccAWSSchemasDiscovererConfig(eventbusName, description string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q +} + +resource "aws_schemas_discoverer" "test" { + source_arn = aws_cloudwatch_event_bus.test.arn + description = %[2]q +} +`, eventbusName, description) +} + +func testAccAWSSchemasDiscovererConfig_Tags1(eventbusName, key, value string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q +} + +resource "aws_schemas_discoverer" "test" { + source_arn = aws_cloudwatch_event_bus.test.arn + + tags = { + %[2]q = %[3]q + } +} +`, eventbusName, key, value) +} + +func testAccAWSSchemasDiscovererConfig_Tags2(eventbusName, key1, value1, key2, value2 string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q +} + +resource "aws_schemas_discoverer" "test" { + source_arn = aws_cloudwatch_event_bus.test.arn + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, eventbusName, key1, value1, key2, value2) +} diff --git a/aws/resource_aws_schemas_registry.go b/aws/resource_aws_schemas_registry.go new file mode 100644 index 00000000000..80f8a02ba8a --- /dev/null +++ b/aws/resource_aws_schemas_registry.go @@ -0,0 +1,161 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + + "github.com/aws/aws-sdk-go/aws" + schemas "github.com/aws/aws-sdk-go/service/schemas" + "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 resourceAwsSchemasRegistry() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSchemasRegistryCreate, + Read: resourceAwsSchemasRegistryRead, + Update: resourceAwsSchemasRegistryUpdate, + Delete: resourceAwsSchemasRegistryDelete, + 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), + validation.StringMatch(regexp.MustCompile(`^[\.\-_A-Za-z0-9]+`), ""), + ), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 256), + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchema(), + }, + } +} + +func resourceAwsSchemasRegistryCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + + input := &schemas.CreateRegistryInput{} + if name, ok := d.GetOk("name"); ok { + input.RegistryName = aws.String(name.(string)) + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + if v, ok := d.GetOk("tags"); ok { + input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().SchemasTags() + } + + log.Printf("[DEBUG] Creating Schemas Registry: %v", input) + + _, err := conn.CreateRegistry(input) + if err != nil { + return fmt.Errorf("Creating Schemas Registry (%s) failed: %w", *input.RegistryName, err) + } + + d.SetId(aws.StringValue(input.RegistryName)) + + log.Printf("[INFO] Schemas Registry (%s) created", d.Id()) + + return resourceAwsSchemasRegistryRead(d, meta) +} + +func resourceAwsSchemasRegistryRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + input := &schemas.DescribeRegistryInput{ + RegistryName: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Reading Schemas Registry (%s)", d.Id()) + output, err := conn.DescribeRegistry(input) + if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { + log.Printf("[WARN] Schemas Registry (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("error reading Schemas Registry: %w", err) + } + + log.Printf("[DEBUG] Found CloudWatch Event bus: %#v", *output) + + d.Set("arn", output.RegistryArn) + d.Set("name", output.RegistryName) + d.Set("description", output.Description) + + tags, err := keyvaluetags.SchemasListTags(conn, *output.RegistryArn) + if err != nil { + return fmt.Errorf("error listing tags for Schemas Registry (%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 +} + +func resourceAwsSchemasRegistryUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + + if d.HasChanges("name", "description") { + input := &schemas.UpdateRegistryInput{ + Description: aws.String(""), + } + if name, ok := d.GetOk("name"); ok { + input.RegistryName = aws.String(name.(string)) + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + + log.Printf("[DEBUG] Updating Schemas Registry: %s", input) + _, err := conn.UpdateRegistry(input) + if err != nil { + return fmt.Errorf("error updating Schemas Registry (%s): %w", d.Id(), err) + } + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.SchemasUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } + } + + return resourceAwsSchemasRegistryRead(d, meta) +} + +func resourceAwsSchemasRegistryDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + + log.Printf("[INFO] Deleting Schemas Registry (%s)", d.Id()) + _, err := conn.DeleteRegistry(&schemas.DeleteRegistryInput{ + RegistryName: aws.String(d.Id()), + }) + if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { + log.Printf("[WARN] Schemas Registry (%s) not found", d.Id()) + return nil + } + if err != nil { + return fmt.Errorf("Error deleting Schemas Registry (%s): %w", d.Id(), err) + } + log.Printf("[INFO] Schemas Registry (%s) deleted", d.Id()) + + return nil +} diff --git a/aws/resource_aws_schemas_registry_test.go b/aws/resource_aws_schemas_registry_test.go new file mode 100644 index 00000000000..cbb33ba1f5c --- /dev/null +++ b/aws/resource_aws_schemas_registry_test.go @@ -0,0 +1,300 @@ +package aws + +import ( + "fmt" + "log" + "testing" + + "github.com/aws/aws-sdk-go/aws" + schemas "github.com/aws/aws-sdk-go/service/schemas" + "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_schemas_registry", &resource.Sweeper{ + Name: "aws_schemas_registry", + F: testSweepSchemasRegistry, + }) +} + +func testSweepSchemasRegistry(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("Error getting client: %w", err) + } + conn := client.(*AWSClient).schemasconn + + var sweeperErrs *multierror.Error + + input := &schemas.ListRegistriesInput{ + Limit: aws.Int64(100), + } + var registries []*schemas.RegistrySummary + for { + output, err := conn.ListRegistries(input) + if err != nil { + return err + } + registries = append(registries, output.Registries...) + + if aws.StringValue(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + for _, registry := range registries { + + input := &schemas.DeleteRegistryInput{ + RegistryName: registry.RegistryName, + } + _, err := conn.DeleteRegistry(input) + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("Error deleting Schemas Registry (%s): %w", *registry.RegistryName, err)) + continue + } + } + + log.Printf("[INFO] Deleted %d Schemas Registries", len(registries)) + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSSchemasRegistry_basic(t *testing.T) { + var v1, v2, v3 schemas.DescribeRegistryOutput + registryName := acctest.RandomWithPrefix("tf-acc-test") + registryNameModified := acctest.RandomWithPrefix("tf-acc-test") + + description := acctest.RandomWithPrefix("tf-acc-test") + descriptionModified := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_schemas_registry.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasRegistryDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSchemasRegistryConfig(registryName, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasRegistryExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", registryName), + resource.TestCheckResourceAttr(resourceName, "description", description), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("registry/%s", registryName)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSchemasRegistryConfig(registryNameModified, descriptionModified), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasRegistryExists(resourceName, &v2), + resource.TestCheckResourceAttr(resourceName, "name", registryNameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("registry/%s", registryNameModified)), + testAccCheckSchemasRegistryRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + Config: testAccAWSSchemasRegistryConfig_Tags1(registryNameModified, "key", "value"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasRegistryExists(resourceName, &v3), + testAccCheckSchemasRegistryNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key", "value"), + ), + }, + }, + }) +} + +func TestAccAWSSchemasRegistry_tags(t *testing.T) { + var v1, v2, v3, v4 schemas.DescribeRegistryOutput + registryName := acctest.RandomWithPrefix("tf-acc-test") + description := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_schemas_registry.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasRegistryDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSchemasRegistryConfig_Tags1(registryName, "key1", "value"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasRegistryExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSchemasRegistryConfig_Tags2(registryName, "key1", "updated", "key2", "added"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasRegistryExists(resourceName, &v2), + testAccCheckSchemasRegistryNotRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), + ), + }, + { + Config: testAccAWSSchemasRegistryConfig_Tags1(registryName, "key2", "added"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasRegistryExists(resourceName, &v3), + testAccCheckSchemasRegistryNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), + ), + }, + { + Config: testAccAWSSchemasRegistryConfig(registryName, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasRegistryExists(resourceName, &v4), + testAccCheckSchemasRegistryNotRecreated(&v3, &v4), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + }, + }) +} + +func TestAccAWSSchemasRegistry_disappears(t *testing.T) { + var v schemas.DescribeRegistryOutput + registryName := acctest.RandomWithPrefix("tf-acc-test") + description := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_schemas_registry.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasRegistryDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSchemasRegistryConfig(registryName, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasRegistryExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSchemasRegistry(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSSchemasRegistryDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).schemasconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_schemas_registry" { + continue + } + + params := schemas.DescribeRegistryInput{ + RegistryName: aws.String(rs.Primary.ID), + } + + resp, err := conn.DescribeRegistry(¶ms) + + if err == nil { + return fmt.Errorf("Schemas Registry (%s) still exists: %s", rs.Primary.ID, resp) + } + } + + return nil +} + +func testAccCheckSchemasRegistryExists(n string, v *schemas.DescribeRegistryOutput) 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).schemasconn + params := schemas.DescribeRegistryInput{ + RegistryName: aws.String(rs.Primary.ID), + } + resp, err := conn.DescribeRegistry(¶ms) + if err != nil { + return err + } + if resp == nil { + return fmt.Errorf("Schemas Registry (%s) not found", n) + } + + *v = *resp + + return nil + } +} + +func testAccCheckSchemasRegistryRecreated(i, j *schemas.DescribeRegistryOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.RegistryArn) == aws.StringValue(j.RegistryArn) { + return fmt.Errorf("Schemas Registry not recreated") + } + return nil + } +} + +func testAccCheckSchemasRegistryNotRecreated(i, j *schemas.DescribeRegistryOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.RegistryArn) != aws.StringValue(j.RegistryArn) { + return fmt.Errorf("Schemas Registry was recreated") + } + return nil + } +} + +func testAccAWSSchemasRegistryConfig(name, description string) string { + return fmt.Sprintf(` +resource "aws_schemas_registry" "test" { + name = %[1]q + description = %[2]q +} +`, name, description) +} + +func testAccAWSSchemasRegistryConfig_Tags1(name, key, value string) string { + return fmt.Sprintf(` +resource "aws_schemas_registry" "test" { + name = %[1]q + + tags = { + %[2]q = %[3]q + } +} +`, name, key, value) +} + +func testAccAWSSchemasRegistryConfig_Tags2(name, key1, value1, key2, value2 string) string { + return fmt.Sprintf(` +resource "aws_schemas_registry" "test" { + name = %[1]q + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, name, key1, value1, key2, value2) +} diff --git a/aws/resource_aws_schemas_schema.go b/aws/resource_aws_schemas_schema.go new file mode 100644 index 00000000000..e6f25da48c0 --- /dev/null +++ b/aws/resource_aws_schemas_schema.go @@ -0,0 +1,235 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "strings" + + "github.com/aws/aws-sdk-go/aws" + schemas "github.com/aws/aws-sdk-go/service/schemas" + "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 resourceAwsSchemasSchema() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSchemasSchemaCreate, + Read: resourceAwsSchemasSchemaRead, + Update: resourceAwsSchemasSchemaUpdate, + Delete: resourceAwsSchemasSchemaDelete, + 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, 385), + validation.StringMatch(regexp.MustCompile(`^[\.\-_A-Za-z@]+`), ""), + ), + }, + "content": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 256), + }, + "registry": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(schemas.Type_Values(), true), + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "version": { + Type: schema.TypeString, + Computed: true, + }, + "version_created_date": { + Type: schema.TypeString, + Computed: true, + }, + "last_modified": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchema(), + }, + } +} + +func resourceAwsSchemasSchemaCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + + input := &schemas.CreateSchemaInput{} + if name, ok := d.GetOk("name"); ok { + input.SchemaName = aws.String(name.(string)) + } + if registry, ok := d.GetOk("registry"); ok { + input.RegistryName = aws.String(registry.(string)) + } + if schemaType, ok := d.GetOk("type"); ok { + input.Type = aws.String(schemaType.(string)) + } + if content, ok := d.GetOk("content"); ok { + input.Content = aws.String(content.(string)) + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + if v, ok := d.GetOk("tags"); ok { + input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().SchemasTags() + } + + log.Printf("[DEBUG] Creating Schemas Schema: %v", input) + + _, err := conn.CreateSchema(input) + if err != nil { + return fmt.Errorf("Creating Schemas Schema (%s) failed: %w", *input.SchemaName, err) + } + + id := fmt.Sprintf("%s/%s", aws.StringValue(input.SchemaName), aws.StringValue(input.RegistryName)) + d.SetId(id) + + log.Printf("[INFO] Schemas Schema (%s) created", d.Id()) + + return resourceAwsSchemasSchemaRead(d, meta) +} + +func resourceAwsSchemasSchemaRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + schemaName, registryName, err := parseSchemaID(d.Id()) + if err != nil { + return err + } + + input := &schemas.DescribeSchemaInput{ + SchemaName: aws.String(schemaName), + RegistryName: aws.String(registryName), + } + + log.Printf("[DEBUG] Reading Schemas Schema (%s)", d.Id()) + output, err := conn.DescribeSchema(input) + if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { + log.Printf("[WARN] Schemas Schema (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("error reading Schemas Schema: %w", err) + } + + log.Printf("[DEBUG] Found CloudWatch Event bus: %#v", *output) + + d.Set("arn", output.SchemaArn) + d.Set("name", output.SchemaName) + d.Set("registry", aws.StringValue(input.RegistryName)) + d.Set("content", output.Content) + d.Set("description", output.Description) + d.Set("type", output.Type) + d.Set("version", output.SchemaVersion) + d.Set("version_created_date", output.VersionCreatedDate.String()) + d.Set("last_modified", output.LastModified.String()) + + tags, err := keyvaluetags.SchemasListTags(conn, *output.SchemaArn) + if err != nil { + return fmt.Errorf("error listing tags for Schemas Schema (%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 +} + +func resourceAwsSchemasSchemaUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + + if d.HasChanges("name", "registry", "type", "content", "description") { + input := &schemas.UpdateSchemaInput{ + Description: aws.String(""), + } + if name, ok := d.GetOk("name"); ok { + input.SchemaName = aws.String(name.(string)) + } + if registry, ok := d.GetOk("registry"); ok { + input.RegistryName = aws.String(registry.(string)) + } + if schemaType, ok := d.GetOk("type"); ok { + input.Type = aws.String(schemaType.(string)) + } + if content, ok := d.GetOk("content"); ok { + input.Content = aws.String(content.(string)) + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + log.Printf("[DEBUG] Updating Schemas Schema: %s", input) + _, err := conn.UpdateSchema(input) + if err != nil { + return fmt.Errorf("error updating Schemas Schema (%s): %w", d.Id(), err) + } + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.SchemasUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } + } + + return resourceAwsSchemasSchemaRead(d, meta) +} + +func resourceAwsSchemasSchemaDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).schemasconn + + schemaName, registryName, err := parseSchemaID(d.Id()) + if err != nil { + return err + } + + input := &schemas.DeleteSchemaInput{ + SchemaName: aws.String(schemaName), + RegistryName: aws.String(registryName), + } + + log.Printf("[INFO] Deleting Schemas Schema (%s)", d.Id()) + _, err = conn.DeleteSchema(input) + if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { + log.Printf("[WARN] Schemas Schema (%s) not found", d.Id()) + return nil + } + if err != nil { + return fmt.Errorf("Error deleting Schemas Schema (%s): %w", d.Id(), err) + } + log.Printf("[INFO] Schemas Schema (%s) deleted", d.Id()) + + return nil +} + +func parseSchemaID(id string) (string, string, error) { + parts := strings.Split(id, "/") + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("unexpected format for ID (%q), expected SCHEMA_NAME:REGISTRY_NAME", id) + } + return parts[0], parts[1], nil +} diff --git a/aws/resource_aws_schemas_schema_test.go b/aws/resource_aws_schemas_schema_test.go new file mode 100644 index 00000000000..0f1133d10f8 --- /dev/null +++ b/aws/resource_aws_schemas_schema_test.go @@ -0,0 +1,472 @@ +package aws + +import ( + "fmt" + "log" + "testing" + + "github.com/aws/aws-sdk-go/aws" + schemas "github.com/aws/aws-sdk-go/service/schemas" + "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" +) + +var schemaType = schemas.TypeOpenApi3 +var content = `{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "Event" + }, + "paths": {}, + "components": { + "schemas": { + "Event": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + } + } + } + } +` +var contentModified = `{ + "openapi": "3.0.0", + "info": { + "version": "2.0.0", + "title": "Event" + }, + "paths": {}, + "components": { + "schemas": { + "Event": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + } + } + } + } + } + } +` + +func init() { + resource.AddTestSweepers("aws_schemas_schema", &resource.Sweeper{ + Name: "aws_schemas_schema", + F: testSweepSchemasSchema, + Dependencies: []string{ + "aws_schemas_registry", + }, + }) +} + +func testSweepSchemasSchema(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("Error getting client: %w", err) + } + conn := client.(*AWSClient).schemasconn + + var sweeperErrs *multierror.Error + var deletedSchemas int + + input := &schemas.ListRegistriesInput{ + Limit: aws.Int64(100), + } + var registries []*schemas.RegistrySummary + for { + output, err := conn.ListRegistries(input) + if err != nil { + return err + } + registries = append(registries, output.Registries...) + + if aws.StringValue(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + for _, registry := range registries { + input := &schemas.ListSchemasInput{ + Limit: aws.Int64(100), + RegistryName: registry.RegistryName, + } + var existingSchemas []*schemas.SchemaSummary + for { + output, err := conn.ListSchemas(input) + if err != nil { + return err + } + existingSchemas = append(existingSchemas, output.Schemas...) + + if aws.StringValue(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + for _, existingSchema := range existingSchemas { + + input := &schemas.DeleteSchemaInput{ + SchemaName: existingSchema.SchemaName, + RegistryName: registry.RegistryName, + } + _, err := conn.DeleteSchema(input) + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("Error deleting Schemas Schema (%s): %w", *existingSchema.SchemaName, err)) + continue + } + deletedSchemas += 1 + } + } + + log.Printf("[INFO] Deleted %d Schemas Schemas", deletedSchemas) + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSSchemasSchema_basic(t *testing.T) { + var v1, v2, v3 schemas.DescribeSchemaOutput + name := acctest.RandomWithPrefix("tf-acc-test") + nameModified := acctest.RandomWithPrefix("tf-acc-test") + + registry := acctest.RandomWithPrefix("tf-acc-test") + + description := acctest.RandomWithPrefix("tf-acc-test") + descriptionModified := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_schemas_schema.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasSchemaDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSchemasSchemaConfig( + name, + registry, + schemaType, + content, + description, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasSchemaExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "registry", registry), + resource.TestCheckResourceAttr(resourceName, "type", schemaType), + resource.TestCheckResourceAttr(resourceName, "content", content), + resource.TestCheckResourceAttr(resourceName, "description", description), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("schema/%s/%s", registry, name)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSchemasSchemaConfig( + nameModified, + registry, + schemaType, + contentModified, + descriptionModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasSchemaExists(resourceName, &v2), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "registry", registry), + resource.TestCheckResourceAttr(resourceName, "type", schemaType), + resource.TestCheckResourceAttr(resourceName, "content", contentModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("schema/%s/%s", registry, nameModified)), + testAccCheckSchemasSchemaRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + Config: testAccAWSSchemasSchemaConfig_Tags1( + nameModified, + registry, + schemaType, + contentModified, + "key", + "value", + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasSchemaExists(resourceName, &v3), + testAccCheckSchemasSchemaNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key", "value"), + ), + }, + }, + }) +} + +func TestAccAWSSchemasSchema_tags(t *testing.T) { + var v1, v2, v3, v4 schemas.DescribeSchemaOutput + name := acctest.RandomWithPrefix("tf-acc-test") + registry := acctest.RandomWithPrefix("tf-acc-test") + description := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_schemas_schema.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasSchemaDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSchemasSchemaConfig_Tags1( + name, + registry, + schemaType, + content, + "key1", + "value", + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasSchemaExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSchemasSchemaConfig_Tags2( + name, + registry, + schemaType, + content, + "key1", + "updated", + "key2", + "added", + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasSchemaExists(resourceName, &v2), + testAccCheckSchemasSchemaNotRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), + ), + }, + { + Config: testAccAWSSchemasSchemaConfig_Tags1( + name, + registry, + schemaType, + content, + "key2", + "added", + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasSchemaExists(resourceName, &v3), + testAccCheckSchemasSchemaNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), + ), + }, + { + Config: testAccAWSSchemasSchemaConfig( + name, + registry, + schemaType, + content, + description, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasSchemaExists(resourceName, &v4), + testAccCheckSchemasSchemaNotRecreated(&v3, &v4), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + }, + }) +} + +func TestAccAWSSchemasSchema_disappears(t *testing.T) { + var v schemas.DescribeSchemaOutput + name := acctest.RandomWithPrefix("tf-acc-test") + registry := acctest.RandomWithPrefix("tf-acc-test") + description := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_schemas_schema.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasSchemaDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSchemasSchemaConfig( + name, + registry, + schemaType, + content, + description, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasSchemaExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSchemasSchema(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSSchemasSchemaDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).schemasconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_schemas_schema" { + continue + } + + schemaName, registryName, err := parseSchemaID(rs.Primary.ID) + if err != nil { + return err + } + + params := schemas.DescribeSchemaInput{ + SchemaName: aws.String(schemaName), + RegistryName: aws.String(registryName), + } + + resp, err := conn.DescribeSchema(¶ms) + + if err == nil { + return fmt.Errorf("Schemas Schema (%s) still exists: %s", rs.Primary.ID, resp) + } + } + + return nil +} + +func testAccCheckSchemasSchemaExists(n string, v *schemas.DescribeSchemaOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + schemaName, registryName, err := parseSchemaID(rs.Primary.ID) + if err != nil { + return err + } + + params := schemas.DescribeSchemaInput{ + SchemaName: aws.String(schemaName), + RegistryName: aws.String(registryName), + } + conn := testAccProvider.Meta().(*AWSClient).schemasconn + + resp, err := conn.DescribeSchema(¶ms) + if err != nil { + return err + } + if resp == nil { + return fmt.Errorf("Schemas Schema (%s) not found", n) + } + + *v = *resp + + return nil + } +} + +func testAccCheckSchemasSchemaRecreated(i, j *schemas.DescribeSchemaOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.SchemaArn) == aws.StringValue(j.SchemaArn) { + return fmt.Errorf("Schemas Schema not recreated") + } + return nil + } +} + +func testAccCheckSchemasSchemaNotRecreated(i, j *schemas.DescribeSchemaOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.SchemaArn) != aws.StringValue(j.SchemaArn) { + return fmt.Errorf("Schemas Schema was recreated") + } + return nil + } +} + +func testAccAWSSchemasSchemaConfig(name, registry, schemaType, content, description string) string { + return fmt.Sprintf(` +resource "aws_schemas_registry" "test" { + name = %[2]q +} + +resource "aws_schemas_schema" "test" { + name = %[1]q + registry = aws_schemas_registry.test.name + type = %[3]q + content = %[4]q + description = %[5]q +} +`, name, registry, schemaType, content, description) +} + +func testAccAWSSchemasSchemaConfig_Tags1(name, registry, schemaType, content, key, value string) string { + return fmt.Sprintf(` +resource "aws_schemas_registry" "test" { + name = %[2]q +} + +resource "aws_schemas_schema" "test" { + name = %[1]q + registry = aws_schemas_registry.test.name + type = %[3]q + content = %[4]q + + tags = { + %[5]q = %[6]q + } +} +`, name, registry, schemaType, content, key, value) +} + +func testAccAWSSchemasSchemaConfig_Tags2(name, registry, schemaType, content, key1, value1, key2, value2 string) string { + return fmt.Sprintf(` +resource "aws_schemas_registry" "test" { + name = %[2]q +} + +resource "aws_schemas_schema" "test" { + name = %[1]q + registry = aws_schemas_registry.test.name + type = %[3]q + content = %[4]q + + tags = { + %[5]q = %[6]q + %[7]q = %[8]q + } +} +`, name, registry, schemaType, content, key1, value1, key2, value2) +} diff --git a/website/docs/r/schemas_discoverer.html.markdown b/website/docs/r/schemas_discoverer.html.markdown new file mode 100644 index 00000000000..c8240b9f1b3 --- /dev/null +++ b/website/docs/r/schemas_discoverer.html.markdown @@ -0,0 +1,51 @@ +--- +subcategory: "EventBridge (CloudWatch Events) Schemas" +layout: "aws" +page_title: "AWS: aws_schemas_discoverer" +description: |- + Provides an EventBridge Schema Discoverer resource. +--- + +# Resource: aws_schemas_discoverer + +Provides an EventBridge Schema Discoverer resource. + +~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. + + +## Example Usage + +```terraform +resource "aws_cloudwatch_event_bus" "messenger" { + name = "chat-messages" +} + +resource "aws_schemas_discoverer" "test" { + source_arn = aws_cloudwatch_event_bus.messenger.arn + description = "Auto discover event schemas" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `source_arn` - (Required) The arn of the event bus to discover event schemas on. +* `description` - (Optional) The description of the discoverer. Maximum of 256 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 discoverer. +* `discoverer_id` - The ID of the discoverer. + + +## Import + +EventBridge discoverers can be imported using the `discoverer_id`, e.g. + +```console +$ terraform import aws_schemas_discoverer.test 123 +``` diff --git a/website/docs/r/schemas_registry.html.markdown b/website/docs/r/schemas_registry.html.markdown new file mode 100644 index 00000000000..97adc47a163 --- /dev/null +++ b/website/docs/r/schemas_registry.html.markdown @@ -0,0 +1,46 @@ +--- +subcategory: "EventBridge (CloudWatch Events) Schemas" +layout: "aws" +page_title: "AWS: aws_schemas_registry" +description: |- + Provides an EventBridge Custom Schema Registry resource. +--- + +# Resource: aws_schemas_registry + +Provides an EventBridge Custom Schema Registry resource. + +~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. + + +## Example Usage + +```terraform +resource "aws_schemas_registry" "test" { + name = "my_own_registry" + description = "A custom schema registry" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the custom event schema registry. Maximum of 64 characters consisting of lower case letters, upper case letters, 0-9, ., -, _. +* `description` - (Optional) The description of the discoverer. Maximum of 256 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 discoverer. + + +## Import + +EventBridge schema registries can be imported using the `name`, e.g. + +```console +$ terraform import aws_schemas_registry.test my_own_registry +``` diff --git a/website/docs/r/schemas_schema.html.markdown b/website/docs/r/schemas_schema.html.markdown new file mode 100644 index 00000000000..2c2646ea4ac --- /dev/null +++ b/website/docs/r/schemas_schema.html.markdown @@ -0,0 +1,78 @@ +--- +subcategory: "EventBridge (CloudWatch Events) Schemas" +layout: "aws" +page_title: "AWS: aws_schemas_schema" +description: |- + Provides an EventBridge Schema resource. +--- + +# Resource: aws_schemas_schema + +Provides an EventBridge Schema resource. + +~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. + + +## Example Usage + +```terraform +resource "aws_schemas_registry" "test" { + name = "my_own_registry" +} + +resource "aws_schemas_schema" "test" { + name = "my_schema" + registry = aws_schemas_registry.test.name + type = "OpenApi3" + description = "The schema definition for my event" + content = jsonencode({ + "openapi" : "3.0.0", + "info" : { + "version" : "1.0.0", + "title" : "Event" + }, + "paths" : {}, + "components" : { + "schemas" : { + "Event" : { + "type" : "object", + "properties" : { + "name" : { + "type" : "string" + } + } + } + } + } + }) +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the schema. Maximum of 385 characters consisting of lower case letters, upper case letters, ., -, _, @. +* `content` - (Required) The schema specification. Must be a valid Open API 3.0 spec. +* `registry` - (Required) The name of the registry in which this schema belongs. +* `type` - (Required) The type of the schema. Possible values: OpenApi3. +* `description` - (Optional) The description of the schema. Maximum of 256 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 discoverer. +* `version` - The version of the schema. +* `version_created_date` - The created date of the version of the schema. +* `last_modified` - The last modified date of the schema. + + +## Import + +EventBridge schema can be imported using the `name` and `registry`, e.g. + +```console +$ terraform import aws_schemas_schema.test registry/name +``` From e233ef7573f4946f60603faf84a35a79c2b8c750 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 10:15:12 -0400 Subject: [PATCH 214/398] Documentation category is 'EventBridge Schemas'. --- website/allowed-subcategories.txt | 1 + website/docs/r/schemas_discoverer.html.markdown | 2 +- website/docs/r/schemas_registry.html.markdown | 2 +- website/docs/r/schemas_schema.html.markdown | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/website/allowed-subcategories.txt b/website/allowed-subcategories.txt index c1584e01a03..79d5df82be0 100644 --- a/website/allowed-subcategories.txt +++ b/website/allowed-subcategories.txt @@ -62,6 +62,7 @@ Elastic Map Reduce Containers Elastic Transcoder ElasticSearch EventBridge (CloudWatch Events) +EventBridge Schemas File System (FSx) Firewall Manager (FMS) Gamelift diff --git a/website/docs/r/schemas_discoverer.html.markdown b/website/docs/r/schemas_discoverer.html.markdown index c8240b9f1b3..a7cf56e3184 100644 --- a/website/docs/r/schemas_discoverer.html.markdown +++ b/website/docs/r/schemas_discoverer.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "EventBridge (CloudWatch Events) Schemas" +subcategory: "EventBridge Schemas" layout: "aws" page_title: "AWS: aws_schemas_discoverer" description: |- diff --git a/website/docs/r/schemas_registry.html.markdown b/website/docs/r/schemas_registry.html.markdown index 97adc47a163..47dd3b1205c 100644 --- a/website/docs/r/schemas_registry.html.markdown +++ b/website/docs/r/schemas_registry.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "EventBridge (CloudWatch Events) Schemas" +subcategory: "EventBridge Schemas" layout: "aws" page_title: "AWS: aws_schemas_registry" description: |- diff --git a/website/docs/r/schemas_schema.html.markdown b/website/docs/r/schemas_schema.html.markdown index 2c2646ea4ac..f54dcf7df75 100644 --- a/website/docs/r/schemas_schema.html.markdown +++ b/website/docs/r/schemas_schema.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "EventBridge (CloudWatch Events) Schemas" +subcategory: "EventBridge Schemas" layout: "aws" page_title: "AWS: aws_schemas_schema" description: |- From 86a4830206c1142a1ce17b99c6d61cd171eeff6f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 10:18:34 -0400 Subject: [PATCH 215/398] Add 'schemas' to the list of customizable endpoints. --- aws/provider.go | 1 + website/docs/guides/custom-service-endpoints.html.md | 1 + 2 files changed, 2 insertions(+) diff --git a/aws/provider.go b/aws/provider.go index 411f97f3e26..66c4a761428 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1390,6 +1390,7 @@ func init() { "s3control", "s3outposts", "sagemaker", + "schemas", "sdb", "secretsmanager", "securityhub", diff --git a/website/docs/guides/custom-service-endpoints.html.md b/website/docs/guides/custom-service-endpoints.html.md index e23f99ffa08..edad3b4262e 100644 --- a/website/docs/guides/custom-service-endpoints.html.md +++ b/website/docs/guides/custom-service-endpoints.html.md @@ -184,6 +184,7 @@ The Terraform AWS Provider allows the following endpoints to be customized:
  • s3control
  • s3outposts
  • sagemaker
  • +
  • schemas
  • sdb
  • secretsmanager
  • securityhub
  • From 3c46cc411c3fe113371940428d3b60183dc0a817 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 10:22:42 -0400 Subject: [PATCH 216/398] Add 'schemas' to labelers. --- .github/labeler-pr-triage.yml | 4 ++++ .hashibot.hcl | 3 +++ infrastructure/repository/labels-service.tf | 1 + 3 files changed, 8 insertions(+) diff --git a/.github/labeler-pr-triage.yml b/.github/labeler-pr-triage.yml index 2458add8c9c..a70cf67696a 100644 --- a/.github/labeler-pr-triage.yml +++ b/.github/labeler-pr-triage.yml @@ -686,6 +686,10 @@ service/sagemaker: - 'aws/internal/service/sagemaker/**/*' - '**/*_sagemaker_*' - '**/sagemaker_*' +service/schemas: + - 'aws/internal/service/schemas/**/*' + - '**/*_schemas_*' + - '**/schemas_*' service/secretsmanager: - 'aws/internal/service/secretsmanager/**/*' - '**/*_secretsmanager_*' diff --git a/.hashibot.hcl b/.hashibot.hcl index 62351a747fc..73046cefac0 100644 --- a/.hashibot.hcl +++ b/.hashibot.hcl @@ -471,6 +471,9 @@ behavior "regexp_issue_labeler_v2" "service_labels" { "service/sagemaker" = [ "aws_sagemaker_", ], + "service/schemas" = [ + "aws_schemas_", + ], "service/secretsmanager" = [ "aws_secretsmanager_", ], diff --git a/infrastructure/repository/labels-service.tf b/infrastructure/repository/labels-service.tf index 753b05e32cc..4f27b2b8ff1 100644 --- a/infrastructure/repository/labels-service.tf +++ b/infrastructure/repository/labels-service.tf @@ -172,6 +172,7 @@ variable "service_labels" { "s3outposts", "sagemaker", "savingsplans", + "schemas", "secretsmanager", "securityhub", "serverlessapplicationrepository", From 7f35b753a3453b9313cc9bdb933e161305e2eff3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 11:19:41 -0400 Subject: [PATCH 217/398] r/aws_schemas_discoverer: Remove 'discoverer_id' attribute. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSSchemasDiscoverer_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSSchemasDiscoverer_ -timeout 180m === RUN TestAccAWSSchemasDiscoverer_basic === PAUSE TestAccAWSSchemasDiscoverer_basic === RUN TestAccAWSSchemasDiscoverer_disappears === PAUSE TestAccAWSSchemasDiscoverer_disappears === RUN TestAccAWSSchemasDiscoverer_Description === PAUSE TestAccAWSSchemasDiscoverer_Description === RUN TestAccAWSSchemasDiscoverer_Tags === PAUSE TestAccAWSSchemasDiscoverer_Tags === CONT TestAccAWSSchemasDiscoverer_basic === CONT TestAccAWSSchemasDiscoverer_Tags === CONT TestAccAWSSchemasDiscoverer_Description === CONT TestAccAWSSchemasDiscoverer_disappears --- PASS: TestAccAWSSchemasDiscoverer_disappears (14.58s) --- PASS: TestAccAWSSchemasDiscoverer_basic (17.70s) --- PASS: TestAccAWSSchemasDiscoverer_Tags (40.38s) --- PASS: TestAccAWSSchemasDiscoverer_Description (40.46s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 43.537s --- aws/internal/service/schemas/finder/finder.go | 36 +++ aws/resource_aws_schemas_discoverer.go | 118 +++++----- aws/resource_aws_schemas_discoverer_test.go | 210 +++++++++--------- .../docs/r/schemas_discoverer.html.markdown | 10 +- 4 files changed, 210 insertions(+), 164 deletions(-) create mode 100644 aws/internal/service/schemas/finder/finder.go diff --git a/aws/internal/service/schemas/finder/finder.go b/aws/internal/service/schemas/finder/finder.go new file mode 100644 index 00000000000..c04a10cc57d --- /dev/null +++ b/aws/internal/service/schemas/finder/finder.go @@ -0,0 +1,36 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/schemas" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func DiscovererByID(conn *schemas.Schemas, id string) (*schemas.DescribeDiscovererOutput, error) { + input := &schemas.DescribeDiscovererInput{ + DiscovererId: aws.String(id), + } + + output, err := conn.DescribeDiscoverer(input) + + if tfawserr.ErrCodeEquals(err, schemas.ErrCodeNotFoundException) { + 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_schemas_discoverer.go b/aws/resource_aws_schemas_discoverer.go index 2864ab80c9b..dfb2f786127 100644 --- a/aws/resource_aws_schemas_discoverer.go +++ b/aws/resource_aws_schemas_discoverer.go @@ -5,10 +5,13 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" - schemas "github.com/aws/aws-sdk-go/service/schemas" + "github.com/aws/aws-sdk-go/service/schemas" + "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/schemas/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsSchemasDiscoverer() *schema.Resource { @@ -22,92 +25,99 @@ func resourceAwsSchemasDiscoverer() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "source_arn": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validateArn, + "arn": { + Type: schema.TypeString, + Computed: true, }, + "description": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringLenBetween(0, 256), }, - "arn": { - Type: schema.TypeString, - Computed: true, - }, - "discoverer_id": { - Type: schema.TypeString, - Computed: true, + + "source_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateArn, }, - "tags": tagsSchema(), + + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), }, + + CustomizeDiff: SetTagsDiff, } } func resourceAwsSchemasDiscovererCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).schemasconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) - input := &schemas.CreateDiscovererInput{} - if source, ok := d.GetOk("source_arn"); ok { - input.SourceArn = aws.String(source.(string)) - } - if description, ok := d.GetOk("description"); ok { - input.Description = aws.String(description.(string)) + sourceARN := d.Get("source_arn").(string) + input := &schemas.CreateDiscovererInput{ + SourceArn: aws.String(sourceARN), } - if v, ok := d.GetOk("tags"); ok { - input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().SchemasTags() + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) } - log.Printf("[DEBUG] Creating Schemas Discoverer: %v", input) + if len(tags) > 0 { + input.Tags = tags.IgnoreAws().SchemasTags() + } + log.Printf("[DEBUG] Creating EventBridge Schemas Discoverer: %s", input) output, err := conn.CreateDiscoverer(input) + if err != nil { - return fmt.Errorf("Creating Schemas Discoverer (%s) failed: %w", *input.SourceArn, err) + return fmt.Errorf("error creating EventBridge Schemas Discoverer (%s): %w", sourceARN, err) } d.SetId(aws.StringValue(output.DiscovererId)) - log.Printf("[INFO] Schemas Discoverer (%s) created", d.Id()) - return resourceAwsSchemasDiscovererRead(d, meta) } func resourceAwsSchemasDiscovererRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).schemasconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - input := &schemas.DescribeDiscovererInput{ - DiscovererId: aws.String(d.Id()), - } + output, err := finder.DiscovererByID(conn, d.Id()) - log.Printf("[DEBUG] Reading Schemas Discoverer (%s)", d.Id()) - output, err := conn.DescribeDiscoverer(input) - if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { - log.Printf("[WARN] Schemas Discoverer (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] EventBridge Schemas Discoverer (%s) not found, removing from state", d.Id()) d.SetId("") return nil } + if err != nil { - return fmt.Errorf("error reading Schemas Discoverer: %w", err) + return fmt.Errorf("error reading EventBridge Schemas Discoverer (%s): %w", d.Id(), err) } - log.Printf("[DEBUG] Found CloudWatch Event bus: %#v", *output) - d.Set("arn", output.DiscovererArn) - d.Set("source_arn", output.SourceArn) d.Set("description", output.Description) - d.Set("discoverer_id", output.DiscovererId) + d.Set("source_arn", output.SourceArn) + + tags, err := keyvaluetags.SchemasListTags(conn, d.Get("arn").(string)) - tags, err := keyvaluetags.SchemasListTags(conn, *output.DiscovererArn) if err != nil { - return fmt.Errorf("error listing tags for Schemas Discoverer (%s): %w", d.Id(), err) + return fmt.Errorf("error listing tags for EventBridge Schemas Discoverer (%s): %w", d.Id(), err) } - if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + + tags = 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 } @@ -117,23 +127,21 @@ func resourceAwsSchemasDiscovererUpdate(d *schema.ResourceData, meta interface{} if d.HasChange("description") { input := &schemas.UpdateDiscovererInput{ DiscovererId: aws.String(d.Id()), - Description: aws.String(""), - } - if description, ok := d.GetOk("description"); ok { - input.Description = aws.String(description.(string)) + Description: aws.String(d.Get("description").(string)), } - log.Printf("[DEBUG] Updating Schemas Discoverer: %s", input) + log.Printf("[DEBUG] Updating EventBridge Schemas Discoverer: %s", input) _, err := conn.UpdateDiscoverer(input) + if err != nil { - return fmt.Errorf("error updating Schemas Discoverer (%s): %w", d.Id(), err) + return fmt.Errorf("error updating EventBridge Schemas Discoverer (%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.SchemasUpdateTags(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) } } @@ -143,18 +151,18 @@ func resourceAwsSchemasDiscovererUpdate(d *schema.ResourceData, meta interface{} func resourceAwsSchemasDiscovererDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).schemasconn - log.Printf("[INFO] Deleting Schemas Discoverer (%s)", d.Id()) + log.Printf("[INFO] Deleting EventBridge Schemas Discoverer (%s)", d.Id()) _, err := conn.DeleteDiscoverer(&schemas.DeleteDiscovererInput{ DiscovererId: aws.String(d.Id()), }) - if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { - log.Printf("[WARN] Schemas Discoverer (%s) not found", d.Id()) + + if tfawserr.ErrCodeEquals(err, schemas.ErrCodeNotFoundException) { return nil } + if err != nil { - return fmt.Errorf("Error deleting Schemas Discoverer (%s): %w", d.Id(), err) + return fmt.Errorf("error deleting EventBridge Schemas Discoverer (%s): %w", d.Id(), err) } - log.Printf("[INFO] Schemas Discoverer (%s) deleted", d.Id()) return nil } diff --git a/aws/resource_aws_schemas_discoverer_test.go b/aws/resource_aws_schemas_discoverer_test.go index a648eca6128..d6276f81f02 100644 --- a/aws/resource_aws_schemas_discoverer_test.go +++ b/aws/resource_aws_schemas_discoverer_test.go @@ -6,11 +6,13 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" - schemas "github.com/aws/aws-sdk-go/service/schemas" + "github.com/aws/aws-sdk-go/service/schemas" "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/schemas/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -67,27 +69,22 @@ func testSweepSchemasDiscoverer(region string) error { } func TestAccAWSSchemasDiscoverer_basic(t *testing.T) { - var v1, v2, v3 schemas.DescribeDiscovererOutput - eventbusName := acctest.RandomWithPrefix("tf-acc-test") - eventbusNameModified := acctest.RandomWithPrefix("tf-acc-test") - - description := acctest.RandomWithPrefix("tf-acc-test") - descriptionModified := acctest.RandomWithPrefix("tf-acc-test") - + var v schemas.DescribeDiscovererOutput + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_schemas_discoverer.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSchemasDiscovererDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSchemasDiscovererConfig(eventbusName, description), + Config: testAccAWSSchemasDiscovererConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasDiscovererExists(resourceName, &v1), - resource.TestCheckResourceAttr(resourceName, "description", description), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("discoverer/events-event-bus-%s", eventbusName)), + testAccCheckSchemasDiscovererExists(resourceName, &v), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("discoverer/events-event-bus-%s", rName)), + resource.TestCheckResourceAttr(resourceName, "description", ""), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, @@ -96,48 +93,49 @@ func TestAccAWSSchemasDiscoverer_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + }, + }) +} + +func TestAccAWSSchemasDiscoverer_disappears(t *testing.T) { + var v schemas.DescribeDiscovererOutput + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_schemas_discoverer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasDiscovererDestroy, + Steps: []resource.TestStep{ { - Config: testAccAWSSchemasDiscovererConfig(eventbusNameModified, descriptionModified), - Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasDiscovererExists(resourceName, &v2), - resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("discoverer/events-event-bus-%s", eventbusNameModified)), - testAccCheckSchemasDiscovererRecreated(&v1, &v2), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - ), - }, - { - Config: testAccAWSSchemasDiscovererConfig_Tags1(eventbusNameModified, "key", "value"), + Config: testAccAWSSchemasDiscovererConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasDiscovererExists(resourceName, &v3), - testAccCheckSchemasDiscovererNotRecreated(&v2, &v3), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key", "value"), + testAccCheckSchemasDiscovererExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSchemasDiscoverer(), resourceName), ), + ExpectNonEmptyPlan: true, }, }, }) } -func TestAccAWSSchemasDiscoverer_tags(t *testing.T) { - var v1, v2, v3, v4 schemas.DescribeDiscovererOutput - eventbusName := acctest.RandomWithPrefix("tf-acc-test") - description := acctest.RandomWithPrefix("tf-acc-test") - +func TestAccAWSSchemasDiscoverer_Description(t *testing.T) { + var v schemas.DescribeDiscovererOutput + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_schemas_discoverer.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSchemasDiscovererDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSchemasDiscovererConfig_Tags1(eventbusName, "key1", "value"), + Config: testAccAWSSchemasDiscovererConfigDescription(rName, "description1"), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasDiscovererExists(resourceName, &v1), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value"), + testAccCheckSchemasDiscovererExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "description", "description1"), ), }, { @@ -146,56 +144,63 @@ func TestAccAWSSchemasDiscoverer_tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSSchemasDiscovererConfig_Tags2(eventbusName, "key1", "updated", "key2", "added"), - Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasDiscovererExists(resourceName, &v2), - testAccCheckSchemasDiscovererNotRecreated(&v1, &v2), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "updated"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), - ), - }, - { - Config: testAccAWSSchemasDiscovererConfig_Tags1(eventbusName, "key2", "added"), + Config: testAccAWSSchemasDiscovererConfigDescription(rName, "description2"), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasDiscovererExists(resourceName, &v3), - testAccCheckSchemasDiscovererNotRecreated(&v2, &v3), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), + testAccCheckSchemasDiscovererExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "description", "description2"), ), }, { - Config: testAccAWSSchemasDiscovererConfig(eventbusName, description), + Config: testAccAWSSchemasDiscovererConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasDiscovererExists(resourceName, &v4), - testAccCheckSchemasDiscovererNotRecreated(&v3, &v4), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + testAccCheckSchemasDiscovererExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "description", ""), ), }, }, }) } -func TestAccAWSSchemasDiscoverer_disappears(t *testing.T) { +func TestAccAWSSchemasDiscoverer_Tags(t *testing.T) { var v schemas.DescribeDiscovererOutput - eventbusName := acctest.RandomWithPrefix("tf-acc-test") - description := acctest.RandomWithPrefix("tf-acc-test") - + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_schemas_discoverer.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSchemasDiscovererDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSchemasDiscovererConfig(eventbusName, description), + Config: testAccAWSSchemasDiscovererConfigTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccCheckSchemasDiscovererExists(resourceName, &v), - testAccCheckResourceDisappears(testAccProvider, resourceAwsSchemasDiscoverer(), resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSchemasDiscovererConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasDiscovererExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSSchemasDiscovererConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasDiscovererExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), - ExpectNonEmptyPlan: true, }, }, }) @@ -209,15 +214,17 @@ func testAccCheckAWSSchemasDiscovererDestroy(s *terraform.State) error { continue } - params := schemas.DescribeDiscovererInput{ - DiscovererId: aws.String(rs.Primary.ID), - } + _, err := finder.DiscovererByID(conn, rs.Primary.ID) - resp, err := conn.DescribeDiscoverer(¶ms) + if tfresource.NotFound(err) { + continue + } - if err == nil { - return fmt.Errorf("Schemas Discoverer (%s) still exists: %s", rs.Primary.ID, resp) + if err != nil { + return err } + + return fmt.Errorf("EventBridge Schemas Discoverer %s still exists", rs.Primary.ID) } return nil @@ -230,84 +237,79 @@ func testAccCheckSchemasDiscovererExists(n string, v *schemas.DescribeDiscoverer return fmt.Errorf("Not found: %s", n) } - conn := testAccProvider.Meta().(*AWSClient).schemasconn - params := schemas.DescribeDiscovererInput{ - DiscovererId: aws.String(rs.Primary.ID), + if rs.Primary.ID == "" { + return fmt.Errorf("No EventBridge Schemas Discoverer ID is set") } - resp, err := conn.DescribeDiscoverer(¶ms) + + conn := testAccProvider.Meta().(*AWSClient).schemasconn + + output, err := finder.DiscovererByID(conn, rs.Primary.ID) + if err != nil { return err } - if resp == nil { - return fmt.Errorf("Schemas Discoverer (%s) not found", n) - } - *v = *resp + *v = *output return nil } } -func testAccCheckSchemasDiscovererRecreated(i, j *schemas.DescribeDiscovererOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - if aws.StringValue(i.DiscovererArn) == aws.StringValue(j.DiscovererArn) { - return fmt.Errorf("Schemas Discoverer not recreated") - } - return nil - } +func testAccAWSSchemasDiscovererConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q } -func testAccCheckSchemasDiscovererNotRecreated(i, j *schemas.DescribeDiscovererOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - if aws.StringValue(i.DiscovererArn) != aws.StringValue(j.DiscovererArn) { - return fmt.Errorf("Schemas Discoverer was recreated") - } - return nil - } +resource "aws_schemas_discoverer" "test" { + source_arn = aws_cloudwatch_event_bus.test.arn +} +`, rName) } -func testAccAWSSchemasDiscovererConfig(eventbusName, description string) string { +func testAccAWSSchemasDiscovererConfigDescription(rName, description string) string { return fmt.Sprintf(` resource "aws_cloudwatch_event_bus" "test" { - name = %[1]q + name = %[1]q } resource "aws_schemas_discoverer" "test" { source_arn = aws_cloudwatch_event_bus.test.arn + description = %[2]q } -`, eventbusName, description) +`, rName, description) } -func testAccAWSSchemasDiscovererConfig_Tags1(eventbusName, key, value string) string { +func testAccAWSSchemasDiscovererConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_cloudwatch_event_bus" "test" { - name = %[1]q + name = %[1]q } resource "aws_schemas_discoverer" "test" { - source_arn = aws_cloudwatch_event_bus.test.arn + source_arn = aws_cloudwatch_event_bus.test.arn tags = { %[2]q = %[3]q } } -`, eventbusName, key, value) +`, rName, tagKey1, tagValue1) } -func testAccAWSSchemasDiscovererConfig_Tags2(eventbusName, key1, value1, key2, value2 string) string { +func testAccAWSSchemasDiscovererConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_cloudwatch_event_bus" "test" { - name = %[1]q + name = %[1]q } resource "aws_schemas_discoverer" "test" { - source_arn = aws_cloudwatch_event_bus.test.arn + source_arn = aws_cloudwatch_event_bus.test.arn tags = { %[2]q = %[3]q %[4]q = %[5]q } } -`, eventbusName, key1, value1, key2, value2) +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) } diff --git a/website/docs/r/schemas_discoverer.html.markdown b/website/docs/r/schemas_discoverer.html.markdown index a7cf56e3184..2889b34ca60 100644 --- a/website/docs/r/schemas_discoverer.html.markdown +++ b/website/docs/r/schemas_discoverer.html.markdown @@ -30,21 +30,21 @@ resource "aws_schemas_discoverer" "test" { The following arguments are supported: -* `source_arn` - (Required) The arn of the event bus to discover event schemas on. +* `source_arn` - (Required) The ARN of the event bus to discover event schemas on. * `description` - (Optional) The description of the discoverer. Maximum of 256 characters. -* `tags` - (Optional) A map of tags to assign to the resource. +* `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. ## Attributes Reference In addition to all arguments above, the following attributes are exported: * `arn` - The Amazon Resource Name (ARN) of the discoverer. -* `discoverer_id` - The ID of the discoverer. - +* `id` - The ID of the discoverer. +* `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). ## Import -EventBridge discoverers can be imported using the `discoverer_id`, e.g. +EventBridge discoverers can be imported using the `id`, e.g. ```console $ terraform import aws_schemas_discoverer.test 123 From 4a99f87b6de0eeb8827e39f6bfce95f7451ce0d6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 12:02:43 -0400 Subject: [PATCH 218/398] r/aws_schemas_registry: Can't update 'name'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSSchemasRegistry_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSSchemasRegistry_ -timeout 180m === RUN TestAccAWSSchemasRegistry_basic === PAUSE TestAccAWSSchemasRegistry_basic === RUN TestAccAWSSchemasRegistry_disappears === PAUSE TestAccAWSSchemasRegistry_disappears === RUN TestAccAWSSchemasRegistry_Description === PAUSE TestAccAWSSchemasRegistry_Description === RUN TestAccAWSSchemasRegistry_Tags === PAUSE TestAccAWSSchemasRegistry_Tags === CONT TestAccAWSSchemasRegistry_basic === CONT TestAccAWSSchemasRegistry_Tags === CONT TestAccAWSSchemasRegistry_Description === CONT TestAccAWSSchemasRegistry_disappears --- PASS: TestAccAWSSchemasRegistry_disappears (10.49s) --- PASS: TestAccAWSSchemasRegistry_basic (16.15s) --- PASS: TestAccAWSSchemasRegistry_Description (36.82s) --- PASS: TestAccAWSSchemasRegistry_Tags (37.17s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 40.482s --- aws/internal/service/schemas/finder/finder.go | 28 +++ aws/resource_aws_schemas_registry.go | 121 ++++++----- aws/resource_aws_schemas_registry_test.go | 202 +++++++++--------- website/docs/r/schemas_registry.html.markdown | 5 +- 4 files changed, 195 insertions(+), 161 deletions(-) diff --git a/aws/internal/service/schemas/finder/finder.go b/aws/internal/service/schemas/finder/finder.go index c04a10cc57d..c56aeee58e1 100644 --- a/aws/internal/service/schemas/finder/finder.go +++ b/aws/internal/service/schemas/finder/finder.go @@ -34,3 +34,31 @@ func DiscovererByID(conn *schemas.Schemas, id string) (*schemas.DescribeDiscover return output, nil } + +func RegistryByName(conn *schemas.Schemas, name string) (*schemas.DescribeRegistryOutput, error) { + input := &schemas.DescribeRegistryInput{ + RegistryName: aws.String(name), + } + + output, err := conn.DescribeRegistry(input) + + if tfawserr.ErrCodeEquals(err, schemas.ErrCodeNotFoundException) { + 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_schemas_registry.go b/aws/resource_aws_schemas_registry.go index 80f8a02ba8a..c14839e3854 100644 --- a/aws/resource_aws_schemas_registry.go +++ b/aws/resource_aws_schemas_registry.go @@ -6,10 +6,13 @@ import ( "regexp" "github.com/aws/aws-sdk-go/aws" - schemas "github.com/aws/aws-sdk-go/service/schemas" + "github.com/aws/aws-sdk-go/service/schemas" + "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/schemas/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsSchemasRegistry() *schema.Resource { @@ -23,118 +26,126 @@ func resourceAwsSchemasRegistry() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "name": { + "arn": { Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 64), - validation.StringMatch(regexp.MustCompile(`^[\.\-_A-Za-z0-9]+`), ""), - ), + Computed: true, }, + "description": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringLenBetween(0, 256), }, - "arn": { + + "name": { Type: schema.TypeString, - Computed: true, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 64), + validation.StringMatch(regexp.MustCompile(`^[\.\-_A-Za-z0-9]+`), ""), + ), }, - "tags": tagsSchema(), + + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), }, + + CustomizeDiff: SetTagsDiff, } } func resourceAwsSchemasRegistryCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).schemasconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) - input := &schemas.CreateRegistryInput{} - if name, ok := d.GetOk("name"); ok { - input.RegistryName = aws.String(name.(string)) + name := d.Get("name").(string) + input := &schemas.CreateRegistryInput{ + RegistryName: aws.String(name), } - if description, ok := d.GetOk("description"); ok { - input.Description = aws.String(description.(string)) - } - if v, ok := d.GetOk("tags"); ok { - input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().SchemasTags() + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) } - log.Printf("[DEBUG] Creating Schemas Registry: %v", input) + if len(tags) > 0 { + input.Tags = tags.IgnoreAws().SchemasTags() + } + log.Printf("[DEBUG] Creating EventBridge Schemas Registry: %s", input) _, err := conn.CreateRegistry(input) + if err != nil { - return fmt.Errorf("Creating Schemas Registry (%s) failed: %w", *input.RegistryName, err) + return fmt.Errorf("error creating EventBridge Schemas Registry (%s): %w", name, err) } d.SetId(aws.StringValue(input.RegistryName)) - log.Printf("[INFO] Schemas Registry (%s) created", d.Id()) - return resourceAwsSchemasRegistryRead(d, meta) } func resourceAwsSchemasRegistryRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).schemasconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - input := &schemas.DescribeRegistryInput{ - RegistryName: aws.String(d.Id()), - } + output, err := finder.RegistryByName(conn, d.Id()) - log.Printf("[DEBUG] Reading Schemas Registry (%s)", d.Id()) - output, err := conn.DescribeRegistry(input) - if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { - log.Printf("[WARN] Schemas Registry (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] EventBridge Schemas Registry (%s) not found, removing from state", d.Id()) d.SetId("") return nil } + if err != nil { - return fmt.Errorf("error reading Schemas Registry: %w", err) + return fmt.Errorf("error reading EventBridge Schemas Registry (%s): %w", d.Id(), err) } - log.Printf("[DEBUG] Found CloudWatch Event bus: %#v", *output) - d.Set("arn", output.RegistryArn) - d.Set("name", output.RegistryName) d.Set("description", output.Description) + d.Set("name", output.RegistryName) + + tags, err := keyvaluetags.SchemasListTags(conn, d.Get("arn").(string)) + + tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) - tags, err := keyvaluetags.SchemasListTags(conn, *output.RegistryArn) if err != nil { - return fmt.Errorf("error listing tags for Schemas Registry (%s): %w", d.Id(), err) + return fmt.Errorf("error listing tags for EventBridge Schemas Registry (%s): %w", d.Id(), err) } - if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + + 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 resourceAwsSchemasRegistryUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).schemasconn - if d.HasChanges("name", "description") { + if d.HasChanges("description") { input := &schemas.UpdateRegistryInput{ - Description: aws.String(""), - } - if name, ok := d.GetOk("name"); ok { - input.RegistryName = aws.String(name.(string)) - } - if description, ok := d.GetOk("description"); ok { - input.Description = aws.String(description.(string)) + Description: aws.String(d.Get("description").(string)), + RegistryName: aws.String(d.Id()), } - log.Printf("[DEBUG] Updating Schemas Registry: %s", input) + log.Printf("[DEBUG] Updating EventBridge Schemas Registry: %s", input) _, err := conn.UpdateRegistry(input) + if err != nil { - return fmt.Errorf("error updating Schemas Registry (%s): %w", d.Id(), err) + return fmt.Errorf("error updating EventBridge Schemas Registry (%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.SchemasUpdateTags(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) } } @@ -144,18 +155,18 @@ func resourceAwsSchemasRegistryUpdate(d *schema.ResourceData, meta interface{}) func resourceAwsSchemasRegistryDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).schemasconn - log.Printf("[INFO] Deleting Schemas Registry (%s)", d.Id()) + log.Printf("[INFO] Deleting EventBridge Schemas Registry (%s)", d.Id()) _, err := conn.DeleteRegistry(&schemas.DeleteRegistryInput{ RegistryName: aws.String(d.Id()), }) - if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { - log.Printf("[WARN] Schemas Registry (%s) not found", d.Id()) + + if tfawserr.ErrCodeEquals(err, schemas.ErrCodeNotFoundException) { return nil } + if err != nil { - return fmt.Errorf("Error deleting Schemas Registry (%s): %w", d.Id(), err) + return fmt.Errorf("error deleting EventBridge Schemas Registry (%s): %w", d.Id(), err) } - log.Printf("[INFO] Schemas Registry (%s) deleted", d.Id()) return nil } diff --git a/aws/resource_aws_schemas_registry_test.go b/aws/resource_aws_schemas_registry_test.go index cbb33ba1f5c..e9bfbd84162 100644 --- a/aws/resource_aws_schemas_registry_test.go +++ b/aws/resource_aws_schemas_registry_test.go @@ -6,11 +6,13 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" - schemas "github.com/aws/aws-sdk-go/service/schemas" + "github.com/aws/aws-sdk-go/service/schemas" "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/schemas/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -64,28 +66,23 @@ func testSweepSchemasRegistry(region string) error { } func TestAccAWSSchemasRegistry_basic(t *testing.T) { - var v1, v2, v3 schemas.DescribeRegistryOutput - registryName := acctest.RandomWithPrefix("tf-acc-test") - registryNameModified := acctest.RandomWithPrefix("tf-acc-test") - - description := acctest.RandomWithPrefix("tf-acc-test") - descriptionModified := acctest.RandomWithPrefix("tf-acc-test") - + var v schemas.DescribeRegistryOutput + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_schemas_registry.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSchemasRegistryDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSchemasRegistryConfig(registryName, description), + Config: testAccAWSSchemasRegistryConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasRegistryExists(resourceName, &v1), - resource.TestCheckResourceAttr(resourceName, "name", registryName), - resource.TestCheckResourceAttr(resourceName, "description", description), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("registry/%s", registryName)), + testAccCheckSchemasRegistryExists(resourceName, &v), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("registry/%s", rName)), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, @@ -94,49 +91,49 @@ func TestAccAWSSchemasRegistry_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + }, + }) +} + +func TestAccAWSSchemasRegistry_disappears(t *testing.T) { + var v schemas.DescribeRegistryOutput + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_schemas_registry.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasRegistryDestroy, + Steps: []resource.TestStep{ { - Config: testAccAWSSchemasRegistryConfig(registryNameModified, descriptionModified), - Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasRegistryExists(resourceName, &v2), - resource.TestCheckResourceAttr(resourceName, "name", registryNameModified), - resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("registry/%s", registryNameModified)), - testAccCheckSchemasRegistryRecreated(&v1, &v2), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - ), - }, - { - Config: testAccAWSSchemasRegistryConfig_Tags1(registryNameModified, "key", "value"), + Config: testAccAWSSchemasRegistryConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasRegistryExists(resourceName, &v3), - testAccCheckSchemasRegistryNotRecreated(&v2, &v3), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key", "value"), + testAccCheckSchemasRegistryExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSchemasRegistry(), resourceName), ), + ExpectNonEmptyPlan: true, }, }, }) } -func TestAccAWSSchemasRegistry_tags(t *testing.T) { - var v1, v2, v3, v4 schemas.DescribeRegistryOutput - registryName := acctest.RandomWithPrefix("tf-acc-test") - description := acctest.RandomWithPrefix("tf-acc-test") - +func TestAccAWSSchemasRegistry_Description(t *testing.T) { + var v schemas.DescribeRegistryOutput + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_schemas_registry.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSchemasRegistryDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSchemasRegistryConfig_Tags1(registryName, "key1", "value"), + Config: testAccAWSSchemasRegistryConfigDescription(rName, "description1"), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasRegistryExists(resourceName, &v1), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value"), + testAccCheckSchemasRegistryExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "description", "description1"), ), }, { @@ -145,56 +142,63 @@ func TestAccAWSSchemasRegistry_tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSSchemasRegistryConfig_Tags2(registryName, "key1", "updated", "key2", "added"), + Config: testAccAWSSchemasRegistryConfigDescription(rName, "description2"), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasRegistryExists(resourceName, &v2), - testAccCheckSchemasRegistryNotRecreated(&v1, &v2), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "updated"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), - ), - }, - { - Config: testAccAWSSchemasRegistryConfig_Tags1(registryName, "key2", "added"), - Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasRegistryExists(resourceName, &v3), - testAccCheckSchemasRegistryNotRecreated(&v2, &v3), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), + testAccCheckSchemasRegistryExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "description", "description2"), ), }, { - Config: testAccAWSSchemasRegistryConfig(registryName, description), + Config: testAccAWSSchemasRegistryConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasRegistryExists(resourceName, &v4), - testAccCheckSchemasRegistryNotRecreated(&v3, &v4), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + testAccCheckSchemasRegistryExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "description", ""), ), }, }, }) } -func TestAccAWSSchemasRegistry_disappears(t *testing.T) { +func TestAccAWSSchemasRegistry_Tags(t *testing.T) { var v schemas.DescribeRegistryOutput - registryName := acctest.RandomWithPrefix("tf-acc-test") - description := acctest.RandomWithPrefix("tf-acc-test") - + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_schemas_registry.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSchemasRegistryDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSchemasRegistryConfig(registryName, description), + Config: testAccAWSSchemasRegistryConfigTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccCheckSchemasRegistryExists(resourceName, &v), - testAccCheckResourceDisappears(testAccProvider, resourceAwsSchemasRegistry(), resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSchemasRegistryConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasRegistryExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSSchemasRegistryConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasRegistryExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), - ExpectNonEmptyPlan: true, }, }, }) @@ -208,15 +212,17 @@ func testAccCheckAWSSchemasRegistryDestroy(s *terraform.State) error { continue } - params := schemas.DescribeRegistryInput{ - RegistryName: aws.String(rs.Primary.ID), - } + _, err := finder.RegistryByName(conn, rs.Primary.ID) - resp, err := conn.DescribeRegistry(¶ms) + if tfresource.NotFound(err) { + continue + } - if err == nil { - return fmt.Errorf("Schemas Registry (%s) still exists: %s", rs.Primary.ID, resp) + if err != nil { + return err } + + return fmt.Errorf("EventBridge Schemas Registry %s still exists", rs.Primary.ID) } return nil @@ -229,52 +235,42 @@ func testAccCheckSchemasRegistryExists(n string, v *schemas.DescribeRegistryOutp return fmt.Errorf("Not found: %s", n) } - conn := testAccProvider.Meta().(*AWSClient).schemasconn - params := schemas.DescribeRegistryInput{ - RegistryName: aws.String(rs.Primary.ID), + if rs.Primary.ID == "" { + return fmt.Errorf("No EventBridge Schemas Registry ID is set") } - resp, err := conn.DescribeRegistry(¶ms) + + conn := testAccProvider.Meta().(*AWSClient).schemasconn + + output, err := finder.RegistryByName(conn, rs.Primary.ID) + if err != nil { return err } - if resp == nil { - return fmt.Errorf("Schemas Registry (%s) not found", n) - } - *v = *resp + *v = *output return nil } } -func testAccCheckSchemasRegistryRecreated(i, j *schemas.DescribeRegistryOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - if aws.StringValue(i.RegistryArn) == aws.StringValue(j.RegistryArn) { - return fmt.Errorf("Schemas Registry not recreated") - } - return nil - } +func testAccAWSSchemasRegistryConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_schemas_registry" "test" { + name = %[1]q } - -func testAccCheckSchemasRegistryNotRecreated(i, j *schemas.DescribeRegistryOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - if aws.StringValue(i.RegistryArn) != aws.StringValue(j.RegistryArn) { - return fmt.Errorf("Schemas Registry was recreated") - } - return nil - } +`, rName) } -func testAccAWSSchemasRegistryConfig(name, description string) string { +func testAccAWSSchemasRegistryConfigDescription(rName, description string) string { return fmt.Sprintf(` resource "aws_schemas_registry" "test" { - name = %[1]q + name = %[1]q description = %[2]q } -`, name, description) +`, rName, description) } -func testAccAWSSchemasRegistryConfig_Tags1(name, key, value string) string { +func testAccAWSSchemasRegistryConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_schemas_registry" "test" { name = %[1]q @@ -283,10 +279,10 @@ resource "aws_schemas_registry" "test" { %[2]q = %[3]q } } -`, name, key, value) +`, rName, tagKey1, tagValue1) } -func testAccAWSSchemasRegistryConfig_Tags2(name, key1, value1, key2, value2 string) string { +func testAccAWSSchemasRegistryConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_schemas_registry" "test" { name = %[1]q @@ -296,5 +292,5 @@ resource "aws_schemas_registry" "test" { %[4]q = %[5]q } } -`, name, key1, value1, key2, value2) +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) } diff --git a/website/docs/r/schemas_registry.html.markdown b/website/docs/r/schemas_registry.html.markdown index 47dd3b1205c..d554f9b9b7c 100644 --- a/website/docs/r/schemas_registry.html.markdown +++ b/website/docs/r/schemas_registry.html.markdown @@ -12,7 +12,6 @@ Provides an EventBridge Custom Schema Registry resource. ~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. - ## Example Usage ```terraform @@ -28,14 +27,14 @@ The following arguments are supported: * `name` - (Required) The name of the custom event schema registry. Maximum of 64 characters consisting of lower case letters, upper case letters, 0-9, ., -, _. * `description` - (Optional) The description of the discoverer. Maximum of 256 characters. -* `tags` - (Optional) A map of tags to assign to the resource. +* `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. ## Attributes Reference In addition to all arguments above, the following attributes are exported: * `arn` - The Amazon Resource Name (ARN) of the discoverer. - +* `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). ## Import From d56659330883fba24eb7d20aa8344b86f1761d91 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 15:49:09 -0400 Subject: [PATCH 219/398] r/aws_schemas_schema: 'registry' -> 'registry_name'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSSchemasSchema_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSSchemasSchema_ -timeout 180m === RUN TestAccAWSSchemasSchema_basic === PAUSE TestAccAWSSchemasSchema_basic === RUN TestAccAWSSchemasSchema_disappears === PAUSE TestAccAWSSchemasSchema_disappears === RUN TestAccAWSSchemasSchema_ContentDescription === PAUSE TestAccAWSSchemasSchema_ContentDescription === RUN TestAccAWSSchemasSchema_Tags === PAUSE TestAccAWSSchemasSchema_Tags === CONT TestAccAWSSchemasSchema_basic === CONT TestAccAWSSchemasSchema_Tags === CONT TestAccAWSSchemasSchema_disappears === CONT TestAccAWSSchemasSchema_ContentDescription --- PASS: TestAccAWSSchemasSchema_disappears (13.71s) --- PASS: TestAccAWSSchemasSchema_basic (17.04s) --- PASS: TestAccAWSSchemasSchema_Tags (39.01s) --- PASS: TestAccAWSSchemasSchema_ContentDescription (39.47s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 42.503s --- aws/internal/service/schemas/finder/finder.go | 29 ++ aws/internal/service/schemas/id.go | 25 ++ aws/resource_aws_schemas_schema.go | 232 +++++----- aws/resource_aws_schemas_schema_test.go | 408 ++++++++---------- website/docs/r/schemas_schema.html.markdown | 24 +- 5 files changed, 373 insertions(+), 345 deletions(-) create mode 100644 aws/internal/service/schemas/id.go diff --git a/aws/internal/service/schemas/finder/finder.go b/aws/internal/service/schemas/finder/finder.go index c56aeee58e1..c2511a294e7 100644 --- a/aws/internal/service/schemas/finder/finder.go +++ b/aws/internal/service/schemas/finder/finder.go @@ -62,3 +62,32 @@ func RegistryByName(conn *schemas.Schemas, name string) (*schemas.DescribeRegist return output, nil } + +func SchemaByNameAndRegistryName(conn *schemas.Schemas, name, registryName string) (*schemas.DescribeSchemaOutput, error) { + input := &schemas.DescribeSchemaInput{ + RegistryName: aws.String(registryName), + SchemaName: aws.String(name), + } + + output, err := conn.DescribeSchema(input) + + if tfawserr.ErrCodeEquals(err, schemas.ErrCodeNotFoundException) { + 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/internal/service/schemas/id.go b/aws/internal/service/schemas/id.go new file mode 100644 index 00000000000..71d0435c119 --- /dev/null +++ b/aws/internal/service/schemas/id.go @@ -0,0 +1,25 @@ +package transfer + +import ( + "fmt" + "strings" +) + +const schemaResourceIDSeparator = "/" + +func SchemaCreateResourceID(schemaName, registryName string) string { + parts := []string{schemaName, registryName} + id := strings.Join(parts, schemaResourceIDSeparator) + + return id +} + +func SchemaParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, schemaResourceIDSeparator) + + if len(parts) == 2 && parts[0] != "" && parts[1] != "" { + return parts[0], parts[1], nil + } + + return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected SCHEMA_NAME%[2]sREGISTRY_NAME", id, schemaResourceIDSeparator) +} diff --git a/aws/resource_aws_schemas_schema.go b/aws/resource_aws_schemas_schema.go index e6f25da48c0..ac1b657dbf8 100644 --- a/aws/resource_aws_schemas_schema.go +++ b/aws/resource_aws_schemas_schema.go @@ -4,13 +4,17 @@ import ( "fmt" "log" "regexp" - "strings" + "time" "github.com/aws/aws-sdk-go/aws" - schemas "github.com/aws/aws-sdk-go/service/schemas" + "github.com/aws/aws-sdk-go/service/schemas" + "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" + tfschemas "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/schemas" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/schemas/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsSchemasSchema() *schema.Resource { @@ -24,175 +28,200 @@ func resourceAwsSchemasSchema() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "name": { + "arn": { Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 385), - validation.StringMatch(regexp.MustCompile(`^[\.\-_A-Za-z@]+`), ""), - ), + Computed: true, }, + "content": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsNotEmpty, + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: suppressEquivalentJsonDiffs, }, + "description": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringLenBetween(0, 256), }, - "registry": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsNotEmpty, + + "last_modified": { + Type: schema.TypeString, + Computed: true, }, + + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 385), + validation.StringMatch(regexp.MustCompile(`^[\.\-_A-Za-z@]+`), ""), + ), + }, + + "registry_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "type": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice(schemas.Type_Values(), true), }, - "arn": { - Type: schema.TypeString, - Computed: true, - }, + "version": { Type: schema.TypeString, Computed: true, }, + "version_created_date": { Type: schema.TypeString, Computed: true, }, - "last_modified": { - Type: schema.TypeString, - Computed: true, - }, - "tags": tagsSchema(), + + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), }, + + CustomizeDiff: SetTagsDiff, } } func resourceAwsSchemasSchemaCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).schemasconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) - input := &schemas.CreateSchemaInput{} - if name, ok := d.GetOk("name"); ok { - input.SchemaName = aws.String(name.(string)) - } - if registry, ok := d.GetOk("registry"); ok { - input.RegistryName = aws.String(registry.(string)) - } - if schemaType, ok := d.GetOk("type"); ok { - input.Type = aws.String(schemaType.(string)) - } - if content, ok := d.GetOk("content"); ok { - input.Content = aws.String(content.(string)) + name := d.Get("name").(string) + registryName := d.Get("registry_name").(string) + input := &schemas.CreateSchemaInput{ + Content: aws.String(d.Get("content").(string)), + RegistryName: aws.String(registryName), + SchemaName: aws.String(name), + Type: aws.String(d.Get("type").(string)), } - if description, ok := d.GetOk("description"); ok { - input.Description = aws.String(description.(string)) + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) } - if v, ok := d.GetOk("tags"); ok { - input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().SchemasTags() + + if len(tags) > 0 { + input.Tags = tags.IgnoreAws().SchemasTags() } - log.Printf("[DEBUG] Creating Schemas Schema: %v", input) + id := tfschemas.SchemaCreateResourceID(name, registryName) + log.Printf("[DEBUG] Creating EventBridge Schemas Schema: %s", input) _, err := conn.CreateSchema(input) + if err != nil { - return fmt.Errorf("Creating Schemas Schema (%s) failed: %w", *input.SchemaName, err) + return fmt.Errorf("error creating EventBridge Schemas Schema (%s): %w", id, err) } - id := fmt.Sprintf("%s/%s", aws.StringValue(input.SchemaName), aws.StringValue(input.RegistryName)) d.SetId(id) - log.Printf("[INFO] Schemas Schema (%s) created", d.Id()) - return resourceAwsSchemasSchemaRead(d, meta) } func resourceAwsSchemasSchemaRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).schemasconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - schemaName, registryName, err := parseSchemaID(d.Id()) + name, registryName, err := tfschemas.SchemaParseResourceID(d.Id()) + if err != nil { - return err + return fmt.Errorf("error parsing EventBridge Schemas Schema ID: %w", err) } - input := &schemas.DescribeSchemaInput{ - SchemaName: aws.String(schemaName), - RegistryName: aws.String(registryName), - } + output, err := finder.SchemaByNameAndRegistryName(conn, name, registryName) - log.Printf("[DEBUG] Reading Schemas Schema (%s)", d.Id()) - output, err := conn.DescribeSchema(input) - if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { - log.Printf("[WARN] Schemas Schema (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] EventBridge Schemas Schema (%s) not found, removing from state", d.Id()) d.SetId("") return nil } + if err != nil { - return fmt.Errorf("error reading Schemas Schema: %w", err) + return fmt.Errorf("error reading EventBridge Schemas Schema (%s): %w", d.Id(), err) } - log.Printf("[DEBUG] Found CloudWatch Event bus: %#v", *output) - d.Set("arn", output.SchemaArn) - d.Set("name", output.SchemaName) - d.Set("registry", aws.StringValue(input.RegistryName)) d.Set("content", output.Content) d.Set("description", output.Description) + if output.LastModified != nil { + d.Set("last_modified", aws.TimeValue(output.LastModified).Format(time.RFC3339)) + } else { + d.Set("last_modified", nil) + } + d.Set("name", output.SchemaName) + d.Set("registry_name", registryName) d.Set("type", output.Type) d.Set("version", output.SchemaVersion) - d.Set("version_created_date", output.VersionCreatedDate.String()) - d.Set("last_modified", output.LastModified.String()) + if output.VersionCreatedDate != nil { + d.Set("version_created_date", aws.TimeValue(output.VersionCreatedDate).Format(time.RFC3339)) + } else { + d.Set("version_created_date", nil) + } + + tags, err := keyvaluetags.SchemasListTags(conn, d.Get("arn").(string)) - tags, err := keyvaluetags.SchemasListTags(conn, *output.SchemaArn) if err != nil { - return fmt.Errorf("error listing tags for Schemas Schema (%s): %w", d.Id(), err) + return fmt.Errorf("error listing tags for EventBridge Schemas Schema (%s): %w", d.Id(), err) } - if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + + tags = 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 } func resourceAwsSchemasSchemaUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).schemasconn - if d.HasChanges("name", "registry", "type", "content", "description") { - input := &schemas.UpdateSchemaInput{ - Description: aws.String(""), - } - if name, ok := d.GetOk("name"); ok { - input.SchemaName = aws.String(name.(string)) - } - if registry, ok := d.GetOk("registry"); ok { - input.RegistryName = aws.String(registry.(string)) + if d.HasChanges("content", "description", "type") { + name, registryName, err := tfschemas.SchemaParseResourceID(d.Id()) + + if err != nil { + return fmt.Errorf("error parsing EventBridge Schemas Schema ID: %w", err) } - if schemaType, ok := d.GetOk("type"); ok { - input.Type = aws.String(schemaType.(string)) + + input := &schemas.UpdateSchemaInput{ + RegistryName: aws.String(registryName), + SchemaName: aws.String(name), } - if content, ok := d.GetOk("content"); ok { - input.Content = aws.String(content.(string)) + + if d.HasChanges("content", "type") { + input.Content = aws.String(d.Get("content").(string)) + input.Type = aws.String(d.Get("type").(string)) } - if description, ok := d.GetOk("description"); ok { - input.Description = aws.String(description.(string)) + + if d.HasChange("description") { + input.Description = aws.String(d.Get("description").(string)) } - log.Printf("[DEBUG] Updating Schemas Schema: %s", input) - _, err := conn.UpdateSchema(input) + + log.Printf("[DEBUG] Updating EventBridge Schemas Schema: %s", input) + _, err = conn.UpdateSchema(input) + if err != nil { - return fmt.Errorf("error updating Schemas Schema (%s): %w", d.Id(), err) + return fmt.Errorf("error updating EventBridge Schemas Schema (%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.SchemasUpdateTags(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) } } @@ -202,34 +231,25 @@ func resourceAwsSchemasSchemaUpdate(d *schema.ResourceData, meta interface{}) er func resourceAwsSchemasSchemaDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).schemasconn - schemaName, registryName, err := parseSchemaID(d.Id()) + name, registryName, err := tfschemas.SchemaParseResourceID(d.Id()) + if err != nil { - return err + return fmt.Errorf("error parsing EventBridge Schemas Schema ID: %w", err) } - input := &schemas.DeleteSchemaInput{ - SchemaName: aws.String(schemaName), + log.Printf("[INFO] Deleting EventBridge Schemas Schema (%s)", d.Id()) + _, err = conn.DeleteSchema(&schemas.DeleteSchemaInput{ RegistryName: aws.String(registryName), - } + SchemaName: aws.String(name), + }) - log.Printf("[INFO] Deleting Schemas Schema (%s)", d.Id()) - _, err = conn.DeleteSchema(input) - if isAWSErr(err, schemas.ErrCodeNotFoundException, "") { - log.Printf("[WARN] Schemas Schema (%s) not found", d.Id()) + if tfawserr.ErrCodeEquals(err, schemas.ErrCodeNotFoundException) { return nil } + if err != nil { - return fmt.Errorf("Error deleting Schemas Schema (%s): %w", d.Id(), err) + return fmt.Errorf("error deleting EventBridge Schemas Schema (%s): %w", d.Id(), err) } - log.Printf("[INFO] Schemas Schema (%s) deleted", d.Id()) return nil } - -func parseSchemaID(id string) (string, string, error) { - parts := strings.Split(id, "/") - if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - return "", "", fmt.Errorf("unexpected format for ID (%q), expected SCHEMA_NAME:REGISTRY_NAME", id) - } - return parts[0], parts[1], nil -} diff --git a/aws/resource_aws_schemas_schema_test.go b/aws/resource_aws_schemas_schema_test.go index 0f1133d10f8..241dab3e863 100644 --- a/aws/resource_aws_schemas_schema_test.go +++ b/aws/resource_aws_schemas_schema_test.go @@ -6,60 +6,67 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" - schemas "github.com/aws/aws-sdk-go/service/schemas" + "github.com/aws/aws-sdk-go/service/schemas" "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" + tfschemas "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/schemas" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/schemas/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -var schemaType = schemas.TypeOpenApi3 -var content = `{ - "openapi": "3.0.0", - "info": { - "version": "1.0.0", - "title": "Event" - }, - "paths": {}, - "components": { - "schemas": { - "Event": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - } - } - } - } +const ( + testAccAWSSchemasSchemaContent = ` +{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "Event" + }, + "paths": {}, + "components": { + "schemas": { + "Event": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + } + } } +} ` -var contentModified = `{ - "openapi": "3.0.0", - "info": { - "version": "2.0.0", - "title": "Event" - }, - "paths": {}, - "components": { - "schemas": { - "Event": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "created_at": { - "type": "string", - "format": "date-time" - } - } - } + + testAccAWSSchemasSchemaContentUpdated = ` +{ + "openapi": "3.0.0", + "info": { + "version": "2.0.0", + "title": "Event" + }, + "paths": {}, + "components": { + "schemas": { + "Event": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + } + } } } } +} ` +) func init() { resource.AddTestSweepers("aws_schemas_schema", &resource.Sweeper{ @@ -138,40 +145,30 @@ func testSweepSchemasSchema(region string) error { } func TestAccAWSSchemasSchema_basic(t *testing.T) { - var v1, v2, v3 schemas.DescribeSchemaOutput - name := acctest.RandomWithPrefix("tf-acc-test") - nameModified := acctest.RandomWithPrefix("tf-acc-test") - - registry := acctest.RandomWithPrefix("tf-acc-test") - - description := acctest.RandomWithPrefix("tf-acc-test") - descriptionModified := acctest.RandomWithPrefix("tf-acc-test") - + var v schemas.DescribeSchemaOutput + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_schemas_schema.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSchemasSchemaDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSchemasSchemaConfig( - name, - registry, - schemaType, - content, - description, - ), + Config: testAccAWSSchemasSchemaConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasSchemaExists(resourceName, &v1), - resource.TestCheckResourceAttr(resourceName, "name", name), - resource.TestCheckResourceAttr(resourceName, "registry", registry), - resource.TestCheckResourceAttr(resourceName, "type", schemaType), - resource.TestCheckResourceAttr(resourceName, "content", content), - resource.TestCheckResourceAttr(resourceName, "description", description), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("schema/%s/%s", registry, name)), + testAccCheckSchemasSchemaExists(resourceName, &v), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("schema/%s/%s", rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "content"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttrSet(resourceName, "last_modified"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "registry_name", rName), + resource.TestCheckResourceAttr(resourceName, "type", "OpenApi3"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "version", "1"), + resource.TestCheckResourceAttrSet(resourceName, "version_created_date"), ), }, { @@ -179,73 +176,51 @@ func TestAccAWSSchemasSchema_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + }, + }) +} + +func TestAccAWSSchemasSchema_disappears(t *testing.T) { + var v schemas.DescribeSchemaOutput + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_schemas_schema.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSchemasSchemaDestroy, + Steps: []resource.TestStep{ { - Config: testAccAWSSchemasSchemaConfig( - nameModified, - registry, - schemaType, - contentModified, - descriptionModified, - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasSchemaExists(resourceName, &v2), - resource.TestCheckResourceAttr(resourceName, "name", nameModified), - resource.TestCheckResourceAttr(resourceName, "registry", registry), - resource.TestCheckResourceAttr(resourceName, "type", schemaType), - resource.TestCheckResourceAttr(resourceName, "content", contentModified), - resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "schemas", fmt.Sprintf("schema/%s/%s", registry, nameModified)), - testAccCheckSchemasSchemaRecreated(&v1, &v2), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - ), - }, - { - Config: testAccAWSSchemasSchemaConfig_Tags1( - nameModified, - registry, - schemaType, - contentModified, - "key", - "value", - ), + Config: testAccAWSSchemasSchemaConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasSchemaExists(resourceName, &v3), - testAccCheckSchemasSchemaNotRecreated(&v2, &v3), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key", "value"), + testAccCheckSchemasSchemaExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSchemasSchema(), resourceName), ), + ExpectNonEmptyPlan: true, }, }, }) } -func TestAccAWSSchemasSchema_tags(t *testing.T) { - var v1, v2, v3, v4 schemas.DescribeSchemaOutput - name := acctest.RandomWithPrefix("tf-acc-test") - registry := acctest.RandomWithPrefix("tf-acc-test") - description := acctest.RandomWithPrefix("tf-acc-test") - +func TestAccAWSSchemasSchema_ContentDescription(t *testing.T) { + var v schemas.DescribeSchemaOutput + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_schemas_schema.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSchemasSchemaDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSchemasSchemaConfig_Tags1( - name, - registry, - schemaType, - content, - "key1", - "value", - ), + Config: testAccAWSSchemasSchemaConfigContentDescription(rName, testAccAWSSchemasSchemaContent, "description1"), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasSchemaExists(resourceName, &v1), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value"), + testAccCheckSchemasSchemaExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "content", testAccAWSSchemasSchemaContent), + resource.TestCheckResourceAttr(resourceName, "description", "description1"), + resource.TestCheckResourceAttr(resourceName, "version", "1"), ), }, { @@ -254,85 +229,66 @@ func TestAccAWSSchemasSchema_tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSSchemasSchemaConfig_Tags2( - name, - registry, - schemaType, - content, - "key1", - "updated", - "key2", - "added", - ), + Config: testAccAWSSchemasSchemaConfigContentDescription(rName, testAccAWSSchemasSchemaContentUpdated, "description2"), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasSchemaExists(resourceName, &v2), - testAccCheckSchemasSchemaNotRecreated(&v1, &v2), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "updated"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), - ), - }, - { - Config: testAccAWSSchemasSchemaConfig_Tags1( - name, - registry, - schemaType, - content, - "key2", - "added", - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasSchemaExists(resourceName, &v3), - testAccCheckSchemasSchemaNotRecreated(&v2, &v3), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "added"), + testAccCheckSchemasSchemaExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "content", testAccAWSSchemasSchemaContentUpdated), + resource.TestCheckResourceAttr(resourceName, "description", "description2"), + resource.TestCheckResourceAttr(resourceName, "version", "2"), ), }, { - Config: testAccAWSSchemasSchemaConfig( - name, - registry, - schemaType, - content, - description, - ), + Config: testAccAWSSchemasSchemaConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckSchemasSchemaExists(resourceName, &v4), - testAccCheckSchemasSchemaNotRecreated(&v3, &v4), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + testAccCheckSchemasSchemaExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "version", "3"), ), }, }, }) } -func TestAccAWSSchemasSchema_disappears(t *testing.T) { +func TestAccAWSSchemasSchema_Tags(t *testing.T) { var v schemas.DescribeSchemaOutput - name := acctest.RandomWithPrefix("tf-acc-test") - registry := acctest.RandomWithPrefix("tf-acc-test") - description := acctest.RandomWithPrefix("tf-acc-test") - + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_schemas_schema.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(schemas.EndpointsID, t) }, ErrorCheck: testAccErrorCheck(t, schemas.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSchemasSchemaDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSchemasSchemaConfig( - name, - registry, - schemaType, - content, - description, + Config: testAccAWSSchemasSchemaConfigTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasSchemaExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSchemasSchemaConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckSchemasSchemaExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), + }, + { + Config: testAccAWSSchemasSchemaConfigTags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckSchemasSchemaExists(resourceName, &v), - testAccCheckResourceDisappears(testAccProvider, resourceAwsSchemasSchema(), resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), - ExpectNonEmptyPlan: true, }, }, }) @@ -346,21 +302,23 @@ func testAccCheckAWSSchemasSchemaDestroy(s *terraform.State) error { continue } - schemaName, registryName, err := parseSchemaID(rs.Primary.ID) + name, registryName, err := tfschemas.SchemaParseResourceID(rs.Primary.ID) + if err != nil { return err } - params := schemas.DescribeSchemaInput{ - SchemaName: aws.String(schemaName), - RegistryName: aws.String(registryName), - } + _, err = finder.SchemaByNameAndRegistryName(conn, name, registryName) - resp, err := conn.DescribeSchema(¶ms) + if tfresource.NotFound(err) { + continue + } - if err == nil { - return fmt.Errorf("Schemas Schema (%s) still exists: %s", rs.Primary.ID, resp) + if err != nil { + return err } + + return fmt.Errorf("EventBridge Schemas Schema %s still exists", rs.Primary.ID) } return nil @@ -373,100 +331,96 @@ func testAccCheckSchemasSchemaExists(n string, v *schemas.DescribeSchemaOutput) return fmt.Errorf("Not found: %s", n) } - schemaName, registryName, err := parseSchemaID(rs.Primary.ID) + if rs.Primary.ID == "" { + return fmt.Errorf("No EventBridge Schemas Schema ID is set") + } + + name, registryName, err := tfschemas.SchemaParseResourceID(rs.Primary.ID) + if err != nil { return err } - params := schemas.DescribeSchemaInput{ - SchemaName: aws.String(schemaName), - RegistryName: aws.String(registryName), - } conn := testAccProvider.Meta().(*AWSClient).schemasconn - resp, err := conn.DescribeSchema(¶ms) + output, err := finder.SchemaByNameAndRegistryName(conn, name, registryName) + if err != nil { return err } - if resp == nil { - return fmt.Errorf("Schemas Schema (%s) not found", n) - } - *v = *resp + *v = *output return nil } } -func testAccCheckSchemasSchemaRecreated(i, j *schemas.DescribeSchemaOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - if aws.StringValue(i.SchemaArn) == aws.StringValue(j.SchemaArn) { - return fmt.Errorf("Schemas Schema not recreated") - } - return nil - } +func testAccAWSSchemasSchemaConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_schemas_registry" "test" { + name = %[1]q } -func testAccCheckSchemasSchemaNotRecreated(i, j *schemas.DescribeSchemaOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - if aws.StringValue(i.SchemaArn) != aws.StringValue(j.SchemaArn) { - return fmt.Errorf("Schemas Schema was recreated") - } - return nil - } +resource "aws_schemas_schema" "test" { + name = %[1]q + registry_name = aws_schemas_registry.test.name + type = "OpenApi3" + content = %[2]q +} +`, rName, testAccAWSSchemasSchemaContent) } -func testAccAWSSchemasSchemaConfig(name, registry, schemaType, content, description string) string { +func testAccAWSSchemasSchemaConfigContentDescription(rName, content, description string) string { return fmt.Sprintf(` resource "aws_schemas_registry" "test" { - name = %[2]q + name = %[1]q } resource "aws_schemas_schema" "test" { - name = %[1]q - registry = aws_schemas_registry.test.name - type = %[3]q - content = %[4]q - description = %[5]q + name = %[1]q + registry_name = aws_schemas_registry.test.name + type = "OpenApi3" + content = %[2]q + description = %[3]q } -`, name, registry, schemaType, content, description) +`, rName, content, description) } -func testAccAWSSchemasSchemaConfig_Tags1(name, registry, schemaType, content, key, value string) string { +func testAccAWSSchemasSchemaConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_schemas_registry" "test" { - name = %[2]q + name = %[1]q } resource "aws_schemas_schema" "test" { - name = %[1]q - registry = aws_schemas_registry.test.name - type = %[3]q - content = %[4]q + name = %[1]q + registry_name = aws_schemas_registry.test.name + type = "OpenApi3" + content = %[2]q tags = { - %[5]q = %[6]q + %[3]q = %[4]q } } -`, name, registry, schemaType, content, key, value) +`, rName, testAccAWSSchemasSchemaContent, tagKey1, tagValue1) } -func testAccAWSSchemasSchemaConfig_Tags2(name, registry, schemaType, content, key1, value1, key2, value2 string) string { +func testAccAWSSchemasSchemaConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_schemas_registry" "test" { - name = %[2]q + name = %[1]q } resource "aws_schemas_schema" "test" { - name = %[1]q - registry = aws_schemas_registry.test.name - type = %[3]q - content = %[4]q + name = %[1]q + registry_name = aws_schemas_registry.test.name + type = "OpenApi3" + content = %[2]q tags = { + %[3]q = %[4]q %[5]q = %[6]q - %[7]q = %[8]q } } -`, name, registry, schemaType, content, key1, value1, key2, value2) +`, rName, testAccAWSSchemasSchemaContent, tagKey1, tagValue1, tagKey2, tagValue2) } diff --git a/website/docs/r/schemas_schema.html.markdown b/website/docs/r/schemas_schema.html.markdown index f54dcf7df75..96ed3eb9b8f 100644 --- a/website/docs/r/schemas_schema.html.markdown +++ b/website/docs/r/schemas_schema.html.markdown @@ -12,7 +12,6 @@ Provides an EventBridge Schema resource. ~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. - ## Example Usage ```terraform @@ -21,10 +20,11 @@ resource "aws_schemas_registry" "test" { } resource "aws_schemas_schema" "test" { - name = "my_schema" - registry = aws_schemas_registry.test.name - type = "OpenApi3" - description = "The schema definition for my event" + name = "my_schema" + registry_name = aws_schemas_registry.test.name + type = "OpenApi3" + description = "The schema definition for my event" + content = jsonencode({ "openapi" : "3.0.0", "info" : { @@ -54,25 +54,25 @@ The following arguments are supported: * `name` - (Required) The name of the schema. Maximum of 385 characters consisting of lower case letters, upper case letters, ., -, _, @. * `content` - (Required) The schema specification. Must be a valid Open API 3.0 spec. -* `registry` - (Required) The name of the registry in which this schema belongs. -* `type` - (Required) The type of the schema. Possible values: OpenApi3. +* `registry_name` - (Required) The name of the registry in which this schema belongs. +* `type` - (Required) The type of the schema. Valid values: `OpenApi3`. * `description` - (Optional) The description of the schema. Maximum of 256 characters. -* `tags` - (Optional) A map of tags to assign to the resource. +* `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. ## Attributes Reference In addition to all arguments above, the following attributes are exported: * `arn` - The Amazon Resource Name (ARN) of the discoverer. +* `last_modified` - The last modified date of the schema. +* `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). * `version` - The version of the schema. * `version_created_date` - The created date of the version of the schema. -* `last_modified` - The last modified date of the schema. - ## Import -EventBridge schema can be imported using the `name` and `registry`, e.g. +EventBridge schema can be imported using the `name` and `registry_name`, e.g. ```console -$ terraform import aws_schemas_schema.test registry/name +$ terraform import aws_schemas_schema.test name/registry ``` From 73058d60dfeceb2f08aaefacd91a8ea2230e51b6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 16:45:10 -0400 Subject: [PATCH 220/398] Tidy up test sweepers for EventBus Schemas. --- aws/resource_aws_cloudwatch_event_bus_test.go | 66 ++++++------- aws/resource_aws_schemas_discoverer_test.go | 54 +++++------ aws/resource_aws_schemas_registry_test.go | 93 +++++++++++++------ aws/resource_aws_schemas_schema_test.go | 79 ---------------- 4 files changed, 126 insertions(+), 166 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_test.go b/aws/resource_aws_cloudwatch_event_bus_test.go index a3731bfe7d2..6a64adca9ea 100644 --- a/aws/resource_aws_cloudwatch_event_bus_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_test.go @@ -8,11 +8,13 @@ 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" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents/lister" ) func init() { @@ -22,6 +24,7 @@ func init() { Dependencies: []string{ "aws_cloudwatch_event_rule", "aws_cloudwatch_event_target", + "aws_schemas_discoverer", }, }) } @@ -32,46 +35,45 @@ func testSweepCloudWatchEventBuses(region string) error { return fmt.Errorf("Error getting client: %w", err) } conn := client.(*AWSClient).cloudwatcheventsconn - input := &events.ListEventBusesInput{} + var sweeperErrs *multierror.Error - for { - output, err := conn.ListEventBuses(input) - if err != nil { - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping CloudWatch Events event bus sweep for %s: %s", region, err) - return nil - } - return fmt.Errorf("Error retrieving CloudWatch Events event bus: %w", err) + err = lister.ListEventBusesPages(conn, input, func(page *events.ListEventBusesOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - if len(output.EventBuses) == 0 { - log.Print("[DEBUG] No CloudWatch Events event buses to sweep") - return nil - } - - for _, eventBus := range output.EventBuses { + for _, eventBus := range page.EventBuses { name := aws.StringValue(eventBus.Name) - if name == "default" { + if name == tfevents.DefaultEventBusName { continue } - log.Printf("[INFO] Deleting CloudWatch Events event bus (%s)", name) - _, err := conn.DeleteEventBus(&events.DeleteEventBusInput{ - Name: aws.String(name), - }) + r := resourceAwsCloudWatchEventBus() + d := r.Data(nil) + d.SetId(name) + err = r.Delete(d, client) + if err != nil { - return fmt.Errorf("Error deleting CloudWatch Events event bus (%s): %w", name, err) + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) + continue } } - if output.NextToken == nil { - break - } - input.NextToken = output.NextToken + return !lastPage + }) + + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping CloudWatch Events event bus 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 CloudWatch Events event buses: %w", err)) + } + + return sweeperErrs.ErrorOrNil() } func TestAccAWSCloudWatchEventBus_basic(t *testing.T) { @@ -83,7 +85,7 @@ func TestAccAWSCloudWatchEventBus_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: testAccCheckAWSCloudWatchEventBusDestroy, Steps: []resource.TestStep{ @@ -134,7 +136,7 @@ func TestAccAWSCloudWatchEventBus_tags(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: testAccCheckAWSCloudWatchEventBusDestroy, Steps: []resource.TestStep{ @@ -185,7 +187,7 @@ func TestAccAWSCloudWatchEventBus_tags(t *testing.T) { func TestAccAWSCloudWatchEventBus_default(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: testAccCheckAWSCloudWatchEventBusDestroy, Steps: []resource.TestStep{ @@ -205,7 +207,7 @@ func TestAccAWSCloudWatchEventBus_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: testAccCheckAWSCloudWatchEventBusDestroy, Steps: []resource.TestStep{ @@ -233,7 +235,7 @@ func TestAccAWSCloudWatchEventBus_PartnerEventSource(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: testAccCheckAWSCloudWatchEventBusDestroy, Steps: []resource.TestStep{ diff --git a/aws/resource_aws_schemas_discoverer_test.go b/aws/resource_aws_schemas_discoverer_test.go index d6276f81f02..1e423446beb 100644 --- a/aws/resource_aws_schemas_discoverer_test.go +++ b/aws/resource_aws_schemas_discoverer_test.go @@ -18,52 +18,48 @@ import ( func init() { resource.AddTestSweepers("aws_schemas_discoverer", &resource.Sweeper{ Name: "aws_schemas_discoverer", - F: testSweepSchemasDiscoverer, - Dependencies: []string{ - "aws_cloudwatch_event_bus", - }, + F: testSweepSchemasDiscoverers, }) } -func testSweepSchemasDiscoverer(region string) error { +func testSweepSchemasDiscoverers(region string) error { client, err := sharedClientForRegion(region) if err != nil { return fmt.Errorf("Error getting client: %w", err) } conn := client.(*AWSClient).schemasconn - + input := &schemas.ListDiscoverersInput{} var sweeperErrs *multierror.Error - input := &schemas.ListDiscoverersInput{ - Limit: aws.Int64(100), - } - var discoverers []*schemas.DiscovererSummary - for { - output, err := conn.ListDiscoverers(input) - if err != nil { - return err + err = conn.ListDiscoverersPages(input, func(page *schemas.ListDiscoverersOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - discoverers = append(discoverers, output.Discoverers...) - if aws.StringValue(output.NextToken) == "" { - break + for _, discoverer := range page.Discoverers { + r := resourceAwsSchemasDiscoverer() + d := r.Data(nil) + d.SetId(aws.StringValue(discoverer.DiscovererId)) + err = r.Delete(d, client) + + if err != nil { + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) + continue + } } - input.NextToken = output.NextToken - } - for _, discoverer := range discoverers { + return !lastPage + }) - input := &schemas.DeleteDiscovererInput{ - DiscovererId: discoverer.DiscovererId, - } - _, err := conn.DeleteDiscoverer(input) - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("Error deleting Schemas Discoverer (%s): %w", *discoverer.DiscovererId, err)) - continue - } + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping EventBridge Schemas Discoverer sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors } - log.Printf("[INFO] Deleted %d Schemas Discoverers", len(discoverers)) + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EventBridge Schemas Discoverers: %w", err)) + } return sweeperErrs.ErrorOrNil() } diff --git a/aws/resource_aws_schemas_registry_test.go b/aws/resource_aws_schemas_registry_test.go index e9bfbd84162..f53d09a2885 100644 --- a/aws/resource_aws_schemas_registry_test.go +++ b/aws/resource_aws_schemas_registry_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "strings" "testing" "github.com/aws/aws-sdk-go/aws" @@ -11,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" + tfschemas "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/schemas" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/schemas/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -18,49 +20,88 @@ import ( func init() { resource.AddTestSweepers("aws_schemas_registry", &resource.Sweeper{ Name: "aws_schemas_registry", - F: testSweepSchemasRegistry, + F: testSweepSchemasRegistries, }) } -func testSweepSchemasRegistry(region string) error { +func testSweepSchemasRegistries(region string) error { client, err := sharedClientForRegion(region) if err != nil { return fmt.Errorf("Error getting client: %w", err) } conn := client.(*AWSClient).schemasconn - + input := &schemas.ListRegistriesInput{} var sweeperErrs *multierror.Error - input := &schemas.ListRegistriesInput{ - Limit: aws.Int64(100), - } - var registries []*schemas.RegistrySummary - for { - output, err := conn.ListRegistries(input) - if err != nil { - return err + err = conn.ListRegistriesPages(input, func(page *schemas.ListRegistriesOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - registries = append(registries, output.Registries...) - if aws.StringValue(output.NextToken) == "" { - break + for _, registry := range page.Registries { + registryName := aws.StringValue(registry.RegistryName) + + input := &schemas.ListSchemasInput{ + RegistryName: aws.String(registryName), + } + + err = conn.ListSchemasPages(input, func(page *schemas.ListSchemasOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, schema := range page.Schemas { + schemaName := aws.StringValue(schema.SchemaName) + if strings.HasPrefix(schemaName, "aws.") { + continue + } + + r := resourceAwsSchemasSchema() + d := r.Data(nil) + d.SetId(tfschemas.SchemaCreateResourceID(schemaName, registryName)) + err = r.Delete(d, client) + + if err != nil { + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) + continue + } + } + + return !lastPage + }) + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EventBridge Schemas Schemas: %w", err)) + } + + if strings.HasPrefix(registryName, "aws.") { + continue + } + + r := resourceAwsSchemasRegistry() + d := r.Data(nil) + d.SetId(registryName) + err = r.Delete(d, client) + + if err != nil { + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) + continue + } } - input.NextToken = output.NextToken - } - for _, registry := range registries { + return !lastPage + }) - input := &schemas.DeleteRegistryInput{ - RegistryName: registry.RegistryName, - } - _, err := conn.DeleteRegistry(input) - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("Error deleting Schemas Registry (%s): %w", *registry.RegistryName, err)) - continue - } + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping EventBridge Schemas Registry sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors } - log.Printf("[INFO] Deleted %d Schemas Registries", len(registries)) + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EventBridge Schemas Registries: %w", err)) + } return sweeperErrs.ErrorOrNil() } diff --git a/aws/resource_aws_schemas_schema_test.go b/aws/resource_aws_schemas_schema_test.go index 241dab3e863..21d5155c993 100644 --- a/aws/resource_aws_schemas_schema_test.go +++ b/aws/resource_aws_schemas_schema_test.go @@ -2,12 +2,9 @@ package aws import ( "fmt" - "log" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/schemas" - "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" @@ -68,82 +65,6 @@ const ( ` ) -func init() { - resource.AddTestSweepers("aws_schemas_schema", &resource.Sweeper{ - Name: "aws_schemas_schema", - F: testSweepSchemasSchema, - Dependencies: []string{ - "aws_schemas_registry", - }, - }) -} - -func testSweepSchemasSchema(region string) error { - client, err := sharedClientForRegion(region) - if err != nil { - return fmt.Errorf("Error getting client: %w", err) - } - conn := client.(*AWSClient).schemasconn - - var sweeperErrs *multierror.Error - var deletedSchemas int - - input := &schemas.ListRegistriesInput{ - Limit: aws.Int64(100), - } - var registries []*schemas.RegistrySummary - for { - output, err := conn.ListRegistries(input) - if err != nil { - return err - } - registries = append(registries, output.Registries...) - - if aws.StringValue(output.NextToken) == "" { - break - } - input.NextToken = output.NextToken - } - - for _, registry := range registries { - input := &schemas.ListSchemasInput{ - Limit: aws.Int64(100), - RegistryName: registry.RegistryName, - } - var existingSchemas []*schemas.SchemaSummary - for { - output, err := conn.ListSchemas(input) - if err != nil { - return err - } - existingSchemas = append(existingSchemas, output.Schemas...) - - if aws.StringValue(output.NextToken) == "" { - break - } - input.NextToken = output.NextToken - } - - for _, existingSchema := range existingSchemas { - - input := &schemas.DeleteSchemaInput{ - SchemaName: existingSchema.SchemaName, - RegistryName: registry.RegistryName, - } - _, err := conn.DeleteSchema(input) - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("Error deleting Schemas Schema (%s): %w", *existingSchema.SchemaName, err)) - continue - } - deletedSchemas += 1 - } - } - - log.Printf("[INFO] Deleted %d Schemas Schemas", deletedSchemas) - - return sweeperErrs.ErrorOrNil() -} - func TestAccAWSSchemasSchema_basic(t *testing.T) { var v schemas.DescribeSchemaOutput rName := acctest.RandomWithPrefix("tf-acc-test") From fe3f5a00163238f583dfb4f451c0a5337e64486c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 16:46:40 -0400 Subject: [PATCH 221/398] Fix terrafmt errors. --- aws/resource_aws_schemas_discoverer_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_schemas_discoverer_test.go b/aws/resource_aws_schemas_discoverer_test.go index 1e423446beb..82d271d6b02 100644 --- a/aws/resource_aws_schemas_discoverer_test.go +++ b/aws/resource_aws_schemas_discoverer_test.go @@ -282,7 +282,7 @@ func testAccAWSSchemasDiscovererConfigTags1(rName, tagKey1, tagValue1 string) st resource "aws_cloudwatch_event_bus" "test" { name = %[1]q } - + resource "aws_schemas_discoverer" "test" { source_arn = aws_cloudwatch_event_bus.test.arn @@ -298,7 +298,7 @@ func testAccAWSSchemasDiscovererConfigTags2(rName, tagKey1, tagValue1, tagKey2, resource "aws_cloudwatch_event_bus" "test" { name = %[1]q } - + resource "aws_schemas_discoverer" "test" { source_arn = aws_cloudwatch_event_bus.test.arn From e4151a4b33e4e6714f4b3a4849b031745ffdac2a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 16:51:15 -0400 Subject: [PATCH 222/398] Tweak CHANGELOG entry. --- .changelog/19404.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.changelog/19404.txt b/.changelog/19404.txt index e1ea47bec81..d48647b4860 100644 --- a/.changelog/19404.txt +++ b/.changelog/19404.txt @@ -3,5 +3,9 @@ data-source/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` attribute ``` ```release-note:enhancement -resource/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` argument +resource/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` attribute +``` + +```release-note:enhancement +resource/aws_msk_cluster: Add `iam` argument to `client_authentication.sasl` configuration block ``` \ No newline at end of file From f135b689cf706e54e6e0c05e0e4b559c9bd65b94 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 16:55:53 -0400 Subject: [PATCH 223/398] Update 19535.txt --- .changelog/19535.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changelog/19535.txt b/.changelog/19535.txt index 4ee30055411..50c62e684b8 100644 --- a/.changelog/19535.txt +++ b/.changelog/19535.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_ec2_capacity_reservation: Add support for outpost_arn attribute -``` \ No newline at end of file +resource/aws_ec2_capacity_reservation: Add `outpost_arn` argument +``` From f69c0d7d09358dadb420219234f31e44a0aa4820 Mon Sep 17 00:00:00 2001 From: Robert Christ Date: Mon, 17 May 2021 17:03:03 -0700 Subject: [PATCH 224/398] 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 c32af92e210..56de42572b9 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 f3113da2e39..9a8bed4a96c 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 225/398] 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 9a8bed4a96c..d8b2fec6b17 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 226/398] 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 00000000000..8fd11e459b3 --- /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 227/398] 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 56de42572b9..d412cf5c62c 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 d8b2fec6b17..94367b53e60 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 9d68d11998a..0cb141ede4e 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 9ffda81bef3..923a93fe0c5 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 228/398] 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 d412cf5c62c..1aa480b3e17 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 229/398] 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 1aa480b3e17..1fdbeca07b2 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 0cb141ede4e..f515bceca76 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 230/398] 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 923a93fe0c5..13d956116c1 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 231/398] 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 13d956116c1..a0833359aca 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 232/398] 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 a0833359aca..6bb1476364f 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 fe831e63cb02e9e4791df4bc711bd19132d62cc4 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 26 May 2021 21:30:29 +0000 Subject: [PATCH 233/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85ce5d25d8d..7ecc31dc35e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ FEATURES: * **New Resource:** `aws_amplify_backend_environment` ([#11936](https://github.com/hashicorp/terraform-provider-aws/issues/11936)) * **New Resource:** `aws_cloudwatch_event_api_destination` ([#18905](https://github.com/hashicorp/terraform-provider-aws/issues/18905)) * **New Resource:** `aws_cloudwatch_event_connection` ([#18905](https://github.com/hashicorp/terraform-provider-aws/issues/18905)) +* **New Resource:** `aws_schemas_discoverer` ([#19100](https://github.com/hashicorp/terraform-provider-aws/issues/19100)) +* **New Resource:** `aws_schemas_registry` ([#19100](https://github.com/hashicorp/terraform-provider-aws/issues/19100)) +* **New Resource:** `aws_schemas_schema` ([#19100](https://github.com/hashicorp/terraform-provider-aws/issues/19100)) * **New Resource:** `aws_servicecatalog_budget_resource_association` ([#19452](https://github.com/hashicorp/terraform-provider-aws/issues/19452)) * **New Resource:** `aws_servicecatalog_provisioning_artifact` ([#19316](https://github.com/hashicorp/terraform-provider-aws/issues/19316)) * **New Resource:** `aws_servicecatalog_tag_option_resource_association` ([#19448](https://github.com/hashicorp/terraform-provider-aws/issues/19448)) @@ -15,7 +18,8 @@ ENHANCEMENTS: * data-source/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` attribute ([#19404](https://github.com/hashicorp/terraform-provider-aws/issues/19404)) * resource/aws_eks_node_group: Add `taint` argument ([#19482](https://github.com/hashicorp/terraform-provider-aws/issues/19482)) -* resource/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` argument ([#19404](https://github.com/hashicorp/terraform-provider-aws/issues/19404)) +* 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)) * resource/aws_sns_topic: Add `firehose_success_feedback_role_arn`, `firehose_success_feedback_sample_rate` and `firehose_failure_feedback_role_arn` arguments. ([#19528](https://github.com/hashicorp/terraform-provider-aws/issues/19528)) * resource/aws_sns_topic: Add `owner` attribute. ([#19528](https://github.com/hashicorp/terraform-provider-aws/issues/19528)) From 59d66d6283496aa47e90ec78d0eb3851e0a640e1 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 26 May 2021 21:37:56 +0000 Subject: [PATCH 234/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ecc31dc35e..12dd512e3f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ 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_ec2_capacity_reservation: Add `outpost_arn` argument ([#19535](https://github.com/hashicorp/terraform-provider-aws/issues/19535)) * resource/aws_eks_node_group: Add `taint` argument ([#19482](https://github.com/hashicorp/terraform-provider-aws/issues/19482)) * 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)) From 4e314f5250693dc52f41d2347ca2b51ac1b0d0a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 May 2021 06:00:24 +0000 Subject: [PATCH 235/398] build(deps): bump github.com/aws/aws-sdk-go from 1.38.48 to 1.38.49 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.48 to 1.38.49. - [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.48...v1.38.49) 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 305c6c103a0..7887c5bc242 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.48 + github.com/aws/aws-sdk-go v1.38.49 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 673ab1271b1..a842351ceed 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.48 h1:4kfX2KFjRaW0/p3rKBXA+QLOTH3gFUBg+ZoKMDkSSqk= -github.com/aws/aws-sdk-go v1.38.48/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/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 9b8efca322ce169821eadb86e325e8108eab3d78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 May 2021 06:01:26 +0000 Subject: [PATCH 236/398] 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.48 to 1.38.49. - [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.48...v1.38.49) 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 022baef5eee..57f3bc183d4 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.48 + github.com/aws/aws-sdk-go v1.38.49 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 e8551f7ba47..defb3271b97 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.48 h1:4kfX2KFjRaW0/p3rKBXA+QLOTH3gFUBg+ZoKMDkSSqk= -github.com/aws/aws-sdk-go v1.38.48/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/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 cca6a68d158..e0d4f2a8665 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.48" +const SDKVersion = "1.38.49" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 445b2cdf3ef..7b7c9f56fe2 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.48 +# github.com/aws/aws-sdk-go v1.38.49 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 31540bfe7c7e14f44d535599064f183b9854e1da Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 09:15:12 -0400 Subject: [PATCH 237/398] 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 1fdbeca07b2..5752cad2b95 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 94367b53e60..51854bbef46 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 238/398] 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 5752cad2b95..79aa72f5d69 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 239/398] 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 8fd11e459b3..e78934729e4 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 79aa72f5d69..d8162e2bf23 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 51854bbef46..e7a0e1fbe92 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 6bb1476364f..580a6419943 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 240/398] 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 e78934729e4..0a98108c4de 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 d8162e2bf23..764d5f07342 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 e7a0e1fbe92..98815547e04 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 580a6419943..586ad46fcee 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 3ebccc1883c0271ba64d837ae30048195c8c6f1c Mon Sep 17 00:00:00 2001 From: Pall Valmundsson Date: Thu, 27 May 2021 15:40:48 +0000 Subject: [PATCH 241/398] adding tags to aws_elasticache_parameter_group and tests --- ...esource_aws_elasticache_parameter_group.go | 40 +++++++++++ ...ce_aws_elasticache_parameter_group_test.go | 72 +++++++++++++++++++ .../elasticache_parameter_group.html.markdown | 3 + 3 files changed, 115 insertions(+) diff --git a/aws/resource_aws_elasticache_parameter_group.go b/aws/resource_aws_elasticache_parameter_group.go index 4cb198f79cd..3a9783dd729 100644 --- a/aws/resource_aws_elasticache_parameter_group.go +++ b/aws/resource_aws_elasticache_parameter_group.go @@ -14,6 +14,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/hashcode" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsElasticacheParameterGroup() *schema.Resource { @@ -45,6 +46,10 @@ func resourceAwsElasticacheParameterGroup() *schema.Resource { ForceNew: true, Default: "Managed by Terraform", }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, "parameter": { Type: schema.TypeSet, Optional: true, @@ -62,17 +67,23 @@ func resourceAwsElasticacheParameterGroup() *schema.Resource { }, Set: resourceAwsElasticacheParameterHash, }, + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), }, + CustomizeDiff: SetTagsDiff, } } func resourceAwsElasticacheParameterGroupCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).elasticacheconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) createOpts := elasticache.CreateCacheParameterGroupInput{ CacheParameterGroupName: aws.String(d.Get("name").(string)), CacheParameterGroupFamily: aws.String(d.Get("family").(string)), Description: aws.String(d.Get("description").(string)), + Tags: tags.IgnoreAws().ElasticacheTags(), } log.Printf("[DEBUG] Create ElastiCache Parameter Group: %#v", createOpts) @@ -82,6 +93,7 @@ func resourceAwsElasticacheParameterGroupCreate(d *schema.ResourceData, meta int } d.SetId(aws.StringValue(resp.CacheParameterGroup.CacheParameterGroupName)) + d.Set("arn", aws.StringValue(resp.CacheParameterGroup.ARN)) log.Printf("[INFO] ElastiCache Parameter Group ID: %s", d.Id()) return resourceAwsElasticacheParameterGroupUpdate(d, meta) @@ -89,6 +101,8 @@ func resourceAwsElasticacheParameterGroupCreate(d *schema.ResourceData, meta int func resourceAwsElasticacheParameterGroupRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).elasticacheconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig describeOpts := elasticache.DescribeCacheParameterGroupsInput{ CacheParameterGroupName: aws.String(d.Id()), @@ -107,6 +121,24 @@ func resourceAwsElasticacheParameterGroupRead(d *schema.ResourceData, meta inter d.Set("name", describeResp.CacheParameterGroups[0].CacheParameterGroupName) d.Set("family", describeResp.CacheParameterGroups[0].CacheParameterGroupFamily) d.Set("description", describeResp.CacheParameterGroups[0].Description) + d.Set("arn", describeResp.CacheParameterGroups[0].ARN) + + tags, err := keyvaluetags.ElasticacheListTags(conn, aws.StringValue(describeResp.CacheParameterGroups[0].ARN)) + + if err != nil { + return fmt.Errorf("error listing tags for ElastiCache Parameter Group (%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_all", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) + } // Only include user customized parameters as there's hundreds of system/default ones describeParametersOpts := elasticache.DescribeCacheParametersInput{ @@ -127,6 +159,14 @@ func resourceAwsElasticacheParameterGroupRead(d *schema.ResourceData, meta inter func resourceAwsElasticacheParameterGroupUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).elasticacheconn + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + + if err := keyvaluetags.ElasticacheUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating ElastiCache Parameter Group (%s) tags: %w", d.Get("arn").(string), err) + } + } + if d.HasChange("parameter") { o, n := d.GetChange("parameter") toRemove, toAdd := elastiCacheParameterChanges(o, n) diff --git a/aws/resource_aws_elasticache_parameter_group_test.go b/aws/resource_aws_elasticache_parameter_group_test.go index 5c6c520d6ef..98100cbc1a2 100644 --- a/aws/resource_aws_elasticache_parameter_group_test.go +++ b/aws/resource_aws_elasticache_parameter_group_test.go @@ -87,6 +87,7 @@ func TestAccAWSElasticacheParameterGroup_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "description", "Managed by Terraform"), resource.TestCheckResourceAttr(resourceName, "family", "redis2.8"), resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -413,6 +414,50 @@ func TestAccAWSElasticacheParameterGroup_Description(t *testing.T) { }) } +func TestAccAWSElasticacheParameterGroup_Tags(t *testing.T) { + var cacheParameterGroup1 elasticache.CacheParameterGroup + resourceName := "aws_elasticache_parameter_group.test" + rName := fmt.Sprintf("parameter-group-test-terraform-%d", acctest.RandInt()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, elasticache.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSElasticacheParameterGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSElasticacheParameterGroupConfigTags1(rName, "redis2.8", "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSElasticacheParameterGroupExists(resourceName, &cacheParameterGroup1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + Config: testAccAWSElasticacheParameterGroupConfigTags2(rName, "redis2.8", "key1", "updatedvalue1", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSElasticacheParameterGroupExists(resourceName, &cacheParameterGroup1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "updatedvalue1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSElasticacheParameterGroupConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSElasticacheParameterGroupExists(resourceName, &cacheParameterGroup1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckAWSElasticacheParameterGroupDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).elasticacheconn @@ -545,6 +590,33 @@ resource "aws_elasticache_parameter_group" "test" { `, family, rName, parameterName1, parameterValue1, parameterName2, parameterValue2) } +func testAccAWSElasticacheParameterGroupConfigTags1(rName, family, tagName1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_elasticache_parameter_group" "test" { + family = %[1]q + name = %[2]q + + tags = { + %[3]s = %[4]q + } +} +`, family, rName, tagName1, tagValue1) +} + +func testAccAWSElasticacheParameterGroupConfigTags2(rName, family, tagName1, tagValue1, tagName2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_elasticache_parameter_group" "test" { + family = %[1]q + name = %[2]q + + tags = { + %[3]s = %[4]q + %[5]s = %[6]q + } +} +`, family, rName, tagName1, tagValue1, tagName2, tagValue2) +} + func TestFlattenElasticacheParameters(t *testing.T) { cases := []struct { Input []*elasticache.Parameter diff --git a/website/docs/r/elasticache_parameter_group.html.markdown b/website/docs/r/elasticache_parameter_group.html.markdown index d3a2effb7f2..4b6273b51c2 100644 --- a/website/docs/r/elasticache_parameter_group.html.markdown +++ b/website/docs/r/elasticache_parameter_group.html.markdown @@ -39,6 +39,7 @@ The following arguments are supported: * `family` - (Required) The family of the ElastiCache parameter group. * `description` - (Optional) The description of the ElastiCache parameter group. Defaults to "Managed by Terraform". * `parameter` - (Optional) A list of ElastiCache parameters to apply. +* `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. Parameter blocks support the following: @@ -50,6 +51,8 @@ Parameter blocks support the following: In addition to all arguments above, the following attributes are exported: * `id` - The ElastiCache parameter group name. +* `arn` - The AWS ARN associated with the parameter group. +* `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 01a308c652b2d65eee84c9feb7e203f1465c9e57 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 May 2021 11:58:33 -0400 Subject: [PATCH 242/398] Add CHANGELOG entry. --- .changelog/19551.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19551.txt diff --git a/.changelog/19551.txt b/.changelog/19551.txt new file mode 100644 index 00000000000..622165ffd20 --- /dev/null +++ b/.changelog/19551.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_elasticache_parameter_group: Add `tags` argument and `arn` and `tags_all` attributes +``` \ No newline at end of file From 9251ae43fd89ea908473d677ebc3d32180556819 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 May 2021 12:01:08 -0400 Subject: [PATCH 243/398] Fix semgrep error. --- aws/resource_aws_elasticache_parameter_group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_elasticache_parameter_group.go b/aws/resource_aws_elasticache_parameter_group.go index 3a9783dd729..e3591da50ff 100644 --- a/aws/resource_aws_elasticache_parameter_group.go +++ b/aws/resource_aws_elasticache_parameter_group.go @@ -93,7 +93,7 @@ func resourceAwsElasticacheParameterGroupCreate(d *schema.ResourceData, meta int } d.SetId(aws.StringValue(resp.CacheParameterGroup.CacheParameterGroupName)) - d.Set("arn", aws.StringValue(resp.CacheParameterGroup.ARN)) + d.Set("arn", resp.CacheParameterGroup.ARN) log.Printf("[INFO] ElastiCache Parameter Group ID: %s", d.Id()) return resourceAwsElasticacheParameterGroupUpdate(d, meta) From cecdbc4d10b74369caa0b4012fe0d81bbf65527f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 May 2021 12:07:21 -0400 Subject: [PATCH 244/398] Fix terrafmt errors. --- aws/resource_aws_elasticache_parameter_group_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_elasticache_parameter_group_test.go b/aws/resource_aws_elasticache_parameter_group_test.go index 98100cbc1a2..4eb7ef93fb2 100644 --- a/aws/resource_aws_elasticache_parameter_group_test.go +++ b/aws/resource_aws_elasticache_parameter_group_test.go @@ -597,7 +597,7 @@ resource "aws_elasticache_parameter_group" "test" { name = %[2]q tags = { - %[3]s = %[4]q + %[3]s = %[4]q } } `, family, rName, tagName1, tagValue1) @@ -610,8 +610,8 @@ resource "aws_elasticache_parameter_group" "test" { name = %[2]q tags = { - %[3]s = %[4]q - %[5]s = %[6]q + %[3]s = %[4]q + %[5]s = %[6]q } } `, family, rName, tagName1, tagValue1, tagName2, tagValue2) From 3779d69218b9d6aa627b05a5ea036b6d4e890cb6 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 27 May 2021 16:26:03 +0000 Subject: [PATCH 245/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12dd512e3f5..44e01947b2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,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_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)) * 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 efa8b7cc2aa22e2cebef56d7f808459ded111a10 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 27 May 2021 13:00:36 -0400 Subject: [PATCH 246/398] hashibot: Migrate regexp_issue_labeler_v2 behavior to GitHub Actions (#19548) Reference: https://github.com/hashicorp/terraform-provider-aws/issues/19356 Verified in a test repository. --- .github/labeler-issue-triage.yml | 348 ++++++++++++ .hashibot.hcl | 557 ------------------- docs/contributing/contribution-checklists.md | 21 +- 3 files changed, 355 insertions(+), 571 deletions(-) diff --git a/.github/labeler-issue-triage.yml b/.github/labeler-issue-triage.yml index 8b506731717..03760b4ff8f 100644 --- a/.github/labeler-issue-triage.yml +++ b/.github/labeler-issue-triage.yml @@ -14,3 +14,351 @@ 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:' +# +# AWS Per-Service Labeling +# +# Catch the following in issues to prevent false positives: +# *aws_XXX +# * aws_XXX +# * `aws_XXX` +# -aws_XXX +# - aws_XXX +# - `aws_XXX` +# data aws_XXX +# data "aws_XXX" +# resource aws_XXX +# resource "aws_XXX" +service/accessanalyzer: + - '((\*|-) ?`?|(data|resource) "?)aws_accessanalyzer_' +service/acm: + - '((\*|-) ?`?|(data|resource) "?)aws_acm_' +service/acmpca: + - '((\*|-) ?`?|(data|resource) "?)aws_acmpca_' +service/alexaforbusiness: + - '((\*|-) ?`?|(data|resource) "?)aws_alexaforbusiness_' +service/amplify: + - '((\*|-) ?`?|(data|resource) "?)aws_amplify_' +service/apigateway: + - '((\*|-) ?`?|(data|resource) "?)aws_api_gateway_' +service/apigatewayv2: + - '((\*|-) ?`?|(data|resource) "?)aws_apigatewayv2_' +service/appconfig: + - '((\*|-) ?`?|(data|resource) "?)aws_appconfig_' +service/applicationautoscaling: + - '((\*|-) ?`?|(data|resource) "?)aws_appautoscaling_' +service/applicationdiscoveryservice: + - '((\*|-) ?`?|(data|resource) "?)aws_applicationdiscoveryservice_' +service/applicationinsights: + - '((\*|-) ?`?|(data|resource) "?)aws_applicationinsights_' +service/appmesh: + - '((\*|-) ?`?|(data|resource) "?)aws_appmesh_' +service/apprunner: + - '((\*|-) ?`?|(data|resource) "?)aws_apprunner_' +service/appstream: + - '((\*|-) ?`?|(data|resource) "?)aws_appstream_' +service/appsync: + - '((\*|-) ?`?|(data|resource) "?)aws_appsync_' +service/athena: + - '((\*|-) ?`?|(data|resource) "?)aws_athena_' +service/auditmanager: + - '((\*|-) ?`?|(data|resource) "?)aws_auditmanager_' +service/autoscaling: + - '((\*|-) ?`?|(data|resource) "?)aws_(autoscaling_|launch_configuration)' +service/autoscalingplans: + - '((\*|-) ?`?|(data|resource) "?)aws_autoscalingplans_' +service/backup: + - '((\*|-) ?`?|(data|resource) "?)aws_backup_' +service/batch: + - '((\*|-) ?`?|(data|resource) "?)aws_batch_' +service/budgets: + - '((\*|-) ?`?|(data|resource) "?)aws_budgets_' +service/chime: + - '((\*|-) ?`?|(data|resource) "?)aws_chime_' +service/cloud9: + - '((\*|-) ?`?|(data|resource) "?)aws_cloud9_' +service/clouddirectory: + - '((\*|-) ?`?|(data|resource) "?)aws_clouddirectory_' +service/cloudformation: + - '((\*|-) ?`?|(data|resource) "?)aws_cloudformation_' +service/cloudfront: + - '((\*|-) ?`?|(data|resource) "?)aws_cloudfront_' +service/cloudhsmv2: + - '((\*|-) ?`?|(data|resource) "?)aws_cloudhsm_v2_' +service/cloudsearch: + - '((\*|-) ?`?|(data|resource) "?)aws_cloudsearch_' +service/cloudtrail: + - '((\*|-) ?`?|(data|resource) "?)aws_cloudtrail' +service/cloudwatch: + - '((\*|-) ?`?|(data|resource) "?)aws_cloudwatch_(?!(event_|log_|query_))' +service/cloudwatchevents: + - '((\*|-) ?`?|(data|resource) "?)aws_cloudwatch_event_' +service/cloudwatchlogs: + - '((\*|-) ?`?|(data|resource) "?)aws_cloudwatch_(log_|query_)' +service/codeartifact: + - '((\*|-) ?`?|(data|resource) "?)aws_codeartifact_' +service/codebuild: + - '((\*|-) ?`?|(data|resource) "?)aws_codebuild_' +service/codecommit: + - '((\*|-) ?`?|(data|resource) "?)aws_codecommit_' +service/codedeploy: + - '((\*|-) ?`?|(data|resource) "?)aws_codedeploy_' +service/codepipeline: + - '((\*|-) ?`?|(data|resource) "?)aws_codepipeline' +service/codestar: + - '((\*|-) ?`?|(data|resource) "?)aws_codestar_' +service/codestarconnections: + - '((\*|-) ?`?|(data|resource) "?)aws_codestarconnections_' +service/codestarnotifications: + - '((\*|-) ?`?|(data|resource) "?)aws_codestarnotifications_' +service/cognito: + - '((\*|-) ?`?|(data|resource) "?)aws_cognito_' +service/configservice: + - '((\*|-) ?`?|(data|resource) "?)aws_config_' +service/connect: + - '((\*|-) ?`?|(data|resource) "?)aws_connect_' +service/databasemigrationservice: + - '((\*|-) ?`?|(data|resource) "?)aws_dms_' +service/dataexchange: + - '((\*|-) ?`?|(data|resource) "?)aws_dataexchange_' +service/datapipeline: + - '((\*|-) ?`?|(data|resource) "?)aws_datapipeline_' +service/datasync: + - '((\*|-) ?`?|(data|resource) "?)aws_datasync_' +service/dax: + - '((\*|-) ?`?|(data|resource) "?)aws_dax_' +service/detective: + - '((\*|-) ?`?|(data|resource) "?)aws_detective' +service/devicefarm: + - '((\*|-) ?`?|(data|resource) "?)aws_devicefarm_' +service/directconnect: + - '((\*|-) ?`?|(data|resource) "?)aws_dx_' +service/directoryservice: + - '((\*|-) ?`?|(data|resource) "?)aws_directory_service_' +service/dlm: + - '((\*|-) ?`?|(data|resource) "?)aws_dlm_' +service/docdb: + - '((\*|-) ?`?|(data|resource) "?)aws_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)' +service/ecr: + - '((\*|-) ?`?|(data|resource) "?)aws_ecr_' +service/ecrpublic: + - '((\*|-) ?`?|(data|resource) "?)aws_ecrpublic_' +service/ecs: + - '((\*|-) ?`?|(data|resource) "?)aws_ecs_' +service/efs: + - '((\*|-) ?`?|(data|resource) "?)aws_efs_' +service/eks: + - '((\*|-) ?`?|(data|resource) "?)aws_eks_' +elastic-transcoder: + - '((\*|-) ?`?|(data|resource) "?)aws_elastictranscoder_' +service/elasticache: + - '((\*|-) ?`?|(data|resource) "?)aws_elasticache_' +service/elasticbeanstalk: + - '((\*|-) ?`?|(data|resource) "?)aws_elastic_beanstalk_' +service/elasticsearch: + - '((\*|-) ?`?|(data|resource) "?)aws_elasticsearch_' +service/elb: + - '((\*|-) ?`?|(data|resource) "?)aws_(app_cookie_stickiness_policy|elb|lb_cookie_stickiness_policy|lb_ssl_negotiation_policy|load_balancer_|proxy_protocol_policy)' +service/elbv2: + - '((\*|-) ?`?|(data|resource) "?)aws_(a)?lb(\"|`|_listener|_target_group|$)' +service/emr: + - '((\*|-) ?`?|(data|resource) "?)aws_emr_' +service/emrcontainers: + - '((\*|-) ?`?|(data|resource) "?)aws_emrcontainers_' +service/eventbridge: + - '((\*|-) ?`?|(data|resource) "?)aws_cloudwatch_event_' +service/firehose: + - '((\*|-) ?`?|(data|resource) "?)aws_kinesis_firehose_' +service/fms: + - '((\*|-) ?`?|(data|resource) "?)aws_fms_' +service/forecast: + - '((\*|-) ?`?|(data|resource) "?)aws_forecast_' +service/fsx: + - '((\*|-) ?`?|(data|resource) "?)aws_fsx_' +service/gamelift: + - '((\*|-) ?`?|(data|resource) "?)aws_gamelift_' +service/glacier: + - '((\*|-) ?`?|(data|resource) "?)aws_glacier_' +service/globalaccelerator: + - '((\*|-) ?`?|(data|resource) "?)aws_globalaccelerator_' +service/glue: + - '((\*|-) ?`?|(data|resource) "?)aws_glue_' +service/greengrass: + - '((\*|-) ?`?|(data|resource) "?)aws_greengrass_' +service/guardduty: + - '((\*|-) ?`?|(data|resource) "?)aws_guardduty_' +service/iam: + - '((\*|-) ?`?|(data|resource) "?)aws_iam_' +service/identitystore: + - '((\*|-) ?`?|(data|resource) "?)aws_identitystore_' +service/imagebuilder: + - '((\*|-) ?`?|(data|resource) "?)aws_imagebuilder_' +service/inspector: + - '((\*|-) ?`?|(data|resource) "?)aws_inspector_' +service/iot: + - '((\*|-) ?`?|(data|resource) "?)aws_iot_' +service/iotanalytics: + - '((\*|-) ?`?|(data|resource) "?)aws_iotanalytics_' +service/iotevents: + - '((\*|-) ?`?|(data|resource) "?)aws_iotevents_' +service/kafka: + - '((\*|-) ?`?|(data|resource) "?)aws_msk_' +service/kinesis: + - '((\*|-) ?`?|(data|resource) "?)aws_kinesis_stream' +service/kinesisanalytics: + - '((\*|-) ?`?|(data|resource) "?)aws_kinesis_analytics_' +service/kinesisanalyticsv2: + - '((\*|-) ?`?|(data|resource) "?)aws_kinesisanalyticsv2_' +service/kms: + - '((\*|-) ?`?|(data|resource) "?)aws_kms_' +service/lakeformation: + - '((\*|-) ?`?|(data|resource) "?)aws_lakeformation_' +service/lambda: + - '((\*|-) ?`?|(data|resource) "?)aws_lambda_' +service/lexmodelbuildingservice: + - '((\*|-) ?`?|(data|resource) "?)aws_lex_' +service/licensemanager: + - '((\*|-) ?`?|(data|resource) "?)aws_licensemanager_' +service/lightsail: + - '((\*|-) ?`?|(data|resource) "?)aws_lightsail_' +service/machinelearning: + - '((\*|-) ?`?|(data|resource) "?)aws_machinelearning_' +service/macie: + - '((\*|-) ?`?|(data|resource) "?)aws_macie_' +service/macie2: + - '((\*|-) ?`?|(data|resource) "?)aws_macie2_' +service/marketplacecatalog: + - '((\*|-) ?`?|(data|resource) "?)aws_marketplace_catalog_' +service/mediaconnect: + - '((\*|-) ?`?|(data|resource) "?)aws_media_connect_' +service/mediaconvert: + - '((\*|-) ?`?|(data|resource) "?)aws_media_convert_' +service/medialive: + - '((\*|-) ?`?|(data|resource) "?)aws_media_live_' +service/mediapackage: + - '((\*|-) ?`?|(data|resource) "?)aws_media_package_' +service/mediastore: + - '((\*|-) ?`?|(data|resource) "?)aws_media_store_' +service/mediatailor: + - '((\*|-) ?`?|(data|resource) "?)aws_media_tailor_' +service/mobile: + - '((\*|-) ?`?|(data|resource) "?)aws_mobile_' +service/mq: + - '((\*|-) ?`?|(data|resource) "?)aws_mq_' +service/mwaa: + - '((\*|-) ?`?|(data|resource) "?)aws_mwaa_' +service/neptune: + - '((\*|-) ?`?|(data|resource) "?)aws_neptune_' +service/networkfirewall: + - '((\*|-) ?`?|(data|resource) "?)aws_networkfirewall_' +service/networkmanager: + - '((\*|-) ?`?|(data|resource) "?)aws_networkmanager_' +service/opsworks: + - '((\*|-) ?`?|(data|resource) "?)aws_opsworks_' +service/organizations: + - '((\*|-) ?`?|(data|resource) "?)aws_organizations_' +service/outposts: + - '((\*|-) ?`?|(data|resource) "?)aws_outposts_' +service/personalize: + - '((\*|-) ?`?|(data|resource) "?)aws_personalize_' +service/pinpoint: + - '((\*|-) ?`?|(data|resource) "?)aws_pinpoint_' +service/polly: + - '((\*|-) ?`?|(data|resource) "?)aws_polly_' +service/pricing: + - '((\*|-) ?`?|(data|resource) "?)aws_pricing_' +service/prometheusservice: + - '((\*|-) ?`?|(data|resource) "?)aws_prometheus_' +service/qldb: + - '((\*|-) ?`?|(data|resource) "?)aws_qldb_' +service/quicksight: + - '((\*|-) ?`?|(data|resource) "?)aws_quicksight_' +service/ram: + - '((\*|-) ?`?|(data|resource) "?)aws_ram_' +service/rds: + - '((\*|-) ?`?|(data|resource) "?)aws_(db_|rds_)' +service/redshift: + - '((\*|-) ?`?|(data|resource) "?)aws_redshift_' +service/resourcegroups: + - '((\*|-) ?`?|(data|resource) "?)aws_resourcegroups_' +service/resourcegroupstaggingapi: + - '((\*|-) ?`?|(data|resource) "?)aws_resourcegroupstaggingapi_' +service/robomaker: + - '((\*|-) ?`?|(data|resource) "?)aws_robomaker_' +service/route53: + - '((\*|-) ?`?|(data|resource) "?)aws_route53_(?!resolver_)' +service/route53domains: + - '((\*|-) ?`?|(data|resource) "?)aws_route53domains_' +service/route53resolver: + - '((\*|-) ?`?|(data|resource) "?)aws_route53_resolver_' +service/s3: + - '((\*|-) ?`?|(data|resource) "?)aws_(canonical_user_id|s3_bucket|s3_object)' +service/s3control: + - '((\*|-) ?`?|(data|resource) "?)aws_(s3_account_|s3control_)' +service/s3outposts: + - '((\*|-) ?`?|(data|resource) "?)aws_s3outposts_' +service/sagemaker: + - '((\*|-) ?`?|(data|resource) "?)aws_sagemaker_' +service/schemas: + - '((\*|-) ?`?|(data|resource) "?)aws_schemas_' +service/secretsmanager: + - '((\*|-) ?`?|(data|resource) "?)aws_secretsmanager_' +service/securityhub: + - '((\*|-) ?`?|(data|resource) "?)aws_securityhub_' +service/serverlessapplicationrepository: + - '((\*|-) ?`?|(data|resource) "?)aws_serverlessapplicationrepository_' +service/servicecatalog: + - '((\*|-) ?`?|(data|resource) "?)aws_servicecatalog_' +service/servicediscovery: + - '((\*|-) ?`?|(data|resource) "?)aws_service_discovery_' +service/servicequotas: + - '((\*|-) ?`?|(data|resource) "?)aws_servicequotas_' +service/ses: + - '((\*|-) ?`?|(data|resource) "?)aws_ses_' +service/sfn: + - '((\*|-) ?`?|(data|resource) "?)aws_sfn_' +service/shield: + - '((\*|-) ?`?|(data|resource) "?)aws_shield_' +service/signer: + - '((\*|-) ?`?|(data|resource) "?)aws_signer_' +service/simpledb: + - '((\*|-) ?`?|(data|resource) "?)aws_simpledb_' +service/snowball: + - '((\*|-) ?`?|(data|resource) "?)aws_snowball_' +service/sns: + - '((\*|-) ?`?|(data|resource) "?)aws_sns_' +service/sqs: + - '((\*|-) ?`?|(data|resource) "?)aws_sqs_' +service/ssm: + - '((\*|-) ?`?|(data|resource) "?)aws_ssm_' +service/ssoadmin: + - '((\*|-) ?`?|(data|resource) "?)aws_ssoadmin_' +service/storagegateway: + - '((\*|-) ?`?|(data|resource) "?)aws_storagegateway_' +service/sts: + - '((\*|-) ?`?|(data|resource) "?)aws_caller_identity' +service/swf: + - '((\*|-) ?`?|(data|resource) "?)aws_swf_' +service/synthetics: + - '((\*|-) ?`?|(data|resource) "?)aws_synthetics_' +service/timestreamwrite: + - '((\*|-) ?`?|(data|resource) "?)aws_timestreamwrite_' +service/transfer: + - '((\*|-) ?`?|(data|resource) "?)aws_transfer_' +service/waf: + - '((\*|-) ?`?|(data|resource) "?)aws_waf(regional)?_' +service/wafv2: + - '((\*|-) ?`?|(data|resource) "?)aws_wafv2_' +service/workdocs: + - '((\*|-) ?`?|(data|resource) "?)aws_workdocs_' +service/worklink: + - '((\*|-) ?`?|(data|resource) "?)aws_worklink_' +service/workmail: + - '((\*|-) ?`?|(data|resource) "?)aws_workmail_' +service/workspaces: + - '((\*|-) ?`?|(data|resource) "?)aws_workspaces_' +service/xray: + - '((\*|-) ?`?|(data|resource) "?)aws_xray_' diff --git a/.hashibot.hcl b/.hashibot.hcl index 73046cefac0..18f7fba7237 100644 --- a/.hashibot.hcl +++ b/.hashibot.hcl @@ -8,563 +8,6 @@ queued_behavior "release_commenter" "releases" { EOF } -# Catch the following in issues: -# *aws_XXX -# * aws_XXX -# * `aws_XXX` -# -aws_XXX -# - aws_XXX -# - `aws_XXX` -# data "aws_XXX" -# resource "aws_XXX" -# NOTE: Go regexp does not support negative lookaheads -behavior "regexp_issue_labeler_v2" "service_labels" { - regexp = "(\\* ?`?|- ?`?|data \"|resource \")aws_(\\w+)" - - label_map = { - "service/accessanalyzer" = [ - "aws_accessanalyzer_", - ], - "service/acm" = [ - "aws_acm_", - ], - "service/acmpca" = [ - "aws_acmpca_", - ], - "service/alexaforbusiness" = [ - "aws_alexaforbusiness_", - ], - "service/amplify" = [ - "aws_amplify_", - ], - "service/apigateway" = [ - # Catch aws_api_gateway_XXX but not aws_api_gateway_v2_ - "aws_api_gateway_([^v]|v[^2]|v2[^_])", - ], - "service/apigatewayv2" = [ - "aws_api_gateway_v2_", - "aws_apigatewayv2_", - ], - "service/appconfig" = [ - "aws_appconfig_", - ], - "service/applicationautoscaling" = [ - "aws_appautoscaling_", - ], - "service/applicationdiscoveryservice" = [ - "aws_applicationdiscoveryservice_", - ], - "service/applicationinsights" = [ - "aws_applicationinsights_", - ], - "service/appmesh" = [ - "aws_appmesh_", - ], - "service/apprunner" = [ - "aws_apprunner_", - ], - "service/appstream" = [ - "aws_appstream_", - ], - "service/appsync" = [ - "aws_appsync_", - ], - "service/athena" = [ - "aws_athena_", - ], - "service/auditmanager" = [ - "aws_auditmanager_", - ], - "service/autoscaling" = [ - "aws_autoscaling_", - "aws_launch_configuration", - ], - "service/autoscalingplans" = [ - "aws_autoscalingplans_", - ], - "service/backup" = [ - "aws_backup_", - ], - "service/batch" = [ - "aws_batch_", - ], - "service/budgets" = [ - "aws_budgets_", - ], - "service/chime" = [ - "aws_chime_", - ], - "service/cloud9" = [ - "aws_cloud9_", - ], - "service/clouddirectory" = [ - "aws_clouddirectory_", - ], - "service/cloudformation" = [ - "aws_cloudformation_", - ], - "service/cloudfront" = [ - "aws_cloudfront_", - ], - "service/cloudhsmv2" = [ - "aws_cloudhsm_v2_", - ], - "service/cloudsearch" = [ - "aws_cloudsearch_", - ], - "service/cloudtrail" = [ - "aws_cloudtrail", - ], - "service/cloudwatch" = [ - "aws_cloudwatch_([^e]|e[^v]|ev[^e]|eve[^n]|even[^t]|event[^_]|[^l]|l[^o]|lo[^g]|log[^_])", - ], - "service/cloudwatchevents" = [ - "aws_cloudwatch_event_", - ], - "service/cloudwatchlogs" = [ - "aws_cloudwatch_log_", - "aws_cloudwatch_query_definition", - ], - "service/codeartifact" = [ - "aws_codeartifact_", - ], - "service/codebuild" = [ - "aws_codebuild_", - ], - "service/codecommit" = [ - "aws_codecommit_", - ], - "service/codedeploy" = [ - "aws_codedeploy_", - ], - "service/codepipeline" = [ - "aws_codepipeline", - ], - "service/codestar" = [ - "aws_codestar_", - ], - "service/codestarconnections" = [ - "aws_codestarconnections_", - ], - "service/codestarnotifications" = [ - "aws_codestarnotifications_", - ], - "service/cognito" = [ - "aws_cognito_", - ], - "service/configservice" = [ - "aws_config_", - ], - "service/connect" = [ - "aws_connect_", - ], - "service/databasemigrationservice" = [ - "aws_dms_", - ], - "service/dataexchange" = [ - "aws_dataexchange_", - ], - "service/datapipeline" = [ - "aws_datapipeline_", - ], - "service/datasync" = [ - "aws_datasync_", - ], - "service/dax" = [ - "aws_dax_", - ], - "service/detective" = [ - "aws_detective_" - ], - "service/devicefarm" = [ - "aws_devicefarm_", - ], - "service/directconnect" = [ - "aws_dx_", - ], - "service/directoryservice" = [ - "aws_directory_service_", - ], - "service/dlm" = [ - "aws_dlm_", - ], - "service/docdb" = [ - "aws_docdb_", - ], - "service/dynamodb" = [ - "aws_dynamodb_", - ], - "service/ec2" = [ - "aws_ami", - "aws_availability_zone", - "aws_customer_gateway", - "aws_(default_)?(network_acl|route_table|security_group|subnet|vpc)", - "aws_ebs_", - "aws_ec2_", - "aws_egress_only_internet_gateway", - "aws_eip", - "aws_flow_log", - "aws_instance", - "aws_internet_gateway", - "aws_key_pair", - "aws_launch_template", - "aws_main_route_table_association", - "aws_network_interface", - "aws_placement_group", - "aws_prefix_list", - "aws_spot", - "aws_route(\"|`|$)", - "aws_vpn_", - "aws_volume_attachment", - ], - "service/ecr" = [ - "aws_ecr_", - ], - "service/ecrpublic" = [ - "aws_ecrpublic_", - ], - "service/ecs" = [ - "aws_ecs_", - ], - "service/efs" = [ - "aws_efs_", - ], - "service/eks" = [ - "aws_eks_", - ], - "service/elastic-transcoder" = [ - "aws_elastictranscoder_", - ], - "service/elasticache" = [ - "aws_elasticache_", - ], - "service/elasticbeanstalk" = [ - "aws_elastic_beanstalk_", - ], - "service/elasticsearch" = [ - "aws_elasticsearch_", - ], - "service/elb" = [ - "aws_app_cookie_stickiness_policy", - "aws_elb", - "aws_lb_cookie_stickiness_policy", - "aws_lb_ssl_negotiation_policy", - "aws_load_balancer_", - "aws_proxy_protocol_policy", - ], - "service/elbv2" = [ - "aws_(a)?lb(\"|`|$)", - # Catch aws_lb_XXX but not aws_lb_cookie_ or aws_lb_ssl_ (Classic ELB) - "aws_(a)?lb_([^c]|c[^o]|co[^o]|coo[^k]|cook[^i]|cooki[^e]|cookie[^_]|[^s]|s[^s]|ss[^l]|ssl[^_])", - ], - "service/emr" = [ - "aws_emr_", - ], - "service/emrcontainers" = [ - "aws_emrcontainers_", - ], - "service/eventbridge" = [ - # EventBridge is rebranded CloudWatch Events - "aws_cloudwatch_event_", - ], - "service/firehose" = [ - "aws_kinesis_firehose_", - ], - "service/fms" = [ - "aws_fms_", - ], - "service/forecast" = [ - "aws_forecast_", - ], - "service/fsx" = [ - "aws_fsx_", - ], - "service/gamelift" = [ - "aws_gamelift_", - ], - "service/glacier" = [ - "aws_glacier_", - ], - "service/globalaccelerator" = [ - "aws_globalaccelerator_", - ], - "service/glue" = [ - "aws_glue_", - ], - "service/greengrass" = [ - "aws_greengrass_", - ], - "service/guardduty" = [ - "aws_guardduty_", - ], - "service/iam" = [ - "aws_iam_", - ], - "service/identitystore" = [ - "aws_identitystore_", - ], - "service/imagebuilder" = [ - "aws_imagebuilder_", - ], - "service/inspector" = [ - "aws_inspector_", - ], - "service/iot" = [ - "aws_iot_", - ], - "service/iotanalytics" = [ - "aws_iotanalytics_", - ], - "service/iotevents" = [ - "aws_iotevents_", - ], - "service/kafka" = [ - "aws_msk_", - ], - "service/kinesis" = [ - # Catch aws_kinesis_XXX but not aws_kinesis_firehose_ - "aws_kinesis_([^f]|f[^i]|fi[^r]|fir[^e]|fire[^h]|fireh[^o]|fireho[^s]|firehos[^e]|firehose[^_])", - ], - "service/kinesisanalytics" = [ - "aws_kinesis_analytics_", - ], - "service/kinesisanalyticsv2" = [ - "aws_kinesisanalyticsv2_", - ], - "service/kms" = [ - "aws_kms_", - ], - "service/lakeformation" = [ - "aws_lakeformation_", - ], - "service/lambda" = [ - "aws_lambda_", - ], - "service/lexmodelbuildingservice" = [ - "aws_lex_", - ], - "service/licensemanager" = [ - "aws_licensemanager_", - ], - "service/lightsail" = [ - "aws_lightsail_", - ], - "service/machinelearning" = [ - "aws_machinelearning_", - ], - "service/macie" = [ - "aws_macie_", - ], - "service/macie2" = [ - "aws_macie2_", - ], - "service/marketplacecatalog" = [ - "aws_marketplace_catalog_", - ], - "service/mediaconnect" = [ - "aws_media_connect_", - ], - "service/mediaconvert" = [ - "aws_media_convert_", - ], - "service/medialive" = [ - "aws_media_live_", - ], - "service/mediapackage" = [ - "aws_media_package_", - ], - "service/mediastore" = [ - "aws_media_store_", - ], - "service/mediatailor" = [ - "aws_media_tailor_", - ], - "service/mobile" = [ - "aws_mobile_", - ], - "service/mq" = [ - "aws_mq_", - ], - "service/mwaa" = [ - "aws_mwaa_", - ], - "service/neptune" = [ - "aws_neptune_", - ], - "service/networkfirewall" = [ - "aws_networkfirewall_", - ], - "service/networkmanager" = [ - "aws_networkmanager_", - ], - "service/opsworks" = [ - "aws_opsworks_", - ], - "service/organizations" = [ - "aws_organizations_", - ], - "service/outposts" = [ - "aws_outposts_", - ], - "service/personalize" = [ - "aws_personalize_", - ], - "service/pinpoint" = [ - "aws_pinpoint_", - ], - "service/polly" = [ - "aws_polly_", - ], - "service/pricing" = [ - "aws_pricing_", - ], - "service/prometheusservice" = [ - "aws_prometheus_", - ], - "service/qldb" = [ - "aws_qldb_", - ], - "service/quicksight" = [ - "aws_quicksight_", - ], - "service/ram" = [ - "aws_ram_", - ], - "service/rds" = [ - "aws_db_", - "aws_rds_", - ], - "service/redshift" = [ - "aws_redshift_", - ], - "service/resourcegroups" = [ - "aws_resourcegroups_", - ], - "service/resourcegroupstaggingapi" = [ - "aws_resourcegroupstaggingapi_", - ], - "service/robomaker" = [ - "aws_robomaker_", - ], - "service/route53" = [ - # Catch aws_route53_XXX but not aws_route53_domains_ or aws_route53_resolver_ - "aws_route53_([^d]|d[^o]|do[^m]|dom[^a]|doma[^i]|domai[^n]|domain[^s]|domains[^_]|[^r]|r[^e]|re[^s]|res[^o]|reso[^l]|resol[^v]|resolv[^e]|resolve[^r]|resolver[^_])", - ], - "service/route53domains" = [ - "aws_route53domains_", - ], - "service/route53resolver" = [ - "aws_route53_resolver_", - ], - "service/s3" = [ - "aws_canonical_user_id", - "aws_s3_bucket", - "aws_s3_object", - ], - "service/s3control" = [ - "aws_s3_account_", - "aws_s3control_", - ], - "service/s3outposts" = [ - "aws_s3outposts_", - ], - "service/sagemaker" = [ - "aws_sagemaker_", - ], - "service/schemas" = [ - "aws_schemas_", - ], - "service/secretsmanager" = [ - "aws_secretsmanager_", - ], - "service/securityhub" = [ - "aws_securityhub_", - ], - "service/serverlessapplicationrepository" = [ - "aws_serverlessapplicationrepository_", - ], - "service/servicecatalog" = [ - "aws_servicecatalog_", - ], - "service/servicediscovery" = [ - "aws_service_discovery_", - ], - "service/servicequotas" = [ - "aws_servicequotas_", - ], - "service/ses" = [ - "aws_ses_", - ], - "service/sfn" = [ - "aws_sfn_", - ], - "service/shield" = [ - "aws_shield_", - ], - "service/signer" = [ - "aws_signer_", - ], - "service/simpledb" = [ - "aws_simpledb_", - ], - "service/snowball" = [ - "aws_snowball_", - ], - "service/sns" = [ - "aws_sns_", - ], - "service/sqs" = [ - "aws_sqs_", - ], - "service/ssm" = [ - "aws_ssm_", - ], - "service/ssoadmin" = [ - "aws_ssoadmin_", - ], - "service/storagegateway" = [ - "aws_storagegateway_", - ], - "service/sts" = [ - "aws_caller_identity", - ], - "service/swf" = [ - "aws_swf_", - ], - "service/synthetics" = [ - "aws_synthetics_", - ], - "service/timestreamwrite" = [ - "aws_timestreamwrite_", - ], - "service/transfer" = [ - "aws_transfer_", - ], - "service/waf" = [ - "aws_waf_", - "aws_wafregional_", - ], - "service/wafv2" = [ - "aws_wafv2_", - ], - "service/workdocs" = [ - "aws_workdocs_", - ], - "service/worklink" = [ - "aws_worklink_", - ], - "service/workmail" = [ - "aws_workmail_", - ], - "service/workspaces" = [ - "aws_workspaces_", - ], - "service/xray" = [ - "aws_xray_", - ], - } -} - behavior "remove_labels_on_reply" "remove_stale" { labels = ["waiting-response", "stale"] only_non_maintainers = true diff --git a/docs/contributing/contribution-checklists.md b/docs/contributing/contribution-checklists.md index 63048478a51..5c50ea6ec66 100644 --- a/docs/contributing/contribution-checklists.md +++ b/docs/contributing/contribution-checklists.md @@ -623,20 +623,13 @@ into Terraform. - In `website/docs/guides/custom-service-endpoints.html.md`: Add the service name in the list of customizable endpoints. - In `infrastructure/repository/labels-service.tf`: Add the new service to create a repository label. - - In `.hashibot.hcl`: Add the new service to automated issue labeling. e.g. with the `quicksight` service - - ```hcl - behavior "regexp_issue_labeler_v2" "service_labels" { - # ... other configuration ... - - label_map = { - # ... other services ... - "service/quicksight" = [ - "aws_quicksight_", - ], - # ... other services ... - } - } + - In `.github/labeler-issue-triage.yml`: Add the new service to automated issue labeling. e.g. with the `quicksight` service + + ```yaml + # ... other services ... + service/quicksight: + - '((\*|-) ?`?|(data|resource) "?)aws_quicksight_' + # ... other services ... ``` - In `.github/labeler-pr-triage.yml`: Add the new service to automated pull request labeling. e.g. with the `quicksight` service From 662a9ead22c4efa00794f7298bc50a3364db0c64 Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Thu, 11 Feb 2021 15:14:37 -0500 Subject: [PATCH 247/398] Allow local and remote IPv4 and IPv6 CIDRs to be of any size Previously the IPv4 parameters were required to be a /32 and the IPv6 parameters were restricted to be a /128. This constraint is not mentioned in the Terraform or AWS documentation, and in fact the default values are /0s. Resolves #16879. --- .changelog/16879.txt | 3 + aws/resource_aws_vpn_connection.go | 4 +- aws/resource_aws_vpn_connection_test.go | 74 +++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 .changelog/16879.txt diff --git a/.changelog/16879.txt b/.changelog/16879.txt new file mode 100644 index 00000000000..6f3641e7363 --- /dev/null +++ b/.changelog/16879.txt @@ -0,0 +1,3 @@ +```release-note:bug +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. +``` diff --git a/aws/resource_aws_vpn_connection.go b/aws/resource_aws_vpn_connection.go index 4738565a837..09866dad865 100644 --- a/aws/resource_aws_vpn_connection.go +++ b/aws/resource_aws_vpn_connection.go @@ -1742,13 +1742,13 @@ func validateVpnConnectionTunnelInsideIpv6CIDR() schema.SchemaValidateFunc { func validateLocalIpv4NetworkCidr() schema.SchemaValidateFunc { return validation.All( - validation.IsCIDRNetwork(32, 32), + validation.IsCIDRNetwork(0, 32), ) } func validateLocalIpv6NetworkCidr() schema.SchemaValidateFunc { return validation.All( - validation.IsCIDRNetwork(128, 128), + validation.IsCIDRNetwork(0, 128), ) } diff --git a/aws/resource_aws_vpn_connection_test.go b/aws/resource_aws_vpn_connection_test.go index 9fd5a5f48ef..366a24b89a5 100644 --- a/aws/resource_aws_vpn_connection_test.go +++ b/aws/resource_aws_vpn_connection_test.go @@ -524,6 +524,50 @@ func TestAccAWSVpnConnection_tags(t *testing.T) { }) } +func TestAccAWSVpnConnection_specifyIpv4(t *testing.T) { + resourceName := "aws_vpn_connection.test" + var vpn ec2.VpnConnection + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccAwsVpnConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsVpnConnectionConfigLocalRemoteIpv4Cidrs("10.111.0.0/16", "10.222.33.0/24"), + Check: resource.ComposeTestCheckFunc( + testAccAwsVpnConnectionExists(resourceName, &vpn), + resource.TestCheckResourceAttr(resourceName, "local_ipv4_network_cidr", "10.111.0.0/16"), + resource.TestCheckResourceAttr(resourceName, "remote_ipv4_network_cidr", "10.222.33.0/24"), + ), + }, + }, + }) +} + +func TestAccAWSVpnConnection_specifyIpv6(t *testing.T) { + resourceName := "aws_vpn_connection.test" + var vpn ec2.VpnConnection + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccAwsVpnConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsVpnConnectionConfigIpv6(65000, "1111:2222:3333:4444::/64", "5555:6666:7777::/48", "fd00:2001:db8:2:2d1:81ff:fe41:d200/126", "fd00:2001:db8:2:2d1:81ff:fe41:d204/126"), + Check: resource.ComposeTestCheckFunc( + testAccAwsVpnConnectionExists(resourceName, &vpn), + resource.TestCheckResourceAttr(resourceName, "local_ipv6_network_cidr", "1111:2222:3333:4444::/64"), + resource.TestCheckResourceAttr(resourceName, "remote_ipv6_network_cidr", "5555:6666:7777::/48"), + ), + }, + }, + }) +} + func TestAccAWSVpnConnection_disappears(t *testing.T) { rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" @@ -1116,6 +1160,36 @@ resource "aws_vpn_connection" "test" { `, rBgpAsn, tagKey1, tagValue1, tagKey2, tagValue2) } +func testAccAwsVpnConnectionConfigLocalRemoteIpv4Cidrs(localIpv4Cidr string, remoteIpv4Cidr string) string { + return fmt.Sprintf(` +resource "aws_vpn_gateway" "vpn_gateway" { + tags = { + Name = "vpn_gateway" + } +} + +resource "aws_customer_gateway" "customer_gateway" { + bgp_asn = 65000 + ip_address = "178.0.0.1" + type = "ipsec.1" + + tags = { + Name = "main-customer-gateway" + } +} + +resource "aws_vpn_connection" "test" { + vpn_gateway_id = aws_vpn_gateway.vpn_gateway.id + customer_gateway_id = aws_customer_gateway.customer_gateway.id + type = "ipsec.1" + static_routes_only = false + + local_ipv4_network_cidr = "%s" + remote_ipv4_network_cidr = "%s" +} +`, localIpv4Cidr, remoteIpv4Cidr) +} + // Test our VPN tunnel config XML parsing const testAccAwsVpnTunnelInfoXML = ` From e08279f942a46c6161d1b2d8e095453d18aa3067 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 15:37:23 -0400 Subject: [PATCH 248/398] r/instance: Add option to EC2 errorcheck --- aws/resource_aws_instance_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index c8b342f4e26..f5cc1067d4e 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -38,6 +38,7 @@ func init() { func testAccErrorCheckSkipEC2(t *testing.T) resource.ErrorCheckFunc { return testAccErrorCheckSkipMessagesContaining(t, "VolumeTypeNotAvailableInRegion", + "Invalid value specified for Phase", ) } From f5aa0e589890b489a46c82127a960a059f797d9c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 15:37:55 -0400 Subject: [PATCH 249/398] tests/r/vpn_connection: Fix tests --- aws/resource_aws_vpn_connection_test.go | 84 ++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_vpn_connection_test.go b/aws/resource_aws_vpn_connection_test.go index 366a24b89a5..440809393f2 100644 --- a/aws/resource_aws_vpn_connection_test.go +++ b/aws/resource_aws_vpn_connection_test.go @@ -397,6 +397,74 @@ func TestAccAWSVpnConnection_tunnelOptions(t *testing.T) { }) } +func TestAccAWSVpnConnection_tunnelOptionsLesser(t *testing.T) { + rBgpAsn := acctest.RandIntRange(64512, 65534) + resourceName := "aws_vpn_connection.test" + var vpn ec2.VpnConnection + + tunnel1 := TunnelOptions{ + psk: "12345678", + tunnelCidr: "169.254.8.0/30", + dpdTimeoutAction: "clear", + dpdTimeoutSeconds: 30, + ikeVersions: "\"ikev1\", \"ikev2\"", + phase1DhGroupNumbers: "14, 15, 16, 17, 18, 19, 20, 21", + phase1EncryptionAlgorithms: "\"AES128\", \"AES256\", \"AES128-GCM-16\", \"AES256-GCM-16\"", + phase1IntegrityAlgorithms: "\"SHA2-256\", \"SHA2-384\", \"SHA2-512\"", + phase1LifetimeSeconds: 28800, + phase2DhGroupNumbers: "14, 15, 16, 17, 18, 19, 20, 21", + phase2EncryptionAlgorithms: "\"AES128\", \"AES256\", \"AES128-GCM-16\", \"AES256-GCM-16\"", + phase2IntegrityAlgorithms: "\"SHA2-256\", \"SHA2-384\", \"SHA2-512\"", + phase2LifetimeSeconds: 3600, + rekeyFuzzPercentage: 100, + rekeyMarginTimeSeconds: 540, + replayWindowSize: 1024, + startupAction: "add", + } + + tunnel2 := TunnelOptions{ + psk: "abcdefgh", + tunnelCidr: "169.254.9.0/30", + dpdTimeoutAction: "clear", + dpdTimeoutSeconds: 30, + ikeVersions: "\"ikev1\", \"ikev2\"", + phase1DhGroupNumbers: "14, 15, 16, 17, 18, 19, 20, 21", + phase1EncryptionAlgorithms: "\"AES128\", \"AES256\", \"AES128-GCM-16\", \"AES256-GCM-16\"", + phase1IntegrityAlgorithms: "\"SHA2-256\", \"SHA2-384\", \"SHA2-512\"", + phase1LifetimeSeconds: 28800, + phase2DhGroupNumbers: "14, 15, 16, 17, 18, 19, 20, 21", + phase2EncryptionAlgorithms: "\"AES128\", \"AES256\", \"AES128-GCM-16\", \"AES256-GCM-16\"", + phase2IntegrityAlgorithms: "\"SHA2-256\", \"SHA2-384\", \"SHA2-512\"", + phase2LifetimeSeconds: 3600, + rekeyFuzzPercentage: 100, + rekeyMarginTimeSeconds: 540, + replayWindowSize: 1024, + startupAction: "add", + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccAwsVpnConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsVpnConnectionConfigTunnelOptions(rBgpAsn, "192.168.1.1/32", "192.168.1.2/32", tunnel1, tunnel2), + Check: resource.ComposeTestCheckFunc( + testAccAwsVpnConnectionExists(resourceName, &vpn), + resource.TestCheckResourceAttr(resourceName, "static_routes_only", "false"), + + resource.TestCheckResourceAttr(resourceName, "tunnel1_inside_cidr", "169.254.8.0/30"), + resource.TestCheckResourceAttr(resourceName, "tunnel1_preshared_key", "12345678"), + + resource.TestCheckResourceAttr(resourceName, "tunnel2_inside_cidr", "169.254.9.0/30"), + resource.TestCheckResourceAttr(resourceName, "tunnel2_preshared_key", "abcdefgh"), + ), + }, + }, + }) +} + func TestAccAWSVpnConnection_withoutStaticRoutes(t *testing.T) { rInt := acctest.RandInt() rBgpAsn := acctest.RandIntRange(64512, 65534) @@ -529,10 +597,10 @@ func TestAccAWSVpnConnection_specifyIpv4(t *testing.T) { var vpn ec2.VpnConnection resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - IDRefreshName: resourceName, - Providers: testAccProviders, - CheckDestroy: testAccAwsVpnConnectionDestroy, + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { Config: testAccAwsVpnConnectionConfigLocalRemoteIpv4Cidrs("10.111.0.0/16", "10.222.33.0/24"), @@ -551,10 +619,10 @@ func TestAccAWSVpnConnection_specifyIpv6(t *testing.T) { var vpn ec2.VpnConnection resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - IDRefreshName: resourceName, - Providers: testAccProviders, - CheckDestroy: testAccAwsVpnConnectionDestroy, + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { Config: testAccAwsVpnConnectionConfigIpv6(65000, "1111:2222:3333:4444::/64", "5555:6666:7777::/48", "fd00:2001:db8:2:2d1:81ff:fe41:d200/126", "fd00:2001:db8:2:2d1:81ff:fe41:d204/126"), From 2d95674a91aafbfeee2ff7c4cf179c5b4dd5279b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 16:34:06 -0400 Subject: [PATCH 250/398] tests/r/vpn_connection: Make tests consistent and random --- aws/resource_aws_vpn_connection_test.go | 417 +++++++++++++----------- 1 file changed, 234 insertions(+), 183 deletions(-) diff --git a/aws/resource_aws_vpn_connection_test.go b/aws/resource_aws_vpn_connection_test.go index 440809393f2..037e2f83f34 100644 --- a/aws/resource_aws_vpn_connection_test.go +++ b/aws/resource_aws_vpn_connection_test.go @@ -93,7 +93,7 @@ func testSweepEc2VpnConnections(region string) error { } func TestAccAWSVpnConnection_basic(t *testing.T) { - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -105,7 +105,7 @@ func TestAccAWSVpnConnection_basic(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfig(rBgpAsn), + Config: testAccAwsVpnConnectionConfig(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "transit_gateway_attachment_id", ""), @@ -120,7 +120,7 @@ func TestAccAWSVpnConnection_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAwsVpnConnectionConfigUpdate(rInt, rBgpAsn), + Config: testAccAwsVpnConnectionConfigUpdate(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), ), @@ -131,6 +131,7 @@ func TestAccAWSVpnConnection_basic(t *testing.T) { func TestAccAWSVpnConnection_TransitGatewayID(t *testing.T) { var vpn ec2.VpnConnection + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) transitGatewayResourceName := "aws_ec2_transit_gateway.test" resourceName := "aws_vpn_connection.test" @@ -145,7 +146,7 @@ func TestAccAWSVpnConnection_TransitGatewayID(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfigTransitGatewayID(rBgpAsn), + Config: testAccAwsVpnConnectionConfigTransitGatewayID(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestMatchResourceAttr(resourceName, "transit_gateway_attachment_id", regexp.MustCompile(`tgw-attach-.+`)), @@ -162,6 +163,7 @@ func TestAccAWSVpnConnection_TransitGatewayID(t *testing.T) { } func TestAccAWSVpnConnection_Tunnel1InsideCidr(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -173,7 +175,7 @@ func TestAccAWSVpnConnection_Tunnel1InsideCidr(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfigTunnel1InsideCidr(rBgpAsn, "169.254.8.0/30", "169.254.9.0/30"), + Config: testAccAwsVpnConnectionConfigTunnel1InsideCidr(rName, rBgpAsn, "169.254.8.0/30", "169.254.9.0/30"), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "tunnel1_inside_cidr", "169.254.8.0/30"), @@ -190,6 +192,7 @@ func TestAccAWSVpnConnection_Tunnel1InsideCidr(t *testing.T) { } func TestAccAWSVpnConnection_Tunnel1InsideIpv6Cidr(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -201,7 +204,7 @@ func TestAccAWSVpnConnection_Tunnel1InsideIpv6Cidr(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfigTunnel1InsideIpv6Cidr(rBgpAsn, "fd00:2001:db8:2:2d1:81ff:fe41:d200/126", "fd00:2001:db8:2:2d1:81ff:fe41:d204/126"), + Config: testAccAwsVpnConnectionConfigTunnel1InsideIpv6Cidr(rName, rBgpAsn, "fd00:2001:db8:2:2d1:81ff:fe41:d200/126", "fd00:2001:db8:2:2d1:81ff:fe41:d204/126"), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "tunnel1_inside_ipv6_cidr", "fd00:2001:db8:2:2d1:81ff:fe41:d200/126"), @@ -218,6 +221,7 @@ func TestAccAWSVpnConnection_Tunnel1InsideIpv6Cidr(t *testing.T) { } func TestAccAWSVpnConnection_Tunnel1PresharedKey(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -229,7 +233,7 @@ func TestAccAWSVpnConnection_Tunnel1PresharedKey(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfigTunnel1PresharedKey(rBgpAsn, "tunnel1presharedkey", "tunnel2presharedkey"), + Config: testAccAwsVpnConnectionConfigTunnel1PresharedKey(rName, rBgpAsn, "tunnel1presharedkey", "tunnel2presharedkey"), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "tunnel1_preshared_key", "tunnel1presharedkey"), @@ -246,6 +250,7 @@ func TestAccAWSVpnConnection_Tunnel1PresharedKey(t *testing.T) { } func TestAccAWSVpnConnection_tunnelOptions(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") badCidrRangeErr := regexp.MustCompile(`expected \w+ to not be any of \[[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/30\s?]+\]`) rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" @@ -299,61 +304,61 @@ func TestAccAWSVpnConnection_tunnelOptions(t *testing.T) { Steps: []resource.TestStep{ // Checking CIDR blocks { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "12345678", "not-a-cidr"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "12345678", "not-a-cidr"), ExpectError: regexp.MustCompile(`invalid CIDR address: not-a-cidr`), }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "12345678", "169.254.254.0/31"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "12345678", "169.254.254.0/31"), ExpectError: regexp.MustCompile(`expected "\w+" to contain a network Value with between 30 and 30 significant bits`), }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "12345678", "172.16.0.0/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "12345678", "172.16.0.0/30"), ExpectError: regexp.MustCompile(`must be within 169.254.0.0/16`), }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "12345678", "169.254.0.0/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "12345678", "169.254.0.0/30"), ExpectError: badCidrRangeErr, }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "12345678", "169.254.1.0/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "12345678", "169.254.1.0/30"), ExpectError: badCidrRangeErr, }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "12345678", "169.254.2.0/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "12345678", "169.254.2.0/30"), ExpectError: badCidrRangeErr, }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "12345678", "169.254.3.0/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "12345678", "169.254.3.0/30"), ExpectError: badCidrRangeErr, }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "12345678", "169.254.4.0/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "12345678", "169.254.4.0/30"), ExpectError: badCidrRangeErr, }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "12345678", "169.254.5.0/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "12345678", "169.254.5.0/30"), ExpectError: badCidrRangeErr, }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "12345678", "169.254.169.252/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "12345678", "169.254.169.252/30"), ExpectError: badCidrRangeErr, }, // Checking PreShared Key { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "1234567", "169.254.254.0/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "1234567", "169.254.254.0/30"), ExpectError: regexp.MustCompile(`expected length of \w+ to be in the range \(8 - 64\)`), }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, acctest.RandStringFromCharSet(65, acctest.CharSetAlpha), "169.254.254.0/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, acctest.RandStringFromCharSet(65, acctest.CharSetAlpha), "169.254.254.0/30"), ExpectError: regexp.MustCompile(`expected length of \w+ to be in the range \(8 - 64\)`), }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "01234567", "169.254.254.0/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "01234567", "169.254.254.0/30"), ExpectError: regexp.MustCompile(`cannot start with zero character`), }, { - Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn, "1234567!", "169.254.254.0/30"), + Config: testAccAwsVpnConnectionConfigSingleTunnelOptions(rName, rBgpAsn, "1234567!", "169.254.254.0/30"), ExpectError: regexp.MustCompile(`can only contain alphanumeric, period and underscore characters`), }, @@ -376,7 +381,7 @@ func TestAccAWSVpnConnection_tunnelOptions(t *testing.T) { //Try actual building { - Config: testAccAwsVpnConnectionConfigTunnelOptions(rBgpAsn, "192.168.1.1/32", "192.168.1.2/32", tunnel1, tunnel2), + Config: testAccAwsVpnConnectionConfigTunnelOptions(rName, rBgpAsn, "192.168.1.1/32", "192.168.1.2/32", tunnel1, tunnel2), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "static_routes_only", "false"), @@ -397,7 +402,9 @@ func TestAccAWSVpnConnection_tunnelOptions(t *testing.T) { }) } +// TestAccAWSVpnConnection_tunnelOptionsLesser tests less algorithms such as those supported in GovCloud. func TestAccAWSVpnConnection_tunnelOptionsLesser(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -449,7 +456,7 @@ func TestAccAWSVpnConnection_tunnelOptionsLesser(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfigTunnelOptions(rBgpAsn, "192.168.1.1/32", "192.168.1.2/32", tunnel1, tunnel2), + Config: testAccAwsVpnConnectionConfigTunnelOptions(rName, rBgpAsn, "192.168.1.1/32", "192.168.1.2/32", tunnel1, tunnel2), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "static_routes_only", "false"), @@ -466,7 +473,7 @@ func TestAccAWSVpnConnection_tunnelOptionsLesser(t *testing.T) { } func TestAccAWSVpnConnection_withoutStaticRoutes(t *testing.T) { - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -478,7 +485,7 @@ func TestAccAWSVpnConnection_withoutStaticRoutes(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfigUpdate(rInt, rBgpAsn), + Config: testAccAwsVpnConnectionConfigUpdate(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "static_routes_only", "false"), @@ -495,6 +502,7 @@ func TestAccAWSVpnConnection_withoutStaticRoutes(t *testing.T) { } func TestAccAWSVpnConnection_withEnableAcceleration(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -506,7 +514,7 @@ func TestAccAWSVpnConnection_withEnableAcceleration(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfigEnableAcceleration(rBgpAsn), + Config: testAccAwsVpnConnectionConfigEnableAcceleration(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "enable_acceleration", "true"), @@ -522,6 +530,7 @@ func TestAccAWSVpnConnection_withEnableAcceleration(t *testing.T) { } func TestAccAWSVpnConnection_withIpv6(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -533,7 +542,7 @@ func TestAccAWSVpnConnection_withIpv6(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfigIpv6(rBgpAsn, "fd00:2001:db8:2:2d1:81ff:fe41:d201/128", "fd00:2001:db8:2:2d1:81ff:fe41:d202/128", "fd00:2001:db8:2:2d1:81ff:fe41:d200/126", "fd00:2001:db8:2:2d1:81ff:fe41:d204/126"), + Config: testAccAwsVpnConnectionConfigIpv6(rName, rBgpAsn, "fd00:2001:db8:2:2d1:81ff:fe41:d201/128", "fd00:2001:db8:2:2d1:81ff:fe41:d202/128", "fd00:2001:db8:2:2d1:81ff:fe41:d200/126", "fd00:2001:db8:2:2d1:81ff:fe41:d204/126"), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), ), @@ -548,6 +557,7 @@ func TestAccAWSVpnConnection_withIpv6(t *testing.T) { } func TestAccAWSVpnConnection_tags(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -559,7 +569,7 @@ func TestAccAWSVpnConnection_tags(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfigTags1(rBgpAsn, "key1", "value1"), + Config: testAccAwsVpnConnectionConfigTags1(rName, rBgpAsn, "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), @@ -572,7 +582,7 @@ func TestAccAWSVpnConnection_tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAwsVpnConnectionConfigTags2(rBgpAsn, "key1", "value1updated", "key2", "value2"), + Config: testAccAwsVpnConnectionConfigTags2(rName, rBgpAsn, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), @@ -581,7 +591,7 @@ func TestAccAWSVpnConnection_tags(t *testing.T) { ), }, { - Config: testAccAwsVpnConnectionConfigTags1(rBgpAsn, "key2", "value2"), + Config: testAccAwsVpnConnectionConfigTags1(rName, rBgpAsn, "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), @@ -593,6 +603,8 @@ func TestAccAWSVpnConnection_tags(t *testing.T) { } func TestAccAWSVpnConnection_specifyIpv4(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -603,7 +615,7 @@ func TestAccAWSVpnConnection_specifyIpv4(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfigLocalRemoteIpv4Cidrs("10.111.0.0/16", "10.222.33.0/24"), + Config: testAccAwsVpnConnectionConfigLocalRemoteIpv4Cidrs(rName, rBgpAsn, "10.111.0.0/16", "10.222.33.0/24"), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "local_ipv4_network_cidr", "10.111.0.0/16"), @@ -615,6 +627,8 @@ func TestAccAWSVpnConnection_specifyIpv4(t *testing.T) { } func TestAccAWSVpnConnection_specifyIpv6(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -625,7 +639,7 @@ func TestAccAWSVpnConnection_specifyIpv6(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfigIpv6(65000, "1111:2222:3333:4444::/64", "5555:6666:7777::/48", "fd00:2001:db8:2:2d1:81ff:fe41:d200/126", "fd00:2001:db8:2:2d1:81ff:fe41:d204/126"), + Config: testAccAwsVpnConnectionConfigIpv6(rName, rBgpAsn, "1111:2222:3333:4444::/64", "5555:6666:7777::/48", "fd00:2001:db8:2:2d1:81ff:fe41:d200/126", "fd00:2001:db8:2:2d1:81ff:fe41:d204/126"), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), resource.TestCheckResourceAttr(resourceName, "local_ipv6_network_cidr", "1111:2222:3333:4444::/64"), @@ -637,6 +651,7 @@ func TestAccAWSVpnConnection_specifyIpv6(t *testing.T) { } func TestAccAWSVpnConnection_disappears(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_vpn_connection.test" var vpn ec2.VpnConnection @@ -648,7 +663,7 @@ func TestAccAWSVpnConnection_disappears(t *testing.T) { CheckDestroy: testAccAwsVpnConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsVpnConnectionConfig(rBgpAsn), + Config: testAccAwsVpnConnectionConfig(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccAwsVpnConnectionExists(resourceName, &vpn), testAccCheckResourceDisappears(testAccProvider, resourceAwsVpnConnection(), resourceName), @@ -839,151 +854,163 @@ func TestXmlConfigToTunnelInfo(t *testing.T) { } } -func testAccAwsVpnConnectionConfig(rBgpAsn int) string { +func testAccAwsVpnConnectionConfig(rName string, rBgpAsn int) string { return fmt.Sprintf(` -resource "aws_vpn_gateway" "vpn_gateway" { +resource "aws_vpn_gateway" "test" { tags = { - Name = "vpn_gateway" + Name = %[1]q } } -resource "aws_customer_gateway" "customer_gateway" { - bgp_asn = %d +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" tags = { - Name = "main-customer-gateway" + Name = %[1]q } } resource "aws_vpn_connection" "test" { - vpn_gateway_id = aws_vpn_gateway.vpn_gateway.id - customer_gateway_id = aws_customer_gateway.customer_gateway.id + vpn_gateway_id = aws_vpn_gateway.test.id + customer_gateway_id = aws_customer_gateway.test.id type = "ipsec.1" static_routes_only = true } -`, rBgpAsn) +`, rName, rBgpAsn) } // Change static_routes_only to be false, forcing a refresh. -func testAccAwsVpnConnectionConfigUpdate(rInt, rBgpAsn int) string { +func testAccAwsVpnConnectionConfigUpdate(rName string, rBgpAsn int) string { return fmt.Sprintf(` -resource "aws_vpn_gateway" "vpn_gateway" { +resource "aws_vpn_gateway" "test" { tags = { - Name = "vpn_gateway" + Name = %[1]q } } -resource "aws_customer_gateway" "customer_gateway" { - bgp_asn = %d +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" tags = { - Name = "main-customer-gateway-%d" + Name = "%[1]s-2" } } resource "aws_vpn_connection" "test" { - vpn_gateway_id = aws_vpn_gateway.vpn_gateway.id - customer_gateway_id = aws_customer_gateway.customer_gateway.id + vpn_gateway_id = aws_vpn_gateway.test.id + customer_gateway_id = aws_customer_gateway.test.id type = "ipsec.1" static_routes_only = false } -`, rBgpAsn, rInt) +`, rName, rBgpAsn) } -func testAccAwsVpnConnectionConfigEnableAcceleration(rBgpAsn int) string { +func testAccAwsVpnConnectionConfigEnableAcceleration(rName string, rBgpAsn int) string { return fmt.Sprintf(` -resource "aws_ec2_transit_gateway" "test" {} -resource "aws_customer_gateway" "customer_gateway" { - bgp_asn = %d +resource "aws_ec2_transit_gateway" "test" { + description = %[1]q +} + +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" + tags = { - Name = "tf-acc-test-ec2-vpn-connection-enable-acceleration" + Name = %[1]q } } + resource "aws_vpn_connection" "test" { - customer_gateway_id = aws_customer_gateway.customer_gateway.id + customer_gateway_id = aws_customer_gateway.test.id transit_gateway_id = aws_ec2_transit_gateway.test.id type = "ipsec.1" static_routes_only = false enable_acceleration = true } -`, rBgpAsn) +`, rName, rBgpAsn) } -func testAccAwsVpnConnectionConfigIpv6(rBgpAsn int, localIpv6NetworkCidr string, remoteIpv6NetworkCidr string, tunnel1InsideIpv6Cidr string, tunnel2InsideIpv6Cidr string) string { +func testAccAwsVpnConnectionConfigIpv6(rName string, rBgpAsn int, localIpv6NetworkCidr string, remoteIpv6NetworkCidr string, tunnel1InsideIpv6Cidr string, tunnel2InsideIpv6Cidr string) string { return fmt.Sprintf(` -resource "aws_ec2_transit_gateway" "test" {} -resource "aws_customer_gateway" "customer_gateway" { - bgp_asn = %d +resource "aws_ec2_transit_gateway" "test" { + description = %[1]q +} + +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" + tags = { - Name = "tf-acc-test-ec2-vpn-connection-enable-acceleration" + Name = %[1]q } } + resource "aws_vpn_connection" "test" { - customer_gateway_id = aws_customer_gateway.customer_gateway.id + customer_gateway_id = aws_customer_gateway.test.id transit_gateway_id = aws_ec2_transit_gateway.test.id type = "ipsec.1" static_routes_only = false enable_acceleration = false - local_ipv6_network_cidr = %[2]q - remote_ipv6_network_cidr = %[3]q + local_ipv6_network_cidr = %[3]q + remote_ipv6_network_cidr = %[4]q tunnel_inside_ip_version = "ipv6" - tunnel1_inside_ipv6_cidr = %[4]q - tunnel2_inside_ipv6_cidr = %[5]q + tunnel1_inside_ipv6_cidr = %[5]q + tunnel2_inside_ipv6_cidr = %[6]q } -`, rBgpAsn, localIpv6NetworkCidr, remoteIpv6NetworkCidr, tunnel1InsideIpv6Cidr, tunnel2InsideIpv6Cidr) +`, rName, rBgpAsn, localIpv6NetworkCidr, remoteIpv6NetworkCidr, tunnel1InsideIpv6Cidr, tunnel2InsideIpv6Cidr) } -func testAccAwsVpnConnectionConfigSingleTunnelOptions(rBgpAsn int, psk string, tunnelCidr string) string { +func testAccAwsVpnConnectionConfigSingleTunnelOptions(rName string, rBgpAsn int, psk string, tunnelCidr string) string { return fmt.Sprintf(` -resource "aws_vpn_gateway" "vpn_gateway" { +resource "aws_vpn_gateway" "test" { tags = { - Name = "vpn_gateway" + Name = %[1]q } } -resource "aws_customer_gateway" "customer_gateway" { - bgp_asn = %d +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" tags = { - Name = "main-customer-gateway" + Name = %[1]q } } resource "aws_vpn_connection" "test" { - vpn_gateway_id = aws_vpn_gateway.vpn_gateway.id - customer_gateway_id = aws_customer_gateway.customer_gateway.id + vpn_gateway_id = aws_vpn_gateway.test.id + customer_gateway_id = aws_customer_gateway.test.id type = "ipsec.1" static_routes_only = false - tunnel1_inside_cidr = "%s" - tunnel1_preshared_key = "%s" + tunnel1_inside_cidr = %[3]q + tunnel1_preshared_key = %[4]q } -`, rBgpAsn, tunnelCidr, psk) +`, rName, rBgpAsn, tunnelCidr, psk) } -func testAccAwsVpnConnectionConfigTransitGatewayID(rBgpAsn int) string { +func testAccAwsVpnConnectionConfigTransitGatewayID(rName string, rBgpAsn int) string { return fmt.Sprintf(` -resource "aws_ec2_transit_gateway" "test" {} +resource "aws_ec2_transit_gateway" "test" { + description = %[1]q +} resource "aws_customer_gateway" "test" { - bgp_asn = %d + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" tags = { - Name = "tf-acc-test-ec2-vpn-connection-transit-gateway-id" + Name = %[1]q } } @@ -992,71 +1019,94 @@ resource "aws_vpn_connection" "test" { transit_gateway_id = aws_ec2_transit_gateway.test.id type = aws_customer_gateway.test.type } -`, rBgpAsn) +`, rName, rBgpAsn) } -func testAccAwsVpnConnectionConfigTunnel1InsideCidr(rBgpAsn int, tunnel1InsideCidr string, tunnel2InsideCidr string) string { +func testAccAwsVpnConnectionConfigTunnel1InsideCidr(rName string, rBgpAsn int, tunnel1InsideCidr string, tunnel2InsideCidr string) string { return fmt.Sprintf(` +resource "aws_vpn_gateway" "test" { + tags = { + Name = %[1]q + } +} + resource "aws_customer_gateway" "test" { - bgp_asn = %[1]d + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" -} -resource "aws_vpn_gateway" "test" {} + tags = { + Name = %[1]q + } +} resource "aws_vpn_connection" "test" { customer_gateway_id = aws_customer_gateway.test.id - tunnel1_inside_cidr = %[2]q - tunnel2_inside_cidr = %[3]q + tunnel1_inside_cidr = %[3]q + tunnel2_inside_cidr = %[4]q type = "ipsec.1" vpn_gateway_id = aws_vpn_gateway.test.id } -`, rBgpAsn, tunnel1InsideCidr, tunnel2InsideCidr) +`, rName, rBgpAsn, tunnel1InsideCidr, tunnel2InsideCidr) } -func testAccAwsVpnConnectionConfigTunnel1InsideIpv6Cidr(rBgpAsn int, tunnel1InsideIpv6Cidr string, tunnel2InsideIpv6Cidr string) string { +func testAccAwsVpnConnectionConfigTunnel1InsideIpv6Cidr(rName string, rBgpAsn int, tunnel1InsideIpv6Cidr string, tunnel2InsideIpv6Cidr string) string { return fmt.Sprintf(` +resource "aws_ec2_transit_gateway" "test" { + description = %[1]q +} + resource "aws_customer_gateway" "test" { - bgp_asn = %[1]d + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" -} -resource "aws_ec2_transit_gateway" "test" {} + tags = { + Name = %[1]q + } +} resource "aws_vpn_connection" "test" { customer_gateway_id = aws_customer_gateway.test.id transit_gateway_id = aws_ec2_transit_gateway.test.id tunnel_inside_ip_version = "ipv6" - tunnel1_inside_ipv6_cidr = %[2]q - tunnel2_inside_ipv6_cidr = %[3]q + tunnel1_inside_ipv6_cidr = %[3]q + tunnel2_inside_ipv6_cidr = %[4]q type = "ipsec.1" } -`, rBgpAsn, tunnel1InsideIpv6Cidr, tunnel2InsideIpv6Cidr) +`, rName, rBgpAsn, tunnel1InsideIpv6Cidr, tunnel2InsideIpv6Cidr) } -func testAccAwsVpnConnectionConfigTunnel1PresharedKey(rBgpAsn int, tunnel1PresharedKey string, tunnel2PresharedKey string) string { +func testAccAwsVpnConnectionConfigTunnel1PresharedKey(rName string, rBgpAsn int, tunnel1PresharedKey string, tunnel2PresharedKey string) string { return fmt.Sprintf(` +resource "aws_vpn_gateway" "test" { + tags = { + Name = %[1]q + } +} + resource "aws_customer_gateway" "test" { - bgp_asn = %[1]d + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" -} -resource "aws_vpn_gateway" "test" {} + tags = { + Name = %[1]q + } +} resource "aws_vpn_connection" "test" { customer_gateway_id = aws_customer_gateway.test.id - tunnel1_preshared_key = %[2]q - tunnel2_preshared_key = %[3]q + tunnel1_preshared_key = %[3]q + tunnel2_preshared_key = %[4]q type = "ipsec.1" vpn_gateway_id = aws_vpn_gateway.test.id } -`, rBgpAsn, tunnel1PresharedKey, tunnel2PresharedKey) +`, rName, rBgpAsn, tunnel1PresharedKey, tunnel2PresharedKey) } func testAccAwsVpnConnectionConfigTunnelOptions( + rName string, rBgpAsn int, localIpv4NetworkCidr string, remoteIpv4NetworkCidr string, @@ -1064,68 +1114,69 @@ func testAccAwsVpnConnectionConfigTunnelOptions( tunnel2 TunnelOptions, ) string { return fmt.Sprintf(` -resource "aws_vpn_gateway" "vpn_gateway" { +resource "aws_vpn_gateway" "test" { tags = { - Name = "vpn_gateway" + Name = %[1]q } } -resource "aws_customer_gateway" "customer_gateway" { - bgp_asn = %d +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" tags = { - Name = "main-customer-gateway" + Name = %[1]q } } resource "aws_vpn_connection" "test" { - vpn_gateway_id = aws_vpn_gateway.vpn_gateway.id - customer_gateway_id = aws_customer_gateway.customer_gateway.id + vpn_gateway_id = aws_vpn_gateway.test.id + customer_gateway_id = aws_customer_gateway.test.id type = "ipsec.1" static_routes_only = false - local_ipv4_network_cidr = %[2]q - remote_ipv4_network_cidr = %[3]q - - tunnel1_inside_cidr = %[4]q - tunnel1_preshared_key = %[5]q - tunnel1_dpd_timeout_action = %[6]q - tunnel1_dpd_timeout_seconds = %[7]d - tunnel1_ike_versions = [%[8]s] - tunnel1_phase1_dh_group_numbers = [%[9]s] - tunnel1_phase1_encryption_algorithms = [%[10]s] - tunnel1_phase1_integrity_algorithms = [%[11]s] - tunnel1_phase1_lifetime_seconds = %[12]d - tunnel1_phase2_dh_group_numbers = [%[13]s] - tunnel1_phase2_encryption_algorithms = [%[14]s] - tunnel1_phase2_integrity_algorithms = [%[15]s] - tunnel1_phase2_lifetime_seconds = %[16]d - tunnel1_rekey_fuzz_percentage = %[17]d - tunnel1_rekey_margin_time_seconds = %[18]d - tunnel1_replay_window_size = %[19]d - tunnel1_startup_action = %[20]q - - tunnel2_inside_cidr = %[21]q - tunnel2_preshared_key = %[22]q - tunnel2_dpd_timeout_action = %[23]q - tunnel2_dpd_timeout_seconds = %[24]d - tunnel2_ike_versions = [%[25]s] - tunnel2_phase1_dh_group_numbers = [%[26]s] - tunnel2_phase1_encryption_algorithms = [%[27]s] - tunnel2_phase1_integrity_algorithms = [%[28]s] - tunnel2_phase1_lifetime_seconds = %[29]d - tunnel2_phase2_dh_group_numbers = [%[30]s] - tunnel2_phase2_encryption_algorithms = [%[31]s] - tunnel2_phase2_integrity_algorithms = [%[32]s] - tunnel2_phase2_lifetime_seconds = %[33]d - tunnel2_rekey_fuzz_percentage = %[34]d - tunnel2_rekey_margin_time_seconds = %[35]d - tunnel2_replay_window_size = %[36]d - tunnel2_startup_action = %[37]q + local_ipv4_network_cidr = %[3]q + remote_ipv4_network_cidr = %[4]q + + tunnel1_inside_cidr = %[5]q + tunnel1_preshared_key = %[6]q + tunnel1_dpd_timeout_action = %[7]q + tunnel1_dpd_timeout_seconds = %[8]d + tunnel1_ike_versions = [%[9]s] + tunnel1_phase1_dh_group_numbers = [%[10]s] + tunnel1_phase1_encryption_algorithms = [%[11]s] + tunnel1_phase1_integrity_algorithms = [%[12]s] + tunnel1_phase1_lifetime_seconds = %[13]d + tunnel1_phase2_dh_group_numbers = [%[14]s] + tunnel1_phase2_encryption_algorithms = [%[15]s] + tunnel1_phase2_integrity_algorithms = [%[16]s] + tunnel1_phase2_lifetime_seconds = %[17]d + tunnel1_rekey_fuzz_percentage = %[18]d + tunnel1_rekey_margin_time_seconds = %[19]d + tunnel1_replay_window_size = %[20]d + tunnel1_startup_action = %[21]q + + tunnel2_inside_cidr = %[22]q + tunnel2_preshared_key = %[23]q + tunnel2_dpd_timeout_action = %[24]q + tunnel2_dpd_timeout_seconds = %[25]d + tunnel2_ike_versions = [%[26]s] + tunnel2_phase1_dh_group_numbers = [%[27]s] + tunnel2_phase1_encryption_algorithms = [%[28]s] + tunnel2_phase1_integrity_algorithms = [%[29]s] + tunnel2_phase1_lifetime_seconds = %[30]d + tunnel2_phase2_dh_group_numbers = [%[31]s] + tunnel2_phase2_encryption_algorithms = [%[32]s] + tunnel2_phase2_integrity_algorithms = [%[33]s] + tunnel2_phase2_lifetime_seconds = %[34]d + tunnel2_rekey_fuzz_percentage = %[35]d + tunnel2_rekey_margin_time_seconds = %[36]d + tunnel2_replay_window_size = %[37]d + tunnel2_startup_action = %[38]q } `, + rName, rBgpAsn, localIpv4NetworkCidr, remoteIpv4NetworkCidr, @@ -1165,97 +1216,97 @@ resource "aws_vpn_connection" "test" { tunnel2.startupAction) } -func testAccAwsVpnConnectionConfigTags1(rBgpAsn int, tagKey1, tagValue1 string) string { +func testAccAwsVpnConnectionConfigTags1(rName string, rBgpAsn int, tagKey1, tagValue1 string) string { return fmt.Sprintf(` -resource "aws_vpn_gateway" "vpn_gateway" { +resource "aws_vpn_gateway" "test" { tags = { - Name = "vpn_gateway" + Name = %[1]q } } -resource "aws_customer_gateway" "customer_gateway" { - bgp_asn = %d +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" tags = { - Name = "main-customer-gateway" + Name = %[1]q } } resource "aws_vpn_connection" "test" { - vpn_gateway_id = aws_vpn_gateway.vpn_gateway.id - customer_gateway_id = aws_customer_gateway.customer_gateway.id + vpn_gateway_id = aws_vpn_gateway.test.id + customer_gateway_id = aws_customer_gateway.test.id type = "ipsec.1" static_routes_only = true tags = { - %[2]q = %[3]q + %[3]q = %[4]q } } -`, rBgpAsn, tagKey1, tagValue1) +`, rName, rBgpAsn, tagKey1, tagValue1) } -func testAccAwsVpnConnectionConfigTags2(rBgpAsn int, tagKey1, tagValue1, tagKey2, tagValue2 string) string { +func testAccAwsVpnConnectionConfigTags2(rName string, rBgpAsn int, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` -resource "aws_vpn_gateway" "vpn_gateway" { +resource "aws_vpn_gateway" "test" { tags = { - Name = "vpn_gateway" + Name = %[1]q } } -resource "aws_customer_gateway" "customer_gateway" { - bgp_asn = %d +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" tags = { - Name = "main-customer-gateway" + Name = %[1]q } } resource "aws_vpn_connection" "test" { - vpn_gateway_id = aws_vpn_gateway.vpn_gateway.id - customer_gateway_id = aws_customer_gateway.customer_gateway.id + vpn_gateway_id = aws_vpn_gateway.test.id + customer_gateway_id = aws_customer_gateway.test.id type = "ipsec.1" static_routes_only = true tags = { - %[2]q = %[3]q - %[4]q = %[5]q + %[3]q = %[4]q + %[5]q = %[6]q } } -`, rBgpAsn, tagKey1, tagValue1, tagKey2, tagValue2) +`, rName, rBgpAsn, tagKey1, tagValue1, tagKey2, tagValue2) } -func testAccAwsVpnConnectionConfigLocalRemoteIpv4Cidrs(localIpv4Cidr string, remoteIpv4Cidr string) string { +func testAccAwsVpnConnectionConfigLocalRemoteIpv4Cidrs(rName string, rBgpAsn int, localIpv4Cidr string, remoteIpv4Cidr string) string { return fmt.Sprintf(` -resource "aws_vpn_gateway" "vpn_gateway" { +resource "aws_vpn_gateway" "test" { tags = { - Name = "vpn_gateway" + Name = %[1]q } } -resource "aws_customer_gateway" "customer_gateway" { - bgp_asn = 65000 +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d ip_address = "178.0.0.1" type = "ipsec.1" tags = { - Name = "main-customer-gateway" + Name = %[1]q } } resource "aws_vpn_connection" "test" { - vpn_gateway_id = aws_vpn_gateway.vpn_gateway.id - customer_gateway_id = aws_customer_gateway.customer_gateway.id + vpn_gateway_id = aws_vpn_gateway.test.id + customer_gateway_id = aws_customer_gateway.test.id type = "ipsec.1" static_routes_only = false - local_ipv4_network_cidr = "%s" - remote_ipv4_network_cidr = "%s" + local_ipv4_network_cidr = %[3]s + remote_ipv4_network_cidr = %[4]s } -`, localIpv4Cidr, remoteIpv4Cidr) +`, rName, rBgpAsn, localIpv4Cidr, remoteIpv4Cidr) } // Test our VPN tunnel config XML parsing From 693a272f9181c070799c4fb134391e0de81f0b0f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 16:41:22 -0400 Subject: [PATCH 251/398] tests/r/vpn_connection: Fix test --- aws/resource_aws_vpn_connection_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_vpn_connection_test.go b/aws/resource_aws_vpn_connection_test.go index 037e2f83f34..847b9d8f65c 100644 --- a/aws/resource_aws_vpn_connection_test.go +++ b/aws/resource_aws_vpn_connection_test.go @@ -1303,8 +1303,8 @@ resource "aws_vpn_connection" "test" { type = "ipsec.1" static_routes_only = false - local_ipv4_network_cidr = %[3]s - remote_ipv4_network_cidr = %[4]s + local_ipv4_network_cidr = %[3]q + remote_ipv4_network_cidr = %[4]q } `, rName, rBgpAsn, localIpv4Cidr, remoteIpv4Cidr) } From 5fd385542f3f8fa26a47d8b6fb494e4cdcd01aa5 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 16:43:38 -0400 Subject: [PATCH 252/398] r/vpn_connection: Rename changelog --- .changelog/{16879.txt => 17573.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .changelog/{16879.txt => 17573.txt} (100%) diff --git a/.changelog/16879.txt b/.changelog/17573.txt similarity index 100% rename from .changelog/16879.txt rename to .changelog/17573.txt From f2eea4fc2439b2803c4eb7c60d99f8790a1c9b81 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 16:44:17 -0400 Subject: [PATCH 253/398] r/vpn_connection: Remove punctuation in changelog --- .changelog/17573.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/17573.txt b/.changelog/17573.txt index 6f3641e7363..3532b0a8319 100644 --- a/.changelog/17573.txt +++ b/.changelog/17573.txt @@ -1,3 +1,3 @@ ```release-note:bug -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. +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 ``` From 3d3cb4e4be0f7ce37eac35c591974a2d5cd0b3e7 Mon Sep 17 00:00:00 2001 From: Stephen Date: Thu, 25 Mar 2021 21:49:32 +0000 Subject: [PATCH 254/398] 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 8f9a37b3a35..d54fd2043bb 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 255/398] 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 a1509ea44cf..b4dc5d4c042 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 256/398] 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 b4dc5d4c042..6bb5ec81b43 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 257/398] 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 00000000000..92c8b1a2138 --- /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 258/398] 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 00000000000..f5d4696408b --- /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 359a5a283d4..c6f3914d0c4 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 e7c2e988a47..6d2d448391c 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 259/398] Update CHANGELOG.md for #19557 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44e01947b2a..d9149b708cf 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 260/398] 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 9f3e0fb21ea..5e7aa85ec22 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 261/398] 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 6bb5ec81b43..bb54b4e643b 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 262/398] 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 6ecfeba9d4c..bace2eca835 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 9ec4495829e..93c5dc6cae4 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 65a31c232bd..59f9a9a2af4 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 cceb23cc901..09cd1962e20 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 aee9eb13100..a56ebf54041 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 ee8accd325193fadd81f5935954d8e8bfc210d3a Mon Sep 17 00:00:00 2001 From: bill-rich Date: Thu, 27 May 2021 16:44:52 -0700 Subject: [PATCH 263/398] 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 93c5dc6cae4..b1ffdc2e859 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 59f9a9a2af4..e69fcfeeeaf 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 09cd1962e20..4b3a0cdf8fe 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 264/398] 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 00000000000..efd40e9764c --- /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 265/398] 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 5e7aa85ec22..4b20a125fe1 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 266/398] 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 4b20a125fe1..c9b6632361b 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 267/398] 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 c59fdeac6dd..044683076d6 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 e967b8ca8d2..031102b7365 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 268/398] Update CHANGELOG.md for #19559 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9149b708cf..3da42894501 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 269/398] 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 00000000000..0b2a3ff42e8 --- /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 270/398] 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 031102b7365..9da884944ee 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 271/398] 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 9da884944ee..f963951487f 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 272/398] 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 f963951487f..d6fc1532520 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 273/398] 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 d6fc1532520..ada95be5169 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 274/398] 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 ada95be5169..fc9ac715632 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 275/398] 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 59a2607e1e0..5bfa5a83d4d 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 7f6c52d88e6..a9957ff79e7 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 276/398] 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 771b877ea36..71e2a863782 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 025966ef59a..d8e8b40e954 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 277/398] 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 5bfa5a83d4d..3704bb313ee 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 a9957ff79e7..119ff6a9af1 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 179417826f2..ae3e53478d1 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 278/398] Update CHANGELOG.md for #19499 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3da42894501..d2f0ebac30b 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 279/398] 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 00000000000..b369c83530b --- /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 280/398] 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 1de5bf2c9d6..e78cf2ca913 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 281/398] 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 43bcea9333b..f5d32df556d 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 e706a43b02f..e6c15d1f84a 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 282/398] 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 00000000000..b2ba1cf5694 --- /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 283/398] 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 f5d32df556d..4e9afa2620e 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 284/398] 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 d8e8b40e954..132f6cbf858 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 285/398] 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 4e9afa2620e..c3ac1c24fed 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 286/398] 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 4fc1249f96e..3b4cd9f8e7b 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 41844b75407..00173c41790 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 287/398] 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 725f073618c..fbe6dfa725a 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 288/398] 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 00000000000..f3b5f5d27bd --- /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 289/398] 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 f3b5f5d27bd..be8af655535 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 3b4cd9f8e7b..643975323f5 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 00173c41790..dcb1d867bb1 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 fbe6dfa725a..7581da69504 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 290/398] 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 dcb1d867bb1..48f831ac0e6 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 291/398] 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 60c14a93aa4..cb995824d6e 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 292/398] 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 37829a3ed78..3d09b7762b8 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 293/398] 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 f2ff0d42af1..0a645db0a8d 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 294/398] 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 00000000000..3c8b2b5ca13 --- /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 295/398] 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 29441ce6844..e162225aa5b 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 0d84bbc706bcf1809c84cd0f797ecdd9a16b219f Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 31 May 2021 16:23:18 -0700 Subject: [PATCH 296/398] 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 3d09b7762b8..32790955784 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 297/398] 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 00000000000..a41995893b1 --- /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 d8bcd7d5054..0b396760eb5 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 298/398] 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 00000000000..b8c4d6bfacc --- /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 18f7fba7237..b8d0b6e0377 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 299/398] Update CHANGELOG.md for #19594 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2f0ebac30b..db7fc3cddb9 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 300/398] 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 0a98108c4de..270d361e8a9 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 764d5f07342..2c8a89d6ae9 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 98815547e04..15d324c5d23 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 301/398] 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 15d324c5d23..72571adfa2d 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 761733ccc38..8c529aed398 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 302/398] 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 2c8a89d6ae9..82bbb8fd0b2 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 303/398] 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 82bbb8fd0b2..dc96af1f1be 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 304/398] 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 72571adfa2d..f5d7c9fe127 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 305/398] 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 8cdb9f54066..81e43f04776 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 00000000000..a56b71d33fa --- /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 00000000000..3d0b5709370 --- /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 00000000000..c360c077efa --- /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 306/398] 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 3d0b5709370..8cff76d877b 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 307/398] 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 a56b71d33fa..a31dedcf1d4 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 8cff76d877b..86b8ac6b29c 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 c360c077efa..5a7dcd18b3d 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 308/398] 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 5a7dcd18b3d..024444396d8 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 309/398] v3.43.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db7fc3cddb9..cdbc545e197 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 310/398] 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 df67db37d2e..2988a3e12f5 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 311/398] Update CHANGELOG.md after v3.43.0 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdbc545e197..e34b0513b8d 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 312/398] 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 00000000000..109278c5337 --- /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 313/398] 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 a31dedcf1d4..33afdc2ff90 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 86b8ac6b29c..ad7be99a5fc 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 024444396d8..58804a13655 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 314/398] 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 7887c5bc242..d7de330e30a 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 a842351ceed..14d7c8704aa 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 315/398] 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 57f3bc183d4..cf9da5e6890 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 defb3271b97..210cb5bdbce 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 2de69cc5bc8..9d1266d5d4c 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 d597c6ead55..fb0a68fce3e 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 e0d4f2a8665..fb58b46640a 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 7b7c9f56fe2..53f729f07fc 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 316/398] Add missing v3.43.0 entries. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e34b0513b8d..bc497f3a719 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 317/398] 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 46c91eac887..7074fabb4c2 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 a6c3210b0f2..0306a36111d 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 8d3b590463b..0faf353cb9f 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 33afdc2ff90..9fd82bd106a 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 ad7be99a5fc..ce9ddd300be 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 58804a13655..55992ca9bf1 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 318/398] 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 00000000000..f520349bd25 --- /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 319/398] 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 9fd82bd106a..b6aecd4fb15 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 ce9ddd300be..59dc3f267df 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 46f5fab6279..dd845329ea1 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 320/398] 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 55992ca9bf1..58f32c6ca92 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 321/398] 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 58f32c6ca92..155eb34a6b9 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 322/398] 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 155eb34a6b9..540a66797ef 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 323/398] 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 59dc3f267df..72f8704e0d8 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 324/398] Update CHANGELOG.md for #19615 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc497f3a719..92bf9e6749d 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 325/398] 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 00000000000..c02aad104ec --- /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 a569d394a81..c667f22507e 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 f2543d6ce26..274be156278 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 b01d4fb2755..8e53c7298ce 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 326/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92bf9e6749d..63b097b10d9 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 e38f478cc5d51c644154eddafbe8d6d642b310c1 Mon Sep 17 00:00:00 2001 From: Erik Paasonen Date: Tue, 1 Jun 2021 21:24:54 -0500 Subject: [PATCH 327/398] 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 cdf681092f3..ddec94b02c7 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 328/398] 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 74aa7ef1b85..fff90aab0c9 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 53a9274a0d2..6823121a15d 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 61e7c068b4e..0d9721a5d86 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 329/398] 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 00000000000..4c3e1cc1dda --- /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 330/398] 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 540a66797ef..5c29b7acf48 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 331/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63b097b10d9..ee8c39a3a3a 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 332/398] 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 00000000000..07d32199b92 --- /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 333/398] 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 00000000000..86efcdc56b8 --- /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 334/398] 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 00000000000..90c53712350 --- /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 335/398] provider: Add new resource --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index 8cdb9f54066..4a1bd2fbeaa 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 336/398] 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 79157804479..d433eeb44b2 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 337/398] 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 03a7f4ef7fe..3eb0a6f8a41 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 338/398] 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 371aa8c8aa5..ca3b480309c 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 8374a859dbd..e4df4eefc6d 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 339/398] 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 d433eeb44b2..0cf7c7496b8 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 340/398] 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 ca3b480309c..338e821b70b 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 341/398] 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 e4df4eefc6d..b388ff87ff6 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 342/398] 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 86efcdc56b8..78996e59c32 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 343/398] 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 07d32199b92..69db6453856 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 344/398] 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 69db6453856..369265f3010 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 345/398] 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 369265f3010..546cff58622 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 346/398] 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 0faf353cb9f..5d5e6c63596 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 b6aecd4fb15..9fd82bd106a 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 72f8704e0d8..4f5cef5185e 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 347/398] 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 00000000000..6d33e373969 --- /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 348/398] 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 d8b8db7bc8e..90f3ea3ccfe 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 349/398] 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 71e2a863782..a8b29de52c5 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 350/398] 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 6bc38d756ed..730a57020da 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 351/398] 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 349cf26cabc..319119e0a6b 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 352/398] 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 b3a798b5a3b..63adb8775b1 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 353/398] 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 b767586f25d..cdd73138c82 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 354/398] 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 008ef7b58d3..05ab38d337f 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 355/398] 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 bd7d153e6b1..f3ed7fa89ae 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 356/398] 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 fe692427ef1..e73856735e2 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 357/398] 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 7d4d4179999..135b8ff70fe 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 358/398] 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 4dce2bcb5b2..cff401e65e7 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 359/398] 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 2f12c649afc..97375e835aa 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 360/398] 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 62afd2a22d8..e4dd573a85a 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 361/398] 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 9fd82bd106a..63dfd74d475 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 4f5cef5185e..68c0cf84c46 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 dd845329ea1..1cb2d189394 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 362/398] 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 546cff58622..3099cbef5ee 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 363/398] 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 78996e59c32..2d2737c0e0e 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 364/398] 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 74644d5b341..20522207ac2 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 365/398] 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 f81472914ae..66843c5fbe4 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 366/398] 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 68c0cf84c46..7a39ead43f4 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 1cb2d189394..40e0e19383c 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 367/398] Update CHANGELOG.md for #19470 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee8c39a3a3a..09907417efe 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 368/398] 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 63dfd74d475..d63bc5a2dbe 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 7a39ead43f4..98cdd23665a 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 40e0e19383c..de678a4c999 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 5c29b7acf48..38a78617f55 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 369/398] 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 98cdd23665a..3ba7103ddfd 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 de678a4c999..03e39da1c05 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 370/398] 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 cf9da5e6890..9ef40ef59bc 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 210cb5bdbce..bbdc129029c 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 fb58b46640a..7d0c72aea7b 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 53f729f07fc..a1510d3c78d 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 371/398] 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 d7de330e30a..dd113710b11 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 14d7c8704aa..2afd4dc501a 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 372/398] 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 f520349bd25..106a416f8af 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 963fffb1269..b28d2ba0120 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 373/398] 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 c4d7bc8c525..d56a0ab1b59 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 6b7f79deb07..e7ff3eb4ac4 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 f99ce052dba..ac2fed58bfd 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 374/398] 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 00000000000..bcced089034 --- /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 375/398] 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 bcced089034..12cd701def3 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 76b673b4eb5..88acbc0a0d3 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 d56a0ab1b59..f111f6e76be 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 1fb1edfa3cf..33c7ea4dd73 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 376/398] 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 634dc59fcb2..b5208464a57 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 377/398] 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 4fd4105c563..74fd8c21cb9 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 00000000000..4707d8682e4 --- /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 00000000000..08a9a8c1694 --- /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 00000000000..5c67836e90b --- /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 378/398] 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 5c67836e90b..e166b6cdcbc 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 379/398] 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 03e39da1c05..a796ea1f63c 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 4707d8682e4..b8414fbded2 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 08a9a8c1694..ef4372f693b 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 e166b6cdcbc..2a0ea85bb96 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 380/398] 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 00000000000..7555c387a8c --- /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 381/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09907417efe..d3b62cfddd2 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 382/398] Spelling correction. --- .changelog/11937.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/11937.txt b/.changelog/11937.txt index 106a416f8af..9da502923d7 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 383/398] 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 7074fabb4c2..ec468523b9f 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 a796ea1f63c..c238c783c87 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 b8414fbded2..fe66597b64d 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 ef4372f693b..18beddc6fb4 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 384/398] 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 74fd8c21cb9..20a1170763a 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 00000000000..51d675f05df --- /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 00000000000..f655bba7950 --- /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 00000000000..67aec0bf3f1 --- /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 385/398] 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 67aec0bf3f1..123c2f6d669 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 386/398] 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 51d675f05df..8453aed28e6 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 f655bba7950..b1d1f6b43df 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 123c2f6d669..9134f6112b8 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 387/398] 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 03760b4ff8f..5aa0a23b7fb 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 a70cf67696a..7c03fe24038 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 8eef7bed53c..f436c240284 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 74fd8c21cb9..f3af9ac1651 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 4f27b2b8ff1..b63fdee1ee2 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 79d5df82be0..1a9b7232940 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 edad3b4262e..36c49148049 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 388/398] 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 ec468523b9f..9440c53a1f0 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 0306a36111d..20bb749cbb0 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 00000000000..49be5ec89c8 --- /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 00000000000..d9b007c8450 --- /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 baa733d20a5..703eb55aa7d 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 8453aed28e6..4e36c21ac40 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 b1d1f6b43df..44d9af61d56 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 9134f6112b8..51c5d3cd8fb 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 3d9d57b5448bb20efafe1099f015666041707fdb Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Jun 2021 13:57:16 -0400 Subject: [PATCH 389/398] 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 4e36c21ac40..64e4334e340 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 44d9af61d56..c9373860483 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 c238c783c87..a4a397bca94 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 390/398] 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 00000000000..29730594689 --- /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 391/398] 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 d9b007c8450..08abc2675ac 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 64e4334e340..f1d7f2a86c6 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 c9373860483..701e197546b 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 a4a397bca94..d4b48560d04 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 2a8d9b3c474..bb36731efe7 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 392/398] 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 701e197546b..6e3a8f4095a 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 393/398] 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 6e3a8f4095a..2ffe7d1d0a2 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 394/398] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3b62cfddd2..324acdc5b62 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 395/398] 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 0a645db0a8d..749becf9958 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 6ee21570cbd..2f0b4045e50 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 396/398] 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 00000000000..3e8303887fb --- /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 397/398] Update CHANGELOG.md for #19654 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 324acdc5b62..2e7f0034b4d 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 c16ad68fc0b64ca6c4ae2a4eea981e38eca0dbf9 Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Thu, 3 Jun 2021 22:06:58 +0000 Subject: [PATCH 398/398] v3.44.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e7f0034b4d..5cebc142d93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 3.44.0 (Unreleased) +## 3.44.0 (June 03, 2021) FEATURES: