From f2810d9a0a8cc2dec937bcd1c523fc3ec7f8fc90 Mon Sep 17 00:00:00 2001 From: "Ian C. Ward" Date: Thu, 17 May 2018 11:47:21 -0400 Subject: [PATCH 001/684] r/lb_target_group health chk proto chg req taint Notify users of TCP lb target groups that changes to health check protocol require the user to taint the resource and let terraform re-create it. This commit Fixes #4150. --- aws/resource_aws_lb_target_group.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index 78d9be0053a..26a750518f1 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -631,6 +631,12 @@ func resourceAwsLbTargetGroupCustomizeDiff(diff *schema.ResourceDiff, v interfac } if protocol == "TCP" { + if diff.HasChange("health_check.0.protocol") { + old, new := diff.GetChange("protocol") + return fmt.Errorf("Health check protocol cannot be updated from %d to %d for TCP based Target Group %s"+ + " use 'terraform taint' to recreate the resource if you wish", + old, new, diff.Id()) + } if diff.HasChange("health_check.0.interval") { old, new := diff.GetChange("health_check.0.interval") return fmt.Errorf("Health check interval cannot be updated from %d to %d for TCP based Target Group %s,"+ From 79178bef8828ee7631d22c9b0d92badf942c2db1 Mon Sep 17 00:00:00 2001 From: "Ian C. Ward" Date: Thu, 17 May 2018 12:12:53 -0400 Subject: [PATCH 002/684] Fix diff.GetChange on previous commit The message needs to indicate the change to the health check protocol, not the LB listener protocol --- aws/resource_aws_lb_target_group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index 26a750518f1..e8220a300cc 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -632,7 +632,7 @@ func resourceAwsLbTargetGroupCustomizeDiff(diff *schema.ResourceDiff, v interfac if protocol == "TCP" { if diff.HasChange("health_check.0.protocol") { - old, new := diff.GetChange("protocol") + old, new := diff.GetChange("health_check.0.protocol") return fmt.Errorf("Health check protocol cannot be updated from %d to %d for TCP based Target Group %s"+ " use 'terraform taint' to recreate the resource if you wish", old, new, diff.Id()) From a7985ff7a92c29f5d927424f49e32d34a8cd878b Mon Sep 17 00:00:00 2001 From: "Ian C. Ward" Date: Thu, 21 Jun 2018 21:25:54 -0400 Subject: [PATCH 003/684] r/aws_lb_target_group: use diff.ForceNew --- aws/resource_aws_lb_target_group.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index 3ba9e9e9e4f..5687e2de333 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -663,24 +663,23 @@ func resourceAwsLbTargetGroupCustomizeDiff(diff *schema.ResourceDiff, v interfac return nil } + // changes to health checks on TCP load balancers (network LBs) require destroy and re-create + // do note this will probably take your service down... if protocol == "TCP" { if diff.HasChange("health_check.0.protocol") { - old, new := diff.GetChange("health_check.0.protocol") - return fmt.Errorf("Health check protocol cannot be updated from %d to %d for TCP based Target Group %s"+ - " use 'terraform taint' to recreate the resource if you wish", - old, new, diff.Id()) + if err := diff.ForceNew("health_check.0.protocol"); err != nil { + return err + } } if diff.HasChange("health_check.0.interval") { - old, new := diff.GetChange("health_check.0.interval") - return fmt.Errorf("Health check interval cannot be updated from %d to %d for TCP based Target Group %s,"+ - " use 'terraform taint' to recreate the resource if you wish", - old, new, diff.Id()) + if err := diff.ForceNew("health_check.0.interval"); err != nil { + return err + } } if diff.HasChange("health_check.0.timeout") { - old, new := diff.GetChange("health_check.0.timeout") - return fmt.Errorf("Health check timeout cannot be updated from %d to %d for TCP based Target Group %s,"+ - " use 'terraform taint' to recreate the resource if you wish", - old, new, diff.Id()) + if err := diff.ForceNew("health_check.0.timeout"); err != nil { + return err + } } } return nil From eda23c7d6f2a456661aa1375f5edc032d071462c Mon Sep 17 00:00:00 2001 From: hawknewton Date: Wed, 16 Jan 2019 20:10:44 -0800 Subject: [PATCH 004/684] Add dms_event_subscription resource --- aws/provider.go | 1 + aws/resource_aws_dms_event_subscription.go | 251 ++++++++++++++++++ ...esource_aws_dms_event_subscription_test.go | 247 +++++++++++++++++ .../r/dms_event_subscription.html.markdown | 59 ++++ 4 files changed, 558 insertions(+) create mode 100644 aws/resource_aws_dms_event_subscription.go create mode 100644 aws/resource_aws_dms_event_subscription_test.go create mode 100644 website/docs/r/dms_event_subscription.html.markdown diff --git a/aws/provider.go b/aws/provider.go index a26572f72c9..62c30b03085 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -404,6 +404,7 @@ func Provider() terraform.ResourceProvider { "aws_dlm_lifecycle_policy": resourceAwsDlmLifecyclePolicy(), "aws_dms_certificate": resourceAwsDmsCertificate(), "aws_dms_endpoint": resourceAwsDmsEndpoint(), + "aws_dms_event_subscription": resourceAwsDmsEventSubscription(), "aws_dms_replication_instance": resourceAwsDmsReplicationInstance(), "aws_dms_replication_subnet_group": resourceAwsDmsReplicationSubnetGroup(), "aws_dms_replication_task": resourceAwsDmsReplicationTask(), diff --git a/aws/resource_aws_dms_event_subscription.go b/aws/resource_aws_dms_event_subscription.go new file mode 100644 index 00000000000..822f2167bc9 --- /dev/null +++ b/aws/resource_aws_dms_event_subscription.go @@ -0,0 +1,251 @@ +package aws + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + dms "github.com/aws/aws-sdk-go/service/databasemigrationservice" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsDmsEventSubscription() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsDmsEventSubscriptionCreate, + Read: resourceAwsDmsEventSubscriptionRead, + Update: resourceAwsDmsEventSubscriptionUpdate, + Delete: resourceAwsDmsEventSubscriptionDelete, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + }, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "event_categories": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "sns_topic_arn": { + Type: schema.TypeString, + Required: true, + }, + "source_ids": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + ForceNew: true, + Optional: true, + }, + "source_type": { + Type: schema.TypeString, + Optional: true, + // The API suppors modification but doing so loses all source_ids + ForceNew: true, + }, + "tags": { + Type: schema.TypeMap, + Optional: true, + }, + }, + } +} + +func resourceAwsDmsEventSubscriptionCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dmsconn + + request := &dms.CreateEventSubscriptionInput{ + Enabled: aws.Bool(d.Get("enabled").(bool)), + SnsTopicArn: aws.String(d.Get("sns_topic_arn").(string)), + SubscriptionName: aws.String(d.Get("name").(string)), + SourceType: aws.String(d.Get("source_type").(string)), + Tags: dmsTagsFromMap(d.Get("tags").(map[string]interface{})), + } + + if v, ok := d.GetOk("event_categories"); ok { + request.EventCategories = expandStringList(v.(*schema.Set).List()) + } + + if v, ok := d.GetOk("source_ids"); ok { + request.SourceIds = expandStringList(v.(*schema.Set).List()) + } + + _, err := conn.CreateEventSubscription(request) + + if err != nil { + return fmt.Errorf("Error creating DMS event subscription: %s", err) + } + + d.SetId(d.Get("name").(string)) + + log.Println("[DEBUG] DMS create event subscription", request) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"creating", "modifying"}, + Target: []string{"active"}, + Refresh: resourceAwsDmsEventSubscriptionStateRefreshFunc(conn, d.Id()), + Timeout: d.Timeout(schema.TimeoutCreate), + MinTimeout: 10 * time.Second, + Delay: 10 * time.Second, + } + + // Wait, catching any errors + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("error waiting for DMS event subscription (%s) creation: %s", d.Id(), err) + } + + return resourceAwsDmsEventSubscriptionUpdate(d, meta) +} + +func resourceAwsDmsEventSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dmsconn + + request := &dms.ModifyEventSubscriptionInput{ + Enabled: aws.Bool(d.Get("enabled").(bool)), + SnsTopicArn: aws.String(d.Get("sns_topic_arn").(string)), + SubscriptionName: aws.String(d.Get("name").(string)), + SourceType: aws.String(d.Get("source_type").(string)), + } + + if v, ok := d.GetOk("event_categories"); ok { + request.EventCategories = expandStringList(v.(*schema.Set).List()) + } + + log.Println("[DEBUG] DMS update event subscription:", request) + + _, err := conn.ModifyEventSubscription(request) + + if err != nil { + return fmt.Errorf("Error updating DMS event subscription: %s", err) + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"modifying"}, + Target: []string{"active"}, + Refresh: resourceAwsDmsEventSubscriptionStateRefreshFunc(conn, d.Id()), + Timeout: d.Timeout(schema.TimeoutCreate), + MinTimeout: 10 * time.Second, + Delay: 10 * time.Second, // Wait 30 secs before starting + } + + // Wait, catching any errors + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("error waiting for DMS event subscription (%s) modification: %s", d.Id(), err) + } + + return resourceAwsDmsEventSubscriptionRead(d, meta) +} + +func resourceAwsDmsEventSubscriptionRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dmsconn + + request := &dms.DescribeEventSubscriptionsInput{ + SubscriptionName: aws.String(d.Id()), + } + + log.Println("[DEBUG] DMS read event subscription:", request) + + response, err := conn.DescribeEventSubscriptions(request) + + if isAWSErr(err, dms.ErrCodeResourceNotFoundFault, "") { + log.Printf("[WARN] DMS event subscription (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("Error reading DMS event subscription: %s", err) + } + + if response == nil || response.EventSubscriptionsList == nil || len(response.EventSubscriptionsList) == 0 { + log.Printf("[WARN] DMS event subscription (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + subscription := response.EventSubscriptionsList[0] + + d.Set("enabled", subscription.Enabled) + d.Set("sns_topic_arn", subscription.SnsTopicArn) + d.Set("source_type", subscription.SourceType) + d.Set("name", d.Id()) + d.Set("event_categories", flattenStringList(subscription.EventCategoriesList)) + d.Set("source_ids", flattenStringList(subscription.SourceIdsList)) + + return nil +} + +func resourceAwsDmsEventSubscriptionDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dmsconn + + request := &dms.DeleteEventSubscriptionInput{ + SubscriptionName: aws.String(d.Get("name").(string)), + } + + log.Println("[DEBUG] DMS event subscription delete:", request) + + _, err := conn.DeleteEventSubscription(request) + + if err != nil { + return fmt.Errorf("Error deleting DMS event subscription: %s", err) + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"deleting"}, + Target: []string{}, + Refresh: resourceAwsDmsEventSubscriptionStateRefreshFunc(conn, d.Id()), + Timeout: d.Timeout(schema.TimeoutCreate), + MinTimeout: 10 * time.Second, + Delay: 10 * time.Second, + } + + // Wait, catching any errors + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("error waiting for DMS event subscription (%s) deletion: %s", d.Id(), err) + } + + return nil +} + +func resourceAwsDmsEventSubscriptionStateRefreshFunc(conn *dms.DatabaseMigrationService, name string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + v, err := conn.DescribeEventSubscriptions(&dms.DescribeEventSubscriptionsInput{ + SubscriptionName: aws.String(name), + }) + + if isAWSErr(err, dms.ErrCodeResourceNotFoundFault, "") { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + if v == nil || len(v.EventSubscriptionsList) == 0 || v.EventSubscriptionsList[0] == nil { + return nil, "", nil + } + + return v, aws.StringValue(v.EventSubscriptionsList[0].Status), nil + } +} diff --git a/aws/resource_aws_dms_event_subscription_test.go b/aws/resource_aws_dms_event_subscription_test.go new file mode 100644 index 00000000000..1238abc1389 --- /dev/null +++ b/aws/resource_aws_dms_event_subscription_test.go @@ -0,0 +1,247 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + dms "github.com/aws/aws-sdk-go/service/databasemigrationservice" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSDmsEventSubscriptionBasic(t *testing.T) { + resourceName := "aws_dms_event_subscription.dms_event_subscription" + randId := acctest.RandString(8) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: dmsEventSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: dmsEventSubscriptionConfig(randId), + Check: resource.ComposeTestCheckFunc( + checkDmsEventSubscriptionExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-dmses-%s", randId)), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "source_type", "replication-task"), + resource.TestCheckResourceAttr(resourceName, "event_categories.#", "2"), + resource.TestCheckResourceAttr(resourceName, "event_categories.1475249524", "creation"), + resource.TestCheckResourceAttr(resourceName, "event_categories.563807169", "failure"), + + resource.TestCheckResourceAttr(resourceName, "source_ids.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "sns_topic_arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: dmsEventSubscriptionUpdate(randId), + Check: resource.ComposeTestCheckFunc( + checkDmsEventSubscriptionExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-dmses-%s", randId)), + resource.TestCheckResourceAttr(resourceName, "enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "source_type", "replication-task"), + resource.TestCheckResourceAttr(resourceName, "event_categories.#", "2"), + resource.TestCheckResourceAttr(resourceName, "event_categories.2890955135", "configuration change"), + resource.TestCheckResourceAttr(resourceName, "event_categories.769513765", "deletion"), + + resource.TestCheckResourceAttr(resourceName, "source_ids.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "sns_topic_arn"), + ), + }, + }, + }, + ) +} + +func dmsEventSubscriptionDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_dms_event_subscription" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).dmsconn + + resp, err := conn.DescribeEventSubscriptions(&dms.DescribeEventSubscriptionsInput{ + SubscriptionName: aws.String(rs.Primary.ID), + }) + + if isAWSErr(err, dms.ErrCodeResourceNotFoundFault, "") { + continue + } + + if err != nil { + return err + } + + if resp != nil && len(resp.EventSubscriptionsList) > 0 { + return fmt.Errorf("DMS event subscription still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func dmsEventSubscriptionBaseConfig(randId string) string { + + return fmt.Sprintf(` + resource "aws_vpc" "dms_vpc" { + cidr_block = "10.1.0.0/16" + + tags = { + Name = "terraform-testacc-dmses-%[1]s" + } + } + + resource "aws_subnet" "dms_subnet_1" { + cidr_block = "10.1.1.0/24" + availability_zone = "us-west-2a" + vpc_id = "${aws_vpc.dms_vpc.id}" + + tags = { + Name = "tf-acc-dmses-1-%[1]s" + } + + depends_on = ["aws_vpc.dms_vpc"] + } + + resource "aws_subnet" "dms_subnet_2" { + cidr_block = "10.1.2.0/24" + availability_zone = "us-west-2b" + vpc_id = "${aws_vpc.dms_vpc.id}" + + tags = { + Name = "tf-acc-dmses-2-%[1]s" + } + + depends_on = ["aws_vpc.dms_vpc"] + } + + resource "aws_dms_endpoint" "dms_endpoint_source" { + database_name = "tf-test-dms-db" + endpoint_id = "tf-test-dmses-source-%[1]s" + endpoint_type = "source" + engine_name = "aurora" + server_name = "tf-test-cluster.cluster-xxxxxxx.us-west-2.rds.amazonaws.com" + port = 3306 + username = "tftest" + password = "tftest" + } + + resource "aws_dms_endpoint" "dms_endpoint_target" { + database_name = "tf-test-dms-db" + endpoint_id = "tf-test-dmses-target-%[1]s" + endpoint_type = "target" + engine_name = "aurora" + server_name = "tf-test-cluster.cluster-xxxxxxx.us-west-2.rds.amazonaws.com" + port = 3306 + username = "tftest" + password = "tftest" + } + + resource "aws_dms_replication_subnet_group" "dms_replication_subnet_group" { + replication_subnet_group_id = "tf-test-dmses-%[1]s" + replication_subnet_group_description = "terraform test for replication subnet group" + subnet_ids = ["${aws_subnet.dms_subnet_1.id}", "${aws_subnet.dms_subnet_2.id}"] + } + + resource "aws_dms_replication_instance" "dms_replication_instance" { + allocated_storage = 5 + auto_minor_version_upgrade = true + replication_instance_class = "dms.t2.micro" + replication_instance_id = "tf-test-dmses-%[1]s" + preferred_maintenance_window = "sun:00:30-sun:02:30" + publicly_accessible = false + replication_subnet_group_id = "${aws_dms_replication_subnet_group.dms_replication_subnet_group.replication_subnet_group_id}" + } + + resource "aws_dms_replication_task" "dms_replication_task" { + migration_type = "full-load" + replication_instance_arn = "${aws_dms_replication_instance.dms_replication_instance.replication_instance_arn}" + replication_task_id = "tf-test-dmses-%[1]s" + replication_task_settings = "{\"TargetMetadata\":{\"TargetSchema\":\"\",\"SupportLobs\":true,\"FullLobMode\":false,\"LobChunkSize\":0,\"LimitedSizeLobMode\":true,\"LobMaxSize\":32,\"InlineLobMaxSize\":0,\"LoadMaxFileSize\":0,\"ParallelLoadThreads\":0,\"ParallelLoadBufferSize\":0,\"BatchApplyEnabled\":false,\"TaskRecoveryTableEnabled\":false},\"FullLoadSettings\":{\"TargetTablePrepMode\":\"DROP_AND_CREATE\",\"CreatePkAfterFullLoad\":false,\"StopTaskCachedChangesApplied\":false,\"StopTaskCachedChangesNotApplied\":false,\"MaxFullLoadSubTasks\":8,\"TransactionConsistencyTimeout\":600,\"CommitRate\":10000},\"Logging\":{\"EnableLogging\":false,\"LogComponents\":[{\"Id\":\"SOURCE_UNLOAD\",\"Severity\":\"LOGGER_SEVERITY_DEFAULT\"},{\"Id\":\"TARGET_LOAD\",\"Severity\":\"LOGGER_SEVERITY_DEFAULT\"},{\"Id\":\"SOURCE_CAPTURE\",\"Severity\":\"LOGGER_SEVERITY_DEFAULT\"},{\"Id\":\"TARGET_APPLY\",\"Severity\":\"LOGGER_SEVERITY_DEFAULT\"},{\"Id\":\"TASK_MANAGER\",\"Severity\":\"LOGGER_SEVERITY_DEFAULT\"}],\"CloudWatchLogGroup\":null,\"CloudWatchLogStream\":null},\"ControlTablesSettings\":{\"historyTimeslotInMinutes\":5,\"ControlSchema\":\"\",\"HistoryTimeslotInMinutes\":5,\"HistoryTableEnabled\":false,\"SuspendedTablesTableEnabled\":false,\"StatusTableEnabled\":false},\"StreamBufferSettings\":{\"StreamBufferCount\":3,\"StreamBufferSizeInMB\":8,\"CtrlStreamBufferSizeInMB\":5},\"ChangeProcessingDdlHandlingPolicy\":{\"HandleSourceTableDropped\":true,\"HandleSourceTableTruncated\":true,\"HandleSourceTableAltered\":true},\"ErrorBehavior\":{\"DataErrorPolicy\":\"LOG_ERROR\",\"DataTruncationErrorPolicy\":\"LOG_ERROR\",\"DataErrorEscalationPolicy\":\"SUSPEND_TABLE\",\"DataErrorEscalationCount\":0,\"TableErrorPolicy\":\"SUSPEND_TABLE\",\"TableErrorEscalationPolicy\":\"STOP_TASK\",\"TableErrorEscalationCount\":0,\"RecoverableErrorCount\":-1,\"RecoverableErrorInterval\":5,\"RecoverableErrorThrottling\":true,\"RecoverableErrorThrottlingMax\":1800,\"ApplyErrorDeletePolicy\":\"IGNORE_RECORD\",\"ApplyErrorInsertPolicy\":\"LOG_ERROR\",\"ApplyErrorUpdatePolicy\":\"LOG_ERROR\",\"ApplyErrorEscalationPolicy\":\"LOG_ERROR\",\"ApplyErrorEscalationCount\":0,\"ApplyErrorFailOnTruncationDdl\":false,\"FullLoadIgnoreConflicts\":true,\"FailOnTransactionConsistencyBreached\":false,\"FailOnNoTablesCaptured\":false},\"ChangeProcessingTuning\":{\"BatchApplyPreserveTransaction\":true,\"BatchApplyTimeoutMin\":1,\"BatchApplyTimeoutMax\":30,\"BatchApplyMemoryLimit\":500,\"BatchSplitSize\":0,\"MinTransactionSize\":1000,\"CommitTimeout\":1,\"MemoryLimitTotal\":1024,\"MemoryKeepTime\":60,\"StatementCacheSize\":50}}" + source_endpoint_arn = "${aws_dms_endpoint.dms_endpoint_source.endpoint_arn}" + table_mappings = "{\"rules\":[{\"rule-type\":\"selection\",\"rule-id\":\"1\",\"rule-name\":\"1\",\"object-locator\":{\"schema-name\":\"%%\",\"table-name\":\"%%\"},\"rule-action\":\"include\"}]}" + + tags = { + Name = "tf-test-dmses-%[1]s" + Update = "to-update" + Remove = "to-remove" + } + + target_endpoint_arn = "${aws_dms_endpoint.dms_endpoint_target.endpoint_arn}" + } + + resource "aws_sns_topic" "topic" { + name = "tf-test-dmses-%[1]s" + } + `, randId) +} + +func dmsEventSubscriptionConfig(randId string) string { + return fmt.Sprintf(` + +resource "aws_dms_event_subscription" "dms_event_subscription" { + name = "tf-test-dmses-%[1]s" + enabled = true + event_categories = ["creation", "failure"] + source_type = "replication-task" + source_ids = ["${aws_dms_replication_task.dms_replication_task.replication_task_id}"] + sns_topic_arn = "${aws_sns_topic.topic.arn}" +} + +%[2]s +`, randId, dmsEventSubscriptionBaseConfig(randId)) + +} + +func dmsEventSubscriptionUpdate(randId string) string { + return fmt.Sprintf(` + +resource "aws_dms_event_subscription" "dms_event_subscription" { + name = "tf-test-dmses-%[1]s" + enabled = false + event_categories = ["deletion", "configuration change"] + source_type = "replication-task" + source_ids = ["${aws_dms_replication_task.dms_replication_task.replication_task_id}"] + sns_topic_arn = "${aws_sns_topic.topic.arn}" +} + +%[2]s +`, randId, dmsEventSubscriptionBaseConfig(randId)) + +} + +func checkDmsEventSubscriptionExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).dmsconn + resp, err := conn.DescribeEventSubscriptions(&dms.DescribeEventSubscriptionsInput{ + SubscriptionName: aws.String(rs.Primary.ID), + }) + + if err != nil { + return fmt.Errorf("DMS event subscription error: %v", err) + } + + if resp.EventSubscriptionsList == nil || len(resp.EventSubscriptionsList) == 0 { + return fmt.Errorf("DMS event subscription not found") + } + + return nil + } +} diff --git a/website/docs/r/dms_event_subscription.html.markdown b/website/docs/r/dms_event_subscription.html.markdown new file mode 100644 index 00000000000..8cbc6941149 --- /dev/null +++ b/website/docs/r/dms_event_subscription.html.markdown @@ -0,0 +1,59 @@ +--- +layout: "aws" +page_title: "AWS: aws_dms_event_subscription" +sidebar_current: "docs-aws-resource-dms-event-subscription" +description: |- + Provides a DMS (Data Migration Service) event subscription resource. +--- + +# aws_dms_event_subscription + +Provides a DMS (Data Migration Service) event subscription resource. DMS event subscriptions can be created, updated, deleted, and imported. + +## Example Usage + +```hcl +# Create a new DMS event subscription +resource "aws_dms_event_subscription" "test" { + name = "my-favorite-event-subscription" + enabled = true + event_categories = ["creation", "failure"] + source_type = "replication-task" + source_ids = ["${aws_dms_replication_task.dms_replication_task.replication_task_id}"] + sns_topic_arn = "${aws_sns_topic.topic.arn}" +} + + tags = { + Name = "test" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Name of event subscription. +* `enabled` - (Optional, Default: true) Whether the event subscription should be enabled. +* `event_categories` - (Optional) List of event categories to listen for, see `DescribeEventCategories` for a canonical list. +* `source_type` - (Optional, Default: all events) If specificed may be either `replication-instance` or `migration-task` +* `source_ids` - (Required) Ids of sources to listen to. +* `sns_topic_arn` - (Required) SNS topic arn to send events on. + + +## Timeouts + +`aws_dms_event_subscription` provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - (Default `30 minutes`) Used for creating event subscriptions. +- `update` - (Default `30 minutes`) Used for event subscription modifications. +- `delete` - (Default `30 minutes`) Used for destroying event descriptions. + +## Import + +Event subscriptions can be imported using the `name`, e.g. + +``` +$ terraform import aws_dms_event_subscription.test my-awesome-event-subscription +``` From 150c6e41598045fb62cd13b94dba8ae941c52ad3 Mon Sep 17 00:00:00 2001 From: jbergknoff Date: Tue, 14 May 2019 13:52:40 -0500 Subject: [PATCH 005/684] aws_dms_endpoint: Add support for Kinesis target endpoint --- aws/resource_aws_dms_endpoint.go | 94 ++++++++++++++ aws/resource_aws_dms_endpoint_test.go | 173 +++++++++++++++++++++++++- 2 files changed, 265 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_dms_endpoint.go b/aws/resource_aws_dms_endpoint.go index 0a43316fcb1..470fb7e39cc 100644 --- a/aws/resource_aws_dms_endpoint.go +++ b/aws/resource_aws_dms_endpoint.go @@ -67,6 +67,7 @@ func resourceAwsDmsEndpoint() *schema.Resource { "azuredb", "docdb", "dynamodb", + "kinesis", "mariadb", "mongodb", "mysql", @@ -139,16 +140,34 @@ func resourceAwsDmsEndpoint() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "PASSWORD", + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if strings.ToLower(old) == strings.ToLower(new) { + return true + } + return false + }, }, "auth_mechanism": { Type: schema.TypeString, Optional: true, Default: "DEFAULT", + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if strings.ToLower(old) == strings.ToLower(new) { + return true + } + return false + }, }, "nesting_level": { Type: schema.TypeString, Optional: true, Default: "NONE", + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if strings.ToLower(old) == strings.ToLower(new) { + return true + } + return false + }, }, "extract_doc_id": { Type: schema.TypeString, @@ -218,6 +237,39 @@ func resourceAwsDmsEndpoint() *schema.Resource { }, }, }, + "kinesis_settings": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if old == "1" && new == "0" { + return true + } + return false + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "message_format": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "JSON", + }, false), + Default: "JSON", + }, + "service_access_role_arn": { + Type: schema.TypeString, + Optional: true, + Default: "", + }, + "stream_arn": { + Type: schema.TypeString, + Optional: true, + Default: "", + }, + }, + }, + }, }, } } @@ -238,6 +290,12 @@ func resourceAwsDmsEndpointCreate(d *schema.ResourceData, meta interface{}) erro request.DynamoDbSettings = &dms.DynamoDbSettings{ ServiceAccessRoleArn: aws.String(d.Get("service_access_role").(string)), } + case "kinesis": + request.KinesisSettings = &dms.KinesisSettings{ + MessageFormat: aws.String(d.Get("kinesis_settings.0.message_format").(string)), + ServiceAccessRoleArn: aws.String(d.Get("kinesis_settings.0.service_access_role_arn").(string)), + StreamArn: aws.String(d.Get("kinesis_settings.0.stream_arn").(string)), + } case "mongodb": request.MongoDbSettings = &dms.MongoDbSettings{ Username: aws.String(d.Get("username").(string)), @@ -413,6 +471,19 @@ func resourceAwsDmsEndpointUpdate(d *schema.ResourceData, meta interface{}) erro } hasChanges = true } + case "kinesis": + if d.HasChange("kinesis_settings.0.service_access_role_arn") || + d.HasChange("kinesis_settings.0.stream_arn") { + // Intentionally omitting MessageFormat, because it's rejected on ModifyEndpoint calls. + // "An error occurred (InvalidParameterValueException) when calling the ModifyEndpoint + // operation: Message format cannot be modified for kinesis endpoints." + request.KinesisSettings = &dms.KinesisSettings{ + ServiceAccessRoleArn: aws.String(d.Get("kinesis_settings.0.service_access_role_arn").(string)), + StreamArn: aws.String(d.Get("kinesis_settings.0.stream_arn").(string)), + } + request.EngineName = aws.String(d.Get("engine_name").(string)) // Must be included (should be 'kinesis') + hasChanges = true + } case "mongodb": if d.HasChange("username") || d.HasChange("password") || @@ -542,6 +613,10 @@ func resourceAwsDmsEndpointSetState(d *schema.ResourceData, endpoint *dms.Endpoi } else { d.Set("service_access_role", "") } + case "kinesis": + if err := d.Set("kinesis_settings", flattenDmsKinesisSettings(endpoint.KinesisSettings)); err != nil { + return fmt.Errorf("Error setting kinesis_settings for DMS: %s", err) + } case "mongodb": if endpoint.MongoDbSettings != nil { d.Set("username", endpoint.MongoDbSettings.Username) @@ -589,6 +664,11 @@ func flattenDmsMongoDbSettings(settings *dms.MongoDbSettings) []map[string]inter "auth_source": aws.StringValue(settings.AuthSource), } + // The DMS API returns "scram-sha-1", cf. https://github.com/aws/aws-sdk-go/issues/2522 + if *settings.AuthMechanism == "scram-sha-1" { + m["auth_mechanism"] = "scram_sha_1" + } + return []map[string]interface{}{m} } @@ -609,3 +689,17 @@ func flattenDmsS3Settings(settings *dms.S3Settings) []map[string]interface{} { return []map[string]interface{}{m} } + +func flattenDmsKinesisSettings(settings *dms.KinesisSettings) []map[string]interface{} { + if settings == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "message_format": aws.StringValue(settings.MessageFormat), + "service_access_role_arn": aws.StringValue(settings.ServiceAccessRoleArn), + "stream_arn": aws.StringValue(settings.StreamArn), + } + + return []map[string]interface{}{m} +} diff --git a/aws/resource_aws_dms_endpoint_test.go b/aws/resource_aws_dms_endpoint_test.go index e95fe61c05f..9a0ed116208 100644 --- a/aws/resource_aws_dms_endpoint_test.go +++ b/aws/resource_aws_dms_endpoint_test.go @@ -128,6 +128,43 @@ func TestAccAwsDmsEndpointDynamoDb(t *testing.T) { }) } +func TestAccAwsDmsEndpointKinesis(t *testing.T) { + resourceName := "aws_dms_endpoint.dms_endpoint" + randId := acctest.RandString(8) + "-kinesis" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: dmsEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: dmsEndpointKinesisConfig(randId), + Check: resource.ComposeTestCheckFunc( + checkDmsEndpointExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "kinesis_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "kinesis_settings.0.message_format", "JSON"), + resource.TestCheckResourceAttrPair(resourceName, "kinesis_settings.0.stream_arn", "aws_kinesis_stream.stream1", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password"}, + }, + { + Config: dmsEndpointKinesisConfigUpdate(randId), + Check: resource.ComposeTestCheckFunc( + checkDmsEndpointExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "kinesis_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "kinesis_settings.0.message_format", "JSON"), + resource.TestCheckResourceAttrPair(resourceName, "kinesis_settings.0.stream_arn", "aws_kinesis_stream.stream2", "arn"), + ), + }, + }, + }) +} + func TestAccAwsDmsEndpointMongoDb(t *testing.T) { resourceName := "aws_dms_endpoint.dms_endpoint" randId := acctest.RandString(8) + "-mongodb" @@ -162,8 +199,8 @@ func TestAccAwsDmsEndpointMongoDb(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "ssl_mode", "require"), resource.TestCheckResourceAttr(resourceName, "extra_connection_attributes", "key=value;"), resource.TestCheckResourceAttr(resourceName, "mongodb_settings.#", "1"), - resource.TestCheckResourceAttr(resourceName, "mongodb_settings.0.auth_mechanism", "SCRAM_SHA_1"), - resource.TestCheckResourceAttr(resourceName, "mongodb_settings.0.nesting_level", "ONE"), + resource.TestCheckResourceAttr(resourceName, "mongodb_settings.0.auth_mechanism", "scram_sha_1"), + resource.TestCheckResourceAttr(resourceName, "mongodb_settings.0.nesting_level", "one"), resource.TestCheckResourceAttr(resourceName, "mongodb_settings.0.extract_doc_id", "true"), resource.TestCheckResourceAttr(resourceName, "mongodb_settings.0.docs_to_investigate", "1001"), ), @@ -574,6 +611,138 @@ EOF `, randId) } +func dmsEndpointKinesisConfig(randId string) string { + return fmt.Sprintf(` +resource "aws_dms_endpoint" "dms_endpoint" { + endpoint_id = "tf-test-dms-endpoint-%[1]s" + endpoint_type = "target" + engine_name = "kinesis" + kinesis_settings { + service_access_role_arn = "${aws_iam_role.iam_role.arn}" + stream_arn = "${aws_kinesis_stream.stream1.arn}" + } + + depends_on = ["aws_iam_role_policy.dms_kinesis_access"] +} + +resource "aws_kinesis_stream" "stream1" { + name = "tf-test-dms-kinesis-1-%[1]s" + shard_count = 1 +} + +resource "aws_kinesis_stream" "stream2" { + name = "tf-test-dms-kinesis-2-%[1]s" + shard_count = 1 +} + +resource "aws_iam_role" "iam_role" { + name_prefix = "tf-test-iam-kinesis-role" + + assume_role_policy = < Date: Tue, 14 May 2019 13:55:35 -0500 Subject: [PATCH 006/684] docs update --- website/docs/r/dms_endpoint.html.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/r/dms_endpoint.html.markdown b/website/docs/r/dms_endpoint.html.markdown index 3b31d807069..8e81734e15d 100644 --- a/website/docs/r/dms_endpoint.html.markdown +++ b/website/docs/r/dms_endpoint.html.markdown @@ -53,7 +53,7 @@ The following arguments are supported: - Must not contain two consecutive hyphens * `endpoint_type` - (Required) The type of endpoint. Can be one of `source | target`. -* `engine_name` - (Required) The type of engine for the endpoint. Can be one of `aurora | azuredb | docdb | dynamodb | mariadb | mongodb | mysql | oracle | postgres | redshift | s3 | sqlserver | sybase`. +* `engine_name` - (Required) The type of engine for the endpoint. Can be one of `aurora | azuredb | docdb | dynamodb | kinesis | mariadb | mongodb | mysql | oracle | postgres | redshift | s3 | sqlserver | sybase`. * `extra_connection_attributes` - (Optional) Additional attributes associated with the connection. For available attributes see [Using Extra Connection Attributes with AWS Database Migration Service](http://docs.aws.amazon.com/dms/latest/userguide/CHAP_Introduction.ConnectionAttributes.html). * `kms_key_arn` - (Required when `engine_name` is `mongodb`, optional otherwise) The Amazon Resource Name (ARN) for the KMS key that will be used to encrypt the connection parameters. If you do not specify a value for `kms_key_arn`, then AWS DMS will use your default encryption key. AWS KMS creates the default encryption key for your AWS account. Your AWS account has a different default encryption key for each AWS region. * `password` - (Optional) The password to be used to login to the endpoint database. @@ -65,6 +65,7 @@ The following arguments are supported: * `service_access_role` - (Optional) The Amazon Resource Name (ARN) used by the service access IAM role for dynamodb endpoints. * `mongodb_settings` - (Optional) Settings for the source MongoDB endpoint. Available settings are `auth_type` (default: `PASSWORD`), `auth_mechanism` (default: `DEFAULT`), `nesting_level` (default: `NONE`), `extract_doc_id` (default: `false`), `docs_to_investigate` (default: `1000`) and `auth_source` (default: `admin`). For more details, see [Using MongoDB as a Source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MongoDB.html). * `s3_settings` - (Optional) Settings for the target S3 endpoint. Available settings are `service_access_role_arn`, `external_table_definition`, `csv_row_delimiter` (default: `\\n`), `csv_delimiter` (default: `,`), `bucket_folder`, `bucket_name` and `compression_type` (default: `NONE`). For more details, see [Using Amazon S3 as a Target for AWS Database Migration Service](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.S3.html). +* `kinesis_settings` - (Optional) Settings for the target Kinesis endpoint. Available settings are `service_access_role_arn` and `stream_arn`. For more details, see [Using Amazon Kinesis Data Streams as a Target for AWS Database Migration Service](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Kinesis.html). ## Attributes Reference From a7d3ac8db5483f57341db3b6a1fe60f8493a6180 Mon Sep 17 00:00:00 2001 From: jbergknoff Date: Tue, 14 May 2019 14:48:31 -0500 Subject: [PATCH 007/684] fix lint --- aws/resource_aws_dms_endpoint.go | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_dms_endpoint.go b/aws/resource_aws_dms_endpoint.go index 470fb7e39cc..13b9c85f432 100644 --- a/aws/resource_aws_dms_endpoint.go +++ b/aws/resource_aws_dms_endpoint.go @@ -141,10 +141,7 @@ func resourceAwsDmsEndpoint() *schema.Resource { Optional: true, Default: "PASSWORD", DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - if strings.ToLower(old) == strings.ToLower(new) { - return true - } - return false + return strings.EqualFold(old, new) }, }, "auth_mechanism": { @@ -152,10 +149,7 @@ func resourceAwsDmsEndpoint() *schema.Resource { Optional: true, Default: "DEFAULT", DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - if strings.ToLower(old) == strings.ToLower(new) { - return true - } - return false + return strings.EqualFold(old, new) }, }, "nesting_level": { @@ -163,10 +157,7 @@ func resourceAwsDmsEndpoint() *schema.Resource { Optional: true, Default: "NONE", DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - if strings.ToLower(old) == strings.ToLower(new) { - return true - } - return false + return strings.EqualFold(old, new) }, }, "extract_doc_id": { From 643457eef78c1b58961abf0838b70698ef4b1c03 Mon Sep 17 00:00:00 2001 From: jecafarelli Date: Tue, 3 Sep 2019 11:06:58 -0400 Subject: [PATCH 008/684] added in changes for storage gateway to accept a vpc endpoint --- aws/resource_aws_storagegateway_gateway.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/aws/resource_aws_storagegateway_gateway.go b/aws/resource_aws_storagegateway_gateway.go index 4739cb7bf04..c8df8df7517 100644 --- a/aws/resource_aws_storagegateway_gateway.go +++ b/aws/resource_aws_storagegateway_gateway.go @@ -45,6 +45,12 @@ func resourceAwsStorageGatewayGateway() *schema.Resource { ForceNew: true, ConflictsWith: []string{"gateway_ip_address"}, }, + "gateway_vpc_endpoint": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, "gateway_id": { Type: schema.TypeString, Computed: true, @@ -147,6 +153,10 @@ func resourceAwsStorageGatewayGatewayCreate(d *schema.ResourceData, meta interfa } requestURL := fmt.Sprintf("http://%s/?activationRegion=%s", gatewayIpAddress, region) + if v, ok := d.GetOk("gateway_vpc_endpoint"); ok { + requestURL = fmt.Sprintf("%s&vpcEndpoint=%s", requestURL, v.(string)) + } + log.Printf("[DEBUG] Creating HTTP request: %s", requestURL) request, err := http.NewRequest("GET", requestURL, nil) if err != nil { @@ -319,6 +329,7 @@ func resourceAwsStorageGatewayGatewayRead(d *schema.ResourceData, meta interface d.Set("gateway_name", output.GatewayName) d.Set("gateway_timezone", output.GatewayTimezone) d.Set("gateway_type", output.GatewayType) + d.Set("gateway_vpc_endpoint", output.VPCEndpoint) // The Storage Gateway API currently provides no way to read this value // We allow Terraform to passthrough the configuration value into the state From 710e61eccc36f0556eb8832c65528962a1ec329c Mon Sep 17 00:00:00 2001 From: jecafarelli Date: Tue, 3 Sep 2019 11:32:26 -0400 Subject: [PATCH 009/684] updated documentation with new parameter --- website/docs/r/storagegateway_gateway.html.markdown | 3 +++ 1 file changed, 3 insertions(+) diff --git a/website/docs/r/storagegateway_gateway.html.markdown b/website/docs/r/storagegateway_gateway.html.markdown index c188b5e6ba0..37296cd3831 100644 --- a/website/docs/r/storagegateway_gateway.html.markdown +++ b/website/docs/r/storagegateway_gateway.html.markdown @@ -60,6 +60,8 @@ resource "aws_storagegateway_gateway" "example" { } ``` + + ## Argument Reference ~> **NOTE:** One of `activation_key` or `gateway_ip_address` must be provided for resource creation (gateway activation). Neither is required for resource import. If using `gateway_ip_address`, Terraform must be able to make an HTTP (port 80) GET request to the specified IP address from where it is running. @@ -71,6 +73,7 @@ The following arguments are supported: * `activation_key` - (Optional) Gateway activation key during resource creation. Conflicts with `gateway_ip_address`. Additional information is available in the [Storage Gateway User Guide](https://docs.aws.amazon.com/storagegateway/latest/userguide/get-activation-key.html). * `gateway_ip_address` - (Optional) Gateway IP address to retrieve activation key during resource creation. Conflicts with `activation_key`. Gateway must be accessible on port 80 from where Terraform is running. Additional information is available in the [Storage Gateway User Guide](https://docs.aws.amazon.com/storagegateway/latest/userguide/get-activation-key.html). * `gateway_type` - (Optional) Type of the gateway. The default value is `STORED`. Valid values: `CACHED`, `FILE_S3`, `STORED`, `VTL`. +* `gateway_vpc_endpoint` - (Optional) VPC endpoint address to be used when activating your gateway. This should be used when your instance is in a private subnet. Requires HTTP access from client computer running terraform. More info on what ports are required by your VPC Endpoint Security group in [Activating a Gateway in a Virtual Private Cloud](https://docs.aws.amazon.com/storagegateway/latest/userguide/gateway-private-link.html). * `media_changer_type` - (Optional) Type of medium changer to use for tape gateway. Terraform cannot detect drift of this argument. Valid values: `STK-L700`, `AWS-Gateway-VTL`. * `smb_active_directory_settings` - (Optional) Nested argument with Active Directory domain join information for Server Message Block (SMB) file shares. Only valid for `FILE_S3` gateway type. Must be set before creating `ActiveDirectory` authentication SMB file shares. More details below. * `smb_guest_password` - (Optional) Guest password for Server Message Block (SMB) file shares. Only valid for `FILE_S3` gateway type. Must be set before creating `GuestAccess` authentication SMB file shares. Terraform can only detect drift of the existence of a guest password, not its actual value from the gateway. Terraform can however update the password with changing the argument. From c3e20be0321daa1f7d41ca006195ea0b9c78c5f7 Mon Sep 17 00:00:00 2001 From: Ryan Kelly Date: Wed, 2 Oct 2019 16:08:05 -0400 Subject: [PATCH 010/684] allow snapshot copy grants to be imported --- aws/resource_aws_redshift_snapshot_copy_grant.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/aws/resource_aws_redshift_snapshot_copy_grant.go b/aws/resource_aws_redshift_snapshot_copy_grant.go index 8f85f419ca9..da3c86360aa 100644 --- a/aws/resource_aws_redshift_snapshot_copy_grant.go +++ b/aws/resource_aws_redshift_snapshot_copy_grant.go @@ -22,6 +22,13 @@ func resourceAwsRedshiftSnapshotCopyGrant() *schema.Resource { Delete: resourceAwsRedshiftSnapshotCopyGrantDelete, Exists: resourceAwsRedshiftSnapshotCopyGrantExists, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + d.Set("snapshot_copy_grant_name", d.Id()) + return []*schema.ResourceData{d}, nil + }, + }, + Schema: map[string]*schema.Schema{ "arn": { Type: schema.TypeString, From b5a75a334e3d07b112b74a4ab136071fa53bd807 Mon Sep 17 00:00:00 2001 From: Tom Elliff Date: Fri, 1 Nov 2019 01:29:55 +0000 Subject: [PATCH 011/684] Various aws_cognito_identity_provider improvements Added plan time checks for some parameters and also ignored the computed diff caused by not specifying the optional attribute_mapping. --- aws/resource_aws_cognito_identity_provider.go | 24 +++++++ ...urce_aws_cognito_identity_provider_test.go | 63 +++++++++++++++++-- 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_cognito_identity_provider.go b/aws/resource_aws_cognito_identity_provider.go index 29044b853c2..6085f5ed60c 100644 --- a/aws/resource_aws_cognito_identity_provider.go +++ b/aws/resource_aws_cognito_identity_provider.go @@ -3,11 +3,13 @@ package aws import ( "fmt" "log" + "regexp" "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func resourceAwsCognitoIdentityProvider() *schema.Resource { @@ -25,6 +27,11 @@ func resourceAwsCognitoIdentityProvider() *schema.Resource { "attribute_mapping": { Type: schema.TypeMap, Optional: true, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 32), + }, }, "idp_identifiers": { @@ -32,6 +39,10 @@ func resourceAwsCognitoIdentityProvider() *schema.Resource { Optional: true, Elem: &schema.Schema{ Type: schema.TypeString, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 40), + validation.StringMatch(regexp.MustCompile(`^[\w\s+=.@-]+$`), "see https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateIdentityProvider.html#API_CreateIdentityProvider_RequestSyntax"), + ), }, }, @@ -43,11 +54,24 @@ func resourceAwsCognitoIdentityProvider() *schema.Resource { "provider_name": { Type: schema.TypeString, Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 32), + validation.StringMatch(regexp.MustCompile(`^[^_][\p{L}\p{M}\p{S}\p{N}\p{P}][^_]+$`), "see https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateIdentityProvider.html#API_CreateIdentityProvider_RequestSyntax"), + ), }, "provider_type": { Type: schema.TypeString, Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + cognitoidentityprovider.IdentityProviderTypeTypeSaml, + cognitoidentityprovider.IdentityProviderTypeTypeFacebook, + cognitoidentityprovider.IdentityProviderTypeTypeGoogle, + cognitoidentityprovider.IdentityProviderTypeTypeLoginWithAmazon, + cognitoidentityprovider.IdentityProviderTypeTypeOidc, + }, false), }, "user_pool_id": { diff --git a/aws/resource_aws_cognito_identity_provider_test.go b/aws/resource_aws_cognito_identity_provider_test.go index 6911e55d4f3..92ad2d83d36 100644 --- a/aws/resource_aws_cognito_identity_provider_test.go +++ b/aws/resource_aws_cognito_identity_provider_test.go @@ -6,6 +6,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" ) @@ -13,6 +14,7 @@ import ( func TestAccAWSCognitoIdentityProvider_basic(t *testing.T) { var identityProvider cognitoidentityprovider.IdentityProviderType resourceName := "aws_cognito_identity_provider.test" + userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, @@ -20,9 +22,11 @@ func TestAccAWSCognitoIdentityProvider_basic(t *testing.T) { CheckDestroy: testAccCheckAWSCognitoIdentityProviderDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoIdentityProviderConfig_basic(), + Config: testAccAWSCognitoIdentityProviderConfig_basic(userPoolName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoIdentityProviderExists(resourceName, &identityProvider), + resource.TestCheckResourceAttr(resourceName, "attribute_mapping.%", "1"), + resource.TestCheckResourceAttr(resourceName, "attribute_mapping.username", "sub"), resource.TestCheckResourceAttr(resourceName, "provider_details.%", "9"), resource.TestCheckResourceAttr(resourceName, "provider_details.authorize_scopes", "email"), resource.TestCheckResourceAttr(resourceName, "provider_details.authorize_url", "https://accounts.google.com/o/oauth2/v2/auth"), @@ -37,6 +41,27 @@ func TestAccAWSCognitoIdentityProvider_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "provider_type", "Google"), ), }, + { + Config: testAccAWSCognitoIdentityProviderConfig_basicUpdated(userPoolName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoIdentityProviderExists(resourceName, &identityProvider), + resource.TestCheckResourceAttr(resourceName, "attribute_mapping.%", "2"), + resource.TestCheckResourceAttr(resourceName, "attribute_mapping.username", "sub"), + resource.TestCheckResourceAttr(resourceName, "attribute_mapping.email", "email"), + resource.TestCheckResourceAttr(resourceName, "provider_details.%", "9"), + resource.TestCheckResourceAttr(resourceName, "provider_details.authorize_scopes", "email"), + resource.TestCheckResourceAttr(resourceName, "provider_details.authorize_url", "https://accounts.google.com/o/oauth2/v2/auth"), + resource.TestCheckResourceAttr(resourceName, "provider_details.client_id", "new-client-id-url.apps.googleusercontent.com"), + resource.TestCheckResourceAttr(resourceName, "provider_details.client_secret", "updated_client_secret"), + resource.TestCheckResourceAttr(resourceName, "provider_details.attributes_url", "https://people.googleapis.com/v1/people/me?personFields="), + resource.TestCheckResourceAttr(resourceName, "provider_details.attributes_url_add_attributes", "true"), + resource.TestCheckResourceAttr(resourceName, "provider_details.token_request_method", "POST"), + resource.TestCheckResourceAttr(resourceName, "provider_details.token_url", "https://www.googleapis.com/oauth2/v4/token"), + resource.TestCheckResourceAttr(resourceName, "provider_details.oidc_issuer", "https://accounts.google.com"), + resource.TestCheckResourceAttr(resourceName, "provider_name", "Google"), + resource.TestCheckResourceAttr(resourceName, "provider_type", "Google"), + ), + }, { ResourceName: resourceName, ImportState: true, @@ -110,11 +135,11 @@ func testAccCheckAWSCognitoIdentityProviderExists(resourceName string, identityP } } -func testAccAWSCognitoIdentityProviderConfig_basic() string { - return ` +func testAccAWSCognitoIdentityProviderConfig_basic(userPoolName string) string { + return fmt.Sprintf(` resource "aws_cognito_user_pool" "test" { - name = "tfmytestpool" + name = "%s" auto_verified_attributes = ["email"] } @@ -134,11 +159,39 @@ resource "aws_cognito_identity_provider" "test" { token_request_method = "POST" token_url = "https://www.googleapis.com/oauth2/v4/token" } +} +`, userPoolName) +} + +func testAccAWSCognitoIdentityProviderConfig_basicUpdated(userPoolName string) string { + return fmt.Sprintf(` + +resource "aws_cognito_user_pool" "test" { + name = "%s" + auto_verified_attributes = ["email"] +} + +resource "aws_cognito_identity_provider" "test" { + user_pool_id = "${aws_cognito_user_pool.test.id}" + provider_name = "Google" + provider_type = "Google" + + provider_details = { + attributes_url = "https://people.googleapis.com/v1/people/me?personFields=" + attributes_url_add_attributes = "true" + authorize_scopes = "email" + authorize_url = "https://accounts.google.com/o/oauth2/v2/auth" + client_id = "new-client-id-url.apps.googleusercontent.com" + client_secret = "updated_client_secret" + oidc_issuer = "https://accounts.google.com" + token_request_method = "POST" + token_url = "https://www.googleapis.com/oauth2/v4/token" + } attribute_mapping = { email = "email" username = "sub" } } -` +`, userPoolName) } From 11a799600ba0fc08cd4ddd0ac4c5b9547986e1a4 Mon Sep 17 00:00:00 2001 From: Omarimcblack Date: Fri, 6 Dec 2019 19:18:46 +0000 Subject: [PATCH 012/684] aws_ec2_transit_gateway_peering_attachment_accepter Update and Delete functions implemented to interact with the AWS GO SDK for transit gateway peering attachments acceptance waitFor functions added for Delete terraform operations. Describe function added for transit gateway peering attachments acceptance. --- aws/ec2_transit_gateway.go | 59 ++++++++++ ...sit_gateway_peering_attachment_accepter.go | 106 ++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go diff --git a/aws/ec2_transit_gateway.go b/aws/ec2_transit_gateway.go index 740eccf1f8d..0709cb09897 100644 --- a/aws/ec2_transit_gateway.go +++ b/aws/ec2_transit_gateway.go @@ -211,6 +211,43 @@ func ec2DescribeTransitGatewayRouteTablePropagation(conn *ec2.EC2, transitGatewa return output.TransitGatewayRouteTablePropagations[0], nil } +func ec2DescribeTransitGatewayPeeringAttachment(conn *ec2.EC2, transitGatewayAttachmentID string) (*ec2.TransitGatewayPeeringAttachment, error) { + input := &ec2.DescribeTransitGatewayPeeringAttachmentsInput{ + TransitGatewayAttachmentIds: []*string{aws.String(transitGatewayAttachmentID)}, + } + + log.Printf("[DEBUG] Reading EC2 Transit Gateway Peering Attachment (%s): %s", transitGatewayAttachmentID, input) + for { + output, err := conn.DescribeTransitGatewayPeeringAttachments(input) + + if err != nil { + return nil, err + } + + if output == nil || len(output.TransitGatewayPeeringAttachments) == 0 { + return nil, nil + } + + for _, transitGatewayPeeringAttachment := range output.TransitGatewayPeeringAttachments { + if transitGatewayPeeringAttachment == nil { + continue + } + + if aws.StringValue(transitGatewayPeeringAttachment.TransitGatewayAttachmentId) == transitGatewayAttachmentID { + return transitGatewayPeeringAttachment, nil + } + } + + if aws.StringValue(output.NextToken) == "" { + break + } + + input.NextToken = output.NextToken + } + + return nil, nil +} + func ec2DescribeTransitGatewayVpcAttachment(conn *ec2.EC2, transitGatewayAttachmentID string) (*ec2.TransitGatewayVpcAttachment, error) { input := &ec2.DescribeTransitGatewayVpcAttachmentsInput{ TransitGatewayAttachmentIds: []*string{aws.String(transitGatewayAttachmentID)}, @@ -541,6 +578,28 @@ func waitForEc2TransitGatewayRouteTableAssociationDeletion(conn *ec2.EC2, transi return err } +func waitForEc2TransitGatewayPeeringAttachmentDeletion(conn *ec2.EC2, transitGatewayAttachmentID string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + ec2.TransitGatewayAttachmentStateAvailable, + ec2.TransitGatewayAttachmentStateDeleting, + }, + Target: []string{ec2.TransitGatewayAttachmentStateDeleted}, + Refresh: ec2TransitGatewayVpcAttachmentRefreshFunc(conn, transitGatewayAttachmentID), + Timeout: 10 * time.Minute, + NotFoundChecks: 1, + } + + log.Printf("[DEBUG] Waiting for EC2 Transit Gateway Peering Attachment (%s) deletion", transitGatewayAttachmentID) + _, err := stateConf.WaitForState() + + if isResourceNotFoundError(err) { + return nil + } + + return err +} + func waitForEc2TransitGatewayVpcAttachmentAcceptance(conn *ec2.EC2, transitGatewayAttachmentID string) error { stateConf := &resource.StateChangeConf{ Pending: []string{ diff --git a/aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go b/aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go new file mode 100644 index 00000000000..dd701927f5f --- /dev/null +++ b/aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go @@ -0,0 +1,106 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceAwsEc2TransitGatewayPeeringAttachmentAccepter() *schema.Resource { + return &schema.Resource{ + Update: resourceAwsEc2TransitGatewayPeeringAttachmentAccepterUpdate, + Delete: resourceAwsEc2TransitGatewayPeeringAttachmentAccepterDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "peer_account_id": { + Type: schema.TypeString, + Computed: true, + }, + "peer_region": { + Type: schema.TypeString, + Computed: true, + }, + "peer_transit_gateway_id": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchema(), + "transit_gateway_attachment_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "transit_gateway_default_route_table_association": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "transit_gateway_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsEc2TransitGatewayPeeringAttachmentAccepterUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + if d.HasChange("transit_gateway_default_route_table_association") { + transitGatewayID := d.Get("transit_gateway_id").(string) + + transitGateway, err := ec2DescribeTransitGateway(conn, transitGatewayID) + if err != nil { + return fmt.Errorf("error describing EC2 Transit Gateway (%s): %s", transitGatewayID, err) + } + + if transitGateway.Options == nil { + return fmt.Errorf("error describing EC2 Transit Gateway (%s): missing options", transitGatewayID) + } + + if d.HasChange("transit_gateway_default_route_table_association") { + if err := ec2TransitGatewayRouteTableAssociationUpdate(conn, aws.StringValue(transitGateway.Options.AssociationDefaultRouteTableId), d.Id(), d.Get("transit_gateway_default_route_table_association").(bool)); err != nil { + return fmt.Errorf("error updating EC2 Transit Gateway Attachment (%s) Route Table (%s) association: %s", d.Id(), aws.StringValue(transitGateway.Options.AssociationDefaultRouteTableId), err) + } + } + } + + if d.HasChange("tags") { + if err := setTags(conn, d); err != nil { + return fmt.Errorf("error updating EC2 Transit Gateway Peering Attachment (%s) tags: %s", d.Id(), err) + } + } + + return nil +} + +func resourceAwsEc2TransitGatewayPeeringAttachmentAccepterDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + input := &ec2.DeleteTransitGatewayPeeringAttachmentInput{ + TransitGatewayAttachmentId: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Deleting EC2 Transit Gateway Peering Attachment (%s): %s", d.Id(), input) + _, err := conn.DeleteTransitGatewayPeeringAttachment(input) + + if isAWSErr(err, "InvalidTransitGatewayAttachmentID.NotFound", "") { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting EC2 Transit Gateway Peering Attachment: %s", err) + } + + if err := waitForEc2TransitGatewayPeeringAttachmentDeletion(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for EC2 Transit Gateway Peering Attachment (%s) deletion: %s", d.Id(), err) + } + + return nil +} From 9a30fa59979666b8216664985fcec47ea56d8760 Mon Sep 17 00:00:00 2001 From: Joe Horner Date: Fri, 6 Dec 2019 19:32:14 +0000 Subject: [PATCH 013/684] Resource aws_ec2_transit_gateway_peering_attachment_accepter Create and read functions implemented to interact with the AWS GO SDK for transit gateway peering attachment acceptance. waitFor functions added for Create/Read terraform operations & acceptance. Add provider resource mapping to provider.go --- aws/ec2_transit_gateway.go | 37 ++++++ aws/provider.go | 1 + ...sit_gateway_peering_attachment_accepter.go | 108 ++++++++++++++++++ 3 files changed, 146 insertions(+) diff --git a/aws/ec2_transit_gateway.go b/aws/ec2_transit_gateway.go index 0709cb09897..45605a3dde0 100644 --- a/aws/ec2_transit_gateway.go +++ b/aws/ec2_transit_gateway.go @@ -411,6 +411,26 @@ func ec2TransitGatewayRouteTableAssociationRefreshFunc(conn *ec2.EC2, transitGat } } +func ec2TransitGatewayPeeringAttachmentRefreshFunc(conn *ec2.EC2, transitGatewayAttachmentID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + transitGatewayPeeringAttachment, err := ec2DescribeTransitGatewayPeeringAttachment(conn, transitGatewayAttachmentID) + + if isAWSErr(err, "InvalidTransitGatewayAttachmentID.NotFound", "") { + return nil, ec2.TransitGatewayAttachmentStateDeleted, nil + } + + if err != nil { + return nil, "", fmt.Errorf("error reading EC2 Transit Gateway Peering Attachment (%s): %s", transitGatewayAttachmentID, err) + } + + if transitGatewayPeeringAttachment == nil { + return nil, ec2.TransitGatewayAttachmentStateDeleted, nil + } + + return transitGatewayPeeringAttachment, aws.StringValue(transitGatewayPeeringAttachment.State), nil + } +} + func ec2TransitGatewayVpcAttachmentRefreshFunc(conn *ec2.EC2, transitGatewayAttachmentID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { transitGatewayVpcAttachment, err := ec2DescribeTransitGatewayVpcAttachment(conn, transitGatewayAttachmentID) @@ -431,6 +451,23 @@ func ec2TransitGatewayVpcAttachmentRefreshFunc(conn *ec2.EC2, transitGatewayAtta } } +func waitForEc2TransitGatewayPeeringAttachmentAcceptance(conn *ec2.EC2, transitGatewayAttachmentID string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + ec2.TransitGatewayAttachmentStatePending, + ec2.TransitGatewayAttachmentStatePendingAcceptance, + }, + Target: []string{ec2.TransitGatewayAttachmentStateAvailable}, + Refresh: ec2TransitGatewayPeeringAttachmentRefreshFunc(conn, transitGatewayAttachmentID), + Timeout: 10 * time.Minute, + } + + log.Printf("[DEBUG] Waiting for EC2 Transit Gateway Peering Attachment (%s) availability", transitGatewayAttachmentID) + _, err := stateConf.WaitForState() + + return err +} + func expandEc2TransitGatewayTagSpecifications(m map[string]interface{}) []*ec2.TagSpecification { if len(m) == 0 { return nil diff --git a/aws/provider.go b/aws/provider.go index 8284165e405..daac2dc6a06 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -484,6 +484,7 @@ func Provider() terraform.ResourceProvider { "aws_ec2_client_vpn_network_association": resourceAwsEc2ClientVpnNetworkAssociation(), "aws_ec2_fleet": resourceAwsEc2Fleet(), "aws_ec2_transit_gateway": resourceAwsEc2TransitGateway(), + "aws_ec2_transit_gateway_peering_attachment_accepter": resourceAwsEc2TransitGatewayPeeringAttachmentAccepter(), "aws_ec2_transit_gateway_route": resourceAwsEc2TransitGatewayRoute(), "aws_ec2_transit_gateway_route_table": resourceAwsEc2TransitGatewayRouteTable(), "aws_ec2_transit_gateway_route_table_association": resourceAwsEc2TransitGatewayRouteTableAssociation(), diff --git a/aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go b/aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go index dd701927f5f..48efe4407ac 100644 --- a/aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go +++ b/aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go @@ -11,6 +11,8 @@ import ( func resourceAwsEc2TransitGatewayPeeringAttachmentAccepter() *schema.Resource { return &schema.Resource{ + Create: resourceAwsEc2TransitGatewayPeeringAttachmentAccepterCreate, + Read: resourceAwsEc2TransitGatewayPeeringAttachmentAccepterRead, Update: resourceAwsEc2TransitGatewayPeeringAttachmentAccepterUpdate, Delete: resourceAwsEc2TransitGatewayPeeringAttachmentAccepterDelete, Importer: &schema.ResourceImporter{ @@ -49,6 +51,112 @@ func resourceAwsEc2TransitGatewayPeeringAttachmentAccepter() *schema.Resource { } } +func resourceAwsEc2TransitGatewayPeeringAttachmentAccepterCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + input := &ec2.AcceptTransitGatewayPeeringAttachmentInput{ + TransitGatewayAttachmentId: aws.String(d.Get("transit_gateway_attachment_id").(string)), + } + + log.Printf("[DEBUG] Accepting EC2 Transit Gateway Peering Attachment: %s", input) + output, err := conn.AcceptTransitGatewayPeeringAttachment(input) + if err != nil { + return fmt.Errorf("error accepting EC2 Transit Gateway Peering Attachment: %s", err) + } + + d.SetId(aws.StringValue(output.TransitGatewayPeeringAttachment.TransitGatewayAttachmentId)) + transitGatewayID := aws.StringValue(output.TransitGatewayPeeringAttachment.AccepterTgwInfo.TransitGatewayId) + + if err := waitForEc2TransitGatewayPeeringAttachmentAcceptance(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for EC2 Transit Gateway Peering Attachment (%s) availability: %s", d.Id(), err) + } + + if err := setTags(conn, d); err != nil { + return fmt.Errorf("error updating EC2 Transit Gateway Peering Attachment (%s) tags: %s", d.Id(), err) + } + + transitGateway, err := ec2DescribeTransitGateway(conn, transitGatewayID) + if err != nil { + return fmt.Errorf("error describing EC2 Transit Gateway (%s): %s", transitGatewayID, err) + } + + if transitGateway.Options == nil { + return fmt.Errorf("error describing EC2 Transit Gateway (%s): missing options", transitGatewayID) + } + + if err := ec2TransitGatewayRouteTableAssociationUpdate(conn, aws.StringValue(transitGateway.Options.AssociationDefaultRouteTableId), d.Id(), d.Get("transit_gateway_default_route_table_association").(bool)); err != nil { + return fmt.Errorf("error updating EC2 Transit Gateway Attachment (%s) Route Table (%s) association: %s", d.Id(), aws.StringValue(transitGateway.Options.AssociationDefaultRouteTableId), err) + } + + if err := ec2TransitGatewayRouteTablePropagationUpdate(conn, aws.StringValue(transitGateway.Options.PropagationDefaultRouteTableId), d.Id(), d.Get("transit_gateway_default_route_table_propagation").(bool)); err != nil { + return fmt.Errorf("error updating EC2 Transit Gateway Attachment (%s) Route Table (%s) propagation: %s", d.Id(), aws.StringValue(transitGateway.Options.PropagationDefaultRouteTableId), err) + } + + return resourceAwsEc2TransitGatewayPeeringAttachmentAccepterRead(d, meta) +} + +func resourceAwsEc2TransitGatewayPeeringAttachmentAccepterRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + transitGatewayPeeringAttachment, err := ec2DescribeTransitGatewayPeeringAttachment(conn, d.Id()) + + if isAWSErr(err, "InvalidTransitGatewayAttachmentID.NotFound", "") { + log.Printf("[WARN] EC2 Transit Gateway Peering Attachment (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading EC2 Transit Gateway Peering Attachment: %s", err) + } + + if transitGatewayPeeringAttachment == nil { + log.Printf("[WARN] EC2 Transit Gateway Peering Attachment (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if aws.StringValue(transitGatewayPeeringAttachment.State) == ec2.TransitGatewayAttachmentStateDeleting || aws.StringValue(transitGatewayPeeringAttachment.State) == ec2.TransitGatewayAttachmentStateDeleted { + log.Printf("[WARN] EC2 Transit Gateway Peering Attachment (%s) in deleted state (%s), removing from state", d.Id(), aws.StringValue(transitGatewayPeeringAttachment.State)) + d.SetId("") + return nil + } + + transitGatewayID := aws.StringValue(transitGatewayPeeringAttachment.AccepterTgwInfo.TransitGatewayId) + transitGateway, err := ec2DescribeTransitGateway(conn, transitGatewayID) + if err != nil { + return fmt.Errorf("error describing EC2 Transit Gateway (%s): %s", transitGatewayID, err) + } + + if transitGateway.Options == nil { + return fmt.Errorf("error describing EC2 Transit Gateway (%s): missing options", transitGatewayID) + } + + transitGatewayAssociationDefaultRouteTableID := aws.StringValue(transitGateway.Options.AssociationDefaultRouteTableId) + transitGatewayDefaultRouteTableAssociation, err := ec2DescribeTransitGatewayRouteTableAssociation(conn, transitGatewayAssociationDefaultRouteTableID, d.Id()) + if err != nil { + return fmt.Errorf("error determining EC2 Transit Gateway Attachment (%s) association to Route Table (%s): %s", d.Id(), transitGatewayAssociationDefaultRouteTableID, err) + } + + transitGatewayPropagationDefaultRouteTableID := aws.StringValue(transitGateway.Options.PropagationDefaultRouteTableId) + if err != nil { + return fmt.Errorf("error determining EC2 Transit Gateway Attachment (%s) propagation to Route Table (%s): %s", d.Id(), transitGatewayPropagationDefaultRouteTableID, err) + } + + if err := d.Set("tags", tagsToMap(transitGatewayPeeringAttachment.Tags)); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + d.Set("transit_gateway_default_route_table_association", (transitGatewayDefaultRouteTableAssociation != nil)) + d.Set("peer_account_id", (transitGatewayPeeringAttachment.AccepterTgwInfo.OwnerId != nil)) + d.Set("peer_region", (transitGatewayPeeringAttachment.AccepterTgwInfo.Region != nil)) + d.Set("peer_transit_gateway_id", (transitGatewayPeeringAttachment.AccepterTgwInfo.TransitGatewayId != nil)) + d.Set("tags", (transitGatewayPeeringAttachment.Tags)) + d.Set("transit_gateway_id", (transitGatewayPeeringAttachment.RequesterTgwInfo.TransitGatewayId)) + + return nil +} + func resourceAwsEc2TransitGatewayPeeringAttachmentAccepterUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn From 475d5b1564794f6b85bb18c76e561230cdbc7b42 Mon Sep 17 00:00:00 2001 From: Joe Horner Date: Fri, 6 Dec 2019 19:56:31 +0000 Subject: [PATCH 014/684] Fix conflicts Move `waitForEc2TransitGatewayPeeringAttachmentAcceptance` into the correct place. --- aws/ec2_transit_gateway.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/aws/ec2_transit_gateway.go b/aws/ec2_transit_gateway.go index 45605a3dde0..84962afbdef 100644 --- a/aws/ec2_transit_gateway.go +++ b/aws/ec2_transit_gateway.go @@ -451,23 +451,6 @@ func ec2TransitGatewayVpcAttachmentRefreshFunc(conn *ec2.EC2, transitGatewayAtta } } -func waitForEc2TransitGatewayPeeringAttachmentAcceptance(conn *ec2.EC2, transitGatewayAttachmentID string) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{ - ec2.TransitGatewayAttachmentStatePending, - ec2.TransitGatewayAttachmentStatePendingAcceptance, - }, - Target: []string{ec2.TransitGatewayAttachmentStateAvailable}, - Refresh: ec2TransitGatewayPeeringAttachmentRefreshFunc(conn, transitGatewayAttachmentID), - Timeout: 10 * time.Minute, - } - - log.Printf("[DEBUG] Waiting for EC2 Transit Gateway Peering Attachment (%s) availability", transitGatewayAttachmentID) - _, err := stateConf.WaitForState() - - return err -} - func expandEc2TransitGatewayTagSpecifications(m map[string]interface{}) []*ec2.TagSpecification { if len(m) == 0 { return nil @@ -615,6 +598,23 @@ func waitForEc2TransitGatewayRouteTableAssociationDeletion(conn *ec2.EC2, transi return err } +func waitForEc2TransitGatewayPeeringAttachmentAcceptance(conn *ec2.EC2, transitGatewayAttachmentID string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + ec2.TransitGatewayAttachmentStatePending, + ec2.TransitGatewayAttachmentStatePendingAcceptance, + }, + Target: []string{ec2.TransitGatewayAttachmentStateAvailable}, + Refresh: ec2TransitGatewayPeeringAttachmentRefreshFunc(conn, transitGatewayAttachmentID), + Timeout: 10 * time.Minute, + } + + log.Printf("[DEBUG] Waiting for EC2 Transit Gateway Peering Attachment (%s) availability", transitGatewayAttachmentID) + _, err := stateConf.WaitForState() + + return err +} + func waitForEc2TransitGatewayPeeringAttachmentDeletion(conn *ec2.EC2, transitGatewayAttachmentID string) error { stateConf := &resource.StateChangeConf{ Pending: []string{ From ab992c3550f124fde6daba8d65216648390b4183 Mon Sep 17 00:00:00 2001 From: Cameron Martin Date: Tue, 10 Dec 2019 14:21:01 -0800 Subject: [PATCH 015/684] Add failing testcase --- aws/resource_aws_appautoscaling_policy_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aws/resource_aws_appautoscaling_policy_test.go b/aws/resource_aws_appautoscaling_policy_test.go index 4a8397d07fa..6953d6ed225 100644 --- a/aws/resource_aws_appautoscaling_policy_test.go +++ b/aws/resource_aws_appautoscaling_policy_test.go @@ -30,6 +30,11 @@ func TestValidateAppautoscalingPolicyImportInput(t *testing.T) { expected: []string{"dynamodb", "table/tableName", "dynamodb:table:ReadCapacityUnits", "DynamoDBReadCapacityUtilization:table/tableName"}, errorExpected: false, }, + { + input: "dynamodb/table/tableName/index/indexName/dynamodb:table:ReadCapacityUnits/DynamoDBReadCapacityUtilization:table/tableName", + expected: []string{"dynamodb", "table/tableName/index/indexName", "dynamodb:table:ReadCapacityUnits", "DynamoDBReadCapacityUtilization:table/tableName"}, + errorExpected: false, + }, { input: "ec2/spot-fleet-request/sfr-d77c6508-1c1d-4e79-8789-fc019ee44c96/ec2:spot-fleet-request:TargetCapacity/test-appautoscaling-policy-ruuhd", expected: []string{"ec2", "spot-fleet-request/sfr-d77c6508-1c1d-4e79-8789-fc019ee44c96", "ec2:spot-fleet-request:TargetCapacity", "test-appautoscaling-policy-ruuhd"}, From 6513b61cee999e28aec9af64c2d89f8b887eca11 Mon Sep 17 00:00:00 2001 From: Cameron Martin Date: Tue, 10 Dec 2019 14:22:55 -0800 Subject: [PATCH 016/684] Detect and handle DynamoDB resource IDs pointing to an index --- aws/resource_aws_appautoscaling_policy.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_appautoscaling_policy.go b/aws/resource_aws_appautoscaling_policy.go index 08b364891cb..1daf4fed6c6 100644 --- a/aws/resource_aws_appautoscaling_policy.go +++ b/aws/resource_aws_appautoscaling_policy.go @@ -445,9 +445,16 @@ func validateAppautoscalingPolicyImportInput(id string) ([]string, error) { switch idParts[0] { case "dynamodb": serviceNamespace = idParts[0] - resourceId = strings.Join(idParts[1:3], "/") - scalableDimension = idParts[3] - policyName = strings.Join(idParts[4:], "/") + + dimensionIx := 3 + // DynamoDB resource ID can be "/table/tableName" or "/table/tableName/index/indexName" + if idParts[dimensionIx] == "index" { + dimensionIx = 5 + } + + resourceId = strings.Join(idParts[1:dimensionIx], "/") + scalableDimension = idParts[dimensionIx] + policyName = strings.Join(idParts[dimensionIx+1:], "/") default: serviceNamespace = idParts[0] resourceId = strings.Join(idParts[1:len(idParts)-2], "/") From 835e0f2302edfb4dd129ac30a4cbe93b7a9cd09b Mon Sep 17 00:00:00 2001 From: Joe Horner Date: Mon, 30 Dec 2019 14:39:12 +0000 Subject: [PATCH 017/684] Remove references to default RT propogation Default route table propogation doesn't appear to be supported by transit gateway peering attachments, only an assocation to the default route table is supported - removed references to propogation. Co-authored-by: Omarimcblack 43746683+Omarimcblack@users.noreply.github.com --- ...ws_ec2_transit_gateway_peering_attachment_accepter.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go b/aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go index 48efe4407ac..1b23d1dcfa5 100644 --- a/aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go +++ b/aws/resource_aws_ec2_transit_gateway_peering_attachment_accepter.go @@ -88,10 +88,6 @@ func resourceAwsEc2TransitGatewayPeeringAttachmentAccepterCreate(d *schema.Resou return fmt.Errorf("error updating EC2 Transit Gateway Attachment (%s) Route Table (%s) association: %s", d.Id(), aws.StringValue(transitGateway.Options.AssociationDefaultRouteTableId), err) } - if err := ec2TransitGatewayRouteTablePropagationUpdate(conn, aws.StringValue(transitGateway.Options.PropagationDefaultRouteTableId), d.Id(), d.Get("transit_gateway_default_route_table_propagation").(bool)); err != nil { - return fmt.Errorf("error updating EC2 Transit Gateway Attachment (%s) Route Table (%s) propagation: %s", d.Id(), aws.StringValue(transitGateway.Options.PropagationDefaultRouteTableId), err) - } - return resourceAwsEc2TransitGatewayPeeringAttachmentAccepterRead(d, meta) } @@ -138,11 +134,6 @@ func resourceAwsEc2TransitGatewayPeeringAttachmentAccepterRead(d *schema.Resourc return fmt.Errorf("error determining EC2 Transit Gateway Attachment (%s) association to Route Table (%s): %s", d.Id(), transitGatewayAssociationDefaultRouteTableID, err) } - transitGatewayPropagationDefaultRouteTableID := aws.StringValue(transitGateway.Options.PropagationDefaultRouteTableId) - if err != nil { - return fmt.Errorf("error determining EC2 Transit Gateway Attachment (%s) propagation to Route Table (%s): %s", d.Id(), transitGatewayPropagationDefaultRouteTableID, err) - } - if err := d.Set("tags", tagsToMap(transitGatewayPeeringAttachment.Tags)); err != nil { return fmt.Errorf("error setting tags: %s", err) } From 148dcfd804f095cc70d2f8382bee1e7bbf3b868e Mon Sep 17 00:00:00 2001 From: Stefan Sundin Date: Sat, 11 Jan 2020 17:03:29 -0800 Subject: [PATCH 018/684] r/aws_egress_only_internet_gateway: Support tagging. --- ...source_aws_egress_only_internet_gateway.go | 21 ++++++ ...e_aws_egress_only_internet_gateway_test.go | 67 +++++++++++++++++++ ...egress_only_internet_gateway.html.markdown | 5 ++ 3 files changed, 93 insertions(+) diff --git a/aws/resource_aws_egress_only_internet_gateway.go b/aws/resource_aws_egress_only_internet_gateway.go index a4e6b3184ef..4ca9130243f 100644 --- a/aws/resource_aws_egress_only_internet_gateway.go +++ b/aws/resource_aws_egress_only_internet_gateway.go @@ -15,6 +15,7 @@ func resourceAwsEgressOnlyInternetGateway() *schema.Resource { return &schema.Resource{ Create: resourceAwsEgressOnlyInternetGatewayCreate, Read: resourceAwsEgressOnlyInternetGatewayRead, + Update: resourceAwsEgressOnlyInternetGatewayUpdate, Delete: resourceAwsEgressOnlyInternetGatewayDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, @@ -26,6 +27,7 @@ func resourceAwsEgressOnlyInternetGateway() *schema.Resource { Required: true, ForceNew: true, }, + "tags": tagsSchema(), }, } } @@ -42,6 +44,11 @@ func resourceAwsEgressOnlyInternetGatewayCreate(d *schema.ResourceData, meta int d.SetId(aws.StringValue(resp.EgressOnlyInternetGateway.EgressOnlyInternetGatewayId)) + err = setTags(conn, d) + if err != nil { + return err + } + return resourceAwsEgressOnlyInternetGatewayRead(d, meta) } @@ -85,6 +92,8 @@ func resourceAwsEgressOnlyInternetGatewayRead(d *schema.ResourceData, meta inter d.Set("vpc_id", igw.Attachments[0].VpcId) } + d.Set("tags", tagsToMap(igw.Tags)) + return nil } @@ -99,6 +108,18 @@ func getEc2EgressOnlyInternetGateway(id string, resp *ec2.DescribeEgressOnlyInte return nil } +func resourceAwsEgressOnlyInternetGatewayUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + if err := setTags(conn, d); err != nil { + return err + } + + d.SetPartial("tags") + + return resourceAwsEgressOnlyInternetGatewayRead(d, meta) +} + func resourceAwsEgressOnlyInternetGatewayDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn diff --git a/aws/resource_aws_egress_only_internet_gateway_test.go b/aws/resource_aws_egress_only_internet_gateway_test.go index 49ebe1cc81c..96f8534816b 100644 --- a/aws/resource_aws_egress_only_internet_gateway_test.go +++ b/aws/resource_aws_egress_only_internet_gateway_test.go @@ -85,6 +85,37 @@ func TestAccAWSEgressOnlyInternetGateway_basic(t *testing.T) { }) } +func TestAccCheckAWSEgressOnlyInternetGateway_tags(t *testing.T) { + var v ec2.EgressOnlyInternetGateway + resourceName := "aws_egress_only_internet_gateway.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEgressOnlyInternetGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEgressOnlyInternetGatewayConfig_Tags, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEgressOnlyInternetGatewayExists(resourceName, &v), + testAccCheckTags(&v.Tags, "Name", "terraform-testacc-egress-only-igw-tags"), + testAccCheckTags(&v.Tags, "test", "bar"), + ), + }, + { + Config: testAccAWSEgressOnlyInternetGatewayConfig_TagsUpdate, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEgressOnlyInternetGatewayExists(resourceName, &v), + testAccCheckTags(&v.Tags, "Name", "terraform-testacc-egress-only-igw-tags"), + testAccCheckTags(&v.Tags, "test", ""), + testAccCheckTags(&v.Tags, "bar", "baz"), + ), + }, + }, + }) +} + func testAccCheckAWSEgressOnlyInternetGatewayDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ec2conn @@ -152,3 +183,39 @@ resource "aws_egress_only_internet_gateway" "test" { vpc_id = "${aws_vpc.test.id}" } ` + +const testAccAWSEgressOnlyInternetGatewayConfig_Tags = ` +resource "aws_vpc" "test" { + cidr_block = "10.1.0.0/16" + assign_generated_ipv6_cidr_block = true + tags = { + Name = "terraform-testacc-egress-only-igw-tags" + } +} + +resource "aws_egress_only_internet_gateway" "test" { + vpc_id = "${aws_vpc.test.id}" + tags = { + Name = "terraform-testacc-egress-only-igw-tags" + test = "bar" + } +} +` + +const testAccAWSEgressOnlyInternetGatewayConfig_TagsUpdate = ` +resource "aws_vpc" "test" { + cidr_block = "10.1.0.0/16" + assign_generated_ipv6_cidr_block = true + tags = { + Name = "terraform-testacc-egress-only-igw-tags" + } +} + +resource "aws_egress_only_internet_gateway" "test" { + vpc_id = "${aws_vpc.test.id}" + tags = { + Name = "terraform-testacc-egress-only-igw-tags" + bar = "baz" + } +} +` diff --git a/website/docs/r/egress_only_internet_gateway.html.markdown b/website/docs/r/egress_only_internet_gateway.html.markdown index 7b3e87514bd..eb51b612da4 100644 --- a/website/docs/r/egress_only_internet_gateway.html.markdown +++ b/website/docs/r/egress_only_internet_gateway.html.markdown @@ -23,6 +23,10 @@ resource "aws_vpc" "example" { resource "aws_egress_only_internet_gateway" "example" { vpc_id = "${aws_vpc.example.id}" + + tags = { + Name = "main" + } } ``` @@ -31,6 +35,7 @@ resource "aws_egress_only_internet_gateway" "example" { The following arguments are supported: * `vpc_id` - (Required) The VPC ID to create in. +* `tags` - (Optional) A mapping of tags to assign to the resource. ## Attributes Reference From eaab907997782d23f4e409ff84eeea6a44d1256e Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 18 Jan 2020 15:17:47 +0200 Subject: [PATCH 019/684] add import support refactor errors + tests --- ...esource_aws_waf_sql_injection_match_set.go | 6 +- ...ce_aws_waf_sql_injection_match_set_test.go | 131 ++++++++---------- .../waf_sql_injection_match_set.html.markdown | 8 ++ 3 files changed, 71 insertions(+), 74 deletions(-) diff --git a/aws/resource_aws_waf_sql_injection_match_set.go b/aws/resource_aws_waf_sql_injection_match_set.go index 33268c98f5e..66aa8e399e0 100644 --- a/aws/resource_aws_waf_sql_injection_match_set.go +++ b/aws/resource_aws_waf_sql_injection_match_set.go @@ -5,7 +5,6 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/waf" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) @@ -16,6 +15,9 @@ func resourceAwsWafSqlInjectionMatchSet() *schema.Resource { Read: resourceAwsWafSqlInjectionMatchSetRead, Update: resourceAwsWafSqlInjectionMatchSetUpdate, Delete: resourceAwsWafSqlInjectionMatchSetDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "name": { @@ -88,7 +90,7 @@ func resourceAwsWafSqlInjectionMatchSetRead(d *schema.ResourceData, meta interfa resp, err := conn.GetSqlInjectionMatchSet(params) if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "WAFNonexistentItemException" { + if isAWSErr(err, waf.ErrCodeNonexistentItemException, "") { log.Printf("[WARN] WAF IPSet (%s) not found, removing from state", d.Id()) d.SetId("") return nil diff --git a/aws/resource_aws_waf_sql_injection_match_set_test.go b/aws/resource_aws_waf_sql_injection_match_set_test.go index cef4f40eb66..70d7b9329f1 100644 --- a/aws/resource_aws_waf_sql_injection_match_set_test.go +++ b/aws/resource_aws_waf_sql_injection_match_set_test.go @@ -8,14 +8,14 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/waf" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" ) func TestAccAWSWafSqlInjectionMatchSet_basic(t *testing.T) { var v waf.SqlInjectionMatchSet - sqlInjectionMatchSet := fmt.Sprintf("sqlInjectionMatchSet-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_waf_sql_injection_match_set.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -23,31 +23,31 @@ func TestAccAWSWafSqlInjectionMatchSet_basic(t *testing.T) { CheckDestroy: testAccCheckAWSWafSqlInjectionMatchSetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSWafSqlInjectionMatchSetConfig(sqlInjectionMatchSet), + Config: testAccAWSWafSqlInjectionMatchSetConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafSqlInjectionMatchSetExists("aws_waf_sql_injection_match_set.sql_injection_match_set", &v), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "name", sqlInjectionMatchSet), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.3367958210.field_to_match.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.3367958210.field_to_match.2316364334.data", ""), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.3367958210.field_to_match.2316364334.type", "QUERY_STRING"), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.3367958210.text_transformation", "URL_DECODE"), + testAccCheckAWSWafSqlInjectionMatchSetExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.#", "1"), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.3367958210.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.3367958210.field_to_match.2316364334.data", ""), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.3367958210.field_to_match.2316364334.type", "QUERY_STRING"), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.3367958210.text_transformation", "URL_DECODE"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } func TestAccAWSWafSqlInjectionMatchSet_changeNameForceNew(t *testing.T) { var before, after waf.SqlInjectionMatchSet - sqlInjectionMatchSet := fmt.Sprintf("sqlInjectionMatchSet-%s", acctest.RandString(5)) - sqlInjectionMatchSetNewName := fmt.Sprintf("sqlInjectionMatchSetNewName-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") + rNameNew := acctest.RandomWithPrefix("tf-acc-test-new") + resourceName := "aws_waf_sql_injection_match_set.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -55,23 +55,19 @@ func TestAccAWSWafSqlInjectionMatchSet_changeNameForceNew(t *testing.T) { CheckDestroy: testAccCheckAWSWafSqlInjectionMatchSetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSWafSqlInjectionMatchSetConfig(sqlInjectionMatchSet), + Config: testAccAWSWafSqlInjectionMatchSetConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafSqlInjectionMatchSetExists("aws_waf_sql_injection_match_set.sql_injection_match_set", &before), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "name", sqlInjectionMatchSet), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.#", "1"), + testAccCheckAWSWafSqlInjectionMatchSetExists(resourceName, &before), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.#", "1"), ), }, { - Config: testAccAWSWafSqlInjectionMatchSetConfigChangeName(sqlInjectionMatchSetNewName), + Config: testAccAWSWafSqlInjectionMatchSetConfigChangeName(rNameNew), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafSqlInjectionMatchSetExists("aws_waf_sql_injection_match_set.sql_injection_match_set", &after), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "name", sqlInjectionMatchSetNewName), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.#", "1"), + testAccCheckAWSWafSqlInjectionMatchSetExists(resourceName, &after), + resource.TestCheckResourceAttr(resourceName, "name", rNameNew), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.#", "1"), ), }, }, @@ -80,7 +76,8 @@ func TestAccAWSWafSqlInjectionMatchSet_changeNameForceNew(t *testing.T) { func TestAccAWSWafSqlInjectionMatchSet_disappears(t *testing.T) { var v waf.SqlInjectionMatchSet - sqlInjectionMatchSet := fmt.Sprintf("sqlInjectionMatchSet-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_waf_sql_injection_match_set.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -88,9 +85,9 @@ func TestAccAWSWafSqlInjectionMatchSet_disappears(t *testing.T) { CheckDestroy: testAccCheckAWSWafSqlInjectionMatchSetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSWafSqlInjectionMatchSetConfig(sqlInjectionMatchSet), + Config: testAccAWSWafSqlInjectionMatchSetConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafSqlInjectionMatchSetExists("aws_waf_sql_injection_match_set.sql_injection_match_set", &v), + testAccCheckAWSWafSqlInjectionMatchSetExists(resourceName, &v), testAccCheckAWSWafSqlInjectionMatchSetDisappears(&v), ), ExpectNonEmptyPlan: true, @@ -101,7 +98,8 @@ func TestAccAWSWafSqlInjectionMatchSet_disappears(t *testing.T) { func TestAccAWSWafSqlInjectionMatchSet_changeTuples(t *testing.T) { var before, after waf.SqlInjectionMatchSet - setName := fmt.Sprintf("sqlInjectionMatchSet-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_waf_sql_injection_match_set.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -109,31 +107,23 @@ func TestAccAWSWafSqlInjectionMatchSet_changeTuples(t *testing.T) { CheckDestroy: testAccCheckAWSWafSqlInjectionMatchSetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSWafSqlInjectionMatchSetConfig(setName), + Config: testAccAWSWafSqlInjectionMatchSetConfig(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafSqlInjectionMatchSetExists("aws_waf_sql_injection_match_set.sql_injection_match_set", &before), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.3367958210.field_to_match.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.3367958210.field_to_match.2316364334.data", ""), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.3367958210.field_to_match.2316364334.type", "QUERY_STRING"), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.3367958210.text_transformation", "URL_DECODE"), + testAccCheckAWSWafSqlInjectionMatchSetExists(resourceName, &before), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.#", "1"), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.3367958210.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.3367958210.field_to_match.2316364334.data", ""), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.3367958210.field_to_match.2316364334.type", "QUERY_STRING"), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.3367958210.text_transformation", "URL_DECODE"), ), }, { - Config: testAccAWSWafSqlInjectionMatchSetConfig_changeTuples(setName), + Config: testAccAWSWafSqlInjectionMatchSetConfig_changeTuples(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafSqlInjectionMatchSetExists("aws_waf_sql_injection_match_set.sql_injection_match_set", &after), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.#", "1"), + testAccCheckAWSWafSqlInjectionMatchSetExists(resourceName, &after), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.#", "1"), ), }, }, @@ -141,8 +131,9 @@ func TestAccAWSWafSqlInjectionMatchSet_changeTuples(t *testing.T) { } func TestAccAWSWafSqlInjectionMatchSet_noTuples(t *testing.T) { - var ipset waf.SqlInjectionMatchSet - setName := fmt.Sprintf("sqlInjectionMatchSet-%s", acctest.RandString(5)) + var sqlSet waf.SqlInjectionMatchSet + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_waf_sql_injection_match_set.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -150,13 +141,11 @@ func TestAccAWSWafSqlInjectionMatchSet_noTuples(t *testing.T) { CheckDestroy: testAccCheckAWSWafSqlInjectionMatchSetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSWafSqlInjectionMatchSetConfig_noTuples(setName), + Config: testAccAWSWafSqlInjectionMatchSetConfig_noTuples(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafSqlInjectionMatchSetExists("aws_waf_sql_injection_match_set.sql_injection_match_set", &ipset), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_sql_injection_match_set.sql_injection_match_set", "sql_injection_match_tuples.#", "0"), + testAccCheckAWSWafSqlInjectionMatchSetExists(resourceName, &sqlSet), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.#", "0"), ), }, }, @@ -176,7 +165,7 @@ func testAccCheckAWSWafSqlInjectionMatchSetDisappears(v *waf.SqlInjectionMatchSe for _, sqlInjectionMatchTuple := range v.SqlInjectionMatchTuples { sqlInjectionMatchTupleUpdate := &waf.SqlInjectionMatchSetUpdate{ - Action: aws.String("DELETE"), + Action: aws.String(waf.ChangeActionDelete), SqlInjectionMatchTuple: &waf.SqlInjectionMatchTuple{ FieldToMatch: sqlInjectionMatchTuple.FieldToMatch, TextTransformation: sqlInjectionMatchTuple.TextTransformation, @@ -235,7 +224,7 @@ func testAccCheckAWSWafSqlInjectionMatchSetExists(n string, v *waf.SqlInjectionM func testAccCheckAWSWafSqlInjectionMatchSetDestroy(s *terraform.State) error { for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_waf_byte_match_set" { + if rs.Type != "aws_waf_sql_injection_match_set" { continue } @@ -252,10 +241,8 @@ func testAccCheckAWSWafSqlInjectionMatchSetDestroy(s *terraform.State) error { } // Return nil if the SqlInjectionMatchSet is already destroyed - if awsErr, ok := err.(awserr.Error); ok { - if awsErr.Code() == "WAFNonexistentItemException" { - return nil - } + if isAWSErr(err, waf.ErrCodeNonexistentItemException, "") { + return nil } return err @@ -266,7 +253,7 @@ func testAccCheckAWSWafSqlInjectionMatchSetDestroy(s *terraform.State) error { func testAccAWSWafSqlInjectionMatchSetConfig(name string) string { return fmt.Sprintf(` -resource "aws_waf_sql_injection_match_set" "sql_injection_match_set" { +resource "aws_waf_sql_injection_match_set" "test" { name = "%s" sql_injection_match_tuples { @@ -282,7 +269,7 @@ resource "aws_waf_sql_injection_match_set" "sql_injection_match_set" { func testAccAWSWafSqlInjectionMatchSetConfigChangeName(name string) string { return fmt.Sprintf(` -resource "aws_waf_sql_injection_match_set" "sql_injection_match_set" { +resource "aws_waf_sql_injection_match_set" "test" { name = "%s" sql_injection_match_tuples { @@ -298,7 +285,7 @@ resource "aws_waf_sql_injection_match_set" "sql_injection_match_set" { func testAccAWSWafSqlInjectionMatchSetConfig_changeTuples(name string) string { return fmt.Sprintf(` -resource "aws_waf_sql_injection_match_set" "sql_injection_match_set" { +resource "aws_waf_sql_injection_match_set" "test" { name = "%s" sql_injection_match_tuples { @@ -314,7 +301,7 @@ resource "aws_waf_sql_injection_match_set" "sql_injection_match_set" { func testAccAWSWafSqlInjectionMatchSetConfig_noTuples(name string) string { return fmt.Sprintf(` -resource "aws_waf_sql_injection_match_set" "sql_injection_match_set" { +resource "aws_waf_sql_injection_match_set" "test" { name = "%s" } `, name) diff --git a/website/docs/r/waf_sql_injection_match_set.html.markdown b/website/docs/r/waf_sql_injection_match_set.html.markdown index e5567ecb537..04a5e260355 100644 --- a/website/docs/r/waf_sql_injection_match_set.html.markdown +++ b/website/docs/r/waf_sql_injection_match_set.html.markdown @@ -63,3 +63,11 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `id` - The ID of the WAF SQL Injection Match Set. + +## Import + +AWS WAF SQL Injection Match Set can be imported using their ID, e.g. + +``` +$ terraform import aws_waf_sql_injection_match_set.example a1b2c3d4-d5f6-7777-8888-9999aaaabbbbcccc +``` \ No newline at end of file From 30984d785f7e63262008029e9473ebbe005c2439 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 18 Jan 2020 15:20:44 +0200 Subject: [PATCH 020/684] add import step to all tests --- ...source_aws_waf_sql_injection_match_set_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/aws/resource_aws_waf_sql_injection_match_set_test.go b/aws/resource_aws_waf_sql_injection_match_set_test.go index 70d7b9329f1..b7ee771c775 100644 --- a/aws/resource_aws_waf_sql_injection_match_set_test.go +++ b/aws/resource_aws_waf_sql_injection_match_set_test.go @@ -62,6 +62,11 @@ func TestAccAWSWafSqlInjectionMatchSet_changeNameForceNew(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.#", "1"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccAWSWafSqlInjectionMatchSetConfigChangeName(rNameNew), Check: resource.ComposeTestCheckFunc( @@ -118,6 +123,11 @@ func TestAccAWSWafSqlInjectionMatchSet_changeTuples(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.3367958210.text_transformation", "URL_DECODE"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccAWSWafSqlInjectionMatchSetConfig_changeTuples(rName), Check: resource.ComposeAggregateTestCheckFunc( @@ -148,6 +158,11 @@ func TestAccAWSWafSqlInjectionMatchSet_noTuples(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "sql_injection_match_tuples.#", "0"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } From b24b4874d13f2f10579d232b8a30d81f7dd310f0 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 18 Jan 2020 18:24:08 +0200 Subject: [PATCH 021/684] add tags to acm cert data source --- aws/data_source_aws_acm_certificate.go | 12 ++++++++++++ aws/data_source_aws_acm_certificate_test.go | 1 + 2 files changed, 13 insertions(+) diff --git a/aws/data_source_aws_acm_certificate.go b/aws/data_source_aws_acm_certificate.go index a5180b77651..c9607aeae5e 100644 --- a/aws/data_source_aws_acm_certificate.go +++ b/aws/data_source_aws_acm_certificate.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/service/acm" "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 dataSourceAwsAcmCertificate() *schema.Resource { @@ -53,6 +54,7 @@ func dataSourceAwsAcmCertificate() *schema.Resource { Optional: true, Default: false, }, + "tags": tagsSchemaComputed(), }, } } @@ -169,6 +171,16 @@ func dataSourceAwsAcmCertificateRead(d *schema.ResourceData, meta interface{}) e d.SetId(time.Now().UTC().String()) d.Set("arn", matchedCertificate.CertificateArn) + tags, err := keyvaluetags.AcmListTags(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error listing tags for ACM Certificate (%s): %s", d.Id(), err) + } + + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + return nil } diff --git a/aws/data_source_aws_acm_certificate_test.go b/aws/data_source_aws_acm_certificate_test.go index b8fc4f7f8a9..3bdbd4060cd 100644 --- a/aws/data_source_aws_acm_certificate_test.go +++ b/aws/data_source_aws_acm_certificate_test.go @@ -191,6 +191,7 @@ func TestAccAWSAcmCertificateDataSource_KeyTypes(t *testing.T) { Config: testAccAwsAcmCertificateDataSourceConfigKeyTypes(tlsPemEscapeNewlines(certificate), tlsPemEscapeNewlines(key)), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), ), }, }, From f57a9bcca518b3ed9a31117b37268a17dc5f9c0d Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 18 Jan 2020 18:25:00 +0200 Subject: [PATCH 022/684] add docs --- website/docs/d/acm_certificate.html.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/d/acm_certificate.html.markdown b/website/docs/d/acm_certificate.html.markdown index f25694b963b..53a3867efdb 100644 --- a/website/docs/d/acm_certificate.html.markdown +++ b/website/docs/d/acm_certificate.html.markdown @@ -48,3 +48,5 @@ data "aws_acm_certificate" "example" { ## Attributes Reference * `arn` - Set to the ARN of the found certificate, suitable for referencing in other resources that support ACM certificates. + * `tags` - A mapping of tags for the resource. + From 5aa99a2f44bf4c8e7dca6f721d3cd5759e47e995 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 31 Jan 2020 21:35:19 +0200 Subject: [PATCH 023/684] add import support use enums add plan time validations remove extraneous list tags call add disappearing test case --- aws/resource_aws_mq_broker.go | 43 ++- aws/resource_aws_mq_broker_test.go | 529 ++++++++++++++++++----------- 2 files changed, 355 insertions(+), 217 deletions(-) diff --git a/aws/resource_aws_mq_broker.go b/aws/resource_aws_mq_broker.go index 00ef70f6f4f..f4db0a1a9a1 100644 --- a/aws/resource_aws_mq_broker.go +++ b/aws/resource_aws_mq_broker.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/mitchellh/copystructure" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) @@ -22,6 +23,9 @@ func resourceAwsMqBroker() *schema.Resource { Read: resourceAwsMqBrokerRead, Update: resourceAwsMqBrokerUpdate, Delete: resourceAwsMqBrokerDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "apply_immediately": { @@ -63,8 +67,12 @@ func resourceAwsMqBroker() *schema.Resource { "deployment_mode": { Type: schema.TypeString, Optional: true, - Default: "SINGLE_INSTANCE", + Default: mq.DeploymentModeSingleInstance, ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + mq.DeploymentModeSingleInstance, + mq.DeploymentModeActiveStandbyMultiAz, + }, true), }, "encryption_options": { Type: schema.TypeList, @@ -94,6 +102,9 @@ func resourceAwsMqBroker() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + mq.EngineTypeActivemq, + }, true), }, "engine_version": { Type: schema.TypeString, @@ -142,6 +153,15 @@ func resourceAwsMqBroker() *schema.Resource { "day_of_week": { Type: schema.TypeString, Required: true, + ValidateFunc: validation.StringInSlice([]string{ + mq.DayOfWeekSunday, + mq.DayOfWeekMonday, + mq.DayOfWeekTuesday, + mq.DayOfWeekWednesday, + mq.DayOfWeekThursday, + mq.DayOfWeekFriday, + mq.DayOfWeekSaturday, + }, true), }, "time_of_day": { Type: schema.TypeString, @@ -185,7 +205,11 @@ func resourceAwsMqBroker() *schema.Resource { }, "groups": { Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, + MaxItems: 20, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(2, 100), + }, Set: schema.HashString, Optional: true, }, @@ -196,8 +220,9 @@ func resourceAwsMqBroker() *schema.Resource { ValidateFunc: validateMqBrokerPassword, }, "username": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(2, 100), }, }, }, @@ -310,13 +335,13 @@ func resourceAwsMqBrokerRead(d *schema.ResourceData, meta interface{}) error { BrokerId: aws.String(d.Id()), }) if err != nil { - if isAWSErr(err, "NotFoundException", "") { + if isAWSErr(err, mq.ErrCodeNotFoundException, "") { log.Printf("[WARN] MQ Broker %q not found, removing from state", d.Id()) d.SetId("") return nil } // API docs say a 404 can also return a 403 - if isAWSErr(err, "ForbiddenException", "Forbidden") { + if isAWSErr(err, mq.ErrCodeForbiddenException, "Forbidden") { log.Printf("[WARN] MQ Broker %q not found, removing from state", d.Id()) d.SetId("") return nil @@ -376,11 +401,7 @@ func resourceAwsMqBrokerRead(d *schema.ResourceData, meta interface{}) error { return err } - tags, err := keyvaluetags.MqListTags(conn, aws.StringValue(out.BrokerArn)) - if err != nil { - return fmt.Errorf("error listing tags for MQ Broker (%s): %s", d.Id(), err) - } - if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + if err := d.Set("tags", keyvaluetags.MqKeyValueTags(out.Tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } diff --git a/aws/resource_aws_mq_broker_test.go b/aws/resource_aws_mq_broker_test.go index f904e01995e..f961e4463ea 100644 --- a/aws/resource_aws_mq_broker_test.go +++ b/aws/resource_aws_mq_broker_test.go @@ -234,8 +234,10 @@ func TestDiffAwsMqBrokerUsers(t *testing.T) { } func TestAccAWSMqBroker_basic(t *testing.T) { + var broker mq.DescribeBrokerResponse sgName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) brokerName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "aws_mq_broker.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMq(t) }, @@ -245,57 +247,64 @@ func TestAccAWSMqBroker_basic(t *testing.T) { { Config: testAccMqBrokerConfig(sgName, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "auto_minor_version_upgrade", "false"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "broker_name", brokerName), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.#", "1"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "configuration.0.revision", regexp.MustCompile(`^[0-9]+$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "deployment_mode", "SINGLE_INSTANCE"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "encryption_options.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "encryption_options.0.use_aws_owned_key", "true"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "engine_type", "ActiveMQ"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "engine_version", "5.15.0"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "host_instance_type", "mq.t2.micro"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "maintenance_window_start_time.#", "1"), - resource.TestCheckResourceAttrSet("aws_mq_broker.test", "maintenance_window_start_time.0.day_of_week"), - resource.TestCheckResourceAttrSet("aws_mq_broker.test", "maintenance_window_start_time.0.time_of_day"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "logs.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "logs.0.general", "true"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "logs.0.audit", "false"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "maintenance_window_start_time.0.time_zone", "UTC"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "publicly_accessible", "false"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "security_groups.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "subnet_ids.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.console_access", "false"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.groups.#", "0"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.username", "Test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.password", "TestTest1234"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "arn", - regexp.MustCompile("^arn:aws:mq:[a-z0-9-]+:[0-9]{12}:broker:[a-z0-9-]+:[a-f0-9-]+$")), - resource.TestCheckResourceAttr("aws_mq_broker.test", "instances.#", "1"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.console_url", + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "false"), + resource.TestCheckResourceAttr(resourceName, "broker_name", brokerName), + resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), + resource.TestMatchResourceAttr(resourceName, "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), + resource.TestMatchResourceAttr(resourceName, "configuration.0.revision", regexp.MustCompile(`^[0-9]+$`)), + resource.TestCheckResourceAttr(resourceName, "deployment_mode", "SINGLE_INSTANCE"), + resource.TestCheckResourceAttr(resourceName, "encryption_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "encryption_options.0.use_aws_owned_key", "true"), + resource.TestCheckResourceAttr(resourceName, "engine_type", "ActiveMQ"), + resource.TestCheckResourceAttr(resourceName, "engine_version", "5.15.0"), + resource.TestCheckResourceAttr(resourceName, "host_instance_type", "mq.t2.micro"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window_start_time.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "maintenance_window_start_time.0.day_of_week"), + resource.TestCheckResourceAttrSet(resourceName, "maintenance_window_start_time.0.time_of_day"), + resource.TestCheckResourceAttr(resourceName, "logs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logs.0.general", "true"), + resource.TestCheckResourceAttr(resourceName, "logs.0.audit", "false"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window_start_time.0.time_zone", "UTC"), + resource.TestCheckResourceAttr(resourceName, "publicly_accessible", "false"), + resource.TestCheckResourceAttr(resourceName, "security_groups.#", "1"), + resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.console_access", "false"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.groups.#", "0"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.username", "Test"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.password", "TestTest1234"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "mq", regexp.MustCompile(`broker:+.`)), + resource.TestCheckResourceAttr(resourceName, "instances.#", "1"), + resource.TestMatchResourceAttr(resourceName, "instances.0.console_url", regexp.MustCompile(`^https://[a-f0-9-]+\.mq.[a-z0-9-]+.amazonaws.com:8162$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.ip_address", + resource.TestMatchResourceAttr(resourceName, "instances.0.ip_address", regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "instances.0.endpoints.#", "5"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.0", regexp.MustCompile(`^ssl://[a-z0-9-\.]+:61617$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.1", regexp.MustCompile(`^amqp\+ssl://[a-z0-9-\.]+:5671$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.2", regexp.MustCompile(`^stomp\+ssl://[a-z0-9-\.]+:61614$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.3", regexp.MustCompile(`^mqtt\+ssl://[a-z0-9-\.]+:8883$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.4", regexp.MustCompile(`^wss://[a-z0-9-\.]+:61619$`)), + resource.TestCheckResourceAttr(resourceName, "instances.0.endpoints.#", "5"), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.0", regexp.MustCompile(`^ssl://[a-z0-9-\.]+:61617$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.1", regexp.MustCompile(`^amqp\+ssl://[a-z0-9-\.]+:5671$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.2", regexp.MustCompile(`^stomp\+ssl://[a-z0-9-\.]+:61614$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.3", regexp.MustCompile(`^mqtt\+ssl://[a-z0-9-\.]+:8883$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.4", regexp.MustCompile(`^wss://[a-z0-9-\.]+:61619$`)), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"apply_immediately", "user"}, + }, }, }) } func TestAccAWSMqBroker_allFieldsDefaultVpc(t *testing.T) { + var broker mq.DescribeBrokerResponse sgName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) cfgNameBefore := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) cfgNameAfter := fmt.Sprintf("tf-acc-test-updated-%s", acctest.RandString(5)) brokerName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "aws_mq_broker.test" cfgBodyBefore := ` @@ -317,83 +326,89 @@ func TestAccAWSMqBroker_allFieldsDefaultVpc(t *testing.T) { { Config: testAccMqBrokerConfig_allFieldsDefaultVpc(sgName, cfgNameBefore, cfgBodyBefore, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "auto_minor_version_upgrade", "true"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "broker_name", brokerName), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.#", "1"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.0.revision", "2"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "deployment_mode", "ACTIVE_STANDBY_MULTI_AZ"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "engine_type", "ActiveMQ"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "engine_version", "5.15.0"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "host_instance_type", "mq.t2.micro"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "maintenance_window_start_time.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "maintenance_window_start_time.0.day_of_week", "TUESDAY"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "maintenance_window_start_time.0.time_of_day", "02:00"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "maintenance_window_start_time.0.time_zone", "CET"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "logs.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "logs.0.general", "false"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "logs.0.audit", "false"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "publicly_accessible", "true"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "security_groups.#", "2"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "subnet_ids.#", "2"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.#", "2"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.console_access", "true"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.groups.#", "3"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.groups.2456940119", "first"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.groups.3055489385", "second"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.groups.607264868", "third"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.password", "SecondTestTest1234"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.username", "SecondTest"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.console_access", "false"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.groups.#", "0"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.password", "TestTest1234"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.username", "Test"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "arn", + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "true"), + resource.TestCheckResourceAttr(resourceName, "broker_name", brokerName), + resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), + resource.TestMatchResourceAttr(resourceName, "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), + resource.TestCheckResourceAttr(resourceName, "configuration.0.revision", "2"), + resource.TestCheckResourceAttr(resourceName, "deployment_mode", "ACTIVE_STANDBY_MULTI_AZ"), + resource.TestCheckResourceAttr(resourceName, "engine_type", "ActiveMQ"), + resource.TestCheckResourceAttr(resourceName, "engine_version", "5.15.0"), + resource.TestCheckResourceAttr(resourceName, "host_instance_type", "mq.t2.micro"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window_start_time.#", "1"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window_start_time.0.day_of_week", "TUESDAY"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window_start_time.0.time_of_day", "02:00"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window_start_time.0.time_zone", "CET"), + resource.TestCheckResourceAttr(resourceName, "logs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logs.0.general", "false"), + resource.TestCheckResourceAttr(resourceName, "logs.0.audit", "false"), + resource.TestCheckResourceAttr(resourceName, "publicly_accessible", "true"), + resource.TestCheckResourceAttr(resourceName, "security_groups.#", "2"), + resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "2"), + resource.TestCheckResourceAttr(resourceName, "user.#", "2"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.console_access", "true"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.groups.#", "3"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.groups.2456940119", "first"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.groups.3055489385", "second"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.groups.607264868", "third"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.password", "SecondTestTest1234"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.username", "SecondTest"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.console_access", "false"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.groups.#", "0"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.password", "TestTest1234"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.username", "Test"), + resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:aws:mq:[a-z0-9-]+:[0-9]{12}:broker:[a-z0-9-]+:[a-f0-9-]+$")), - resource.TestCheckResourceAttr("aws_mq_broker.test", "instances.#", "2"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.console_url", + resource.TestCheckResourceAttr(resourceName, "instances.#", "2"), + resource.TestMatchResourceAttr(resourceName, "instances.0.console_url", regexp.MustCompile(`^https://[a-f0-9-]+\.mq.[a-z0-9-]+.amazonaws.com:8162$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.ip_address", + resource.TestMatchResourceAttr(resourceName, "instances.0.ip_address", regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "instances.0.endpoints.#", "5"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.0", regexp.MustCompile(`^ssl://[a-z0-9-\.]+:61617$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.1", regexp.MustCompile(`^amqp\+ssl://[a-z0-9-\.]+:5671$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.2", regexp.MustCompile(`^stomp\+ssl://[a-z0-9-\.]+:61614$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.3", regexp.MustCompile(`^mqtt\+ssl://[a-z0-9-\.]+:8883$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.4", regexp.MustCompile(`^wss://[a-z0-9-\.]+:61619$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.console_url", + resource.TestCheckResourceAttr(resourceName, "instances.0.endpoints.#", "5"), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.0", regexp.MustCompile(`^ssl://[a-z0-9-\.]+:61617$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.1", regexp.MustCompile(`^amqp\+ssl://[a-z0-9-\.]+:5671$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.2", regexp.MustCompile(`^stomp\+ssl://[a-z0-9-\.]+:61614$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.3", regexp.MustCompile(`^mqtt\+ssl://[a-z0-9-\.]+:8883$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.4", regexp.MustCompile(`^wss://[a-z0-9-\.]+:61619$`)), + resource.TestMatchResourceAttr(resourceName, "instances.1.console_url", regexp.MustCompile(`^https://[a-f0-9-]+\.mq.[a-z0-9-]+.amazonaws.com:8162$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.ip_address", + resource.TestMatchResourceAttr(resourceName, "instances.1.ip_address", regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "instances.1.endpoints.#", "5"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.endpoints.0", regexp.MustCompile(`^ssl://[a-z0-9-\.]+:61617$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.endpoints.1", regexp.MustCompile(`^amqp\+ssl://[a-z0-9-\.]+:5671$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.endpoints.2", regexp.MustCompile(`^stomp\+ssl://[a-z0-9-\.]+:61614$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.endpoints.3", regexp.MustCompile(`^mqtt\+ssl://[a-z0-9-\.]+:8883$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.endpoints.4", regexp.MustCompile(`^wss://[a-z0-9-\.]+:61619$`)), + resource.TestCheckResourceAttr(resourceName, "instances.1.endpoints.#", "5"), + resource.TestMatchResourceAttr(resourceName, "instances.1.endpoints.0", regexp.MustCompile(`^ssl://[a-z0-9-\.]+:61617$`)), + resource.TestMatchResourceAttr(resourceName, "instances.1.endpoints.1", regexp.MustCompile(`^amqp\+ssl://[a-z0-9-\.]+:5671$`)), + resource.TestMatchResourceAttr(resourceName, "instances.1.endpoints.2", regexp.MustCompile(`^stomp\+ssl://[a-z0-9-\.]+:61614$`)), + resource.TestMatchResourceAttr(resourceName, "instances.1.endpoints.3", regexp.MustCompile(`^mqtt\+ssl://[a-z0-9-\.]+:8883$`)), + resource.TestMatchResourceAttr(resourceName, "instances.1.endpoints.4", regexp.MustCompile(`^wss://[a-z0-9-\.]+:61619$`)), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"apply_immediately", "user"}, + }, { // Update configuration in-place Config: testAccMqBrokerConfig_allFieldsDefaultVpc(sgName, cfgNameBefore, cfgBodyAfter, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "broker_name", brokerName), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.#", "1"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.0.revision", "3"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "broker_name", brokerName), + resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), + resource.TestMatchResourceAttr(resourceName, "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), + resource.TestCheckResourceAttr(resourceName, "configuration.0.revision", "3"), ), }, { // Replace configuration Config: testAccMqBrokerConfig_allFieldsDefaultVpc(sgName, cfgNameAfter, cfgBodyAfter, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "broker_name", brokerName), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.#", "1"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.0.revision", "2"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "broker_name", brokerName), + resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), + resource.TestMatchResourceAttr(resourceName, "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), + resource.TestCheckResourceAttr(resourceName, "configuration.0.revision", "2"), ), }, }, @@ -401,10 +416,12 @@ func TestAccAWSMqBroker_allFieldsDefaultVpc(t *testing.T) { } func TestAccAWSMqBroker_allFieldsCustomVpc(t *testing.T) { + var broker mq.DescribeBrokerResponse sgName := fmt.Sprintf("tf-acc-test-vpc-%s", acctest.RandString(5)) cfgNameBefore := fmt.Sprintf("tf-acc-test-vpc-%s", acctest.RandString(5)) cfgNameAfter := fmt.Sprintf("tf-acc-test-vpc-updated-%s", acctest.RandString(5)) brokerName := fmt.Sprintf("tf-acc-test-vpc-%s", acctest.RandString(5)) + resourceName := "aws_mq_broker.test" cfgBodyBefore := ` @@ -426,83 +443,89 @@ func TestAccAWSMqBroker_allFieldsCustomVpc(t *testing.T) { { Config: testAccMqBrokerConfig_allFieldsCustomVpc(sgName, cfgNameBefore, cfgBodyBefore, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "auto_minor_version_upgrade", "true"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "broker_name", brokerName), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.#", "1"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.0.revision", "2"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "deployment_mode", "ACTIVE_STANDBY_MULTI_AZ"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "engine_type", "ActiveMQ"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "engine_version", "5.15.0"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "host_instance_type", "mq.t2.micro"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "maintenance_window_start_time.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "maintenance_window_start_time.0.day_of_week", "TUESDAY"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "maintenance_window_start_time.0.time_of_day", "02:00"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "maintenance_window_start_time.0.time_zone", "CET"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "logs.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "logs.0.general", "true"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "logs.0.audit", "true"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "publicly_accessible", "true"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "security_groups.#", "2"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "subnet_ids.#", "2"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.#", "2"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.console_access", "true"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.groups.#", "3"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.groups.2456940119", "first"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.groups.3055489385", "second"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.groups.607264868", "third"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.password", "SecondTestTest1234"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1344916805.username", "SecondTest"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.console_access", "false"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.groups.#", "0"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.password", "TestTest1234"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3793764891.username", "Test"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "arn", + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "true"), + resource.TestCheckResourceAttr(resourceName, "broker_name", brokerName), + resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), + resource.TestMatchResourceAttr(resourceName, "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), + resource.TestCheckResourceAttr(resourceName, "configuration.0.revision", "2"), + resource.TestCheckResourceAttr(resourceName, "deployment_mode", "ACTIVE_STANDBY_MULTI_AZ"), + resource.TestCheckResourceAttr(resourceName, "engine_type", "ActiveMQ"), + resource.TestCheckResourceAttr(resourceName, "engine_version", "5.15.0"), + resource.TestCheckResourceAttr(resourceName, "host_instance_type", "mq.t2.micro"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window_start_time.#", "1"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window_start_time.0.day_of_week", "TUESDAY"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window_start_time.0.time_of_day", "02:00"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window_start_time.0.time_zone", "CET"), + resource.TestCheckResourceAttr(resourceName, "logs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logs.0.general", "true"), + resource.TestCheckResourceAttr(resourceName, "logs.0.audit", "true"), + resource.TestCheckResourceAttr(resourceName, "publicly_accessible", "true"), + resource.TestCheckResourceAttr(resourceName, "security_groups.#", "2"), + resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "2"), + resource.TestCheckResourceAttr(resourceName, "user.#", "2"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.console_access", "true"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.groups.#", "3"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.groups.2456940119", "first"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.groups.3055489385", "second"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.groups.607264868", "third"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.password", "SecondTestTest1234"), + resource.TestCheckResourceAttr(resourceName, "user.1344916805.username", "SecondTest"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.console_access", "false"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.groups.#", "0"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.password", "TestTest1234"), + resource.TestCheckResourceAttr(resourceName, "user.3793764891.username", "Test"), + resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:aws:mq:[a-z0-9-]+:[0-9]{12}:broker:[a-z0-9-]+:[a-f0-9-]+$")), - resource.TestCheckResourceAttr("aws_mq_broker.test", "instances.#", "2"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.console_url", + resource.TestCheckResourceAttr(resourceName, "instances.#", "2"), + resource.TestMatchResourceAttr(resourceName, "instances.0.console_url", regexp.MustCompile(`^https://[a-f0-9-]+\.mq.[a-z0-9-]+.amazonaws.com:8162$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.ip_address", + resource.TestMatchResourceAttr(resourceName, "instances.0.ip_address", regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "instances.0.endpoints.#", "5"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.0", regexp.MustCompile(`^ssl://[a-z0-9-\.]+:61617$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.1", regexp.MustCompile(`^amqp\+ssl://[a-z0-9-\.]+:5671$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.2", regexp.MustCompile(`^stomp\+ssl://[a-z0-9-\.]+:61614$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.3", regexp.MustCompile(`^mqtt\+ssl://[a-z0-9-\.]+:8883$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.0.endpoints.4", regexp.MustCompile(`^wss://[a-z0-9-\.]+:61619$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.console_url", + resource.TestCheckResourceAttr(resourceName, "instances.0.endpoints.#", "5"), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.0", regexp.MustCompile(`^ssl://[a-z0-9-\.]+:61617$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.1", regexp.MustCompile(`^amqp\+ssl://[a-z0-9-\.]+:5671$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.2", regexp.MustCompile(`^stomp\+ssl://[a-z0-9-\.]+:61614$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.3", regexp.MustCompile(`^mqtt\+ssl://[a-z0-9-\.]+:8883$`)), + resource.TestMatchResourceAttr(resourceName, "instances.0.endpoints.4", regexp.MustCompile(`^wss://[a-z0-9-\.]+:61619$`)), + resource.TestMatchResourceAttr(resourceName, "instances.1.console_url", regexp.MustCompile(`^https://[a-f0-9-]+\.mq.[a-z0-9-]+.amazonaws.com:8162$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.ip_address", + resource.TestMatchResourceAttr(resourceName, "instances.1.ip_address", regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "instances.1.endpoints.#", "5"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.endpoints.0", regexp.MustCompile(`^ssl://[a-z0-9-\.]+:61617$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.endpoints.1", regexp.MustCompile(`^amqp\+ssl://[a-z0-9-\.]+:5671$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.endpoints.2", regexp.MustCompile(`^stomp\+ssl://[a-z0-9-\.]+:61614$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.endpoints.3", regexp.MustCompile(`^mqtt\+ssl://[a-z0-9-\.]+:8883$`)), - resource.TestMatchResourceAttr("aws_mq_broker.test", "instances.1.endpoints.4", regexp.MustCompile(`^wss://[a-z0-9-\.]+:61619$`)), + resource.TestCheckResourceAttr(resourceName, "instances.1.endpoints.#", "5"), + resource.TestMatchResourceAttr(resourceName, "instances.1.endpoints.0", regexp.MustCompile(`^ssl://[a-z0-9-\.]+:61617$`)), + resource.TestMatchResourceAttr(resourceName, "instances.1.endpoints.1", regexp.MustCompile(`^amqp\+ssl://[a-z0-9-\.]+:5671$`)), + resource.TestMatchResourceAttr(resourceName, "instances.1.endpoints.2", regexp.MustCompile(`^stomp\+ssl://[a-z0-9-\.]+:61614$`)), + resource.TestMatchResourceAttr(resourceName, "instances.1.endpoints.3", regexp.MustCompile(`^mqtt\+ssl://[a-z0-9-\.]+:8883$`)), + resource.TestMatchResourceAttr(resourceName, "instances.1.endpoints.4", regexp.MustCompile(`^wss://[a-z0-9-\.]+:61619$`)), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"apply_immediately", "user"}, + }, { // Update configuration in-place Config: testAccMqBrokerConfig_allFieldsCustomVpc(sgName, cfgNameBefore, cfgBodyAfter, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "broker_name", brokerName), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.#", "1"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.0.revision", "3"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "broker_name", brokerName), + resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), + resource.TestMatchResourceAttr(resourceName, "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), + resource.TestCheckResourceAttr(resourceName, "configuration.0.revision", "3"), ), }, { // Replace configuration Config: testAccMqBrokerConfig_allFieldsCustomVpc(sgName, cfgNameAfter, cfgBodyAfter, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "broker_name", brokerName), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.#", "1"), - resource.TestMatchResourceAttr("aws_mq_broker.test", "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), - resource.TestCheckResourceAttr("aws_mq_broker.test", "configuration.0.revision", "2"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "broker_name", brokerName), + resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), + resource.TestMatchResourceAttr(resourceName, "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), + resource.TestCheckResourceAttr(resourceName, "configuration.0.revision", "2"), ), }, }, @@ -510,6 +533,7 @@ func TestAccAWSMqBroker_allFieldsCustomVpc(t *testing.T) { } func TestAccAWSMqBroker_EncryptionOptions_KmsKeyId(t *testing.T) { + var broker mq.DescribeBrokerResponse rName := acctest.RandomWithPrefix("tf-acc-test") kmsKeyResourceName := "aws_kms_key.test" resourceName := "aws_mq_broker.test" @@ -522,17 +546,24 @@ func TestAccAWSMqBroker_EncryptionOptions_KmsKeyId(t *testing.T) { { Config: testAccMqBrokerConfigEncryptionOptionsKmsKeyId(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists(resourceName), + testAccCheckAwsMqBrokerExists(resourceName, &broker), resource.TestCheckResourceAttr(resourceName, "encryption_options.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "encryption_options.0.kms_key_id", kmsKeyResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "encryption_options.0.use_aws_owned_key", "false"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"apply_immediately", "user"}, + }, }, }) } func TestAccAWSMqBroker_EncryptionOptions_UseAwsOwnedKey_Disabled(t *testing.T) { + var broker mq.DescribeBrokerResponse rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_mq_broker.test" @@ -544,16 +575,23 @@ func TestAccAWSMqBroker_EncryptionOptions_UseAwsOwnedKey_Disabled(t *testing.T) { Config: testAccMqBrokerConfigEncryptionOptionsUseAwsOwnedKey(rName, false), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists(resourceName), + testAccCheckAwsMqBrokerExists(resourceName, &broker), resource.TestCheckResourceAttr(resourceName, "encryption_options.#", "1"), resource.TestCheckResourceAttr(resourceName, "encryption_options.0.use_aws_owned_key", "false"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"apply_immediately", "user"}, + }, }, }) } func TestAccAWSMqBroker_EncryptionOptions_UseAwsOwnedKey_Enabled(t *testing.T) { + var broker mq.DescribeBrokerResponse rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_mq_broker.test" @@ -565,18 +603,26 @@ func TestAccAWSMqBroker_EncryptionOptions_UseAwsOwnedKey_Enabled(t *testing.T) { { Config: testAccMqBrokerConfigEncryptionOptionsUseAwsOwnedKey(rName, true), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists(resourceName), + testAccCheckAwsMqBrokerExists(resourceName, &broker), resource.TestCheckResourceAttr(resourceName, "encryption_options.#", "1"), resource.TestCheckResourceAttr(resourceName, "encryption_options.0.use_aws_owned_key", "true"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"apply_immediately", "user"}, + }, }, }) } func TestAccAWSMqBroker_updateUsers(t *testing.T) { + var broker mq.DescribeBrokerResponse sgName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) brokerName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "aws_mq_broker.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMq(t) }, @@ -586,41 +632,47 @@ func TestAccAWSMqBroker_updateUsers(t *testing.T) { { Config: testAccMqBrokerConfig_updateUsers1(sgName, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3400735725.console_access", "false"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3400735725.groups.#", "0"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3400735725.password", "TestTest1111"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.3400735725.username", "first"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "user.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.3400735725.console_access", "false"), + resource.TestCheckResourceAttr(resourceName, "user.3400735725.groups.#", "0"), + resource.TestCheckResourceAttr(resourceName, "user.3400735725.password", "TestTest1111"), + resource.TestCheckResourceAttr(resourceName, "user.3400735725.username", "first"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"apply_immediately", "user"}, + }, // Adding new user + modify existing { Config: testAccMqBrokerConfig_updateUsers2(sgName, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.#", "2"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1074486012.console_access", "false"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1074486012.groups.#", "0"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1074486012.password", "TestTest2222"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1074486012.username", "second"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1166726986.console_access", "true"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1166726986.groups.#", "0"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1166726986.password", "TestTest1111updated"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.1166726986.username", "first"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "user.#", "2"), + resource.TestCheckResourceAttr(resourceName, "user.1074486012.console_access", "false"), + resource.TestCheckResourceAttr(resourceName, "user.1074486012.groups.#", "0"), + resource.TestCheckResourceAttr(resourceName, "user.1074486012.password", "TestTest2222"), + resource.TestCheckResourceAttr(resourceName, "user.1074486012.username", "second"), + resource.TestCheckResourceAttr(resourceName, "user.1166726986.console_access", "true"), + resource.TestCheckResourceAttr(resourceName, "user.1166726986.groups.#", "0"), + resource.TestCheckResourceAttr(resourceName, "user.1166726986.password", "TestTest1111updated"), + resource.TestCheckResourceAttr(resourceName, "user.1166726986.username", "first"), ), }, // Deleting user + modify existing { Config: testAccMqBrokerConfig_updateUsers3(sgName, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.2244717082.console_access", "false"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.2244717082.groups.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.2244717082.groups.2282622326", "admin"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.2244717082.password", "TestTest2222"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.2244717082.username", "second"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "user.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.2244717082.console_access", "false"), + resource.TestCheckResourceAttr(resourceName, "user.2244717082.groups.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.2244717082.groups.2282622326", "admin"), + resource.TestCheckResourceAttr(resourceName, "user.2244717082.password", "TestTest2222"), + resource.TestCheckResourceAttr(resourceName, "user.2244717082.username", "second"), ), }, }, @@ -628,8 +680,10 @@ func TestAccAWSMqBroker_updateUsers(t *testing.T) { } func TestAccAWSMqBroker_updateTags(t *testing.T) { + var broker mq.DescribeBrokerResponse sgName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) brokerName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "aws_mq_broker.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMq(t) }, @@ -639,28 +693,34 @@ func TestAccAWSMqBroker_updateTags(t *testing.T) { { Config: testAccMqBrokerConfig_updateTags1(sgName, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "tags.%", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "tags.env", "test"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "test"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"apply_immediately", "user"}, + }, // Modify existing tags { Config: testAccMqBrokerConfig_updateTags2(sgName, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "tags.%", "2"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "tags.env", "test2"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "tags.role", "test-role"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "test2"), + resource.TestCheckResourceAttr(resourceName, "tags.role", "test-role"), ), }, // Deleting tags { Config: testAccMqBrokerConfig_updateTags3(sgName, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "tags.%", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "tags.role", "test-role"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.role", "test-role"), ), }, }, @@ -668,8 +728,10 @@ func TestAccAWSMqBroker_updateTags(t *testing.T) { } func TestAccAWSMqBroker_updateSecurityGroup(t *testing.T) { + var broker mq.DescribeBrokerResponse sgName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) brokerName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "aws_mq_broker.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMq(t) }, @@ -679,15 +741,21 @@ func TestAccAWSMqBroker_updateSecurityGroup(t *testing.T) { { Config: testAccMqBrokerConfig(sgName, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "security_groups.#", "1"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "security_groups.#", "1"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"apply_immediately", "user"}, + }, { Config: testAccMqBrokerConfig_updateSecurityGroups(sgName, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "security_groups.#", "2"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "security_groups.#", "2"), ), }, // Trigger a reboot and ensure the password change was applied @@ -695,17 +763,40 @@ func TestAccAWSMqBroker_updateSecurityGroup(t *testing.T) { { Config: testAccMqBrokerConfig_updateUsersSecurityGroups(sgName, brokerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqBrokerExists("aws_mq_broker.test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "security_groups.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.#", "1"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.2209734970.username", "Test"), - resource.TestCheckResourceAttr("aws_mq_broker.test", "user.2209734970.password", "TestTest9999"), + testAccCheckAwsMqBrokerExists(resourceName, &broker), + resource.TestCheckResourceAttr(resourceName, "security_groups.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.2209734970.username", "Test"), + resource.TestCheckResourceAttr(resourceName, "user.2209734970.password", "TestTest9999"), ), }, }, }) } +func TestAccAWSMqBroker_disappears(t *testing.T) { + var broker mq.DescribeBrokerResponse + sgName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + brokerName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "aws_mq_broker.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMq(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsMqBrokerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccMqBrokerConfig(sgName, brokerName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsMqBrokerExists(resourceName, &broker), + testAccCheckAwsMqBrokerDisappears(&broker), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAwsMqBrokerDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).mqconn @@ -720,7 +811,7 @@ func testAccCheckAwsMqBrokerDestroy(s *terraform.State) error { _, err := conn.DescribeBroker(input) if err != nil { - if isAWSErr(err, "NotFoundException", "") { + if isAWSErr(err, mq.ErrCodeNotFoundException, "") { return nil } return err @@ -732,17 +823,43 @@ func testAccCheckAwsMqBrokerDestroy(s *terraform.State) error { return nil } -func testAccCheckAwsMqBrokerExists(name string) resource.TestCheckFunc { +func testAccCheckAwsMqBrokerExists(name string, broker *mq.DescribeBrokerResponse) resource.TestCheckFunc { return func(s *terraform.State) error { - _, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[name] if !ok { return fmt.Errorf("Not found: %s", name) } + if rs.Primary.ID == "" { + return fmt.Errorf("No MQ Broker is set") + } + + conn := testAccProvider.Meta().(*AWSClient).mqconn + resp, err := conn.DescribeBroker(&mq.DescribeBrokerInput{ + BrokerId: aws.String(rs.Primary.ID), + }) + + if err != nil { + return fmt.Errorf("Error describing MQ Broker: %s", err.Error()) + } + + *broker = *resp + return nil } } +func testAccCheckAwsMqBrokerDisappears(broker *mq.DescribeBrokerResponse) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).mqconn + _, err := conn.DeleteBroker(&mq.DeleteBrokerInput{ + BrokerId: broker.BrokerId, + }) + + return err + } +} + func testAccPreCheckAWSMq(t *testing.T) { conn := testAccProvider.Meta().(*AWSClient).mqconn From ffbe0c6e130cb54f7a667ee69b6ddbc68085c3f8 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 31 Jan 2020 22:22:11 +0200 Subject: [PATCH 024/684] update arn test --- aws/resource_aws_mq_broker_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_mq_broker_test.go b/aws/resource_aws_mq_broker_test.go index f961e4463ea..5c2c8f56b1b 100644 --- a/aws/resource_aws_mq_broker_test.go +++ b/aws/resource_aws_mq_broker_test.go @@ -358,8 +358,7 @@ func TestAccAWSMqBroker_allFieldsDefaultVpc(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "user.3793764891.groups.#", "0"), resource.TestCheckResourceAttr(resourceName, "user.3793764891.password", "TestTest1234"), resource.TestCheckResourceAttr(resourceName, "user.3793764891.username", "Test"), - resource.TestMatchResourceAttr(resourceName, "arn", - regexp.MustCompile("^arn:aws:mq:[a-z0-9-]+:[0-9]{12}:broker:[a-z0-9-]+:[a-f0-9-]+$")), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "mq", regexp.MustCompile(`broker:+.`)), resource.TestCheckResourceAttr(resourceName, "instances.#", "2"), resource.TestMatchResourceAttr(resourceName, "instances.0.console_url", regexp.MustCompile(`^https://[a-f0-9-]+\.mq.[a-z0-9-]+.amazonaws.com:8162$`)), @@ -475,8 +474,7 @@ func TestAccAWSMqBroker_allFieldsCustomVpc(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "user.3793764891.groups.#", "0"), resource.TestCheckResourceAttr(resourceName, "user.3793764891.password", "TestTest1234"), resource.TestCheckResourceAttr(resourceName, "user.3793764891.username", "Test"), - resource.TestMatchResourceAttr(resourceName, "arn", - regexp.MustCompile("^arn:aws:mq:[a-z0-9-]+:[0-9]{12}:broker:[a-z0-9-]+:[a-f0-9-]+$")), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "mq", regexp.MustCompile(`broker:+.`)), resource.TestCheckResourceAttr(resourceName, "instances.#", "2"), resource.TestMatchResourceAttr(resourceName, "instances.0.console_url", regexp.MustCompile(`^https://[a-f0-9-]+\.mq.[a-z0-9-]+.amazonaws.com:8162$`)), From 50b08ac969fe4f24d6f7ceb7d4008fa6e5e0dfc6 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 31 Jan 2020 22:43:16 +0200 Subject: [PATCH 025/684] update docs --- website/docs/r/mq_broker.html.markdown | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/website/docs/r/mq_broker.html.markdown b/website/docs/r/mq_broker.html.markdown index 10b85163d84..d37145072e3 100644 --- a/website/docs/r/mq_broker.html.markdown +++ b/website/docs/r/mq_broker.html.markdown @@ -120,4 +120,8 @@ In addition to all arguments above, the following attributes are exported: ## Import -MQ Broker is currently not importable. +MQ Brokers can be imported using their broker id, e.g. + +``` +$ terraform import aws_mq_broker.example a1b2c3d4-d5f6-7777-8888-9999aaaabbbbcccc +``` From 760f831d6064d21c48920739a739adb7df7c585f Mon Sep 17 00:00:00 2001 From: Stefan Sundin Date: Sun, 2 Feb 2020 15:42:54 -0800 Subject: [PATCH 026/684] Update to use keyvaluetags. --- ...source_aws_egress_only_internet_gateway.go | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_egress_only_internet_gateway.go b/aws/resource_aws_egress_only_internet_gateway.go index 4ca9130243f..043a10f1c1c 100644 --- a/aws/resource_aws_egress_only_internet_gateway.go +++ b/aws/resource_aws_egress_only_internet_gateway.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsEgressOnlyInternetGateway() *schema.Resource { @@ -44,9 +45,10 @@ func resourceAwsEgressOnlyInternetGatewayCreate(d *schema.ResourceData, meta int d.SetId(aws.StringValue(resp.EgressOnlyInternetGateway.EgressOnlyInternetGatewayId)) - err = setTags(conn, d) - if err != nil { - return err + if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { + if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), nil, v); err != nil { + return fmt.Errorf("error adding tags: %s", err) + } } return resourceAwsEgressOnlyInternetGatewayRead(d, meta) @@ -92,7 +94,9 @@ func resourceAwsEgressOnlyInternetGatewayRead(d *schema.ResourceData, meta inter d.Set("vpc_id", igw.Attachments[0].VpcId) } - d.Set("tags", tagsToMap(igw.Tags)) + if err := d.Set("tags", keyvaluetags.Ec2KeyValueTags(igw.Tags).IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } return nil } @@ -111,8 +115,12 @@ func getEc2EgressOnlyInternetGateway(id string, resp *ec2.DescribeEgressOnlyInte func resourceAwsEgressOnlyInternetGatewayUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - if err := setTags(conn, d); err != nil { - return err + if d.HasChange("tags") { + o, n := d.GetChange("tags") + + if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil { + return fmt.Errorf("error updating Egress Only Internet Gateway (%s) tags: %s", d.Id(), err) + } } d.SetPartial("tags") From ae1af3c30310e27d1907da1a10ee7b8ab21878e6 Mon Sep 17 00:00:00 2001 From: Aaron Smith Date: Mon, 3 Feb 2020 09:12:41 -0600 Subject: [PATCH 027/684] initial commit --- aws/resource_aws_backup_plan.go | 114 ++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/aws/resource_aws_backup_plan.go b/aws/resource_aws_backup_plan.go index c6811bb6707..66489ef4e02 100644 --- a/aws/resource_aws_backup_plan.go +++ b/aws/resource_aws_backup_plan.go @@ -69,6 +69,35 @@ func resourceAwsBackupPlan() *schema.Resource { }, }, }, + "copy_actions": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "lifecycle": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cold_storage_after": { + Type: schema.TypeInt, + Optional: true, + }, + "delete_after": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + "destination_vault_arn": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, "recovery_point_tags": tagsSchema(), }, }, @@ -235,12 +264,44 @@ func expandBackupPlanRules(vRules *schema.Set) []*backup.RuleInput { rule.Lifecycle = lifecycle } + if vCopyActions := expandBackupPlanCopyActions(mRule["copy_action"].(*schema.Set).List()); len(vCopyActions) > 0 { + rule.CopyActions = vCopyActions + } + rules = append(rules, rule) } return rules } +func expandBackupPlanCopyActions(actionList []interface{}) []*backup.CopyAction { + actions := []*backup.CopyAction{} + + for _, i := range actionList { + item := i.(map[string]interface{}) + action := &backup.CopyAction{} + + action.DestinationBackupVaultArn = aws.String(item["destination_vault_arn"].(string)) + action.Lifecycle = expandBackupPlanLifecycle(item["lifecycle"].(*schema.Set)) + + actions = append(actions, action) + } + + return actions +} + +func expandBackupPlanLifecycle(l *schema.Set) *backup.Lifecycle { + var lifecycle *backup.Lifecycle + + for _, i := range l.List() { + lc := i.(map[string]interface{}) + lifecycle.DeleteAfterDays = aws.Int64(int64(lc["delete_after"].(int))) + lifecycle.MoveToColdStorageAfterDays = aws.Int64(int64(lc["cold_storage_after"].(int))) + } + + return lifecycle +} + func flattenBackupPlanRules(rules []*backup.Rule) *schema.Set { vRules := []interface{}{} @@ -263,12 +324,36 @@ func flattenBackupPlanRules(rules []*backup.Rule) *schema.Set { } } + if actions := rule.CopyActions; actions != nil { + for _, action := range actions { + mRule["copy_action"] = []interface{}{ + map[string]interface{}{ + "lifecycle": flattenBackupPlanCopyActionLifecycle(action.Lifecycle), + "destination_vault_arn": aws.StringValue(action.DestinationBackupVaultArn), + }, + } + } + } + vRules = append(vRules, mRule) } return schema.NewSet(backupBackupPlanHash, vRules) } +func flattenBackupPlanCopyActionLifecycle(copyActionLifecycle *backup.Lifecycle) []interface{} { + if copyActionLifecycle == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "delete_after": aws.Int64Value(copyActionLifecycle.DeleteAfterDays), + "cold_storage_after": aws.Int64Value(copyActionLifecycle.MoveToColdStorageAfterDays), + } + + return []interface{}{m} +} + func backupBackupPlanHash(vRule interface{}) int { var buf bytes.Buffer @@ -305,5 +390,34 @@ func backupBackupPlanHash(vRule interface{}) int { } } + if v, ok := mRule["copy_action"]; ok { + vCopyActions := v.([]map[string]interface{}) + if len(vCopyActions) > 1 { + for _, action := range vCopyActions { + if v, ok := action["lifecycle"].([]interface{}); ok { + buf.WriteString(fmt.Sprintf("%d-", backupBackupPlanCopyActionLifecycleHash(v))) + } + + if v, ok := action["destination_vault_arn"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + } + } + } + + return hashcode.String(buf.String()) +} + +func backupBackupPlanCopyActionLifecycleHash(vLifecycle interface{}) int { + var buf bytes.Buffer + mLifecycle := vLifecycle.(map[string]interface{}) + + if v, ok := mLifecycle["delete_after"].(int); ok { + buf.WriteString(fmt.Sprintf("%d-", v)) + } + if v, ok := mLifecycle["cold_storage_after"].(int); ok { + buf.WriteString(fmt.Sprintf("%d-", v)) + } + return hashcode.String(buf.String()) } From 99f311d8bde75e5cf65f26bd4fd749df813b5d72 Mon Sep 17 00:00:00 2001 From: Aaron Smith Date: Wed, 5 Feb 2020 21:52:03 -0600 Subject: [PATCH 028/684] fixing bugs, adding tests, updating docs --- aws/resource_aws_backup_plan.go | 62 +++--- aws/resource_aws_backup_plan_test.go | 241 +++++++++++++++++++++++ website/docs/r/backup_plan.html.markdown | 21 +- 3 files changed, 283 insertions(+), 41 deletions(-) diff --git a/aws/resource_aws_backup_plan.go b/aws/resource_aws_backup_plan.go index 66489ef4e02..5d0f9648c24 100644 --- a/aws/resource_aws_backup_plan.go +++ b/aws/resource_aws_backup_plan.go @@ -69,8 +69,8 @@ func resourceAwsBackupPlan() *schema.Resource { }, }, }, - "copy_actions": { - Type: schema.TypeSet, + "copy_action": { + Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -229,8 +229,6 @@ func expandBackupPlanRules(vRules *schema.Set) []*backup.RuleInput { if vRuleName, ok := mRule["rule_name"].(string); ok && vRuleName != "" { rule.RuleName = aws.String(vRuleName) - } else { - continue } if vTargetVaultName, ok := mRule["target_vault_name"].(string); ok && vTargetVaultName != "" { rule.TargetBackupVaultName = aws.String(vTargetVaultName) @@ -264,7 +262,7 @@ func expandBackupPlanRules(vRules *schema.Set) []*backup.RuleInput { rule.Lifecycle = lifecycle } - if vCopyActions := expandBackupPlanCopyActions(mRule["copy_action"].(*schema.Set).List()); len(vCopyActions) > 0 { + if vCopyActions := expandBackupPlanCopyActions(mRule["copy_action"].([]interface{})); len(vCopyActions) > 0 { rule.CopyActions = vCopyActions } @@ -282,7 +280,7 @@ func expandBackupPlanCopyActions(actionList []interface{}) []*backup.CopyAction action := &backup.CopyAction{} action.DestinationBackupVaultArn = aws.String(item["destination_vault_arn"].(string)) - action.Lifecycle = expandBackupPlanLifecycle(item["lifecycle"].(*schema.Set)) + action.Lifecycle = expandBackupPlanLifecycle(item["lifecycle"].([]interface{})) actions = append(actions, action) } @@ -290,13 +288,17 @@ func expandBackupPlanCopyActions(actionList []interface{}) []*backup.CopyAction return actions } -func expandBackupPlanLifecycle(l *schema.Set) *backup.Lifecycle { - var lifecycle *backup.Lifecycle +func expandBackupPlanLifecycle(l []interface{}) *backup.Lifecycle { + lifecycle := new(backup.Lifecycle) - for _, i := range l.List() { + for _, i := range l { lc := i.(map[string]interface{}) - lifecycle.DeleteAfterDays = aws.Int64(int64(lc["delete_after"].(int))) - lifecycle.MoveToColdStorageAfterDays = aws.Int64(int64(lc["cold_storage_after"].(int))) + if vDeleteAfter, ok := lc["delete_after"]; ok && vDeleteAfter.(int) > 0 { + lifecycle.DeleteAfterDays = aws.Int64(int64(vDeleteAfter.(int))) + } + if vMoveToColdStorageAfterDays, ok := lc["cold_storage_after"]; ok && vMoveToColdStorageAfterDays.(int) > 0 { + lifecycle.MoveToColdStorageAfterDays = aws.Int64(int64(vMoveToColdStorageAfterDays.(int))) + } } return lifecycle @@ -390,34 +392,26 @@ func backupBackupPlanHash(vRule interface{}) int { } } - if v, ok := mRule["copy_action"]; ok { - vCopyActions := v.([]map[string]interface{}) - if len(vCopyActions) > 1 { - for _, action := range vCopyActions { - if v, ok := action["lifecycle"].([]interface{}); ok { - buf.WriteString(fmt.Sprintf("%d-", backupBackupPlanCopyActionLifecycleHash(v))) + if vCopyActions, ok := mRule["copy_action"].([]interface{}); ok && len(vCopyActions) > 0 && vCopyActions[0] != nil { + for _, a := range vCopyActions { + action := a.(map[string]interface{}) + if mLifecycle, ok := action["lifecycle"].([]interface{}); ok { + for _, l := range mLifecycle { + lifecycle := l.(map[string]interface{}) + if v, ok := lifecycle["delete_after"].(int); ok { + buf.WriteString(fmt.Sprintf("%d-", v)) + } + if v, ok := lifecycle["cold_storage_after"].(int); ok { + buf.WriteString(fmt.Sprintf("%d-", v)) + } } + } - if v, ok := action["destination_vault_arn"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } + if v, ok := action["destination_vault_arn"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) } } } return hashcode.String(buf.String()) } - -func backupBackupPlanCopyActionLifecycleHash(vLifecycle interface{}) int { - var buf bytes.Buffer - mLifecycle := vLifecycle.(map[string]interface{}) - - if v, ok := mLifecycle["delete_after"].(int); ok { - buf.WriteString(fmt.Sprintf("%d-", v)) - } - if v, ok := mLifecycle["cold_storage_after"].(int); ok { - buf.WriteString(fmt.Sprintf("%d-", v)) - } - - return hashcode.String(buf.String()) -} diff --git a/aws/resource_aws_backup_plan_test.go b/aws/resource_aws_backup_plan_test.go index 7ce2dab20c5..69ca697e331 100644 --- a/aws/resource_aws_backup_plan_test.go +++ b/aws/resource_aws_backup_plan_test.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/service/backup" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/terraform" ) @@ -294,6 +295,134 @@ func TestAccAwsBackupPlan_withRecoveryPointTags(t *testing.T) { }) } +func TestAccAwsBackupPlan_withCopyActions(t *testing.T) { + var plan backup.GetBackupPlanOutput + ruleNameMap := map[string]string{} + resourceName := "aws_backup_plan.test" + rName1 := fmt.Sprintf("tf-testacc-backup-%[1]s", acctest.RandString(14)) + rName2 := fmt.Sprintf("tf-testacc-backup-%[1]s", acctest.RandString(14)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSBackup(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsBackupPlanDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsBackupPlanConfig_copyAction(rName1, rName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsBackupPlanExists(resourceName, &plan, &ruleNameMap), + resource.TestCheckResourceAttr(resourceName, "name", rName1), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "rule_name", rName1), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.0.cold_storage_after", "30"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.0.delete_after", "180"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.#", "1"), + testAccCheckAwsBackupPlanRuleAttrSet(resourceName, &ruleNameMap, rName1, "copy_action.0.destination_vault_arn"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.0.cold_storage_after", "30"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.0.delete_after", "180"), + ), + }, + { + Config: testAccAwsBackupPlanConfig_copyActionUpdated(rName1, rName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsBackupPlanExists(resourceName, &plan, &ruleNameMap), + resource.TestCheckResourceAttr(resourceName, "name", rName1), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "rule_name", rName1), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.0.cold_storage_after", "30"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.0.delete_after", "180"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.#", "1"), + testAccCheckAwsBackupPlanRuleAttrSet(resourceName, &ruleNameMap, rName1, "copy_action.0.destination_vault_arn"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.0.cold_storage_after", "60"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.0.delete_after", "365"), + ), + }, + { + Config: testAccAwsBackupPlanConfig_basic(rName1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsBackupPlanExists(resourceName, &plan, &ruleNameMap), + resource.TestCheckResourceAttr(resourceName, "name", rName1), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "rule_name", rName1), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.#", "0"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.#", "0"), + ), + }, + }, + }) +} + +func TestAccAwsBackupPlan_withCopyActionsCrossRegion(t *testing.T) { + var providers []*schema.Provider + var plan backup.GetBackupPlanOutput + ruleNameMap := map[string]string{} + resourceName := "aws_backup_plan.test" + rName1 := fmt.Sprintf("tf-testacc-backup-%[1]s", acctest.RandString(14)) + rName2 := fmt.Sprintf("tf-testacc-backup-%[1]s", acctest.RandString(14)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckAWSBackup(t) + testAccMultipleRegionsPreCheck(t) + testAccAlternateRegionPreCheck(t) + }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckAwsBackupPlanDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsBackupPlanConfig_copyActionCrossRegion(rName1, rName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsBackupPlanExists(resourceName, &plan, &ruleNameMap), + resource.TestCheckResourceAttr(resourceName, "name", rName1), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "rule_name", rName1), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.0.cold_storage_after", "30"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.0.delete_after", "180"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.#", "1"), + testAccCheckAwsBackupPlanRuleAttrSet(resourceName, &ruleNameMap, rName1, "copy_action.0.destination_vault_arn"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.0.cold_storage_after", "30"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.0.delete_after", "180"), + ), + }, + { + Config: testAccAwsBackupPlanConfig_copyActionUpdated(rName1, rName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsBackupPlanExists(resourceName, &plan, &ruleNameMap), + resource.TestCheckResourceAttr(resourceName, "name", rName1), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "rule_name", rName1), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.0.cold_storage_after", "30"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.0.delete_after", "180"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.#", "1"), + testAccCheckAwsBackupPlanRuleAttrSet(resourceName, &ruleNameMap, rName1, "copy_action.0.destination_vault_arn"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.0.cold_storage_after", "60"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.0.lifecycle.0.delete_after", "365"), + ), + }, + { + Config: testAccAwsBackupPlanConfig_basic(rName1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsBackupPlanExists(resourceName, &plan, &ruleNameMap), + resource.TestCheckResourceAttr(resourceName, "name", rName1), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "rule_name", rName1), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "lifecycle.#", "0"), + testAccCheckAwsBackupPlanRuleAttr(resourceName, &ruleNameMap, rName1, "copy_action.#", "0"), + ), + }, + }, + }) +} + func TestAccAwsBackupPlan_disappears(t *testing.T) { var plan backup.GetBackupPlanOutput ruleNameMap := map[string]string{} @@ -394,6 +523,12 @@ func testAccCheckAwsBackupPlanRuleAttr(name string, ruleNameMap *map[string]stri } } +func testAccCheckAwsBackupPlanRuleAttrSet(name string, ruleNameMap *map[string]string, ruleName, value string) resource.TestCheckFunc { + return func(s *terraform.State) error { + return resource.TestCheckResourceAttrSet(name, fmt.Sprintf("rule.%s.%s", (*ruleNameMap)[ruleName], value))(s) + } +} + func testAccAwsBackupPlanConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_backup_vault" "test" { @@ -625,3 +760,109 @@ resource "aws_backup_plan" "test" { } `, rName) } + +func testAccAwsBackupPlanConfig_copyAction(rName1 string, rName2 string) string { + return fmt.Sprintf(` +resource "aws_backup_vault" "test" { + name = %[1]q +} + +resource "aws_backup_vault" "test2" { + name = %[2]q +} + +resource "aws_backup_plan" "test" { + name = %[1]q + + rule { + rule_name = %[1]q + target_vault_name = "${aws_backup_vault.test.name}" + schedule = "cron(0 12 * * ? *)" + + lifecycle { + cold_storage_after = 30 + delete_after = 180 + } + + copy_action { + lifecycle { + cold_storage_after = 30 + delete_after = 180 + } + destination_vault_arn = "${aws_backup_vault.test2.arn}" + } + } +} +`, rName1, rName2) +} + +func testAccAwsBackupPlanConfig_copyActionUpdated(rName1 string, rName2 string) string { + return fmt.Sprintf(` +resource "aws_backup_vault" "test" { + name = %[1]q +} + +resource "aws_backup_vault" "test2" { + name = %[2]q +} + +resource "aws_backup_plan" "test" { + name = %[1]q + + rule { + rule_name = %[1]q + target_vault_name = "${aws_backup_vault.test.name}" + schedule = "cron(0 12 * * ? *)" + + lifecycle { + cold_storage_after = 30 + delete_after = 180 + } + + copy_action { + lifecycle { + cold_storage_after = 60 + delete_after = 365 + } + destination_vault_arn = "${aws_backup_vault.test2.arn}" + } + } +} +`, rName1, rName2) +} + +func testAccAwsBackupPlanConfig_copyActionCrossRegion(rName1 string, rName2 string) string { + return testAccAlternateRegionProviderConfig() + fmt.Sprintf(` +resource "aws_backup_vault" "test" { + name = %[1]q +} + +resource "aws_backup_vault" "test2" { + provider = "aws.alternate" + name = %[2]q +} + +resource "aws_backup_plan" "test" { + name = %[1]q + + rule { + rule_name = %[1]q + target_vault_name = "${aws_backup_vault.test.name}" + schedule = "cron(0 12 * * ? *)" + + lifecycle { + cold_storage_after = 30 + delete_after = 180 + } + + copy_action { + lifecycle { + cold_storage_after = 30 + delete_after = 180 + } + destination_vault_arn = "${aws_backup_vault.test2.arn}" + } + } +} +`, rName1, rName2) +} diff --git a/website/docs/r/backup_plan.html.markdown b/website/docs/r/backup_plan.html.markdown index 7bada31b497..3526c2b9730 100644 --- a/website/docs/r/backup_plan.html.markdown +++ b/website/docs/r/backup_plan.html.markdown @@ -36,18 +36,25 @@ The following arguments are supported: For **rule** the following attributes are supported: * `rule_name` - (Required) An display name for a backup rule. -* `target_vault_name` (Required) - The name of a logical container where backups are stored. -* `schedule` (Optional) - A CRON expression specifying when AWS Backup initiates a backup job. -* `start_window` (Optional) - The amount of time in minutes before beginning a backup. -* `completion_window` (Optional) - The amount of time AWS Backup attempts a backup before canceling the job and returning an error. -* `lifecycle` (Optional) - The lifecycle defines when a protected resource is transitioned to cold storage and when it expires. Fields documented below. -* `recovery_point_tags` (Optional) - Metadata that you can assign to help organize the resources that you create. +* `target_vault_name` - (Required) The name of a logical container where backups are stored. +* `schedule` - (Optional) A CRON expression specifying when AWS Backup initiates a backup job. +* `start_window` - (Optional) The amount of time in minutes before beginning a backup. +* `completion_window` - (Optional) The amount of time AWS Backup attempts a backup before canceling the job and returning an error. +* `lifecycle` - (Optional) The lifecycle defines when a protected resource is transitioned to cold storage and when it expires. Fields documented below. +* `recovery_point_tags` - (Optional) Metadata that you can assign to help organize the resources that you create. +* `copy_action` - (Optional) ### Lifecycle Arguments For **lifecycle** the following attributes are supported: * `cold_storage_after` - (Optional) Specifies the number of days after creation that a recovery point is moved to cold storage. -* `delete_after` (Optional) - Specifies the number of days after creation that a recovery point is deleted. Must be 90 days greater than `cold_storage_after`. +* `delete_after` - (Optional) Specifies the number of days after creation that a recovery point is deleted. Must be 90 days greater than `cold_storage_after`. + +### Copy Action Arguments +For **copy_action** the following attributes are supported: + +* `lifecycle` - (Optional) The lifecycle defines when a protected resource is copied over to a backup vault and when it expires. Fields documented above. +* `destination_vault_arn` - (Required) An Amazon Resource Name (ARN) that uniquely identifies the destination backup vault for the copied backup. ## Attributes Reference From c8830d3a02b0e6e28c4427d19d30b4ed09d7d389 Mon Sep 17 00:00:00 2001 From: Aaron Smith Date: Thu, 6 Feb 2020 07:31:50 -0600 Subject: [PATCH 029/684] removing unnecessary nil check --- aws/resource_aws_backup_plan.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_backup_plan.go b/aws/resource_aws_backup_plan.go index 5d0f9648c24..69d11d7759d 100644 --- a/aws/resource_aws_backup_plan.go +++ b/aws/resource_aws_backup_plan.go @@ -326,14 +326,12 @@ func flattenBackupPlanRules(rules []*backup.Rule) *schema.Set { } } - if actions := rule.CopyActions; actions != nil { - for _, action := range actions { - mRule["copy_action"] = []interface{}{ - map[string]interface{}{ - "lifecycle": flattenBackupPlanCopyActionLifecycle(action.Lifecycle), - "destination_vault_arn": aws.StringValue(action.DestinationBackupVaultArn), - }, - } + for _, action := range rule.CopyActions { + mRule["copy_action"] = []interface{}{ + map[string]interface{}{ + "lifecycle": flattenBackupPlanCopyActionLifecycle(action.Lifecycle), + "destination_vault_arn": aws.StringValue(action.DestinationBackupVaultArn), + }, } } From 0d9cfdeaf77b5271c93218459608bb82eddb74a4 Mon Sep 17 00:00:00 2001 From: Tim Coulson Date: Wed, 29 Jan 2020 15:36:50 +0000 Subject: [PATCH 030/684] add dms elasticsearch target --- aws/resource_aws_dms_endpoint.go | 76 ++++++++++++++++ aws/resource_aws_dms_endpoint_test.go | 100 ++++++++++++++++++++++ website/docs/r/dms_endpoint.html.markdown | 3 +- 3 files changed, 178 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_dms_endpoint.go b/aws/resource_aws_dms_endpoint.go index 7aadf3eb708..9c086e3494c 100644 --- a/aws/resource_aws_dms_endpoint.go +++ b/aws/resource_aws_dms_endpoint.go @@ -69,6 +69,7 @@ func resourceAwsDmsEndpoint() *schema.Resource { "db2", "docdb", "dynamodb", + "elasticsearch", "mariadb", "mongodb", "mysql", @@ -217,6 +218,41 @@ func resourceAwsDmsEndpoint() *schema.Resource { }, }, }, + "elasticsearch_settings": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if old == "1" && new == "0" { + return true + } + return false + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_access_role_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "endpoint_uri": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "error_retry_duration": { + Type: schema.TypeInt, + Optional: true, + Default: "300", + }, + "full_load_error_percentage": { + Type: schema.TypeInt, + Optional: true, + Default: "10", + }, + }, + }, + }, }, } } @@ -270,6 +306,13 @@ func resourceAwsDmsEndpointCreate(d *schema.ResourceData, meta interface{}) erro BucketName: aws.String(d.Get("s3_settings.0.bucket_name").(string)), CompressionType: aws.String(d.Get("s3_settings.0.compression_type").(string)), } + case "elasticsearch": + request.ElasticsearchSettings = &dms.ElasticsearchSettings{ + ServiceAccessRoleArn: aws.String(d.Get("elasticsearch_settings.0.service_access_role_arn").(string)), + EndpointUri: aws.String(d.Get("elasticsearch_settings.0.endpoint_uri").(string)), + ErrorRetryDuration: aws.Int64(int64(d.Get("elasticsearch_settings.0.error_retry_duration").(int))), + FullLoadErrorPercentage: aws.Int64(int64(d.Get("elasticsearch_settings.0.full_load_error_percentage").(int))), + } default: request.Password = aws.String(d.Get("password").(string)) request.Port = aws.Int64(int64(d.Get("port").(int))) @@ -477,6 +520,20 @@ func resourceAwsDmsEndpointUpdate(d *schema.ResourceData, meta interface{}) erro request.EngineName = aws.String(d.Get("engine_name").(string)) // Must be included (should be 's3') hasChanges = true } + case "elasticsearch": + if d.HasChange("elasticsearch_settings.0.endpoint_uri") || + d.HasChange("elasticsearch_settings.0.error_retry_duration") || + d.HasChange("elasticsearch_settings.0.full_load_error_percentage") || + d.HasChange("elasticsearch_settings.0.service_access_role_arn") { + request.ElasticsearchSettings = &dms.ElasticsearchSettings{ + ServiceAccessRoleArn: aws.String(d.Get("elasticsearch_settings.0.service_access_role_arn").(string)), + EndpointUri: aws.String(d.Get("elasticsearch_settings.0.endpoint_uri").(string)), + ErrorRetryDuration: aws.Int64(int64(d.Get("elasticsearch_settings.0.error_retry_duration").(int))), + FullLoadErrorPercentage: aws.Int64(int64(d.Get("elasticsearch_settings.0.full_load_error_percentage").(int))), + } + request.EngineName = aws.String(d.Get("engine_name").(string)) + hasChanges = true + } default: if d.HasChange("database_name") { request.DatabaseName = aws.String(d.Get("database_name").(string)) @@ -567,6 +624,10 @@ func resourceAwsDmsEndpointSetState(d *schema.ResourceData, endpoint *dms.Endpoi if err := d.Set("s3_settings", flattenDmsS3Settings(endpoint.S3Settings)); err != nil { return fmt.Errorf("Error setting s3_settings for DMS: %s", err) } + case "elasticsearch": + if err := d.Set("elasticsearch_settings", flattenDmsElasticsearchSettings(endpoint.ElasticsearchSettings)); err != nil { + return fmt.Errorf("Error setting elasticsearch for DMS: %s", err) + } default: d.Set("database_name", endpoint.DatabaseName) d.Set("extra_connection_attributes", endpoint.ExtraConnectionAttributes) @@ -615,3 +676,18 @@ func flattenDmsS3Settings(settings *dms.S3Settings) []map[string]interface{} { return []map[string]interface{}{m} } + +func flattenDmsElasticsearchSettings(settings *dms.ElasticsearchSettings) []map[string]interface{} { + if settings == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "service_access_role_arn": aws.StringValue(settings.ServiceAccessRoleArn), + "endpoint_uri": aws.StringValue(settings.EndpointUri), + "full_load_error_percentage": aws.Int64Value(settings.FullLoadErrorPercentage), + "error_retry_duration": aws.Int64Value(settings.ErrorRetryDuration), + } + + return []map[string]interface{}{m} +} diff --git a/aws/resource_aws_dms_endpoint_test.go b/aws/resource_aws_dms_endpoint_test.go index c2d11a14a4d..a43aebe815c 100644 --- a/aws/resource_aws_dms_endpoint_test.go +++ b/aws/resource_aws_dms_endpoint_test.go @@ -96,6 +96,37 @@ func TestAccAwsDmsEndpoint_S3(t *testing.T) { }) } +func TestAccAwsDmsEndpoint_Elasticsearch(t *testing.T) { + resourceName := "aws_dms_endpoint.dms_endpoint" + randId := acctest.RandString(8) + "-elasticsearch" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: dmsEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: dmsEndpointElasticsearchConfig(randId), + Check: resource.ComposeTestCheckFunc( + checkDmsEndpointExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "elasticsearch_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch_settings.0.endpoint_uri", "search-estest.us-west-2.es.amazonaws.com"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch_settings.0.full_load_error_percentage", "10"), + resource.TestCheckResourceAttr(resourceName, "elasticsearch_settings.0.error_retry_duration", "300"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password"}, + }, + // No update step due to: + // InvalidParameterCombinationException: Elasticsearch endpoint cant be modified. + }, + }) +} + func TestAccAwsDmsEndpoint_DynamoDb(t *testing.T) { resourceName := "aws_dms_endpoint.dms_endpoint" randId := acctest.RandString(8) + "-dynamodb" @@ -623,6 +654,75 @@ EOF `, randId) } +func dmsEndpointElasticsearchConfig(randId string) string { + return fmt.Sprintf(` +resource "aws_dms_endpoint" "dms_endpoint" { + endpoint_id = "tf-test-dms-endpoint-%[1]s" + endpoint_type = "target" + engine_name = "elasticsearch" + ssl_mode = "none" + + tags = { + Name = "tf-test-elasticsearch-endpoint-%[1]s" + Update = "to-update" + Remove = "to-remove" + } + + elasticsearch_settings { + service_access_role_arn = "${aws_iam_role.iam_role.arn}" + endpoint_uri = "search-estest.us-west-2.es.amazonaws.com" + full_load_error_percentage = 10 + error_retry_duration = 300 + } + + depends_on = ["aws_iam_role_policy.dms_elasticsearch_access"] +} + +resource "aws_iam_role" "iam_role" { + name = "tf-test-iam-elasticsearch-role-%[1]s" + + assume_role_policy = < Date: Sat, 7 Mar 2020 17:03:57 +0200 Subject: [PATCH 031/684] suppress diff when expanded ipv6 address is the same --- aws/resource_aws_route53_health_check.go | 9 +++++ aws/resource_aws_route53_health_check_test.go | 40 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/aws/resource_aws_route53_health_check.go b/aws/resource_aws_route53_health_check.go index 3cf19ab7aaf..615c94b6496 100644 --- a/aws/resource_aws_route53_health_check.go +++ b/aws/resource_aws_route53_health_check.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "net" "strings" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -57,6 +58,9 @@ func resourceAwsRoute53HealthCheck() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return net.ParseIP(old).Equal(net.ParseIP(new)) + }, }, "fqdn": { Type: schema.TypeString, @@ -114,6 +118,11 @@ func resourceAwsRoute53HealthCheck() *schema.Resource { "insufficient_data_health_status": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + route53.InsufficientDataHealthStatusHealthy, + route53.InsufficientDataHealthStatusLastKnownStatus, + route53.InsufficientDataHealthStatusUnhealthy, + }, true), }, "reference_name": { Type: schema.TypeString, diff --git a/aws/resource_aws_route53_health_check_test.go b/aws/resource_aws_route53_health_check_test.go index dd7f77eff86..746f8fa84a2 100644 --- a/aws/resource_aws_route53_health_check_test.go +++ b/aws/resource_aws_route53_health_check_test.go @@ -22,6 +22,7 @@ func TestAccAWSRoute53HealthCheck_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckRoute53HealthCheckExists(resourceName), resource.TestCheckResourceAttr(resourceName, "measure_latency", "true"), + resource.TestCheckResourceAttr(resourceName, "port", "80"), resource.TestCheckResourceAttr(resourceName, "invert_healthcheck", "true"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), @@ -174,6 +175,30 @@ func TestAccAWSRoute53HealthCheck_IpConfig(t *testing.T) { Config: testAccRoute53HealthCheckIpConfig, Check: resource.ComposeTestCheckFunc( testAccCheckRoute53HealthCheckExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "ip_address", "1.2.3.4"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSRoute53HealthCheck_Ipv6Config(t *testing.T) { + resourceName := "aws_route53_health_check.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53HealthCheckDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53HealthCheckIpv6Config, + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53HealthCheckExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "ip_address", "1234:5678:9abc:6811:0:0:0:4"), ), }, { @@ -386,6 +411,21 @@ resource "aws_route53_health_check" "test" { } ` +const testAccRoute53HealthCheckIpv6Config = ` +resource "aws_route53_health_check" "test" { + ip_address = "1234:5678:9abc:6811::4" + port = 80 + type = "HTTP" + resource_path = "/" + failure_threshold = "2" + request_interval = "30" + + tags = { + Name = "tf-test-health-check" + } +} +` + const testAccRoute53HealthCheckConfig_withChildHealthChecks = ` resource "aws_route53_health_check" "child1" { fqdn = "child1.notexample.com" From ab7460fc4d950fbf2cea252d0f9fcce5ea377a9e Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 7 Mar 2020 17:56:35 +0200 Subject: [PATCH 032/684] add disappears test case --- aws/resource_aws_route53_health_check_test.go | 98 ++++++++++++++++--- 1 file changed, 82 insertions(+), 16 deletions(-) diff --git a/aws/resource_aws_route53_health_check_test.go b/aws/resource_aws_route53_health_check_test.go index 746f8fa84a2..268143f7549 100644 --- a/aws/resource_aws_route53_health_check_test.go +++ b/aws/resource_aws_route53_health_check_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "log" "testing" "github.com/aws/aws-sdk-go/service/route53" @@ -10,6 +11,7 @@ import ( ) func TestAccAWSRoute53HealthCheck_basic(t *testing.T) { + var check route53.HealthCheck resourceName := "aws_route53_health_check.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -20,7 +22,7 @@ func TestAccAWSRoute53HealthCheck_basic(t *testing.T) { { Config: testAccRoute53HealthCheckConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "measure_latency", "true"), resource.TestCheckResourceAttr(resourceName, "port", "80"), resource.TestCheckResourceAttr(resourceName, "invert_healthcheck", "true"), @@ -35,7 +37,7 @@ func TestAccAWSRoute53HealthCheck_basic(t *testing.T) { { Config: testAccRoute53HealthCheckConfigUpdate, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "failure_threshold", "5"), resource.TestCheckResourceAttr(resourceName, "invert_healthcheck", "false"), ), @@ -45,6 +47,7 @@ func TestAccAWSRoute53HealthCheck_basic(t *testing.T) { } func TestAccAWSRoute53HealthCheck_tags(t *testing.T) { + var check route53.HealthCheck resourceName := "aws_route53_health_check.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -55,7 +58,7 @@ func TestAccAWSRoute53HealthCheck_tags(t *testing.T) { { Config: testAccRoute53HealthCheckConfigTags1("key1", "value1"), Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), @@ -68,7 +71,7 @@ func TestAccAWSRoute53HealthCheck_tags(t *testing.T) { { Config: testAccRoute53HealthCheckConfigTags2("key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), @@ -77,7 +80,7 @@ func TestAccAWSRoute53HealthCheck_tags(t *testing.T) { { Config: testAccRoute53HealthCheckConfigTags1("key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), @@ -87,6 +90,7 @@ func TestAccAWSRoute53HealthCheck_tags(t *testing.T) { } func TestAccAWSRoute53HealthCheck_withSearchString(t *testing.T) { + var check route53.HealthCheck resourceName := "aws_route53_health_check.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -97,7 +101,7 @@ func TestAccAWSRoute53HealthCheck_withSearchString(t *testing.T) { { Config: testAccRoute53HealthCheckConfigWithSearchString, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "invert_healthcheck", "false"), resource.TestCheckResourceAttr(resourceName, "search_string", "OK"), ), @@ -110,7 +114,7 @@ func TestAccAWSRoute53HealthCheck_withSearchString(t *testing.T) { { Config: testAccRoute53HealthCheckConfigWithSearchStringUpdate, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "invert_healthcheck", "true"), resource.TestCheckResourceAttr(resourceName, "search_string", "FAILED"), ), @@ -120,6 +124,7 @@ func TestAccAWSRoute53HealthCheck_withSearchString(t *testing.T) { } func TestAccAWSRoute53HealthCheck_withChildHealthChecks(t *testing.T) { + var check route53.HealthCheck resourceName := "aws_route53_health_check.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -129,7 +134,7 @@ func TestAccAWSRoute53HealthCheck_withChildHealthChecks(t *testing.T) { { Config: testAccRoute53HealthCheckConfig_withChildHealthChecks, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), ), }, { @@ -142,6 +147,7 @@ func TestAccAWSRoute53HealthCheck_withChildHealthChecks(t *testing.T) { } func TestAccAWSRoute53HealthCheck_withHealthCheckRegions(t *testing.T) { + var check route53.HealthCheck resourceName := "aws_route53_health_check.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -151,7 +157,7 @@ func TestAccAWSRoute53HealthCheck_withHealthCheckRegions(t *testing.T) { { Config: testAccRoute53HealthCheckConfig_withHealthCheckRegions, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "regions.#", "3"), ), }, @@ -165,6 +171,7 @@ func TestAccAWSRoute53HealthCheck_withHealthCheckRegions(t *testing.T) { } func TestAccAWSRoute53HealthCheck_IpConfig(t *testing.T) { + var check route53.HealthCheck resourceName := "aws_route53_health_check.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -174,7 +181,7 @@ func TestAccAWSRoute53HealthCheck_IpConfig(t *testing.T) { { Config: testAccRoute53HealthCheckIpConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "ip_address", "1.2.3.4"), ), }, @@ -188,6 +195,7 @@ func TestAccAWSRoute53HealthCheck_IpConfig(t *testing.T) { } func TestAccAWSRoute53HealthCheck_Ipv6Config(t *testing.T) { + var check route53.HealthCheck resourceName := "aws_route53_health_check.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -197,7 +205,7 @@ func TestAccAWSRoute53HealthCheck_Ipv6Config(t *testing.T) { { Config: testAccRoute53HealthCheckIpv6Config, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "ip_address", "1234:5678:9abc:6811:0:0:0:4"), ), }, @@ -206,11 +214,19 @@ func TestAccAWSRoute53HealthCheck_Ipv6Config(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccRoute53HealthCheckIpv6ExpandedConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53HealthCheckExists(resourceName, &check), + resource.TestCheckResourceAttr(resourceName, "ip_address", "1234:5678:9abc:6811:0:0:0:4"), + ), + }, }, }) } func TestAccAWSRoute53HealthCheck_CloudWatchAlarmCheck(t *testing.T) { + var check route53.HealthCheck resourceName := "aws_route53_health_check.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -220,7 +236,7 @@ func TestAccAWSRoute53HealthCheck_CloudWatchAlarmCheck(t *testing.T) { { Config: testAccRoute53HealthCheckCloudWatchAlarm, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "cloudwatch_alarm_name", "cloudwatch-healthcheck-alarm"), ), }, @@ -234,6 +250,7 @@ func TestAccAWSRoute53HealthCheck_CloudWatchAlarmCheck(t *testing.T) { } func TestAccAWSRoute53HealthCheck_withSNI(t *testing.T) { + var check route53.HealthCheck resourceName := "aws_route53_health_check.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -244,7 +261,7 @@ func TestAccAWSRoute53HealthCheck_withSNI(t *testing.T) { { Config: testAccRoute53HealthCheckConfigWithoutSNI, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "enable_sni", "true"), ), }, @@ -256,14 +273,14 @@ func TestAccAWSRoute53HealthCheck_withSNI(t *testing.T) { { Config: testAccRoute53HealthCheckConfigWithSNIDisabled, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "enable_sni", "false"), ), }, { Config: testAccRoute53HealthCheckConfigWithSNI, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName), + testAccCheckRoute53HealthCheckExists(resourceName, &check), resource.TestCheckResourceAttr(resourceName, "enable_sni", "true"), ), }, @@ -271,6 +288,26 @@ func TestAccAWSRoute53HealthCheck_withSNI(t *testing.T) { }) } +func TestAccAWSRoute53HealthCheck_disappears(t *testing.T) { + var check route53.HealthCheck + resourceName := "aws_route53_health_check.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53HealthCheckDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53HealthCheckConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53HealthCheckExists(resourceName, &check), + testAccCheckRoute53HealthCheckDisappears(&check), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckRoute53HealthCheckDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).r53conn @@ -299,7 +336,7 @@ func testAccCheckRoute53HealthCheckDestroy(s *terraform.State) error { return nil } -func testAccCheckRoute53HealthCheckExists(n string) resource.TestCheckFunc { +func testAccCheckRoute53HealthCheckExists(n string, hCheck *route53.HealthCheck) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).r53conn @@ -323,6 +360,7 @@ func testAccCheckRoute53HealthCheckExists(n string) resource.TestCheckFunc { for _, check := range resp.HealthChecks { if *check.Id == rs.Primary.ID { + *hCheck = *check return nil } @@ -331,6 +369,19 @@ func testAccCheckRoute53HealthCheckExists(n string) resource.TestCheckFunc { } } +func testAccCheckRoute53HealthCheckDisappears(hCheck *route53.HealthCheck) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).r53conn + input := &route53.DeleteHealthCheckInput{ + HealthCheckId: hCheck.Id, + } + log.Printf("[DEBUG] Deleting Route53 Health Check: %#v", input) + _, err := conn.DeleteHealthCheck(input) + + return err + } +} + const testAccRoute53HealthCheckConfig = ` resource "aws_route53_health_check" "test" { fqdn = "dev.notexample.com" @@ -426,6 +477,21 @@ resource "aws_route53_health_check" "test" { } ` +const testAccRoute53HealthCheckIpv6ExpandedConfig = ` +resource "aws_route53_health_check" "test" { + ip_address = "1234:5678:9abc:6811:0:0:0:4" + port = 80 + type = "HTTP" + resource_path = "/" + failure_threshold = "2" + request_interval = "30" + + tags = { + Name = "tf-test-health-check" + } +} +` + const testAccRoute53HealthCheckConfig_withChildHealthChecks = ` resource "aws_route53_health_check" "child1" { fqdn = "child1.notexample.com" From 9158b5fede7e9ba6e89581ef5e674c0643d89812 Mon Sep 17 00:00:00 2001 From: drexler Date: Mon, 9 Mar 2020 21:30:07 -0400 Subject: [PATCH 033/684] docs: fix S3 ACL permissions --- website/docs/r/s3_bucket.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/s3_bucket.html.markdown b/website/docs/r/s3_bucket.html.markdown index ac6e23747f0..c5b2a02d953 100644 --- a/website/docs/r/s3_bucket.html.markdown +++ b/website/docs/r/s3_bucket.html.markdown @@ -320,12 +320,12 @@ resource "aws_s3_bucket" "bucket" { grant { id = "${data.aws_canonical_user_id.current_user.id}" type = "CanonicalUser" - permission = ["FULL_ACCESS"] + permissions = ["FULL_CONTROL"] } grant { type = "Group" - permission = ["READ", "WRITE"] + permissions = ["READ", "WRITE"] uri = "http://acs.amazonaws.com/groups/s3/LogDelivery" } } @@ -485,7 +485,7 @@ The `grant` object supports the following: * `id` - (optional) Canonical user id to grant for. Used only when `type` is `CanonicalUser`. * `type` - (required) - Type of grantee to apply for. Valid values are `CanonicalUser` and `Group`. `AmazonCustomerByEmail` is not supported. -* `permissions` - (required) List of permissions to apply for grantee. Valid values are `READ`, `WRITE`, `READ_ACP`, `WRITE_ACP`, `FULL_ACCESS`. +* `permissions` - (required) List of permissions to apply for grantee. Valid values are `READ`, `WRITE`, `READ_ACP`, `WRITE_ACP`, `FULL_CONTROL`. * `uri` - (optional) Uri address to grant for. Used only when `type` is `Group`. The `access_control_translation` object supports the following: From 97f89c8340e229ad1999e2affd8269a404c36a17 Mon Sep 17 00:00:00 2001 From: cory Date: Tue, 10 Mar 2020 21:36:05 +0000 Subject: [PATCH 034/684] Adds support for DynamoDB v2019.11.21. --- aws/provider.go | 1 + aws/resource_aws_dynamodb_table_2019.go | 1227 ++++++++++++++++++ aws/resource_aws_dynamodb_table_2019_test.go | 207 +++ aws/structure.go | 185 +++ 4 files changed, 1620 insertions(+) create mode 100644 aws/resource_aws_dynamodb_table_2019.go create mode 100644 aws/resource_aws_dynamodb_table_2019_test.go diff --git a/aws/provider.go b/aws/provider.go index c7c84fd1b01..71087b6eb83 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -483,6 +483,7 @@ func Provider() terraform.ResourceProvider { "aws_dx_public_virtual_interface": resourceAwsDxPublicVirtualInterface(), "aws_dx_transit_virtual_interface": resourceAwsDxTransitVirtualInterface(), "aws_dynamodb_table": resourceAwsDynamoDbTable(), + "aws_dynamodb_table_2019": resourceAwsDynamoDbTable2019(), "aws_dynamodb_table_item": resourceAwsDynamoDbTableItem(), "aws_dynamodb_global_table": resourceAwsDynamoDbGlobalTable(), "aws_ebs_default_kms_key": resourceAwsEbsDefaultKmsKey(), diff --git a/aws/resource_aws_dynamodb_table_2019.go b/aws/resource_aws_dynamodb_table_2019.go new file mode 100644 index 00000000000..7fe0978db13 --- /dev/null +++ b/aws/resource_aws_dynamodb_table_2019.go @@ -0,0 +1,1227 @@ +package aws + +import ( + "bytes" + "fmt" + "log" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/hashicorp/terraform-plugin-sdk/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "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 resourceAwsDynamoDbTable2019() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsDynamoDbTable2019Create, + Read: resourceAwsDynamoDbTable2019Read, + Update: resourceAwsDynamoDbTable2019Update, + Delete: resourceAwsDynamoDbTable2019Delete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + }, + + CustomizeDiff: customdiff.Sequence( + func(diff *schema.ResourceDiff, v interface{}) error { + return validateDynamoDbStreamSpec(diff) + }, + func(diff *schema.ResourceDiff, v interface{}) error { + return validateDynamoDbTableAttributes(diff) + }, + func(diff *schema.ResourceDiff, v interface{}) error { + if diff.Id() != "" && diff.HasChange("server_side_encryption") { + o, n := diff.GetChange("server_side_encryption") + if isDynamoDbTableOptionDisabled(o) && isDynamoDbTableOptionDisabled(n) { + return diff.Clear("server_side_encryption") + } + } + return nil + }, + func(diff *schema.ResourceDiff, v interface{}) error { + if diff.Id() != "" && diff.HasChange("point_in_time_recovery") { + o, n := diff.GetChange("point_in_time_recovery") + if isDynamoDbTableOptionDisabled(o) && isDynamoDbTableOptionDisabled(n) { + return diff.Clear("point_in_time_recovery") + } + } + return nil + }, + ), + + SchemaVersion: 1, + MigrateState: resourceAwsDynamoDbTableMigrateState, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "hash_key": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "range_key": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "billing_mode": { + Type: schema.TypeString, + Optional: true, + Default: dynamodb.BillingModeProvisioned, + ValidateFunc: validation.StringInSlice([]string{ + dynamodb.BillingModePayPerRequest, + dynamodb.BillingModeProvisioned, + }, false), + }, + "write_capacity": { + Type: schema.TypeInt, + Optional: true, + }, + "read_capacity": { + Type: schema.TypeInt, + Optional: true, + }, + "attribute": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + dynamodb.ScalarAttributeTypeB, + dynamodb.ScalarAttributeTypeN, + dynamodb.ScalarAttributeTypeS, + }, false), + }, + }, + }, + Set: func(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) + return hashcode.String(buf.String()) + }, + }, + "ttl": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attribute_name": { + Type: schema.TypeString, + Required: true, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, + }, + "local_secondary_index": { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "range_key": { + Type: schema.TypeString, + Required: true, + }, + "projection_type": { + Type: schema.TypeString, + Required: true, + }, + "non_key_attributes": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + Set: func(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) + return hashcode.String(buf.String()) + }, + }, + "global_secondary_index": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "write_capacity": { + Type: schema.TypeInt, + Optional: true, + }, + "read_capacity": { + Type: schema.TypeInt, + Optional: true, + }, + "hash_key": { + Type: schema.TypeString, + Required: true, + }, + "range_key": { + Type: schema.TypeString, + Optional: true, + }, + "projection_type": { + Type: schema.TypeString, + Required: true, + }, + "non_key_attributes": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "stream_enabled": { + Type: schema.TypeBool, + Optional: true, + }, + "stream_view_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + StateFunc: func(v interface{}) string { + value := v.(string) + return strings.ToUpper(value) + }, + ValidateFunc: validation.StringInSlice([]string{ + "", + dynamodb.StreamViewTypeNewImage, + dynamodb.StreamViewTypeOldImage, + dynamodb.StreamViewTypeNewAndOldImages, + dynamodb.StreamViewTypeKeysOnly, + }, false), + }, + "stream_arn": { + Type: schema.TypeString, + Computed: true, + }, + "stream_label": { + Type: schema.TypeString, + Computed: true, + }, + "server_side_encryption": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Required: true, + }, + "kms_key_arn": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validateArn, + }, + }, + }, + }, + "tags": tagsSchema(), + "point_in_time_recovery": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Required: true, + }, + }, + }, + }, + "replica": { + Type: schema.TypeList, + Optional: true, + Computed: false, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + } +} + +func resourceAwsDynamoDbTable2019Create(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dynamodbconn + + keySchemaMap := map[string]interface{}{ + "hash_key": d.Get("hash_key").(string), + } + if v, ok := d.GetOk("range_key"); ok { + keySchemaMap["range_key"] = v.(string) + } + + log.Printf("[DEBUG] Creating DynamoDB table with key schema: %#v", keySchemaMap) + + tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().DynamodbTags() + + req := &dynamodb.CreateTableInput{ + TableName: aws.String(d.Get("name").(string)), + BillingMode: aws.String(d.Get("billing_mode").(string)), + KeySchema: expandDynamoDbKeySchema(keySchemaMap), + Tags: tags, + } + + billingMode := d.Get("billing_mode").(string) + capacityMap := map[string]interface{}{ + "write_capacity": d.Get("write_capacity"), + "read_capacity": d.Get("read_capacity"), + } + + if err := validateDynamoDbProvisionedThroughput(capacityMap, billingMode); err != nil { + return err + } + + req.ProvisionedThroughput = expandDynamoDbProvisionedThroughput(capacityMap, billingMode) + + if v, ok := d.GetOk("attribute"); ok { + aSet := v.(*schema.Set) + req.AttributeDefinitions = expandDynamoDbAttributes(aSet.List()) + } + + if v, ok := d.GetOk("local_secondary_index"); ok { + lsiSet := v.(*schema.Set) + req.LocalSecondaryIndexes = expandDynamoDbLocalSecondaryIndexes(lsiSet.List(), keySchemaMap) + } + + if v, ok := d.GetOk("global_secondary_index"); ok { + globalSecondaryIndexes := []*dynamodb.GlobalSecondaryIndex{} + gsiSet := v.(*schema.Set) + + for _, gsiObject := range gsiSet.List() { + gsi := gsiObject.(map[string]interface{}) + if err := validateDynamoDbProvisionedThroughput(gsi, billingMode); err != nil { + return fmt.Errorf("Failed to create GSI: %v", err) + } + + gsiObject := expandDynamoDbGlobalSecondaryIndex(gsi, billingMode) + globalSecondaryIndexes = append(globalSecondaryIndexes, gsiObject) + } + req.GlobalSecondaryIndexes = globalSecondaryIndexes + } + + if v, ok := d.GetOk("stream_enabled"); ok { + req.StreamSpecification = &dynamodb.StreamSpecification{ + StreamEnabled: aws.Bool(v.(bool)), + StreamViewType: aws.String(d.Get("stream_view_type").(string)), + } + } + + if v, ok := d.GetOk("server_side_encryption"); ok { + req.SSESpecification = expandDynamoDbEncryptAtRestOptions(v.([]interface{})) + } + + var output *dynamodb.CreateTableOutput + var requiresTagging bool + err := resource.Retry(2*time.Minute, func() *resource.RetryError { + var err error + output, err = conn.CreateTable(req) + if err != nil { + if isAWSErr(err, "ThrottlingException", "") { + return resource.RetryableError(err) + } + if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "can be created, updated, or deleted simultaneously") { + return resource.RetryableError(err) + } + if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "indexed tables that can be created simultaneously") { + return resource.RetryableError(err) + } + // AWS GovCloud (US) and others may reply with the following until their API is updated: + // ValidationException: One or more parameter values were invalid: Unsupported input parameter BillingMode + if isAWSErr(err, "ValidationException", "Unsupported input parameter BillingMode") { + req.BillingMode = nil + return resource.RetryableError(err) + } + // AWS GovCloud (US) and others may reply with the following until their API is updated: + // ValidationException: Unsupported input parameter Tags + if isAWSErr(err, "ValidationException", "Unsupported input parameter Tags") { + req.Tags = nil + requiresTagging = true + return resource.RetryableError(err) + } + + return resource.NonRetryableError(err) + } + return nil + }) + if isResourceTimeoutError(err) { + output, err = conn.CreateTable(req) + } + if err != nil { + return fmt.Errorf("error creating DynamoDB Table: %s", err) + } + + d.SetId(*output.TableDescription.TableName) + d.Set("arn", output.TableDescription.TableArn) + + if err := waitForDynamoDbTableToBeActive(d.Id(), d.Timeout(schema.TimeoutCreate), conn); err != nil { + return err + } + + if requiresTagging { + if err := keyvaluetags.DynamodbUpdateTags(conn, d.Get("arn").(string), nil, tags); err != nil { + return fmt.Errorf("error adding DynamoDB Table (%s) tags: %s", d.Id(), err) + } + } + + if d.Get("ttl.0.enabled").(bool) { + if err := updateDynamoDbTimeToLive(d.Id(), d.Get("ttl").([]interface{}), conn); err != nil { + return fmt.Errorf("error enabling DynamoDB Table (%s) Time to Live: %s", d.Id(), err) + } + } + + if d.Get("point_in_time_recovery.0.enabled").(bool) { + if err := updateDynamoDbPITR(d, conn); err != nil { + return fmt.Errorf("error enabling DynamoDB Table (%s) point in time recovery: %s", d.Id(), err) + } + } + + if _, ok := d.GetOk("replica"); ok { + if err := createDynamoDbReplicas(d.Id(), d.Get("replica").([]interface{}), conn); err != nil { + return fmt.Errorf("error enabled DynamoDB Table (%s) replicas: %s", d.Id(), err) + } + } + + if err := waitForDynamoDbTableToBeActive(d.Id(), d.Timeout(schema.TimeoutCreate), conn); err != nil { + return err + } + + return resourceAwsDynamoDbTable2019Read(d, meta) +} + +func createDynamoDbReplicas(tableName string, replicas []interface{}, conn *dynamodb.DynamoDB) error { + for _, replica := range replicas { + var ops []*dynamodb.ReplicationGroupUpdate + if region, ok := replica.(map[string]interface{})["region"]; ok { + ops = append(ops, &dynamodb.ReplicationGroupUpdate{ + Create: &dynamodb.CreateReplicationGroupMemberAction{ + RegionName: aws.String(region.(string)), + }, + }) + + input := &dynamodb.UpdateTableInput{ + TableName: aws.String(tableName), + ReplicaUpdates: ops, + } + + log.Printf("[DEBUG] Updating DynamoDB Replicas to %v", input) + + err := resource.Retry(20*time.Minute, func() *resource.RetryError { + _, err := conn.UpdateTable(input) + if err != nil { + return resource.NonRetryableError(err) + } + return nil + }) + if isResourceTimeoutError(err) { + _, err = conn.UpdateTable(input) + } + if err != nil { + return fmt.Errorf("Error updating DynamoDB Replicas status: %s", err) + } + + if err := waitForDynamoDbReplicaUpdateToBeCompleted(tableName, region.(string), 20*time.Minute, conn); err != nil { + return fmt.Errorf("Error waiting for DynamoDB replica update: %s", err) + } + } + } + return nil +} + +func deleteDynamoDbReplicas(tableName string, replicas []interface{}, conn *dynamodb.DynamoDB) error { + for _, replica := range replicas { + var ops []*dynamodb.ReplicationGroupUpdate + if region, ok := replica.(map[string]interface{})["region"]; ok { + ops = append(ops, &dynamodb.ReplicationGroupUpdate{ + Delete: &dynamodb.DeleteReplicationGroupMemberAction{ + RegionName: aws.String(region.(string)), + }, + }) + + input := &dynamodb.UpdateTableInput{ + TableName: aws.String(tableName), + ReplicaUpdates: ops, + } + + log.Printf("[DEBUG] Deleting DynamoDB Replicas to %v", input) + + err := resource.Retry(20*time.Minute, func() *resource.RetryError { + _, err := conn.UpdateTable(input) + if err != nil { + return resource.NonRetryableError(err) + } + return nil + }) + if isResourceTimeoutError(err) { + _, err = conn.UpdateTable(input) + } + if err != nil { + return fmt.Errorf("Error deleting DynamoDB Replicas status: %s", err) + } + + if err := waitForDynamoDbReplicaDeleteToBeCompleted(tableName, region.(string), 20*time.Minute, conn); err != nil { + return fmt.Errorf("Error waiting for DynamoDB replica delete: %s", err) + } + } + } + return nil +} + +func resourceAwsDynamoDbTable2019Update(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dynamodbconn + billingMode := d.Get("billing_mode").(string) + + // Global Secondary Index operations must occur in multiple phases + // to prevent various error scenarios. If there are no detected required + // updates in the Terraform configuration, later validation or API errors + // will signal the problems. + var gsiUpdates []*dynamodb.GlobalSecondaryIndexUpdate + + if d.HasChange("global_secondary_index") { + var err error + o, n := d.GetChange("global_secondary_index") + gsiUpdates, err = diffDynamoDbGSI(o.(*schema.Set).List(), n.(*schema.Set).List(), billingMode) + + if err != nil { + return fmt.Errorf("computing difference for DynamoDB Table (%s) Global Secondary Index updates failed: %s", d.Id(), err) + } + + log.Printf("[DEBUG] Computed DynamoDB Table (%s) Global Secondary Index updates: %s", d.Id(), gsiUpdates) + } + + // Phase 1 of Global Secondary Index Operations: Delete Only + // * Delete indexes first to prevent error when simultaneously updating + // BillingMode to PROVISIONED, which requires updating index + // ProvisionedThroughput first, but we have no definition + // * Only 1 online index can be deleted simultaneously per table + for _, gsiUpdate := range gsiUpdates { + if gsiUpdate.Delete == nil { + continue + } + + idxName := aws.StringValue(gsiUpdate.Delete.IndexName) + input := &dynamodb.UpdateTableInput{ + GlobalSecondaryIndexUpdates: []*dynamodb.GlobalSecondaryIndexUpdate{gsiUpdate}, + TableName: aws.String(d.Id()), + } + + if _, err := conn.UpdateTable(input); err != nil { + return fmt.Errorf("error deleting DynamoDB Table (%s) Global Secondary Index (%s): %s", d.Id(), idxName, err) + } + + if err := waitForDynamoDbGSIToBeDeleted(d.Id(), idxName, d.Timeout(schema.TimeoutUpdate), conn); err != nil { + return fmt.Errorf("error waiting for DynamoDB Table (%s) Global Secondary Index (%s) deletion: %s", d.Id(), idxName, err) + } + } + + hasTableUpdate := false + input := &dynamodb.UpdateTableInput{ + TableName: aws.String(d.Id()), + } + + if d.HasChange("billing_mode") || d.HasChange("read_capacity") || d.HasChange("write_capacity") { + hasTableUpdate = true + + capacityMap := map[string]interface{}{ + "write_capacity": d.Get("write_capacity"), + "read_capacity": d.Get("read_capacity"), + } + + if err := validateDynamoDbProvisionedThroughput(capacityMap, billingMode); err != nil { + return err + } + + input.BillingMode = aws.String(billingMode) + input.ProvisionedThroughput = expandDynamoDbProvisionedThroughput(capacityMap, billingMode) + } + + if d.HasChange("stream_enabled") || d.HasChange("stream_view_type") { + hasTableUpdate = true + + input.StreamSpecification = &dynamodb.StreamSpecification{ + StreamEnabled: aws.Bool(d.Get("stream_enabled").(bool)), + } + if d.Get("stream_enabled").(bool) { + input.StreamSpecification.StreamViewType = aws.String(d.Get("stream_view_type").(string)) + } + } + + // Phase 2 of Global Secondary Index Operations: Update Only + // Cannot create or delete index while updating table ProvisionedThroughput + // Must skip all index updates when switching BillingMode from PROVISIONED to PAY_PER_REQUEST + // Must update all indexes when switching BillingMode from PAY_PER_REQUEST to PROVISIONED + if billingMode == dynamodb.BillingModeProvisioned { + for _, gsiUpdate := range gsiUpdates { + if gsiUpdate.Update == nil { + continue + } + + input.GlobalSecondaryIndexUpdates = append(input.GlobalSecondaryIndexUpdates, gsiUpdate) + } + } + + if d.HasChange("replica") { + var replicaUpdates []*dynamodb.ReplicationGroupUpdate + o, n := d.GetChange("replica") + + replicaUpdates, _ = diffDynamoDbReplicas(o.([]interface{}), n.([]interface{})) + log.Printf("[DEBUG] replica updates %s", replicaUpdates) + for _, replicaUpdate := range replicaUpdates { + var ops []*dynamodb.ReplicationGroupUpdate + ops = append(ops, replicaUpdate) + + replicaInput := &dynamodb.UpdateTableInput{ + TableName: aws.String(d.Id()), + ReplicaUpdates: ops, + } + replicaInput.ReplicaUpdates = replicaUpdates + _, replicaErr := conn.UpdateTable(replicaInput) + if replicaErr == nil { + if replicaUpdate.Delete == nil { + log.Printf("[DEBUG] waiting for replica to be updated") + waitForDynamoDbReplicaUpdateToBeCompleted(d.Id(), aws.StringValue(replicaUpdate.Update.RegionName), 20*time.Minute, conn) + } else { + log.Printf("[DEBUG] waiting for replica to be deleted") + waitForDynamoDbReplicaDeleteToBeCompleted(d.Id(), aws.StringValue(replicaUpdate.Delete.RegionName), 20*time.Minute, conn) + } + } else { + return fmt.Errorf("error updating DynamoDB Table (%s): %s", d.Id(), replicaErr) + } + } + } + + if hasTableUpdate { + log.Printf("[DEBUG] Updating DynamoDB Table: %s", input) + _, err := conn.UpdateTable(input) + + if err != nil { + log.Printf("[DEBUG] Updating DynamoDB Table: %s", input) + return fmt.Errorf("error updating DynamoDB Table (%s): %s", d.Id(), err) + } + + if err := waitForDynamoDbTableToBeActive(d.Id(), d.Timeout(schema.TimeoutUpdate), conn); err != nil { + return fmt.Errorf("error waiting for DynamoDB Table (%s) update: %s", d.Id(), err) + } + + for _, gsiUpdate := range gsiUpdates { + if gsiUpdate.Update == nil { + continue + } + + idxName := aws.StringValue(gsiUpdate.Update.IndexName) + if err := waitForDynamoDbGSIToBeActive(d.Id(), idxName, d.Timeout(schema.TimeoutUpdate), conn); err != nil { + return fmt.Errorf("error waiting for DynamoDB Table (%s) Global Secondary Index (%s) update: %s", d.Id(), idxName, err) + } + } + } + + // Phase 3 of Global Secondary Index Operations: Create Only + // Only 1 online index can be created simultaneously per table + for _, gsiUpdate := range gsiUpdates { + if gsiUpdate.Create == nil { + continue + } + + idxName := aws.StringValue(gsiUpdate.Create.IndexName) + input := &dynamodb.UpdateTableInput{ + AttributeDefinitions: expandDynamoDbAttributes(d.Get("attribute").(*schema.Set).List()), + GlobalSecondaryIndexUpdates: []*dynamodb.GlobalSecondaryIndexUpdate{gsiUpdate}, + TableName: aws.String(d.Id()), + } + + if _, err := conn.UpdateTable(input); err != nil { + return fmt.Errorf("error creating DynamoDB Table (%s) Global Secondary Index (%s): %s", d.Id(), idxName, err) + } + + if err := waitForDynamoDbGSIToBeActive(d.Id(), idxName, d.Timeout(schema.TimeoutUpdate), conn); err != nil { + return fmt.Errorf("error waiting for DynamoDB Table (%s) Global Secondary Index (%s) creation: %s", d.Id(), idxName, err) + } + } + + if d.HasChange("server_side_encryption") { + // "ValidationException: One or more parameter values were invalid: Server-Side Encryption modification must be the only operation in the request". + _, err := conn.UpdateTable(&dynamodb.UpdateTableInput{ + TableName: aws.String(d.Id()), + SSESpecification: expandDynamoDbEncryptAtRestOptions(d.Get("server_side_encryption").([]interface{})), + }) + if err != nil { + return fmt.Errorf("error updating DynamoDB Table (%s) SSE: %s", d.Id(), err) + } + + if err := waitForDynamoDbSSEUpdateToBeCompleted(d.Id(), d.Timeout(schema.TimeoutUpdate), conn); err != nil { + return fmt.Errorf("error waiting for DynamoDB Table (%s) SSE update: %s", d.Id(), err) + } + } + + if d.HasChange("ttl") { + if err := updateDynamoDbTimeToLive(d.Id(), d.Get("ttl").([]interface{}), conn); err != nil { + return fmt.Errorf("error updating DynamoDB Table (%s) time to live: %s", d.Id(), err) + } + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.DynamodbUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating DynamoDB Table (%s) tags: %s", d.Id(), err) + } + } + + if d.HasChange("point_in_time_recovery") { + if err := updateDynamoDbPITR(d, conn); err != nil { + return fmt.Errorf("error updating DynamoDB Table (%s) point in time recovery: %s", d.Id(), err) + } + } + + return resourceAwsDynamoDbTable2019Read(d, meta) +} + +func resourceAwsDynamoDbTable2019Read(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dynamodbconn + + result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ + TableName: aws.String(d.Id()), + }) + + if err != nil { + if isAWSErr(err, dynamodb.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Dynamodb Table (%s) not found, error code (404)", d.Id()) + d.SetId("") + return nil + } + return err + } + + err = flattenAwsDynamoDbTableResource_2019(d, result.Table) + if err != nil { + return err + } + + ttlOut, err := conn.DescribeTimeToLive(&dynamodb.DescribeTimeToLiveInput{ + TableName: aws.String(d.Id()), + }) + if err != nil { + return fmt.Errorf("error describing DynamoDB Table (%s) Time to Live: %s", d.Id(), err) + } + if err := d.Set("ttl", flattenDynamoDbTtl(ttlOut)); err != nil { + return fmt.Errorf("error setting ttl: %s", err) + } + + tags, err := readDynamoDbTableTags(d.Get("arn").(string), conn) + if err != nil { + return err + } + + d.Set("tags", tags) + + pitrOut, err := conn.DescribeContinuousBackups(&dynamodb.DescribeContinuousBackupsInput{ + TableName: aws.String(d.Id()), + }) + if err != nil && !isAWSErr(err, "UnknownOperationException", "") { + return err + } + d.Set("point_in_time_recovery", flattenDynamoDbPitr(pitrOut)) + + return nil +} + +func resourceAwsDynamoDbTable2019Delete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dynamodbconn + + log.Printf("[DEBUG] DynamoDB delete table: %s", d.Id()) + + input := &dynamodb.DescribeTableInput{ + TableName: aws.String(d.Id()), + } + + output, err := conn.DescribeTable(input) + log.Printf("[DEBUG] DynamoDB delete describe: %s", output) + + if len(output.Table.Replicas) > 0 { + if err := deleteDynamoDbReplicas(d.Id(), d.Get("replica").([]interface{}), conn); err != nil { + return fmt.Errorf("error enabled DynamoDB Table (%s) replicas: %s", d.Id(), err) + } + } + + err = deleteAwsDynamoDbTable(d.Id(), conn) + if err != nil { + if isAWSErr(err, dynamodb.ErrCodeResourceNotFoundException, "Requested resource not found: Table: ") { + return nil + } + return fmt.Errorf("error deleting DynamoDB Table (%s): %s", d.Id(), err) + } + + if err := waitForDynamodbTableDeletion(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + return fmt.Errorf("error waiting for DynamoDB Table (%s) deletion: %s", d.Id(), err) + } + + return nil +} + +// func deleteAwsDynamoDbTable(tableName string, conn *dynamodb.DynamoDB) error { +// input := &dynamodb.DeleteTableInput{ +// TableName: aws.String(tableName), +// } +// +// err := resource.Retry(5*time.Minute, func() *resource.RetryError { +// _, err := conn.DeleteTable(input) +// if err != nil { +// // Subscriber limit exceeded: Only 10 tables can be created, updated, or deleted simultaneously +// if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "simultaneously") { +// return resource.RetryableError(err) +// } +// // This handles multiple scenarios in the DynamoDB API: +// // 1. Updating a table immediately before deletion may return: +// // ResourceInUseException: Attempt to change a resource which is still in use: Table is being updated: +// // 2. Removing a table from a DynamoDB global table may return: +// // ResourceInUseException: Attempt to change a resource which is still in use: Table is being deleted: +// if isAWSErr(err, dynamodb.ErrCodeResourceInUseException, "") { +// return resource.RetryableError(err) +// } +// if isAWSErr(err, dynamodb.ErrCodeResourceNotFoundException, "Requested resource not found: Table: ") { +// return resource.NonRetryableError(err) +// } +// return resource.NonRetryableError(err) +// } +// return nil +// }) +// +// if isResourceTimeoutError(err) { +// _, err = conn.DeleteTable(input) +// } +// +// return err +// } +// +// func waitForDynamodbTableDeletion(conn *dynamodb.DynamoDB, tableName string, timeout time.Duration) error { +// stateConf := &resource.StateChangeConf{ +// Pending: []string{ +// dynamodb.TableStatusActive, +// dynamodb.TableStatusDeleting, +// }, +// Target: []string{}, +// Timeout: timeout, +// Refresh: func() (interface{}, string, error) { +// input := &dynamodb.DescribeTableInput{ +// TableName: aws.String(tableName), +// } +// +// output, err := conn.DescribeTable(input) +// +// if isAWSErr(err, dynamodb.ErrCodeResourceNotFoundException, "") { +// return nil, "", nil +// } +// +// if err != nil { +// return 42, "", err +// } +// +// if output == nil { +// return nil, "", nil +// } +// +// return output.Table, aws.StringValue(output.Table.TableStatus), nil +// }, +// } +// +// _, err := stateConf.WaitForState() +// +// return err +// } +// +// func updateDynamoDbTimeToLive(tableName string, ttlList []interface{}, conn *dynamodb.DynamoDB) error { +// ttlMap := ttlList[0].(map[string]interface{}) +// +// input := &dynamodb.UpdateTimeToLiveInput{ +// TableName: aws.String(tableName), +// TimeToLiveSpecification: &dynamodb.TimeToLiveSpecification{ +// AttributeName: aws.String(ttlMap["attribute_name"].(string)), +// Enabled: aws.Bool(ttlMap["enabled"].(bool)), +// }, +// } +// +// log.Printf("[DEBUG] Updating DynamoDB Table (%s) Time To Live: %s", tableName, input) +// if _, err := conn.UpdateTimeToLive(input); err != nil { +// return fmt.Errorf("error updating DynamoDB Table (%s) Time To Live: %s", tableName, err) +// } +// +// log.Printf("[DEBUG] Waiting for DynamoDB Table (%s) Time to Live update to complete", tableName) +// if err := waitForDynamoDbTtlUpdateToBeCompleted(tableName, ttlMap["enabled"].(bool), conn); err != nil { +// return fmt.Errorf("error waiting for DynamoDB Table (%s) Time To Live update: %s", tableName, err) +// } +// +// return nil +// } +// +// func updateDynamoDbPITR(d *schema.ResourceData, conn *dynamodb.DynamoDB) error { +// toEnable := d.Get("point_in_time_recovery.0.enabled").(bool) +// +// input := &dynamodb.UpdateContinuousBackupsInput{ +// TableName: aws.String(d.Id()), +// PointInTimeRecoverySpecification: &dynamodb.PointInTimeRecoverySpecification{ +// PointInTimeRecoveryEnabled: aws.Bool(toEnable), +// }, +// } +// +// log.Printf("[DEBUG] Updating DynamoDB point in time recovery status to %v", toEnable) +// +// err := resource.Retry(20*time.Minute, func() *resource.RetryError { +// _, err := conn.UpdateContinuousBackups(input) +// if err != nil { +// // Backups are still being enabled for this newly created table +// if isAWSErr(err, dynamodb.ErrCodeContinuousBackupsUnavailableException, "Backups are being enabled") { +// return resource.RetryableError(err) +// } +// return resource.NonRetryableError(err) +// } +// return nil +// }) +// if isResourceTimeoutError(err) { +// _, err = conn.UpdateContinuousBackups(input) +// } +// if err != nil { +// return fmt.Errorf("Error updating DynamoDB PITR status: %s", err) +// } +// +// if err := waitForDynamoDbBackupUpdateToBeCompleted(d.Id(), toEnable, conn); err != nil { +// return fmt.Errorf("Error waiting for DynamoDB PITR update: %s", err) +// } +// +// return nil +// } +// +// func readDynamoDbTableTags(arn string, conn *dynamodb.DynamoDB) (map[string]string, error) { +// output, err := conn.ListTagsOfResource(&dynamodb.ListTagsOfResourceInput{ +// ResourceArn: aws.String(arn), +// }) +// +// // Do not fail if interfacing with dynamodb-local +// if err != nil && !isAWSErr(err, "UnknownOperationException", "Tagging is not currently supported in DynamoDB Local.") { +// return nil, fmt.Errorf("Error reading tags from dynamodb resource: %s", err) +// } +// +// result := keyvaluetags.DynamodbKeyValueTags(output.Tags).IgnoreAws().Map() +// +// // TODO Read NextToken if available +// +// return result, nil +// } +// +// // Waiters +// +// func waitForDynamoDbGSIToBeActive(tableName string, gsiName string, timeout time.Duration, conn *dynamodb.DynamoDB) error { +// stateConf := &resource.StateChangeConf{ +// Pending: []string{ +// dynamodb.IndexStatusCreating, +// dynamodb.IndexStatusUpdating, +// }, +// Target: []string{dynamodb.IndexStatusActive}, +// Timeout: timeout, +// Refresh: func() (interface{}, string, error) { +// result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ +// TableName: aws.String(tableName), +// }) +// if err != nil { +// return 42, "", err +// } +// +// table := result.Table +// +// // Find index +// var targetGSI *dynamodb.GlobalSecondaryIndexDescription +// for _, gsi := range table.GlobalSecondaryIndexes { +// if *gsi.IndexName == gsiName { +// targetGSI = gsi +// } +// } +// +// if targetGSI != nil { +// return table, *targetGSI.IndexStatus, nil +// } +// +// return nil, "", nil +// }, +// } +// _, err := stateConf.WaitForState() +// return err +// } +// +// func waitForDynamoDbGSIToBeDeleted(tableName string, gsiName string, timeout time.Duration, conn *dynamodb.DynamoDB) error { +// stateConf := &resource.StateChangeConf{ +// Pending: []string{ +// dynamodb.IndexStatusActive, +// dynamodb.IndexStatusDeleting, +// }, +// Target: []string{}, +// Timeout: timeout, +// Refresh: func() (interface{}, string, error) { +// result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ +// TableName: aws.String(tableName), +// }) +// if err != nil { +// return 42, "", err +// } +// +// table := result.Table +// +// // Find index +// var targetGSI *dynamodb.GlobalSecondaryIndexDescription +// for _, gsi := range table.GlobalSecondaryIndexes { +// if *gsi.IndexName == gsiName { +// targetGSI = gsi +// } +// } +// +// if targetGSI == nil { +// return nil, "", nil +// } +// +// return targetGSI, *targetGSI.IndexStatus, nil +// }, +// } +// _, err := stateConf.WaitForState() +// return err +// } +// +// func waitForDynamoDbTableToBeActive(tableName string, timeout time.Duration, conn *dynamodb.DynamoDB) error { +// stateConf := &resource.StateChangeConf{ +// Pending: []string{dynamodb.TableStatusCreating, dynamodb.TableStatusUpdating}, +// Target: []string{dynamodb.TableStatusActive}, +// Timeout: timeout, +// Refresh: func() (interface{}, string, error) { +// result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ +// TableName: aws.String(tableName), +// }) +// if err != nil { +// return 42, "", err +// } +// +// return result, *result.Table.TableStatus, nil +// }, +// } +// _, err := stateConf.WaitForState() +// +// return err +// } +// +// func waitForDynamoDbBackupUpdateToBeCompleted(tableName string, toEnable bool, conn *dynamodb.DynamoDB) error { +// var pending []string +// target := []string{dynamodb.TimeToLiveStatusDisabled} +// +// if toEnable { +// pending = []string{ +// "ENABLING", +// } +// target = []string{dynamodb.PointInTimeRecoveryStatusEnabled} +// } +// +// stateConf := &resource.StateChangeConf{ +// Pending: pending, +// Target: target, +// Timeout: 10 * time.Second, +// Refresh: func() (interface{}, string, error) { +// result, err := conn.DescribeContinuousBackups(&dynamodb.DescribeContinuousBackupsInput{ +// TableName: aws.String(tableName), +// }) +// if err != nil { +// return 42, "", err +// } +// +// if result.ContinuousBackupsDescription == nil || result.ContinuousBackupsDescription.PointInTimeRecoveryDescription == nil { +// return 42, "", errors.New("Error reading backup status from dynamodb resource: empty description") +// } +// pitr := result.ContinuousBackupsDescription.PointInTimeRecoveryDescription +// +// return result, *pitr.PointInTimeRecoveryStatus, nil +// }, +// } +// _, err := stateConf.WaitForState() +// return err +// } +// +// func waitForDynamoDbTtlUpdateToBeCompleted(tableName string, toEnable bool, conn *dynamodb.DynamoDB) error { +// pending := []string{ +// dynamodb.TimeToLiveStatusEnabled, +// dynamodb.TimeToLiveStatusDisabling, +// } +// target := []string{dynamodb.TimeToLiveStatusDisabled} +// +// if toEnable { +// pending = []string{ +// dynamodb.TimeToLiveStatusDisabled, +// dynamodb.TimeToLiveStatusEnabling, +// } +// target = []string{dynamodb.TimeToLiveStatusEnabled} +// } +// +// stateConf := &resource.StateChangeConf{ +// Pending: pending, +// Target: target, +// Timeout: 10 * time.Second, +// Refresh: func() (interface{}, string, error) { +// result, err := conn.DescribeTimeToLive(&dynamodb.DescribeTimeToLiveInput{ +// TableName: aws.String(tableName), +// }) +// if err != nil { +// return 42, "", err +// } +// +// ttlDesc := result.TimeToLiveDescription +// +// return result, *ttlDesc.TimeToLiveStatus, nil +// }, +// } +// +// _, err := stateConf.WaitForState() +// return err +// } +// +func waitForDynamoDbReplicaUpdateToBeCompleted(tableName string, region string, timeout time.Duration, conn *dynamodb.DynamoDB) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + dynamodb.ReplicaStatusCreating, + dynamodb.ReplicaStatusUpdating, + dynamodb.ReplicaStatusDeleting, + }, + Target: []string{ + dynamodb.ReplicaStatusActive, + }, + Timeout: timeout, + Refresh: func() (interface{}, string, error) { + result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ + TableName: aws.String(tableName), + }) + if err != nil { + return 42, "", err + } + log.Printf("[DEBUG] DynamoDB replicas: %s", result.Table.Replicas) + + if len(result.Table.Replicas) == 0 { + return result, dynamodb.ReplicaStatusCreating, nil + } + // Find replica + var targetReplica *dynamodb.ReplicaDescription + for _, replica := range result.Table.Replicas { + if *replica.RegionName == region { + targetReplica = replica + } + } + + if targetReplica == nil { + return nil, "", nil + } + + return result, aws.StringValue(targetReplica.ReplicaStatus), nil + }, + } + _, err := stateConf.WaitForState() + + return err +} + +func waitForDynamoDbReplicaDeleteToBeCompleted(tableName string, region string, timeout time.Duration, conn *dynamodb.DynamoDB) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + dynamodb.ReplicaStatusCreating, + dynamodb.ReplicaStatusUpdating, + dynamodb.ReplicaStatusDeleting, + dynamodb.ReplicaStatusActive, + }, + Target: []string{}, + Timeout: timeout, + Refresh: func() (interface{}, string, error) { + result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ + TableName: aws.String(tableName), + }) + if err != nil { + return 42, "", err + } + + log.Printf("[DEBUG] all replicas for waiting: %s", result.Table.Replicas) + if len(result.Table.Replicas) == 0 { + return result, "", nil + } + + // Find replica + var targetReplica *dynamodb.ReplicaDescription + for _, replica := range result.Table.Replicas { + if *replica.RegionName == region { + targetReplica = replica + } + } + log.Printf("[DEBUG] targetReplica: %s", targetReplica) + + if targetReplica == nil { + return result, "", nil + } + + return result, aws.StringValue(targetReplica.ReplicaStatus), nil + }, + } + _, err := stateConf.WaitForState() + + return err +} + +// +// func isDynamoDbTableOptionDisabled(v interface{}) bool { +// options := v.([]interface{}) +// if len(options) == 0 { +// return true +// } +// e := options[0].(map[string]interface{})["enabled"] +// return !e.(bool) +// } diff --git a/aws/resource_aws_dynamodb_table_2019_test.go b/aws/resource_aws_dynamodb_table_2019_test.go new file mode 100644 index 00000000000..d7c81c1adae --- /dev/null +++ b/aws/resource_aws_dynamodb_table_2019_test.go @@ -0,0 +1,207 @@ +package aws + +import ( + "fmt" + "log" + "testing" + + "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func init() { + resource.AddTestSweepers("aws_dynamodb_table_2019", &resource.Sweeper{ + Name: "aws_dynamodb_table_2019", + F: testSweepDynamoDbTables2019, + }) +} + +func testSweepDynamoDbTables2019(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).dynamodbconn + + err = conn.ListTablesPages(&dynamodb.ListTablesInput{}, func(out *dynamodb.ListTablesOutput, lastPage bool) bool { + for _, tableName := range out.TableNames { + log.Printf("[INFO] Deleting DynamoDB Table: %s", *tableName) + + err := deleteAwsDynamoDbTable(*tableName, conn) + if err != nil { + log.Printf("[ERROR] Failed to delete DynamoDB Table %s: %s", *tableName, err) + continue + } + } + return !lastPage + }) + if err != nil { + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping DynamoDB Table sweep for %s: %s", region, err) + return nil + } + return fmt.Errorf("Error retrieving DynamoDB Tables: %s", err) + } + + return nil +} + +func TestAccAWSDynamoDbTable2019_basic(t *testing.T) { + var conf dynamodb.DescribeTableOutput + resourceName := "aws_dynamodb_table_2019.test" + tableName := acctest.RandomWithPrefix("TerraformTestTable2019-") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDynamoDbTableDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDynamoDbReplicaUpdates(tableName), + Check: resource.ComposeTestCheckFunc( + testAccCheckInitialAWSDynamoDbTableExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "name", tableName), + resource.TestCheckResourceAttr(resourceName, "hash_key", "TestTableHashKey"), + resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.name", "TestTableHashKey"), + resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.type", "S"), + resource.TestCheckResourceAttr(resourceName, "replica.#", "1"), + resource.TestCheckResourceAttr(resourceName, "replica.0.region", "us-west-1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSDynamoDbReplicaDeletes(tableName), + Check: resource.ComposeTestCheckFunc( + testAccCheckInitialAWSDynamoDbTableExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "name", tableName), + resource.TestCheckResourceAttr(resourceName, "hash_key", "TestTableHashKey"), + resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.name", "TestTableHashKey"), + resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.type", "S"), + resource.TestCheckResourceAttr(resourceName, "hash_key", "TestTableHashKey"), + resource.TestCheckResourceAttr(resourceName, "replica.#", "0"), + ), + }, + }, + }) +} + +// func testAccCheckInitialAWSDynamoDbTableConf(n string) resource.TestCheckFunc { +// return func(s *terraform.State) error { +// log.Printf("[DEBUG] Trying to create initial table state!") +// rs, ok := s.RootModule().Resources[n] +// if !ok { +// return fmt.Errorf("Not found: %s", n) +// } +// +// if rs.Primary.ID == "" { +// return fmt.Errorf("No DynamoDB table name specified!") +// } +// +// conn := testAccProvider.Meta().(*AWSClient).dynamodbconn +// +// params := &dynamodb.DescribeTableInput{ +// TableName: aws.String(rs.Primary.ID), +// } +// +// resp, err := conn.DescribeTable(params) +// +// if err != nil { +// return fmt.Errorf("Problem describing table '%s': %s", rs.Primary.ID, err) +// } +// +// table := resp.Table +// +// log.Printf("[DEBUG] Checking on table %s", rs.Primary.ID) +// +// if table.BillingModeSummary != nil && aws.StringValue(table.BillingModeSummary.BillingMode) != dynamodb.BillingModeProvisioned { +// return fmt.Errorf("Billing Mode was %s, not %s!", aws.StringValue(table.BillingModeSummary.BillingMode), dynamodb.BillingModeProvisioned) +// } +// +// if *table.ProvisionedThroughput.WriteCapacityUnits != 2 { +// return fmt.Errorf("Provisioned write capacity was %d, not 2!", table.ProvisionedThroughput.WriteCapacityUnits) +// } +// +// if *table.ProvisionedThroughput.ReadCapacityUnits != 1 { +// return fmt.Errorf("Provisioned read capacity was %d, not 1!", table.ProvisionedThroughput.ReadCapacityUnits) +// } +// +// if table.SSEDescription != nil && *table.SSEDescription.Status != dynamodb.SSEStatusDisabled { +// return fmt.Errorf("SSE status was %s, not %s", *table.SSEDescription.Status, dynamodb.SSEStatusDisabled) +// } +// +// attrCount := len(table.AttributeDefinitions) +// gsiCount := len(table.GlobalSecondaryIndexes) +// lsiCount := len(table.LocalSecondaryIndexes) +// +// if attrCount != 4 { +// return fmt.Errorf("There were %d attributes, not 4 like there should have been!", attrCount) +// } +// +// if gsiCount != 1 { +// return fmt.Errorf("There were %d GSIs, not 1 like there should have been!", gsiCount) +// } +// +// if lsiCount != 1 { +// return fmt.Errorf("There were %d LSIs, not 1 like there should have been!", lsiCount) +// } +// +// attrmap := dynamoDbAttributesToMap(&table.AttributeDefinitions) +// if attrmap["TestTableHashKey"] != "S" { +// return fmt.Errorf("Test table hash key was of type %s instead of S!", attrmap["TestTableHashKey"]) +// } +// if attrmap["TestTableRangeKey"] != "S" { +// return fmt.Errorf("Test table range key was of type %s instead of S!", attrmap["TestTableRangeKey"]) +// } +// if attrmap["TestLSIRangeKey"] != "N" { +// return fmt.Errorf("Test table LSI range key was of type %s instead of N!", attrmap["TestLSIRangeKey"]) +// } +// if attrmap["TestGSIRangeKey"] != "S" { +// return fmt.Errorf("Test table GSI range key was of type %s instead of S!", attrmap["TestGSIRangeKey"]) +// } +// +// return nil +// } +// } + +func testAccAWSDynamoDbReplicaUpdates(rName string) string { + return fmt.Sprintf(` +resource "aws_dynamodb_table_2019" "test" { + name = "%s" + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region = "us-west-1" + } +} +`, rName) +} + +func testAccAWSDynamoDbReplicaDeletes(rName string) string { + return fmt.Sprintf(` +resource "aws_dynamodb_table_2019" "test" { + name = "%s" + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } +} +`, rName) +} diff --git a/aws/structure.go b/aws/structure.go index a2e8cfda8f5..699f747e0f5 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "log" "reflect" "regexp" "sort" @@ -4256,6 +4257,55 @@ func diffDynamoDbGSI(oldGsi, newGsi []interface{}, billingMode string) (ops []*d return } +func diffDynamoDbReplicas(oldReplica, newReplica []interface{}) (ops []*dynamodb.ReplicationGroupUpdate, e error) { + // Transform slices into maps + oldReplicas := make(map[string]interface{}) + for _, replicaData := range oldReplica { + m := replicaData.(map[string]interface{}) + oldReplicas[m["region"].(string)] = m + } + newReplicas := make(map[string]interface{}) + for _, replicaData := range newReplica { + m := replicaData.(map[string]interface{}) + newReplicas[m["region"].(string)] = m + } + + for _, data := range newReplica { + newMap := data.(map[string]interface{}) + newName := newMap["region"].(string) + + if _, exists := oldReplicas[newName]; !exists { + m := data.(map[string]interface{}) + regionName := m["region"].(string) + + ops = append(ops, &dynamodb.ReplicationGroupUpdate{ + Create: &dynamodb.CreateReplicationGroupMemberAction{ + RegionName: aws.String(regionName), + }, + }) + } + } + + for _, data := range oldReplicas { + oldMap := data.(map[string]interface{}) + oldName := oldMap["region"].(string) + + _, exists := newReplicas[oldName] + if exists { + // newMap := newData.(map[string]interface{}) + // regionName := newMap["region"].(string) + } else { + regionName := oldName + ops = append(ops, &dynamodb.ReplicationGroupUpdate{ + Delete: &dynamodb.DeleteReplicationGroupMemberAction{ + RegionName: aws.String(regionName), + }, + }) + } + } + return +} + func stripCapacityAttributes(in map[string]interface{}) (map[string]interface{}, error) { mapCopy, err := copystructure.Copy(in) if err != nil { @@ -4308,6 +4358,141 @@ func flattenDynamoDbPitr(pitrDesc *dynamodb.DescribeContinuousBackupsOutput) []i return []interface{}{m} } +func flattenAwsDynamoDbTableResource_2019(d *schema.ResourceData, table *dynamodb.TableDescription) error { + d.Set("billing_mode", dynamodb.BillingModeProvisioned) + if table.BillingModeSummary != nil { + d.Set("billing_mode", table.BillingModeSummary.BillingMode) + } + + d.Set("write_capacity", table.ProvisionedThroughput.WriteCapacityUnits) + d.Set("read_capacity", table.ProvisionedThroughput.ReadCapacityUnits) + + attributes := []interface{}{} + for _, attrdef := range table.AttributeDefinitions { + attribute := map[string]string{ + "name": *attrdef.AttributeName, + "type": *attrdef.AttributeType, + } + attributes = append(attributes, attribute) + } + + d.Set("attribute", attributes) + d.Set("name", table.TableName) + + for _, attribute := range table.KeySchema { + if *attribute.KeyType == dynamodb.KeyTypeHash { + d.Set("hash_key", attribute.AttributeName) + } + + if *attribute.KeyType == dynamodb.KeyTypeRange { + d.Set("range_key", attribute.AttributeName) + } + } + + lsiList := make([]map[string]interface{}, 0, len(table.LocalSecondaryIndexes)) + for _, lsiObject := range table.LocalSecondaryIndexes { + lsi := map[string]interface{}{ + "name": *lsiObject.IndexName, + "projection_type": *lsiObject.Projection.ProjectionType, + } + + for _, attribute := range lsiObject.KeySchema { + + if *attribute.KeyType == dynamodb.KeyTypeRange { + lsi["range_key"] = *attribute.AttributeName + } + } + nkaList := make([]string, len(lsiObject.Projection.NonKeyAttributes)) + for _, nka := range lsiObject.Projection.NonKeyAttributes { + nkaList = append(nkaList, *nka) + } + lsi["non_key_attributes"] = nkaList + + lsiList = append(lsiList, lsi) + } + + err := d.Set("local_secondary_index", lsiList) + if err != nil { + return err + } + + gsiList := make([]map[string]interface{}, 0, len(table.GlobalSecondaryIndexes)) + for _, gsiObject := range table.GlobalSecondaryIndexes { + gsi := map[string]interface{}{ + "write_capacity": *gsiObject.ProvisionedThroughput.WriteCapacityUnits, + "read_capacity": *gsiObject.ProvisionedThroughput.ReadCapacityUnits, + "name": *gsiObject.IndexName, + } + + for _, attribute := range gsiObject.KeySchema { + if *attribute.KeyType == dynamodb.KeyTypeHash { + gsi["hash_key"] = *attribute.AttributeName + } + + if *attribute.KeyType == dynamodb.KeyTypeRange { + gsi["range_key"] = *attribute.AttributeName + } + } + + gsi["projection_type"] = *(gsiObject.Projection.ProjectionType) + + nonKeyAttrs := make([]string, 0, len(gsiObject.Projection.NonKeyAttributes)) + for _, nonKeyAttr := range gsiObject.Projection.NonKeyAttributes { + nonKeyAttrs = append(nonKeyAttrs, *nonKeyAttr) + } + gsi["non_key_attributes"] = nonKeyAttrs + + gsiList = append(gsiList, gsi) + } + + if table.StreamSpecification != nil { + d.Set("stream_view_type", table.StreamSpecification.StreamViewType) + d.Set("stream_enabled", table.StreamSpecification.StreamEnabled) + } else { + d.Set("stream_view_type", "") + d.Set("stream_enabled", false) + } + + d.Set("stream_arn", table.LatestStreamArn) + d.Set("stream_label", table.LatestStreamLabel) + + err = d.Set("global_secondary_index", gsiList) + if err != nil { + return err + } + + sseOptions := []map[string]interface{}{} + if sseDescription := table.SSEDescription; sseDescription != nil { + sseOptions = []map[string]interface{}{{ + "enabled": aws.StringValue(sseDescription.Status) == dynamodb.SSEStatusEnabled, + "kms_key_arn": aws.StringValue(sseDescription.KMSMasterKeyArn), + }} + } + err = d.Set("server_side_encryption", sseOptions) + if err != nil { + return err + } + + replicaList := make([]map[string]interface{}, 0, len(table.Replicas)) + for _, replicaObject := range table.Replicas { + replica := map[string]interface{}{ + "region": aws.StringValue(replicaObject.RegionName), + } + + replicaList = append(replicaList, replica) + } + + log.Printf("[DEBUG] Creating replica list: %#v", replicaList) + err = d.Set("replica", replicaList) + if err != nil { + return err + } + + d.Set("arn", table.TableArn) + + return nil +} + func flattenAwsDynamoDbTableResource(d *schema.ResourceData, table *dynamodb.TableDescription) error { d.Set("billing_mode", dynamodb.BillingModeProvisioned) if table.BillingModeSummary != nil { From 499ccaf328189cc6ec87fbe2def0c0b496efba5d Mon Sep 17 00:00:00 2001 From: cory Date: Tue, 10 Mar 2020 21:37:41 +0000 Subject: [PATCH 035/684] Removes comments. --- aws/resource_aws_dynamodb_table_2019.go | 328 ------------------------ 1 file changed, 328 deletions(-) diff --git a/aws/resource_aws_dynamodb_table_2019.go b/aws/resource_aws_dynamodb_table_2019.go index 7fe0978db13..d6228984b56 100644 --- a/aws/resource_aws_dynamodb_table_2019.go +++ b/aws/resource_aws_dynamodb_table_2019.go @@ -811,324 +811,6 @@ func resourceAwsDynamoDbTable2019Delete(d *schema.ResourceData, meta interface{} return nil } -// func deleteAwsDynamoDbTable(tableName string, conn *dynamodb.DynamoDB) error { -// input := &dynamodb.DeleteTableInput{ -// TableName: aws.String(tableName), -// } -// -// err := resource.Retry(5*time.Minute, func() *resource.RetryError { -// _, err := conn.DeleteTable(input) -// if err != nil { -// // Subscriber limit exceeded: Only 10 tables can be created, updated, or deleted simultaneously -// if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "simultaneously") { -// return resource.RetryableError(err) -// } -// // This handles multiple scenarios in the DynamoDB API: -// // 1. Updating a table immediately before deletion may return: -// // ResourceInUseException: Attempt to change a resource which is still in use: Table is being updated: -// // 2. Removing a table from a DynamoDB global table may return: -// // ResourceInUseException: Attempt to change a resource which is still in use: Table is being deleted: -// if isAWSErr(err, dynamodb.ErrCodeResourceInUseException, "") { -// return resource.RetryableError(err) -// } -// if isAWSErr(err, dynamodb.ErrCodeResourceNotFoundException, "Requested resource not found: Table: ") { -// return resource.NonRetryableError(err) -// } -// return resource.NonRetryableError(err) -// } -// return nil -// }) -// -// if isResourceTimeoutError(err) { -// _, err = conn.DeleteTable(input) -// } -// -// return err -// } -// -// func waitForDynamodbTableDeletion(conn *dynamodb.DynamoDB, tableName string, timeout time.Duration) error { -// stateConf := &resource.StateChangeConf{ -// Pending: []string{ -// dynamodb.TableStatusActive, -// dynamodb.TableStatusDeleting, -// }, -// Target: []string{}, -// Timeout: timeout, -// Refresh: func() (interface{}, string, error) { -// input := &dynamodb.DescribeTableInput{ -// TableName: aws.String(tableName), -// } -// -// output, err := conn.DescribeTable(input) -// -// if isAWSErr(err, dynamodb.ErrCodeResourceNotFoundException, "") { -// return nil, "", nil -// } -// -// if err != nil { -// return 42, "", err -// } -// -// if output == nil { -// return nil, "", nil -// } -// -// return output.Table, aws.StringValue(output.Table.TableStatus), nil -// }, -// } -// -// _, err := stateConf.WaitForState() -// -// return err -// } -// -// func updateDynamoDbTimeToLive(tableName string, ttlList []interface{}, conn *dynamodb.DynamoDB) error { -// ttlMap := ttlList[0].(map[string]interface{}) -// -// input := &dynamodb.UpdateTimeToLiveInput{ -// TableName: aws.String(tableName), -// TimeToLiveSpecification: &dynamodb.TimeToLiveSpecification{ -// AttributeName: aws.String(ttlMap["attribute_name"].(string)), -// Enabled: aws.Bool(ttlMap["enabled"].(bool)), -// }, -// } -// -// log.Printf("[DEBUG] Updating DynamoDB Table (%s) Time To Live: %s", tableName, input) -// if _, err := conn.UpdateTimeToLive(input); err != nil { -// return fmt.Errorf("error updating DynamoDB Table (%s) Time To Live: %s", tableName, err) -// } -// -// log.Printf("[DEBUG] Waiting for DynamoDB Table (%s) Time to Live update to complete", tableName) -// if err := waitForDynamoDbTtlUpdateToBeCompleted(tableName, ttlMap["enabled"].(bool), conn); err != nil { -// return fmt.Errorf("error waiting for DynamoDB Table (%s) Time To Live update: %s", tableName, err) -// } -// -// return nil -// } -// -// func updateDynamoDbPITR(d *schema.ResourceData, conn *dynamodb.DynamoDB) error { -// toEnable := d.Get("point_in_time_recovery.0.enabled").(bool) -// -// input := &dynamodb.UpdateContinuousBackupsInput{ -// TableName: aws.String(d.Id()), -// PointInTimeRecoverySpecification: &dynamodb.PointInTimeRecoverySpecification{ -// PointInTimeRecoveryEnabled: aws.Bool(toEnable), -// }, -// } -// -// log.Printf("[DEBUG] Updating DynamoDB point in time recovery status to %v", toEnable) -// -// err := resource.Retry(20*time.Minute, func() *resource.RetryError { -// _, err := conn.UpdateContinuousBackups(input) -// if err != nil { -// // Backups are still being enabled for this newly created table -// if isAWSErr(err, dynamodb.ErrCodeContinuousBackupsUnavailableException, "Backups are being enabled") { -// return resource.RetryableError(err) -// } -// return resource.NonRetryableError(err) -// } -// return nil -// }) -// if isResourceTimeoutError(err) { -// _, err = conn.UpdateContinuousBackups(input) -// } -// if err != nil { -// return fmt.Errorf("Error updating DynamoDB PITR status: %s", err) -// } -// -// if err := waitForDynamoDbBackupUpdateToBeCompleted(d.Id(), toEnable, conn); err != nil { -// return fmt.Errorf("Error waiting for DynamoDB PITR update: %s", err) -// } -// -// return nil -// } -// -// func readDynamoDbTableTags(arn string, conn *dynamodb.DynamoDB) (map[string]string, error) { -// output, err := conn.ListTagsOfResource(&dynamodb.ListTagsOfResourceInput{ -// ResourceArn: aws.String(arn), -// }) -// -// // Do not fail if interfacing with dynamodb-local -// if err != nil && !isAWSErr(err, "UnknownOperationException", "Tagging is not currently supported in DynamoDB Local.") { -// return nil, fmt.Errorf("Error reading tags from dynamodb resource: %s", err) -// } -// -// result := keyvaluetags.DynamodbKeyValueTags(output.Tags).IgnoreAws().Map() -// -// // TODO Read NextToken if available -// -// return result, nil -// } -// -// // Waiters -// -// func waitForDynamoDbGSIToBeActive(tableName string, gsiName string, timeout time.Duration, conn *dynamodb.DynamoDB) error { -// stateConf := &resource.StateChangeConf{ -// Pending: []string{ -// dynamodb.IndexStatusCreating, -// dynamodb.IndexStatusUpdating, -// }, -// Target: []string{dynamodb.IndexStatusActive}, -// Timeout: timeout, -// Refresh: func() (interface{}, string, error) { -// result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ -// TableName: aws.String(tableName), -// }) -// if err != nil { -// return 42, "", err -// } -// -// table := result.Table -// -// // Find index -// var targetGSI *dynamodb.GlobalSecondaryIndexDescription -// for _, gsi := range table.GlobalSecondaryIndexes { -// if *gsi.IndexName == gsiName { -// targetGSI = gsi -// } -// } -// -// if targetGSI != nil { -// return table, *targetGSI.IndexStatus, nil -// } -// -// return nil, "", nil -// }, -// } -// _, err := stateConf.WaitForState() -// return err -// } -// -// func waitForDynamoDbGSIToBeDeleted(tableName string, gsiName string, timeout time.Duration, conn *dynamodb.DynamoDB) error { -// stateConf := &resource.StateChangeConf{ -// Pending: []string{ -// dynamodb.IndexStatusActive, -// dynamodb.IndexStatusDeleting, -// }, -// Target: []string{}, -// Timeout: timeout, -// Refresh: func() (interface{}, string, error) { -// result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ -// TableName: aws.String(tableName), -// }) -// if err != nil { -// return 42, "", err -// } -// -// table := result.Table -// -// // Find index -// var targetGSI *dynamodb.GlobalSecondaryIndexDescription -// for _, gsi := range table.GlobalSecondaryIndexes { -// if *gsi.IndexName == gsiName { -// targetGSI = gsi -// } -// } -// -// if targetGSI == nil { -// return nil, "", nil -// } -// -// return targetGSI, *targetGSI.IndexStatus, nil -// }, -// } -// _, err := stateConf.WaitForState() -// return err -// } -// -// func waitForDynamoDbTableToBeActive(tableName string, timeout time.Duration, conn *dynamodb.DynamoDB) error { -// stateConf := &resource.StateChangeConf{ -// Pending: []string{dynamodb.TableStatusCreating, dynamodb.TableStatusUpdating}, -// Target: []string{dynamodb.TableStatusActive}, -// Timeout: timeout, -// Refresh: func() (interface{}, string, error) { -// result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ -// TableName: aws.String(tableName), -// }) -// if err != nil { -// return 42, "", err -// } -// -// return result, *result.Table.TableStatus, nil -// }, -// } -// _, err := stateConf.WaitForState() -// -// return err -// } -// -// func waitForDynamoDbBackupUpdateToBeCompleted(tableName string, toEnable bool, conn *dynamodb.DynamoDB) error { -// var pending []string -// target := []string{dynamodb.TimeToLiveStatusDisabled} -// -// if toEnable { -// pending = []string{ -// "ENABLING", -// } -// target = []string{dynamodb.PointInTimeRecoveryStatusEnabled} -// } -// -// stateConf := &resource.StateChangeConf{ -// Pending: pending, -// Target: target, -// Timeout: 10 * time.Second, -// Refresh: func() (interface{}, string, error) { -// result, err := conn.DescribeContinuousBackups(&dynamodb.DescribeContinuousBackupsInput{ -// TableName: aws.String(tableName), -// }) -// if err != nil { -// return 42, "", err -// } -// -// if result.ContinuousBackupsDescription == nil || result.ContinuousBackupsDescription.PointInTimeRecoveryDescription == nil { -// return 42, "", errors.New("Error reading backup status from dynamodb resource: empty description") -// } -// pitr := result.ContinuousBackupsDescription.PointInTimeRecoveryDescription -// -// return result, *pitr.PointInTimeRecoveryStatus, nil -// }, -// } -// _, err := stateConf.WaitForState() -// return err -// } -// -// func waitForDynamoDbTtlUpdateToBeCompleted(tableName string, toEnable bool, conn *dynamodb.DynamoDB) error { -// pending := []string{ -// dynamodb.TimeToLiveStatusEnabled, -// dynamodb.TimeToLiveStatusDisabling, -// } -// target := []string{dynamodb.TimeToLiveStatusDisabled} -// -// if toEnable { -// pending = []string{ -// dynamodb.TimeToLiveStatusDisabled, -// dynamodb.TimeToLiveStatusEnabling, -// } -// target = []string{dynamodb.TimeToLiveStatusEnabled} -// } -// -// stateConf := &resource.StateChangeConf{ -// Pending: pending, -// Target: target, -// Timeout: 10 * time.Second, -// Refresh: func() (interface{}, string, error) { -// result, err := conn.DescribeTimeToLive(&dynamodb.DescribeTimeToLiveInput{ -// TableName: aws.String(tableName), -// }) -// if err != nil { -// return 42, "", err -// } -// -// ttlDesc := result.TimeToLiveDescription -// -// return result, *ttlDesc.TimeToLiveStatus, nil -// }, -// } -// -// _, err := stateConf.WaitForState() -// return err -// } -// func waitForDynamoDbReplicaUpdateToBeCompleted(tableName string, region string, timeout time.Duration, conn *dynamodb.DynamoDB) error { stateConf := &resource.StateChangeConf{ Pending: []string{ @@ -1215,13 +897,3 @@ func waitForDynamoDbReplicaDeleteToBeCompleted(tableName string, region string, return err } - -// -// func isDynamoDbTableOptionDisabled(v interface{}) bool { -// options := v.([]interface{}) -// if len(options) == 0 { -// return true -// } -// e := options[0].(map[string]interface{})["enabled"] -// return !e.(bool) -// } From ebc6ba2bc68984f6f0f83d00118bf67a7424e600 Mon Sep 17 00:00:00 2001 From: cory Date: Tue, 10 Mar 2020 21:45:37 +0000 Subject: [PATCH 036/684] Uses resourceAwsDynamoDbTableCreate --- aws/resource_aws_dynamodb_table_2019.go | 134 +----------------------- 1 file changed, 3 insertions(+), 131 deletions(-) diff --git a/aws/resource_aws_dynamodb_table_2019.go b/aws/resource_aws_dynamodb_table_2019.go index d6228984b56..375d0370ceb 100644 --- a/aws/resource_aws_dynamodb_table_2019.go +++ b/aws/resource_aws_dynamodb_table_2019.go @@ -296,139 +296,11 @@ func resourceAwsDynamoDbTable2019() *schema.Resource { } func resourceAwsDynamoDbTable2019Create(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).dynamodbconn - - keySchemaMap := map[string]interface{}{ - "hash_key": d.Get("hash_key").(string), - } - if v, ok := d.GetOk("range_key"); ok { - keySchemaMap["range_key"] = v.(string) - } - - log.Printf("[DEBUG] Creating DynamoDB table with key schema: %#v", keySchemaMap) - - tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().DynamodbTags() - - req := &dynamodb.CreateTableInput{ - TableName: aws.String(d.Get("name").(string)), - BillingMode: aws.String(d.Get("billing_mode").(string)), - KeySchema: expandDynamoDbKeySchema(keySchemaMap), - Tags: tags, - } - - billingMode := d.Get("billing_mode").(string) - capacityMap := map[string]interface{}{ - "write_capacity": d.Get("write_capacity"), - "read_capacity": d.Get("read_capacity"), - } - - if err := validateDynamoDbProvisionedThroughput(capacityMap, billingMode); err != nil { - return err - } - - req.ProvisionedThroughput = expandDynamoDbProvisionedThroughput(capacityMap, billingMode) - - if v, ok := d.GetOk("attribute"); ok { - aSet := v.(*schema.Set) - req.AttributeDefinitions = expandDynamoDbAttributes(aSet.List()) - } - - if v, ok := d.GetOk("local_secondary_index"); ok { - lsiSet := v.(*schema.Set) - req.LocalSecondaryIndexes = expandDynamoDbLocalSecondaryIndexes(lsiSet.List(), keySchemaMap) - } - - if v, ok := d.GetOk("global_secondary_index"); ok { - globalSecondaryIndexes := []*dynamodb.GlobalSecondaryIndex{} - gsiSet := v.(*schema.Set) - - for _, gsiObject := range gsiSet.List() { - gsi := gsiObject.(map[string]interface{}) - if err := validateDynamoDbProvisionedThroughput(gsi, billingMode); err != nil { - return fmt.Errorf("Failed to create GSI: %v", err) - } - - gsiObject := expandDynamoDbGlobalSecondaryIndex(gsi, billingMode) - globalSecondaryIndexes = append(globalSecondaryIndexes, gsiObject) - } - req.GlobalSecondaryIndexes = globalSecondaryIndexes - } - - if v, ok := d.GetOk("stream_enabled"); ok { - req.StreamSpecification = &dynamodb.StreamSpecification{ - StreamEnabled: aws.Bool(v.(bool)), - StreamViewType: aws.String(d.Get("stream_view_type").(string)), - } - } - - if v, ok := d.GetOk("server_side_encryption"); ok { - req.SSESpecification = expandDynamoDbEncryptAtRestOptions(v.([]interface{})) - } - - var output *dynamodb.CreateTableOutput - var requiresTagging bool - err := resource.Retry(2*time.Minute, func() *resource.RetryError { - var err error - output, err = conn.CreateTable(req) - if err != nil { - if isAWSErr(err, "ThrottlingException", "") { - return resource.RetryableError(err) - } - if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "can be created, updated, or deleted simultaneously") { - return resource.RetryableError(err) - } - if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "indexed tables that can be created simultaneously") { - return resource.RetryableError(err) - } - // AWS GovCloud (US) and others may reply with the following until their API is updated: - // ValidationException: One or more parameter values were invalid: Unsupported input parameter BillingMode - if isAWSErr(err, "ValidationException", "Unsupported input parameter BillingMode") { - req.BillingMode = nil - return resource.RetryableError(err) - } - // AWS GovCloud (US) and others may reply with the following until their API is updated: - // ValidationException: Unsupported input parameter Tags - if isAWSErr(err, "ValidationException", "Unsupported input parameter Tags") { - req.Tags = nil - requiresTagging = true - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) - } - return nil - }) - if isResourceTimeoutError(err) { - output, err = conn.CreateTable(req) - } + err := resourceAwsDynamoDbTableCreate(d, meta) if err != nil { - return fmt.Errorf("error creating DynamoDB Table: %s", err) - } - - d.SetId(*output.TableDescription.TableName) - d.Set("arn", output.TableDescription.TableArn) - - if err := waitForDynamoDbTableToBeActive(d.Id(), d.Timeout(schema.TimeoutCreate), conn); err != nil { - return err - } - - if requiresTagging { - if err := keyvaluetags.DynamodbUpdateTags(conn, d.Get("arn").(string), nil, tags); err != nil { - return fmt.Errorf("error adding DynamoDB Table (%s) tags: %s", d.Id(), err) - } - } - - if d.Get("ttl.0.enabled").(bool) { - if err := updateDynamoDbTimeToLive(d.Id(), d.Get("ttl").([]interface{}), conn); err != nil { - return fmt.Errorf("error enabling DynamoDB Table (%s) Time to Live: %s", d.Id(), err) - } - } - - if d.Get("point_in_time_recovery.0.enabled").(bool) { - if err := updateDynamoDbPITR(d, conn); err != nil { - return fmt.Errorf("error enabling DynamoDB Table (%s) point in time recovery: %s", d.Id(), err) - } + return fmt.Errorf("error creating DynamoDB Table (%s) %s", d.Id(), err) } + conn := meta.(*AWSClient).dynamodbconn if _, ok := d.GetOk("replica"); ok { if err := createDynamoDbReplicas(d.Id(), d.Get("replica").([]interface{}), conn); err != nil { From b8c00b95dfcc70ab2e940a0cdb01b5c14fa0b3cf Mon Sep 17 00:00:00 2001 From: cory Date: Tue, 10 Mar 2020 22:01:46 +0000 Subject: [PATCH 037/684] Uses resourceAwsDynamoDbTableUpdate. --- aws/resource_aws_dynamodb_table_2019.go | 176 +----------------------- 1 file changed, 4 insertions(+), 172 deletions(-) diff --git a/aws/resource_aws_dynamodb_table_2019.go b/aws/resource_aws_dynamodb_table_2019.go index 375d0370ceb..fa972d77b42 100644 --- a/aws/resource_aws_dynamodb_table_2019.go +++ b/aws/resource_aws_dynamodb_table_2019.go @@ -14,7 +14,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "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 resourceAwsDynamoDbTable2019() *schema.Resource { @@ -394,97 +393,12 @@ func deleteDynamoDbReplicas(tableName string, replicas []interface{}, conn *dyna } func resourceAwsDynamoDbTable2019Update(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).dynamodbconn - billingMode := d.Get("billing_mode").(string) - - // Global Secondary Index operations must occur in multiple phases - // to prevent various error scenarios. If there are no detected required - // updates in the Terraform configuration, later validation or API errors - // will signal the problems. - var gsiUpdates []*dynamodb.GlobalSecondaryIndexUpdate - - if d.HasChange("global_secondary_index") { - var err error - o, n := d.GetChange("global_secondary_index") - gsiUpdates, err = diffDynamoDbGSI(o.(*schema.Set).List(), n.(*schema.Set).List(), billingMode) - - if err != nil { - return fmt.Errorf("computing difference for DynamoDB Table (%s) Global Secondary Index updates failed: %s", d.Id(), err) - } - - log.Printf("[DEBUG] Computed DynamoDB Table (%s) Global Secondary Index updates: %s", d.Id(), gsiUpdates) - } - - // Phase 1 of Global Secondary Index Operations: Delete Only - // * Delete indexes first to prevent error when simultaneously updating - // BillingMode to PROVISIONED, which requires updating index - // ProvisionedThroughput first, but we have no definition - // * Only 1 online index can be deleted simultaneously per table - for _, gsiUpdate := range gsiUpdates { - if gsiUpdate.Delete == nil { - continue - } - - idxName := aws.StringValue(gsiUpdate.Delete.IndexName) - input := &dynamodb.UpdateTableInput{ - GlobalSecondaryIndexUpdates: []*dynamodb.GlobalSecondaryIndexUpdate{gsiUpdate}, - TableName: aws.String(d.Id()), - } - - if _, err := conn.UpdateTable(input); err != nil { - return fmt.Errorf("error deleting DynamoDB Table (%s) Global Secondary Index (%s): %s", d.Id(), idxName, err) - } - - if err := waitForDynamoDbGSIToBeDeleted(d.Id(), idxName, d.Timeout(schema.TimeoutUpdate), conn); err != nil { - return fmt.Errorf("error waiting for DynamoDB Table (%s) Global Secondary Index (%s) deletion: %s", d.Id(), idxName, err) - } - } - - hasTableUpdate := false - input := &dynamodb.UpdateTableInput{ - TableName: aws.String(d.Id()), - } - - if d.HasChange("billing_mode") || d.HasChange("read_capacity") || d.HasChange("write_capacity") { - hasTableUpdate = true - - capacityMap := map[string]interface{}{ - "write_capacity": d.Get("write_capacity"), - "read_capacity": d.Get("read_capacity"), - } - - if err := validateDynamoDbProvisionedThroughput(capacityMap, billingMode); err != nil { - return err - } - - input.BillingMode = aws.String(billingMode) - input.ProvisionedThroughput = expandDynamoDbProvisionedThroughput(capacityMap, billingMode) - } - - if d.HasChange("stream_enabled") || d.HasChange("stream_view_type") { - hasTableUpdate = true - - input.StreamSpecification = &dynamodb.StreamSpecification{ - StreamEnabled: aws.Bool(d.Get("stream_enabled").(bool)), - } - if d.Get("stream_enabled").(bool) { - input.StreamSpecification.StreamViewType = aws.String(d.Get("stream_view_type").(string)) - } + err := resourceAwsDynamoDbTableUpdate(d, meta) + if err != nil { + return fmt.Errorf("error updating DynamoDB Table (%s) %s", d.Id(), err) } - // Phase 2 of Global Secondary Index Operations: Update Only - // Cannot create or delete index while updating table ProvisionedThroughput - // Must skip all index updates when switching BillingMode from PROVISIONED to PAY_PER_REQUEST - // Must update all indexes when switching BillingMode from PAY_PER_REQUEST to PROVISIONED - if billingMode == dynamodb.BillingModeProvisioned { - for _, gsiUpdate := range gsiUpdates { - if gsiUpdate.Update == nil { - continue - } - - input.GlobalSecondaryIndexUpdates = append(input.GlobalSecondaryIndexUpdates, gsiUpdate) - } - } + conn := meta.(*AWSClient).dynamodbconn if d.HasChange("replica") { var replicaUpdates []*dynamodb.ReplicationGroupUpdate @@ -516,88 +430,6 @@ func resourceAwsDynamoDbTable2019Update(d *schema.ResourceData, meta interface{} } } - if hasTableUpdate { - log.Printf("[DEBUG] Updating DynamoDB Table: %s", input) - _, err := conn.UpdateTable(input) - - if err != nil { - log.Printf("[DEBUG] Updating DynamoDB Table: %s", input) - return fmt.Errorf("error updating DynamoDB Table (%s): %s", d.Id(), err) - } - - if err := waitForDynamoDbTableToBeActive(d.Id(), d.Timeout(schema.TimeoutUpdate), conn); err != nil { - return fmt.Errorf("error waiting for DynamoDB Table (%s) update: %s", d.Id(), err) - } - - for _, gsiUpdate := range gsiUpdates { - if gsiUpdate.Update == nil { - continue - } - - idxName := aws.StringValue(gsiUpdate.Update.IndexName) - if err := waitForDynamoDbGSIToBeActive(d.Id(), idxName, d.Timeout(schema.TimeoutUpdate), conn); err != nil { - return fmt.Errorf("error waiting for DynamoDB Table (%s) Global Secondary Index (%s) update: %s", d.Id(), idxName, err) - } - } - } - - // Phase 3 of Global Secondary Index Operations: Create Only - // Only 1 online index can be created simultaneously per table - for _, gsiUpdate := range gsiUpdates { - if gsiUpdate.Create == nil { - continue - } - - idxName := aws.StringValue(gsiUpdate.Create.IndexName) - input := &dynamodb.UpdateTableInput{ - AttributeDefinitions: expandDynamoDbAttributes(d.Get("attribute").(*schema.Set).List()), - GlobalSecondaryIndexUpdates: []*dynamodb.GlobalSecondaryIndexUpdate{gsiUpdate}, - TableName: aws.String(d.Id()), - } - - if _, err := conn.UpdateTable(input); err != nil { - return fmt.Errorf("error creating DynamoDB Table (%s) Global Secondary Index (%s): %s", d.Id(), idxName, err) - } - - if err := waitForDynamoDbGSIToBeActive(d.Id(), idxName, d.Timeout(schema.TimeoutUpdate), conn); err != nil { - return fmt.Errorf("error waiting for DynamoDB Table (%s) Global Secondary Index (%s) creation: %s", d.Id(), idxName, err) - } - } - - if d.HasChange("server_side_encryption") { - // "ValidationException: One or more parameter values were invalid: Server-Side Encryption modification must be the only operation in the request". - _, err := conn.UpdateTable(&dynamodb.UpdateTableInput{ - TableName: aws.String(d.Id()), - SSESpecification: expandDynamoDbEncryptAtRestOptions(d.Get("server_side_encryption").([]interface{})), - }) - if err != nil { - return fmt.Errorf("error updating DynamoDB Table (%s) SSE: %s", d.Id(), err) - } - - if err := waitForDynamoDbSSEUpdateToBeCompleted(d.Id(), d.Timeout(schema.TimeoutUpdate), conn); err != nil { - return fmt.Errorf("error waiting for DynamoDB Table (%s) SSE update: %s", d.Id(), err) - } - } - - if d.HasChange("ttl") { - if err := updateDynamoDbTimeToLive(d.Id(), d.Get("ttl").([]interface{}), conn); err != nil { - return fmt.Errorf("error updating DynamoDB Table (%s) time to live: %s", d.Id(), err) - } - } - - if d.HasChange("tags") { - o, n := d.GetChange("tags") - if err := keyvaluetags.DynamodbUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating DynamoDB Table (%s) tags: %s", d.Id(), err) - } - } - - if d.HasChange("point_in_time_recovery") { - if err := updateDynamoDbPITR(d, conn); err != nil { - return fmt.Errorf("error updating DynamoDB Table (%s) point in time recovery: %s", d.Id(), err) - } - } - return resourceAwsDynamoDbTable2019Read(d, meta) } From 705f9f14ef4df4a1d966520804fe4026c65da366 Mon Sep 17 00:00:00 2001 From: cory Date: Tue, 10 Mar 2020 22:02:52 +0000 Subject: [PATCH 038/684] Removes comments. --- aws/resource_aws_dynamodb_table_2019_test.go | 78 -------------------- 1 file changed, 78 deletions(-) diff --git a/aws/resource_aws_dynamodb_table_2019_test.go b/aws/resource_aws_dynamodb_table_2019_test.go index d7c81c1adae..b018d05a324 100644 --- a/aws/resource_aws_dynamodb_table_2019_test.go +++ b/aws/resource_aws_dynamodb_table_2019_test.go @@ -90,84 +90,6 @@ func TestAccAWSDynamoDbTable2019_basic(t *testing.T) { }) } -// func testAccCheckInitialAWSDynamoDbTableConf(n string) resource.TestCheckFunc { -// return func(s *terraform.State) error { -// log.Printf("[DEBUG] Trying to create initial table state!") -// rs, ok := s.RootModule().Resources[n] -// if !ok { -// return fmt.Errorf("Not found: %s", n) -// } -// -// if rs.Primary.ID == "" { -// return fmt.Errorf("No DynamoDB table name specified!") -// } -// -// conn := testAccProvider.Meta().(*AWSClient).dynamodbconn -// -// params := &dynamodb.DescribeTableInput{ -// TableName: aws.String(rs.Primary.ID), -// } -// -// resp, err := conn.DescribeTable(params) -// -// if err != nil { -// return fmt.Errorf("Problem describing table '%s': %s", rs.Primary.ID, err) -// } -// -// table := resp.Table -// -// log.Printf("[DEBUG] Checking on table %s", rs.Primary.ID) -// -// if table.BillingModeSummary != nil && aws.StringValue(table.BillingModeSummary.BillingMode) != dynamodb.BillingModeProvisioned { -// return fmt.Errorf("Billing Mode was %s, not %s!", aws.StringValue(table.BillingModeSummary.BillingMode), dynamodb.BillingModeProvisioned) -// } -// -// if *table.ProvisionedThroughput.WriteCapacityUnits != 2 { -// return fmt.Errorf("Provisioned write capacity was %d, not 2!", table.ProvisionedThroughput.WriteCapacityUnits) -// } -// -// if *table.ProvisionedThroughput.ReadCapacityUnits != 1 { -// return fmt.Errorf("Provisioned read capacity was %d, not 1!", table.ProvisionedThroughput.ReadCapacityUnits) -// } -// -// if table.SSEDescription != nil && *table.SSEDescription.Status != dynamodb.SSEStatusDisabled { -// return fmt.Errorf("SSE status was %s, not %s", *table.SSEDescription.Status, dynamodb.SSEStatusDisabled) -// } -// -// attrCount := len(table.AttributeDefinitions) -// gsiCount := len(table.GlobalSecondaryIndexes) -// lsiCount := len(table.LocalSecondaryIndexes) -// -// if attrCount != 4 { -// return fmt.Errorf("There were %d attributes, not 4 like there should have been!", attrCount) -// } -// -// if gsiCount != 1 { -// return fmt.Errorf("There were %d GSIs, not 1 like there should have been!", gsiCount) -// } -// -// if lsiCount != 1 { -// return fmt.Errorf("There were %d LSIs, not 1 like there should have been!", lsiCount) -// } -// -// attrmap := dynamoDbAttributesToMap(&table.AttributeDefinitions) -// if attrmap["TestTableHashKey"] != "S" { -// return fmt.Errorf("Test table hash key was of type %s instead of S!", attrmap["TestTableHashKey"]) -// } -// if attrmap["TestTableRangeKey"] != "S" { -// return fmt.Errorf("Test table range key was of type %s instead of S!", attrmap["TestTableRangeKey"]) -// } -// if attrmap["TestLSIRangeKey"] != "N" { -// return fmt.Errorf("Test table LSI range key was of type %s instead of N!", attrmap["TestLSIRangeKey"]) -// } -// if attrmap["TestGSIRangeKey"] != "S" { -// return fmt.Errorf("Test table GSI range key was of type %s instead of S!", attrmap["TestGSIRangeKey"]) -// } -// -// return nil -// } -// } - func testAccAWSDynamoDbReplicaUpdates(rName string) string { return fmt.Sprintf(` resource "aws_dynamodb_table_2019" "test" { From 39d6750c7325544dff9589cb1ac8f0161af2e955 Mon Sep 17 00:00:00 2001 From: cory Date: Tue, 10 Mar 2020 22:26:02 +0000 Subject: [PATCH 039/684] Uses flattenAwsDynamoDbTableResource. --- aws/structure.go | 115 +---------------------------------------------- 1 file changed, 1 insertion(+), 114 deletions(-) diff --git a/aws/structure.go b/aws/structure.go index 699f747e0f5..9fdf6dff618 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - "log" "reflect" "regexp" "sort" @@ -4359,116 +4358,7 @@ func flattenDynamoDbPitr(pitrDesc *dynamodb.DescribeContinuousBackupsOutput) []i } func flattenAwsDynamoDbTableResource_2019(d *schema.ResourceData, table *dynamodb.TableDescription) error { - d.Set("billing_mode", dynamodb.BillingModeProvisioned) - if table.BillingModeSummary != nil { - d.Set("billing_mode", table.BillingModeSummary.BillingMode) - } - - d.Set("write_capacity", table.ProvisionedThroughput.WriteCapacityUnits) - d.Set("read_capacity", table.ProvisionedThroughput.ReadCapacityUnits) - - attributes := []interface{}{} - for _, attrdef := range table.AttributeDefinitions { - attribute := map[string]string{ - "name": *attrdef.AttributeName, - "type": *attrdef.AttributeType, - } - attributes = append(attributes, attribute) - } - - d.Set("attribute", attributes) - d.Set("name", table.TableName) - - for _, attribute := range table.KeySchema { - if *attribute.KeyType == dynamodb.KeyTypeHash { - d.Set("hash_key", attribute.AttributeName) - } - - if *attribute.KeyType == dynamodb.KeyTypeRange { - d.Set("range_key", attribute.AttributeName) - } - } - - lsiList := make([]map[string]interface{}, 0, len(table.LocalSecondaryIndexes)) - for _, lsiObject := range table.LocalSecondaryIndexes { - lsi := map[string]interface{}{ - "name": *lsiObject.IndexName, - "projection_type": *lsiObject.Projection.ProjectionType, - } - - for _, attribute := range lsiObject.KeySchema { - - if *attribute.KeyType == dynamodb.KeyTypeRange { - lsi["range_key"] = *attribute.AttributeName - } - } - nkaList := make([]string, len(lsiObject.Projection.NonKeyAttributes)) - for _, nka := range lsiObject.Projection.NonKeyAttributes { - nkaList = append(nkaList, *nka) - } - lsi["non_key_attributes"] = nkaList - - lsiList = append(lsiList, lsi) - } - - err := d.Set("local_secondary_index", lsiList) - if err != nil { - return err - } - - gsiList := make([]map[string]interface{}, 0, len(table.GlobalSecondaryIndexes)) - for _, gsiObject := range table.GlobalSecondaryIndexes { - gsi := map[string]interface{}{ - "write_capacity": *gsiObject.ProvisionedThroughput.WriteCapacityUnits, - "read_capacity": *gsiObject.ProvisionedThroughput.ReadCapacityUnits, - "name": *gsiObject.IndexName, - } - - for _, attribute := range gsiObject.KeySchema { - if *attribute.KeyType == dynamodb.KeyTypeHash { - gsi["hash_key"] = *attribute.AttributeName - } - - if *attribute.KeyType == dynamodb.KeyTypeRange { - gsi["range_key"] = *attribute.AttributeName - } - } - - gsi["projection_type"] = *(gsiObject.Projection.ProjectionType) - - nonKeyAttrs := make([]string, 0, len(gsiObject.Projection.NonKeyAttributes)) - for _, nonKeyAttr := range gsiObject.Projection.NonKeyAttributes { - nonKeyAttrs = append(nonKeyAttrs, *nonKeyAttr) - } - gsi["non_key_attributes"] = nonKeyAttrs - - gsiList = append(gsiList, gsi) - } - - if table.StreamSpecification != nil { - d.Set("stream_view_type", table.StreamSpecification.StreamViewType) - d.Set("stream_enabled", table.StreamSpecification.StreamEnabled) - } else { - d.Set("stream_view_type", "") - d.Set("stream_enabled", false) - } - - d.Set("stream_arn", table.LatestStreamArn) - d.Set("stream_label", table.LatestStreamLabel) - - err = d.Set("global_secondary_index", gsiList) - if err != nil { - return err - } - - sseOptions := []map[string]interface{}{} - if sseDescription := table.SSEDescription; sseDescription != nil { - sseOptions = []map[string]interface{}{{ - "enabled": aws.StringValue(sseDescription.Status) == dynamodb.SSEStatusEnabled, - "kms_key_arn": aws.StringValue(sseDescription.KMSMasterKeyArn), - }} - } - err = d.Set("server_side_encryption", sseOptions) + err := flattenAwsDynamoDbTableResource(d, table) if err != nil { return err } @@ -4482,14 +4372,11 @@ func flattenAwsDynamoDbTableResource_2019(d *schema.ResourceData, table *dynamod replicaList = append(replicaList, replica) } - log.Printf("[DEBUG] Creating replica list: %#v", replicaList) err = d.Set("replica", replicaList) if err != nil { return err } - d.Set("arn", table.TableArn) - return nil } From a94d01d1053d64a06f7b2e2562bf210df85ad66b Mon Sep 17 00:00:00 2001 From: cory Date: Tue, 10 Mar 2020 22:49:28 +0000 Subject: [PATCH 040/684] Changes `region` to `region_name`. --- aws/resource_aws_dynamodb_table_2019.go | 14 +++++++------- aws/resource_aws_dynamodb_table_2019_test.go | 4 ++-- aws/structure.go | 12 ++++++------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/aws/resource_aws_dynamodb_table_2019.go b/aws/resource_aws_dynamodb_table_2019.go index fa972d77b42..89b7ae7366b 100644 --- a/aws/resource_aws_dynamodb_table_2019.go +++ b/aws/resource_aws_dynamodb_table_2019.go @@ -283,7 +283,7 @@ func resourceAwsDynamoDbTable2019() *schema.Resource { Computed: false, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "region": { + "region_name": { Type: schema.TypeString, Required: true, }, @@ -317,10 +317,10 @@ func resourceAwsDynamoDbTable2019Create(d *schema.ResourceData, meta interface{} func createDynamoDbReplicas(tableName string, replicas []interface{}, conn *dynamodb.DynamoDB) error { for _, replica := range replicas { var ops []*dynamodb.ReplicationGroupUpdate - if region, ok := replica.(map[string]interface{})["region"]; ok { + if regionName, ok := replica.(map[string]interface{})["region_name"]; ok { ops = append(ops, &dynamodb.ReplicationGroupUpdate{ Create: &dynamodb.CreateReplicationGroupMemberAction{ - RegionName: aws.String(region.(string)), + RegionName: aws.String(regionName.(string)), }, }) @@ -345,7 +345,7 @@ func createDynamoDbReplicas(tableName string, replicas []interface{}, conn *dyna return fmt.Errorf("Error updating DynamoDB Replicas status: %s", err) } - if err := waitForDynamoDbReplicaUpdateToBeCompleted(tableName, region.(string), 20*time.Minute, conn); err != nil { + if err := waitForDynamoDbReplicaUpdateToBeCompleted(tableName, regionName.(string), 20*time.Minute, conn); err != nil { return fmt.Errorf("Error waiting for DynamoDB replica update: %s", err) } } @@ -356,10 +356,10 @@ func createDynamoDbReplicas(tableName string, replicas []interface{}, conn *dyna func deleteDynamoDbReplicas(tableName string, replicas []interface{}, conn *dynamodb.DynamoDB) error { for _, replica := range replicas { var ops []*dynamodb.ReplicationGroupUpdate - if region, ok := replica.(map[string]interface{})["region"]; ok { + if regionName, ok := replica.(map[string]interface{})["region_name"]; ok { ops = append(ops, &dynamodb.ReplicationGroupUpdate{ Delete: &dynamodb.DeleteReplicationGroupMemberAction{ - RegionName: aws.String(region.(string)), + RegionName: aws.String(regionName.(string)), }, }) @@ -384,7 +384,7 @@ func deleteDynamoDbReplicas(tableName string, replicas []interface{}, conn *dyna return fmt.Errorf("Error deleting DynamoDB Replicas status: %s", err) } - if err := waitForDynamoDbReplicaDeleteToBeCompleted(tableName, region.(string), 20*time.Minute, conn); err != nil { + if err := waitForDynamoDbReplicaDeleteToBeCompleted(tableName, regionName.(string), 20*time.Minute, conn); err != nil { return fmt.Errorf("Error waiting for DynamoDB replica delete: %s", err) } } diff --git a/aws/resource_aws_dynamodb_table_2019_test.go b/aws/resource_aws_dynamodb_table_2019_test.go index b018d05a324..216364744fd 100644 --- a/aws/resource_aws_dynamodb_table_2019_test.go +++ b/aws/resource_aws_dynamodb_table_2019_test.go @@ -66,7 +66,7 @@ func TestAccAWSDynamoDbTable2019_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.name", "TestTableHashKey"), resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.type", "S"), resource.TestCheckResourceAttr(resourceName, "replica.#", "1"), - resource.TestCheckResourceAttr(resourceName, "replica.0.region", "us-west-1"), + resource.TestCheckResourceAttr(resourceName, "replica.0.region_name", "us-west-1"), ), }, { @@ -105,7 +105,7 @@ resource "aws_dynamodb_table_2019" "test" { } replica { - region = "us-west-1" + region_name = "us-west-1" } } `, rName) diff --git a/aws/structure.go b/aws/structure.go index 9fdf6dff618..c2112cd7459 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -4261,21 +4261,21 @@ func diffDynamoDbReplicas(oldReplica, newReplica []interface{}) (ops []*dynamodb oldReplicas := make(map[string]interface{}) for _, replicaData := range oldReplica { m := replicaData.(map[string]interface{}) - oldReplicas[m["region"].(string)] = m + oldReplicas[m["region_name"].(string)] = m } newReplicas := make(map[string]interface{}) for _, replicaData := range newReplica { m := replicaData.(map[string]interface{}) - newReplicas[m["region"].(string)] = m + newReplicas[m["region_name"].(string)] = m } for _, data := range newReplica { newMap := data.(map[string]interface{}) - newName := newMap["region"].(string) + newName := newMap["region_name"].(string) if _, exists := oldReplicas[newName]; !exists { m := data.(map[string]interface{}) - regionName := m["region"].(string) + regionName := m["region_name"].(string) ops = append(ops, &dynamodb.ReplicationGroupUpdate{ Create: &dynamodb.CreateReplicationGroupMemberAction{ @@ -4287,7 +4287,7 @@ func diffDynamoDbReplicas(oldReplica, newReplica []interface{}) (ops []*dynamodb for _, data := range oldReplicas { oldMap := data.(map[string]interface{}) - oldName := oldMap["region"].(string) + oldName := oldMap["region_name"].(string) _, exists := newReplicas[oldName] if exists { @@ -4366,7 +4366,7 @@ func flattenAwsDynamoDbTableResource_2019(d *schema.ResourceData, table *dynamod replicaList := make([]map[string]interface{}, 0, len(table.Replicas)) for _, replicaObject := range table.Replicas { replica := map[string]interface{}{ - "region": aws.StringValue(replicaObject.RegionName), + "region_name": aws.StringValue(replicaObject.RegionName), } replicaList = append(replicaList, replica) From eb5e20d0e6f9e37cc8c104dddd13b8feda37ce45 Mon Sep 17 00:00:00 2001 From: cory Date: Wed, 11 Mar 2020 01:12:32 +0000 Subject: [PATCH 041/684] Use resourceAwsDynamoDbTable to drive main schema. --- aws/resource_aws_dynamodb_table_2019.go | 298 ++---------------------- 1 file changed, 21 insertions(+), 277 deletions(-) diff --git a/aws/resource_aws_dynamodb_table_2019.go b/aws/resource_aws_dynamodb_table_2019.go index 89b7ae7366b..e3f040c9bf2 100644 --- a/aws/resource_aws_dynamodb_table_2019.go +++ b/aws/resource_aws_dynamodb_table_2019.go @@ -1,299 +1,43 @@ package aws import ( - "bytes" "fmt" "log" - "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/dynamodb" - "github.com/hashicorp/terraform-plugin-sdk/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) -func resourceAwsDynamoDbTable2019() *schema.Resource { - return &schema.Resource{ - Create: resourceAwsDynamoDbTable2019Create, - Read: resourceAwsDynamoDbTable2019Read, - Update: resourceAwsDynamoDbTable2019Update, - Delete: resourceAwsDynamoDbTable2019Delete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(60 * time.Minute), - }, - - CustomizeDiff: customdiff.Sequence( - func(diff *schema.ResourceDiff, v interface{}) error { - return validateDynamoDbStreamSpec(diff) - }, - func(diff *schema.ResourceDiff, v interface{}) error { - return validateDynamoDbTableAttributes(diff) - }, - func(diff *schema.ResourceDiff, v interface{}) error { - if diff.Id() != "" && diff.HasChange("server_side_encryption") { - o, n := diff.GetChange("server_side_encryption") - if isDynamoDbTableOptionDisabled(o) && isDynamoDbTableOptionDisabled(n) { - return diff.Clear("server_side_encryption") - } - } - return nil - }, - func(diff *schema.ResourceDiff, v interface{}) error { - if diff.Id() != "" && diff.HasChange("point_in_time_recovery") { - o, n := diff.GetChange("point_in_time_recovery") - if isDynamoDbTableOptionDisabled(o) && isDynamoDbTableOptionDisabled(n) { - return diff.Clear("point_in_time_recovery") - } - } - return nil - }, - ), - - SchemaVersion: 1, - MigrateState: resourceAwsDynamoDbTableMigrateState, - - Schema: map[string]*schema.Schema{ - "arn": { - Type: schema.TypeString, - Computed: true, - }, - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "hash_key": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "range_key": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - "billing_mode": { - Type: schema.TypeString, - Optional: true, - Default: dynamodb.BillingModeProvisioned, - ValidateFunc: validation.StringInSlice([]string{ - dynamodb.BillingModePayPerRequest, - dynamodb.BillingModeProvisioned, - }, false), - }, - "write_capacity": { - Type: schema.TypeInt, - Optional: true, - }, - "read_capacity": { - Type: schema.TypeInt, - Optional: true, - }, - "attribute": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - dynamodb.ScalarAttributeTypeB, - dynamodb.ScalarAttributeTypeN, - dynamodb.ScalarAttributeTypeS, - }, false), - }, - }, - }, - Set: func(v interface{}) int { - var buf bytes.Buffer - m := v.(map[string]interface{}) - buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) - return hashcode.String(buf.String()) - }, - }, - "ttl": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "attribute_name": { - Type: schema.TypeString, - Required: true, - }, - "enabled": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - }, - }, - DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, - }, - "local_secondary_index": { - Type: schema.TypeSet, - Optional: true, - ForceNew: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - "range_key": { - Type: schema.TypeString, - Required: true, - }, - "projection_type": { - Type: schema.TypeString, - Required: true, - }, - "non_key_attributes": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - Set: func(v interface{}) int { - var buf bytes.Buffer - m := v.(map[string]interface{}) - buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) - return hashcode.String(buf.String()) - }, - }, - "global_secondary_index": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - "write_capacity": { - Type: schema.TypeInt, - Optional: true, - }, - "read_capacity": { - Type: schema.TypeInt, - Optional: true, - }, - "hash_key": { - Type: schema.TypeString, - Required: true, - }, - "range_key": { - Type: schema.TypeString, - Optional: true, - }, - "projection_type": { - Type: schema.TypeString, - Required: true, - }, - "non_key_attributes": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - }, - "stream_enabled": { - Type: schema.TypeBool, - Optional: true, - }, - "stream_view_type": { - Type: schema.TypeString, - Optional: true, - Computed: true, - StateFunc: func(v interface{}) string { - value := v.(string) - return strings.ToUpper(value) - }, - ValidateFunc: validation.StringInSlice([]string{ - "", - dynamodb.StreamViewTypeNewImage, - dynamodb.StreamViewTypeOldImage, - dynamodb.StreamViewTypeNewAndOldImages, - dynamodb.StreamViewTypeKeysOnly, - }, false), - }, - "stream_arn": { - Type: schema.TypeString, - Computed: true, - }, - "stream_label": { - Type: schema.TypeString, - Computed: true, - }, - "server_side_encryption": { - Type: schema.TypeList, - Optional: true, - Computed: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Required: true, - }, - "kms_key_arn": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validateArn, - }, - }, - }, - }, - "tags": tagsSchema(), - "point_in_time_recovery": { - Type: schema.TypeList, - Optional: true, - Computed: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Required: true, - }, - }, - }, - }, - "replica": { - Type: schema.TypeList, - Optional: true, - Computed: false, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "region_name": { - Type: schema.TypeString, - Required: true, - }, - }, +func replicaSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: false, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region_name": { + Type: schema.TypeString, + Required: true, }, }, }, } } +func resourceAwsDynamoDbTable2019() *schema.Resource { + schema := resourceAwsDynamoDbTable() + schema.Create = resourceAwsDynamoDbTable2019Create + schema.Read = resourceAwsDynamoDbTable2019Read + schema.Update = resourceAwsDynamoDbTable2019Update + schema.Delete = resourceAwsDynamoDbTable2019Delete + schema.Schema["replica"] = replicaSchema() + + return schema +} + func resourceAwsDynamoDbTable2019Create(d *schema.ResourceData, meta interface{}) error { err := resourceAwsDynamoDbTableCreate(d, meta) if err != nil { From 8db7d1d11367d4711c37497e6013c9bd9e689f7d Mon Sep 17 00:00:00 2001 From: cory Date: Wed, 11 Mar 2020 01:28:13 +0000 Subject: [PATCH 042/684] Adds rest of Replica schema. --- aws/resource_aws_dynamodb_table_2019.go | 40 +++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/aws/resource_aws_dynamodb_table_2019.go b/aws/resource_aws_dynamodb_table_2019.go index e3f040c9bf2..a625d0d215b 100644 --- a/aws/resource_aws_dynamodb_table_2019.go +++ b/aws/resource_aws_dynamodb_table_2019.go @@ -22,6 +22,46 @@ func replicaSchema() *schema.Schema { Type: schema.TypeString, Required: true, }, + "kms_master_key_id": { + Type: schema.TypeString, + Optional: true, + }, + "provision_capacity_override": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "read_capacity": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + "global_secondary_index": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "provisioned_capcity_override": { + Type: schema.TypeMap, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "read_capacity": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + }, + }, + }, }, }, } From ff641b768e4d4633f33eb1db5c600272d25fe4a3 Mon Sep 17 00:00:00 2001 From: cory Date: Wed, 11 Mar 2020 01:29:01 +0000 Subject: [PATCH 043/684] Spell check. --- aws/resource_aws_dynamodb_table_2019.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_dynamodb_table_2019.go b/aws/resource_aws_dynamodb_table_2019.go index a625d0d215b..187644ee9f8 100644 --- a/aws/resource_aws_dynamodb_table_2019.go +++ b/aws/resource_aws_dynamodb_table_2019.go @@ -47,7 +47,7 @@ func replicaSchema() *schema.Schema { Type: schema.TypeString, Required: true, }, - "provisioned_capcity_override": { + "provisioned_capacity_override": { Type: schema.TypeMap, Required: true, Elem: &schema.Resource{ From 7163623ffb209a1f472990eb1c6d4ac687740c08 Mon Sep 17 00:00:00 2001 From: cory Date: Wed, 11 Mar 2020 15:06:33 +0000 Subject: [PATCH 044/684] Lint fixes. --- aws/resource_aws_dynamodb_table_2019.go | 30 +++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_dynamodb_table_2019.go b/aws/resource_aws_dynamodb_table_2019.go index 187644ee9f8..be55f366f17 100644 --- a/aws/resource_aws_dynamodb_table_2019.go +++ b/aws/resource_aws_dynamodb_table_2019.go @@ -15,7 +15,6 @@ func replicaSchema() *schema.Schema { return &schema.Schema{ Type: schema.TypeList, Optional: true, - Computed: false, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "region_name": { @@ -118,6 +117,13 @@ func createDynamoDbReplicas(tableName string, replicas []interface{}, conn *dyna err := resource.Retry(20*time.Minute, func() *resource.RetryError { _, err := conn.UpdateTable(input) if err != nil { + if isAWSErr(err, "ThrottlingException", "") { + return resource.RetryableError(err) + } + if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "can be created, updated, or deleted simultaneously") { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) } return nil @@ -157,6 +163,13 @@ func deleteDynamoDbReplicas(tableName string, replicas []interface{}, conn *dyna err := resource.Retry(20*time.Minute, func() *resource.RetryError { _, err := conn.UpdateTable(input) if err != nil { + if isAWSErr(err, "ThrottlingException", "") { + return resource.RetryableError(err) + } + if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "can be created, updated, or deleted simultaneously") { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) } return nil @@ -203,10 +216,16 @@ func resourceAwsDynamoDbTable2019Update(d *schema.ResourceData, meta interface{} if replicaErr == nil { if replicaUpdate.Delete == nil { log.Printf("[DEBUG] waiting for replica to be updated") - waitForDynamoDbReplicaUpdateToBeCompleted(d.Id(), aws.StringValue(replicaUpdate.Update.RegionName), 20*time.Minute, conn) + err = waitForDynamoDbReplicaUpdateToBeCompleted(d.Id(), aws.StringValue(replicaUpdate.Update.RegionName), 20*time.Minute, conn) + if err != nil { + return fmt.Errorf("error waiting for DynamoDB Table Replicas to update (%s): %s", d.Id(), err) + } } else { log.Printf("[DEBUG] waiting for replica to be deleted") - waitForDynamoDbReplicaDeleteToBeCompleted(d.Id(), aws.StringValue(replicaUpdate.Delete.RegionName), 20*time.Minute, conn) + err = waitForDynamoDbReplicaDeleteToBeCompleted(d.Id(), aws.StringValue(replicaUpdate.Delete.RegionName), 20*time.Minute, conn) + if err != nil { + return fmt.Errorf("error waiting for DynamoDB Table Replicas to delete (%s): %s", d.Id(), err) + } } } else { return fmt.Errorf("error updating DynamoDB Table (%s): %s", d.Id(), replicaErr) @@ -277,10 +296,13 @@ func resourceAwsDynamoDbTable2019Delete(d *schema.ResourceData, meta interface{} output, err := conn.DescribeTable(input) log.Printf("[DEBUG] DynamoDB delete describe: %s", output) + if err != nil { + return fmt.Errorf("error describing DynamoDB Table (%s): %s", d.Id(), err) + } if len(output.Table.Replicas) > 0 { if err := deleteDynamoDbReplicas(d.Id(), d.Get("replica").([]interface{}), conn); err != nil { - return fmt.Errorf("error enabled DynamoDB Table (%s) replicas: %s", d.Id(), err) + return fmt.Errorf("error deleting DynamoDB Table (%s) replicas: %s", d.Id(), err) } } From d47f89ad883b68e763a31a414ffc2f74ff419c7e Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Mon, 16 Mar 2020 09:20:44 +0200 Subject: [PATCH 045/684] add support for filtering launch templates --- aws/data_source_aws_launch_template.go | 28 +++++-- aws/data_source_aws_launch_template_test.go | 82 ++++++++++++++++++++ website/docs/d/launch_template.html.markdown | 7 +- 3 files changed, 111 insertions(+), 6 deletions(-) diff --git a/aws/data_source_aws_launch_template.go b/aws/data_source_aws_launch_template.go index 7d043dfcb0e..b14232c620b 100644 --- a/aws/data_source_aws_launch_template.go +++ b/aws/data_source_aws_launch_template.go @@ -19,7 +19,7 @@ func dataSourceAwsLaunchTemplate() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { Type: schema.TypeString, - Required: true, + Optional: true, }, "description": { Type: schema.TypeString, @@ -336,7 +336,8 @@ func dataSourceAwsLaunchTemplate() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "tags": tagsSchemaComputed(), + "tags": tagsSchemaComputed(), + "filter": dataSourceFiltersSchema(), }, } } @@ -346,9 +347,26 @@ func dataSourceAwsLaunchTemplateRead(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] Reading launch template %s", d.Get("name")) - dlt, err := conn.DescribeLaunchTemplates(&ec2.DescribeLaunchTemplatesInput{ - LaunchTemplateNames: []*string{aws.String(d.Get("name").(string))}, - }) + filters, filtersOk := d.GetOk("filter") + name, nameOk := d.GetOk("name") + tags, tagsOk := d.GetOk("tags") + + if !filtersOk && !nameOk && !tagsOk { + return fmt.Errorf("One of filters, tags, or name must be assigned") + } + + params := &ec2.DescribeLaunchTemplatesInput{} + if filtersOk { + params.Filters = buildAwsDataSourceFilters(filters.(*schema.Set)) + } + if nameOk { + params.LaunchTemplateNames = []*string{aws.String(name.(string))} + } + if tagsOk { + params.Filters = append(params.Filters, ec2TagFiltersFromMap(tags.(map[string]interface{}))...) + } + + dlt, err := conn.DescribeLaunchTemplates(params) if isAWSErr(err, ec2.LaunchTemplateErrorCodeLaunchTemplateIdDoesNotExist, "") { log.Printf("[WARN] launch template (%s) not found - removing from state", d.Id()) diff --git a/aws/data_source_aws_launch_template_test.go b/aws/data_source_aws_launch_template_test.go index 9622a6e86cb..325bf449970 100644 --- a/aws/data_source_aws_launch_template_test.go +++ b/aws/data_source_aws_launch_template_test.go @@ -31,6 +31,54 @@ func TestAccAWSLaunchTemplateDataSource_basic(t *testing.T) { }) } +func TestAccAWSLaunchTemplateDataSource_basic_filter(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_launch_template.test" + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLaunchTemplateDataSourceConfigBasicFilter(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_version", dataSourceName, "default_version"), + resource.TestCheckResourceAttrPair(resourceName, "latest_version", dataSourceName, "latest_version"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + ), + }, + }, + }) +} + +func TestAccAWSLaunchTemplateDataSource_tags(t *testing.T) { + rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_launch_template.test" + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLaunchTemplateDataSourceConfigFilterTags(rName, rInt), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_version", dataSourceName, "default_version"), + resource.TestCheckResourceAttrPair(resourceName, "latest_version", dataSourceName, "latest_version"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + ), + }, + }, + }) +} + func testAccAWSLaunchTemplateDataSourceConfig_Basic(rName string) string { return fmt.Sprintf(` resource "aws_launch_template" "test" { @@ -42,3 +90,37 @@ data "aws_launch_template" "test" { } `, rName) } + +func testAccAWSLaunchTemplateDataSourceConfigBasicFilter(rName string) string { + return fmt.Sprintf(` +resource "aws_launch_template" "test" { + name = %[1]q +} + +data "aws_launch_template" "test" { + filter { + name = "launch-template-name" + values = ["${aws_launch_template.test.name}"] + } +} +`, rName) +} + +func testAccAWSLaunchTemplateDataSourceConfigFilterTags(rName string, rInt int) string { + return fmt.Sprintf(` +resource "aws_launch_template" "test" { + name = %[1]q + tags = { + Name = "key1" + TestSeed = "%[2]d" + } +} + +data "aws_launch_template" "test" { + tags = { + Name = "${aws_launch_template.test.tags["Name"]}" + TestSeed = "%[2]d" + } +} +`, rName, rInt) +} diff --git a/website/docs/d/launch_template.html.markdown b/website/docs/d/launch_template.html.markdown index 83a8f3bb2e6..fb1552fbac1 100644 --- a/website/docs/d/launch_template.html.markdown +++ b/website/docs/d/launch_template.html.markdown @@ -22,7 +22,10 @@ data "aws_launch_template" "default" { The following arguments are supported: -* `name` - (Required) The name of the launch template. +* `name` - (Optional) The name of the launch template. +* `filter` - (Optional) One or more name/value pairs to use as filters. There are +several valid keys, for a full reference, check out +[describe-launch-templates in the AWS CLI reference][1]. ## Attributes Reference @@ -62,3 +65,5 @@ In addition to all arguments above, the following attributes are exported: * `tag_specifications` - The tags to apply to the resources during launch. * `tags` - (Optional) A mapping of tags to assign to the launch template. * `user_data` - The Base64-encoded user data to provide when launching the instance. + +[1]: https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-launch-templates.html From 18a0b813e6b5745365c11559fb337b9d200a1fd7 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Mon, 16 Mar 2020 09:56:08 +0200 Subject: [PATCH 046/684] rename tests --- aws/data_source_aws_launch_template_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/data_source_aws_launch_template_test.go b/aws/data_source_aws_launch_template_test.go index 325bf449970..dc192cf178e 100644 --- a/aws/data_source_aws_launch_template_test.go +++ b/aws/data_source_aws_launch_template_test.go @@ -31,7 +31,7 @@ func TestAccAWSLaunchTemplateDataSource_basic(t *testing.T) { }) } -func TestAccAWSLaunchTemplateDataSource_basic_filter(t *testing.T) { +func TestAccAWSLaunchTemplateDataSource_filter_basic(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") dataSourceName := "data.aws_launch_template.test" resourceName := "aws_launch_template.test" @@ -54,7 +54,7 @@ func TestAccAWSLaunchTemplateDataSource_basic_filter(t *testing.T) { }) } -func TestAccAWSLaunchTemplateDataSource_tags(t *testing.T) { +func TestAccAWSLaunchTemplateDataSource_filter_tags(t *testing.T) { rInt := acctest.RandInt() rName := acctest.RandomWithPrefix("tf-acc-test") dataSourceName := "data.aws_launch_template.test" From 5c1be0b20550d035fbf649336aab1d58f7bffa8c Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Mon, 16 Mar 2020 10:42:13 +0200 Subject: [PATCH 047/684] rename tests --- aws/data_source_aws_launch_template.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/aws/data_source_aws_launch_template.go b/aws/data_source_aws_launch_template.go index b14232c620b..cf50c1a031a 100644 --- a/aws/data_source_aws_launch_template.go +++ b/aws/data_source_aws_launch_template.go @@ -345,8 +345,6 @@ func dataSourceAwsLaunchTemplate() *schema.Resource { func dataSourceAwsLaunchTemplateRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - log.Printf("[DEBUG] Reading launch template %s", d.Get("name")) - filters, filtersOk := d.GetOk("filter") name, nameOk := d.GetOk("name") tags, tagsOk := d.GetOk("tags") From 72d197f220691a9a22d68d7146e43504a2df607f Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Mon, 16 Mar 2020 13:08:40 +0200 Subject: [PATCH 048/684] add filter support - docs --- website/docs/d/launch_template.html.markdown | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/website/docs/d/launch_template.html.markdown b/website/docs/d/launch_template.html.markdown index fb1552fbac1..610de03efd5 100644 --- a/website/docs/d/launch_template.html.markdown +++ b/website/docs/d/launch_template.html.markdown @@ -18,6 +18,16 @@ data "aws_launch_template" "default" { } ``` +Filter usage: +```hcl +data "aws_launch_template" "test" { + filter { + name = "launch-template-name" + values = ["some-template"] + } +} +``` + ## Argument Reference The following arguments are supported: From 2909a40fd7a79aa26b5a9f7ab4dc778da8a77619 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Mon, 16 Mar 2020 17:16:19 +0200 Subject: [PATCH 049/684] Update launch_template.html.markdown --- website/docs/d/launch_template.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/d/launch_template.html.markdown b/website/docs/d/launch_template.html.markdown index 610de03efd5..52512bd210f 100644 --- a/website/docs/d/launch_template.html.markdown +++ b/website/docs/d/launch_template.html.markdown @@ -19,6 +19,7 @@ data "aws_launch_template" "default" { ``` Filter usage: + ```hcl data "aws_launch_template" "test" { filter { From ac6b904ab0b189eef2bab8cc93a2d3889fc35359 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Mon, 16 Mar 2020 22:06:09 +0200 Subject: [PATCH 050/684] remove check --- aws/data_source_aws_launch_template.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/aws/data_source_aws_launch_template.go b/aws/data_source_aws_launch_template.go index cf50c1a031a..66ce2b65dd2 100644 --- a/aws/data_source_aws_launch_template.go +++ b/aws/data_source_aws_launch_template.go @@ -349,10 +349,6 @@ func dataSourceAwsLaunchTemplateRead(d *schema.ResourceData, meta interface{}) e name, nameOk := d.GetOk("name") tags, tagsOk := d.GetOk("tags") - if !filtersOk && !nameOk && !tagsOk { - return fmt.Errorf("One of filters, tags, or name must be assigned") - } - params := &ec2.DescribeLaunchTemplatesInput{} if filtersOk { params.Filters = buildAwsDataSourceFilters(filters.(*schema.Set)) From 13a4b4109c046eed393b3e711dc2259090c1bdbd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 3 Jun 2019 09:40:32 -0400 Subject: [PATCH 051/684] Add 'aws_api_gateway_v2_authorizer' resource. --- aws/provider.go | 1 + aws/resource_aws_api_gateway2_authorizer.go | 174 +++++++++++++ ...source_aws_api_gateway2_authorizer_test.go | 237 ++++++++++++++++++ website/aws.erb | 3 + .../r/api_gateway_v2_authorizer.html.markdown | 53 ++++ 5 files changed, 468 insertions(+) create mode 100644 aws/resource_aws_api_gateway2_authorizer.go create mode 100644 aws/resource_aws_api_gateway2_authorizer_test.go create mode 100644 website/docs/r/api_gateway_v2_authorizer.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 7de35b36bd8..1d3b8df6646 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -355,6 +355,7 @@ func Provider() terraform.ResourceProvider { "aws_api_gateway_usage_plan_key": resourceAwsApiGatewayUsagePlanKey(), "aws_api_gateway_vpc_link": resourceAwsApiGatewayVpcLink(), "aws_apigatewayv2_api": resourceAwsApiGatewayV2Api(), + "aws_api_gateway_v2_authorizer": resourceAwsApiGateway2Authorizer(), "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), "aws_appautoscaling_target": resourceAwsAppautoscalingTarget(), "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), diff --git a/aws/resource_aws_api_gateway2_authorizer.go b/aws/resource_aws_api_gateway2_authorizer.go new file mode 100644 index 00000000000..e08ba4e97f8 --- /dev/null +++ b/aws/resource_aws_api_gateway2_authorizer.go @@ -0,0 +1,174 @@ +package aws + +import ( + "fmt" + "log" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func resourceAwsApiGateway2Authorizer() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsApiGateway2AuthorizerCreate, + Read: resourceAwsApiGateway2AuthorizerRead, + Update: resourceAwsApiGateway2AuthorizerUpdate, + Delete: resourceAwsApiGateway2AuthorizerDelete, + Importer: &schema.ResourceImporter{ + State: resourceAwsApiGateway2AuthorizerImport, + }, + + Schema: map[string]*schema.Schema{ + "api_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "authorizer_credentials_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, + }, + "authorizer_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + apigatewayv2.AuthorizerTypeRequest, + }, false), + }, + "authorizer_uri": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 2048), + }, + "identity_sources": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + }, + } +} + +func resourceAwsApiGateway2AuthorizerCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + req := &apigatewayv2.CreateAuthorizerInput{ + ApiId: aws.String(d.Get("api_id").(string)), + AuthorizerType: aws.String(d.Get("authorizer_type").(string)), + AuthorizerUri: aws.String(d.Get("authorizer_uri").(string)), + IdentitySource: expandStringSet(d.Get("identity_sources").(*schema.Set)), + Name: aws.String(d.Get("name").(string)), + } + if v, ok := d.GetOk("authorizer_credentials_arn"); ok { + req.AuthorizerCredentialsArn = aws.String(v.(string)) + } + + log.Printf("[DEBUG] Creating API Gateway v2 authorizer: %s", req) + resp, err := conn.CreateAuthorizer(req) + if err != nil { + return fmt.Errorf("error creating API Gateway v2 authorizer: %s", err) + } + + d.SetId(aws.StringValue(resp.AuthorizerId)) + + return resourceAwsApiGateway2AuthorizerRead(d, meta) +} + +func resourceAwsApiGateway2AuthorizerRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + resp, err := conn.GetAuthorizer(&apigatewayv2.GetAuthorizerInput{ + ApiId: aws.String(d.Get("api_id").(string)), + AuthorizerId: aws.String(d.Id()), + }) + if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") { + log.Printf("[WARN] API Gateway v2 authorizer (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("error reading API Gateway v2 authorizer: %s", err) + } + + d.Set("authorizer_credentials_arn", resp.AuthorizerCredentialsArn) + d.Set("authorizer_type", resp.AuthorizerType) + d.Set("authorizer_uri", resp.AuthorizerUri) + if err := d.Set("identity_sources", flattenStringSet(resp.IdentitySource)); err != nil { + return fmt.Errorf("error setting identity_sources: %s", err) + } + d.Set("name", resp.Name) + + return nil +} + +func resourceAwsApiGateway2AuthorizerUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + req := &apigatewayv2.UpdateAuthorizerInput{ + ApiId: aws.String(d.Get("api_id").(string)), + AuthorizerId: aws.String(d.Id()), + } + if d.HasChange("authorizer_credentials_arn") { + req.AuthorizerCredentialsArn = aws.String(d.Get("authorizer_credentials_arn").(string)) + } + if d.HasChange("authorizer_type") { + req.AuthorizerType = aws.String(d.Get("authorizer_type").(string)) + } + if d.HasChange("authorizer_uri") { + req.AuthorizerUri = aws.String(d.Get("authorizer_uri").(string)) + } + if d.HasChange("identity_sources") { + req.IdentitySource = expandStringSet(d.Get("identity_sources").(*schema.Set)) + } + if d.HasChange("name") { + req.Name = aws.String(d.Get("name").(string)) + } + + log.Printf("[DEBUG] Updating API Gateway v2 authorizer: %s", req) + _, err := conn.UpdateAuthorizer(req) + if err != nil { + return fmt.Errorf("error updating API Gateway v2 authorizer: %s", err) + } + + return resourceAwsApiGateway2AuthorizerRead(d, meta) +} + +func resourceAwsApiGateway2AuthorizerDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + log.Printf("[DEBUG] Deleting API Gateway v2 authorizer (%s)", d.Id()) + _, err := conn.DeleteAuthorizer(&apigatewayv2.DeleteAuthorizerInput{ + ApiId: aws.String(d.Get("api_id").(string)), + AuthorizerId: aws.String(d.Id()), + }) + if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") { + return nil + } + if err != nil { + return fmt.Errorf("error deleting API Gateway v2 authorizer: %s", err) + } + + return nil +} + +func resourceAwsApiGateway2AuthorizerImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + parts := strings.Split(d.Id(), "/") + if len(parts) != 2 { + return []*schema.ResourceData{}, fmt.Errorf("Wrong format of resource: %s. Please follow 'api-id/authorizer-id'", d.Id()) + } + + d.SetId(parts[1]) + d.Set("api_id", parts[0]) + + return []*schema.ResourceData{d}, nil +} diff --git a/aws/resource_aws_api_gateway2_authorizer_test.go b/aws/resource_aws_api_gateway2_authorizer_test.go new file mode 100644 index 00000000000..b6738422b30 --- /dev/null +++ b/aws/resource_aws_api_gateway2_authorizer_test.go @@ -0,0 +1,237 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccAWSAPIGateway2Authorizer_basic(t *testing.T) { + resourceName := "aws_api_gateway_v2_authorizer.test" + lambdaResourceName := "aws_lambda_function.test" + rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGateway2AuthorizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGateway2AuthorizerConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2AuthorizerExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "authorizer_credentials_arn", ""), + resource.TestCheckResourceAttr(resourceName, "authorizer_type", "REQUEST"), + resource.TestCheckResourceAttrPair(resourceName, "authorizer_uri", lambdaResourceName, "invoke_arn"), + resource.TestCheckResourceAttr(resourceName, "identity_sources.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_sources.645907014", "route.request.header.Auth"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAPIGateway2AuthorizerImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAPIGateway2Authorizer_Credentials(t *testing.T) { + resourceName := "aws_api_gateway_v2_authorizer.test" + iamRoleResourceName := "aws_iam_role.test" + lambdaResourceName := "aws_lambda_function.test" + rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGateway2AuthorizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGateway2AuthorizerConfig_credentials(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2AuthorizerExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "authorizer_credentials_arn", iamRoleResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "authorizer_type", "REQUEST"), + resource.TestCheckResourceAttrPair(resourceName, "authorizer_uri", lambdaResourceName, "invoke_arn"), + resource.TestCheckResourceAttr(resourceName, "identity_sources.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_sources.645907014", "route.request.header.Auth"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAPIGateway2AuthorizerImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAPIGateway2AuthorizerConfig_credentialsUpdated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2AuthorizerExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "authorizer_credentials_arn", iamRoleResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "authorizer_type", "REQUEST"), + resource.TestCheckResourceAttrPair(resourceName, "authorizer_uri", lambdaResourceName, "invoke_arn"), + resource.TestCheckResourceAttr(resourceName, "identity_sources.#", "2"), + resource.TestCheckResourceAttr(resourceName, "identity_sources.645907014", "route.request.header.Auth"), + resource.TestCheckResourceAttr(resourceName, "identity_sources.4138478046", "route.request.querystring.Name"), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("%s-updated", rName)), + ), + }, + { + Config: testAccAWSAPIGateway2AuthorizerConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2AuthorizerExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "authorizer_credentials_arn", ""), + resource.TestCheckResourceAttr(resourceName, "authorizer_type", "REQUEST"), + resource.TestCheckResourceAttrPair(resourceName, "authorizer_uri", lambdaResourceName, "invoke_arn"), + resource.TestCheckResourceAttr(resourceName, "identity_sources.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_sources.645907014", "route.request.header.Auth"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + ), + }, + }, + }) +} + +func testAccCheckAWSAPIGateway2AuthorizerDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_api_gateway_v2_authorizer" { + continue + } + + _, err := conn.GetAuthorizer(&apigatewayv2.GetAuthorizerInput{ + ApiId: aws.String(rs.Primary.Attributes["api_id"]), + AuthorizerId: aws.String(rs.Primary.ID), + }) + if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") { + continue + } + if err != nil { + return err + } + + return fmt.Errorf("API Gateway v2 authorizer %s still exists", rs.Primary.ID) + } + + return nil +} + +func testAccCheckAWSAPIGateway2AuthorizerExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No API Gateway v2 authorizer ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + _, err := conn.GetAuthorizer(&apigatewayv2.GetAuthorizerInput{ + ApiId: aws.String(rs.Primary.Attributes["api_id"]), + AuthorizerId: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + + return nil + } +} + +func testAccAWSAPIGateway2AuthorizerImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("Not Found: %s", resourceName) + } + + return fmt.Sprintf("%s/%s", rs.Primary.Attributes["api_id"], rs.Primary.ID), nil + } +} + +func testAccAWSAPIGateway2AuthorizerConfig_base(rName string) string { + return baseAccAWSLambdaConfig(rName, rName, rName) + fmt.Sprintf(` +resource "aws_lambda_function" "test" { + filename = "test-fixtures/lambdatest.zip" + function_name = %[1]q + role = "${aws_iam_role.iam_for_lambda.arn}" + handler = "index.handler" + runtime = "nodejs10.x" +} + +resource "aws_api_gateway_v2_api" "test" { + name = %[1]q + protocol_type = "WEBSOCKET" + route_selection_expression = "$request.body.action" +} + +resource "aws_iam_role" "test" { + name = "%[1]s_auth_invocation_role" + path = "/" + + assume_role_policy = < aws_apigatewayv2_api +
  • + aws_api_gateway_v2_authorizer +
  • diff --git a/website/docs/r/api_gateway_v2_authorizer.html.markdown b/website/docs/r/api_gateway_v2_authorizer.html.markdown new file mode 100644 index 00000000000..ca10461a9e5 --- /dev/null +++ b/website/docs/r/api_gateway_v2_authorizer.html.markdown @@ -0,0 +1,53 @@ +--- +layout: "aws" +page_title: "AWS: aws_api_gateway_v2_authorizer" +sidebar_current: "docs-aws-resource-api-gateway-v2-authorizer" +description: |- + Manages an Amazon API Gateway Version 2 authorizer. +--- + +# Resource: aws_api_gateway_v2_authorizer + +Manages an Amazon API Gateway Version 2 authorizer. +More information can be found in the [Amazon API Gateway Developer Guide](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html). + +## Example Usage + +### Basic + +```hcl +resource "aws_api_gateway_v2_authorizer" "example" { + api_id = "${aws_api_gateway_v2_api.example.id}" + authorizer_type = "REQUEST" + authorizer_uri = "${aws_lambda_function.example.invoke_arn}" + identity_sources = ["route.request.header.Auth"] + name = "example-authorizer" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `api_id` - (Required) The API identifier. +* `authorizer_type` - (Required) The authorizer type. Valid values: `REQUEST`. +* `authorizer_uri` - (Required) The authorizer's Uniform Resource Identifier (URI). +For `REQUEST` authorizers this must be a well-formed Lambda function URI, such as the `invoke_arn` attribute of the [`aws_lambda_function`](/docs/providers/aws/r/lambda_function.html) resource. +* `identity_sources` - (Required) The identity sources for which authorization is requested. +For `REQUEST` authorizers the value is a list of one or more mapping expressions of the specified request parameters. +* `name` - (Required) The name of the authorizer. +* `authorizer_credentials_arn` - (Optional) The required credentials as an IAM role for API Gateway to invoke the authorizer. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The authorizer identifier. + +## Import + +`aws_api_gateway_v2_authorizer` can be imported by using the API identifier and authorizer identifier, e.g. + +``` +$ terraform import aws_api_gateway_v2_authorizer.example aabbccddee/1122334 +``` From 6d33537eae2afd2d293bff7af963e736aba51c57 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 13 Mar 2020 15:09:32 -0400 Subject: [PATCH 052/684] 'aws_api_gateway2_authorizer' -> 'aws_apigatewayv2_authorizer'. --- aws/provider.go | 2 +- ...> resource_aws_apigatewayv2_authorizer.go} | 26 ++-- ...ource_aws_apigatewayv2_authorizer_test.go} | 120 ++++++++++++------ website/aws.erb | 2 +- ... => apigatewayv2_authorizer.html.markdown} | 14 +- 5 files changed, 104 insertions(+), 60 deletions(-) rename aws/{resource_aws_api_gateway2_authorizer.go => resource_aws_apigatewayv2_authorizer.go} (83%) rename aws/{resource_aws_api_gateway2_authorizer_test.go => resource_aws_apigatewayv2_authorizer_test.go} (61%) rename website/docs/r/{api_gateway_v2_authorizer.html.markdown => apigatewayv2_authorizer.html.markdown} (77%) diff --git a/aws/provider.go b/aws/provider.go index 1d3b8df6646..07adf0d34b5 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -355,7 +355,7 @@ func Provider() terraform.ResourceProvider { "aws_api_gateway_usage_plan_key": resourceAwsApiGatewayUsagePlanKey(), "aws_api_gateway_vpc_link": resourceAwsApiGatewayVpcLink(), "aws_apigatewayv2_api": resourceAwsApiGatewayV2Api(), - "aws_api_gateway_v2_authorizer": resourceAwsApiGateway2Authorizer(), + "aws_apigatewayv2_authorizer": resourceAwsApiGatewayV2Authorizer(), "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), "aws_appautoscaling_target": resourceAwsAppautoscalingTarget(), "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), diff --git a/aws/resource_aws_api_gateway2_authorizer.go b/aws/resource_aws_apigatewayv2_authorizer.go similarity index 83% rename from aws/resource_aws_api_gateway2_authorizer.go rename to aws/resource_aws_apigatewayv2_authorizer.go index e08ba4e97f8..c1a1bf7bbda 100644 --- a/aws/resource_aws_api_gateway2_authorizer.go +++ b/aws/resource_aws_apigatewayv2_authorizer.go @@ -11,14 +11,14 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) -func resourceAwsApiGateway2Authorizer() *schema.Resource { +func resourceAwsApiGatewayV2Authorizer() *schema.Resource { return &schema.Resource{ - Create: resourceAwsApiGateway2AuthorizerCreate, - Read: resourceAwsApiGateway2AuthorizerRead, - Update: resourceAwsApiGateway2AuthorizerUpdate, - Delete: resourceAwsApiGateway2AuthorizerDelete, + Create: resourceAwsApiGatewayV2AuthorizerCreate, + Read: resourceAwsApiGatewayV2AuthorizerRead, + Update: resourceAwsApiGatewayV2AuthorizerUpdate, + Delete: resourceAwsApiGatewayV2AuthorizerDelete, Importer: &schema.ResourceImporter{ - State: resourceAwsApiGateway2AuthorizerImport, + State: resourceAwsApiGatewayV2AuthorizerImport, }, Schema: map[string]*schema.Schema{ @@ -59,7 +59,7 @@ func resourceAwsApiGateway2Authorizer() *schema.Resource { } } -func resourceAwsApiGateway2AuthorizerCreate(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2AuthorizerCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn req := &apigatewayv2.CreateAuthorizerInput{ @@ -81,10 +81,10 @@ func resourceAwsApiGateway2AuthorizerCreate(d *schema.ResourceData, meta interfa d.SetId(aws.StringValue(resp.AuthorizerId)) - return resourceAwsApiGateway2AuthorizerRead(d, meta) + return resourceAwsApiGatewayV2AuthorizerRead(d, meta) } -func resourceAwsApiGateway2AuthorizerRead(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2AuthorizerRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn resp, err := conn.GetAuthorizer(&apigatewayv2.GetAuthorizerInput{ @@ -111,7 +111,7 @@ func resourceAwsApiGateway2AuthorizerRead(d *schema.ResourceData, meta interface return nil } -func resourceAwsApiGateway2AuthorizerUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2AuthorizerUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn req := &apigatewayv2.UpdateAuthorizerInput{ @@ -140,10 +140,10 @@ func resourceAwsApiGateway2AuthorizerUpdate(d *schema.ResourceData, meta interfa return fmt.Errorf("error updating API Gateway v2 authorizer: %s", err) } - return resourceAwsApiGateway2AuthorizerRead(d, meta) + return resourceAwsApiGatewayV2AuthorizerRead(d, meta) } -func resourceAwsApiGateway2AuthorizerDelete(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2AuthorizerDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn log.Printf("[DEBUG] Deleting API Gateway v2 authorizer (%s)", d.Id()) @@ -161,7 +161,7 @@ func resourceAwsApiGateway2AuthorizerDelete(d *schema.ResourceData, meta interfa return nil } -func resourceAwsApiGateway2AuthorizerImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { +func resourceAwsApiGatewayV2AuthorizerImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { parts := strings.Split(d.Id(), "/") if len(parts) != 2 { return []*schema.ResourceData{}, fmt.Errorf("Wrong format of resource: %s. Please follow 'api-id/authorizer-id'", d.Id()) diff --git a/aws/resource_aws_api_gateway2_authorizer_test.go b/aws/resource_aws_apigatewayv2_authorizer_test.go similarity index 61% rename from aws/resource_aws_api_gateway2_authorizer_test.go rename to aws/resource_aws_apigatewayv2_authorizer_test.go index b6738422b30..adafc4710db 100644 --- a/aws/resource_aws_api_gateway2_authorizer_test.go +++ b/aws/resource_aws_apigatewayv2_authorizer_test.go @@ -11,20 +11,22 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/terraform" ) -func TestAccAWSAPIGateway2Authorizer_basic(t *testing.T) { - resourceName := "aws_api_gateway_v2_authorizer.test" +func TestAccAWSAPIGatewayV2Authorizer_basic(t *testing.T) { + var apiId string + var v apigatewayv2.GetAuthorizerOutput + resourceName := "aws_apigatewayv2_authorizer.test" lambdaResourceName := "aws_lambda_function.test" - rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAPIGateway2AuthorizerDestroy, + CheckDestroy: testAccCheckAWSAPIGatewayV2AuthorizerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAPIGateway2AuthorizerConfig_basic(rName), + Config: testAccAWSAPIGatewayV2AuthorizerConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2AuthorizerExists(resourceName), + testAccCheckAWSAPIGatewayV2AuthorizerExists(resourceName, &apiId, &v), resource.TestCheckResourceAttr(resourceName, "authorizer_credentials_arn", ""), resource.TestCheckResourceAttr(resourceName, "authorizer_type", "REQUEST"), resource.TestCheckResourceAttrPair(resourceName, "authorizer_uri", lambdaResourceName, "invoke_arn"), @@ -35,7 +37,7 @@ func TestAccAWSAPIGateway2Authorizer_basic(t *testing.T) { }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAPIGateway2AuthorizerImportStateIdFunc(resourceName), + ImportStateIdFunc: testAccAWSAPIGatewayV2AuthorizerImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -43,21 +45,46 @@ func TestAccAWSAPIGateway2Authorizer_basic(t *testing.T) { }) } -func TestAccAWSAPIGateway2Authorizer_Credentials(t *testing.T) { - resourceName := "aws_api_gateway_v2_authorizer.test" +func TestAccAWSAPIGatewayV2Authorizer_disappears(t *testing.T) { + var apiId string + var v apigatewayv2.GetAuthorizerOutput + resourceName := "aws_apigatewayv2_authorizer.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGatewayV2AuthorizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2AuthorizerConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayV2AuthorizerExists(resourceName, &apiId, &v), + testAccCheckAWSAPIGatewayV2AuthorizerDisappears(&apiId, &v), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSAPIGatewayV2Authorizer_Credentials(t *testing.T) { + var apiId string + var v apigatewayv2.GetAuthorizerOutput + resourceName := "aws_apigatewayv2_authorizer.test" iamRoleResourceName := "aws_iam_role.test" lambdaResourceName := "aws_lambda_function.test" - rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAPIGateway2AuthorizerDestroy, + CheckDestroy: testAccCheckAWSAPIGatewayV2AuthorizerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAPIGateway2AuthorizerConfig_credentials(rName), + Config: testAccAWSAPIGatewayV2AuthorizerConfig_credentials(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2AuthorizerExists(resourceName), + testAccCheckAWSAPIGatewayV2AuthorizerExists(resourceName, &apiId, &v), resource.TestCheckResourceAttrPair(resourceName, "authorizer_credentials_arn", iamRoleResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "authorizer_type", "REQUEST"), resource.TestCheckResourceAttrPair(resourceName, "authorizer_uri", lambdaResourceName, "invoke_arn"), @@ -68,14 +95,14 @@ func TestAccAWSAPIGateway2Authorizer_Credentials(t *testing.T) { }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAPIGateway2AuthorizerImportStateIdFunc(resourceName), + ImportStateIdFunc: testAccAWSAPIGatewayV2AuthorizerImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, { - Config: testAccAWSAPIGateway2AuthorizerConfig_credentialsUpdated(rName), + Config: testAccAWSAPIGatewayV2AuthorizerConfig_credentialsUpdated(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2AuthorizerExists(resourceName), + testAccCheckAWSAPIGatewayV2AuthorizerExists(resourceName, &apiId, &v), resource.TestCheckResourceAttrPair(resourceName, "authorizer_credentials_arn", iamRoleResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "authorizer_type", "REQUEST"), resource.TestCheckResourceAttrPair(resourceName, "authorizer_uri", lambdaResourceName, "invoke_arn"), @@ -86,9 +113,9 @@ func TestAccAWSAPIGateway2Authorizer_Credentials(t *testing.T) { ), }, { - Config: testAccAWSAPIGateway2AuthorizerConfig_basic(rName), + Config: testAccAWSAPIGatewayV2AuthorizerConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2AuthorizerExists(resourceName), + testAccCheckAWSAPIGatewayV2AuthorizerExists(resourceName, &apiId, &v), resource.TestCheckResourceAttr(resourceName, "authorizer_credentials_arn", ""), resource.TestCheckResourceAttr(resourceName, "authorizer_type", "REQUEST"), resource.TestCheckResourceAttrPair(resourceName, "authorizer_uri", lambdaResourceName, "invoke_arn"), @@ -101,11 +128,11 @@ func TestAccAWSAPIGateway2Authorizer_Credentials(t *testing.T) { }) } -func testAccCheckAWSAPIGateway2AuthorizerDestroy(s *terraform.State) error { +func testAccCheckAWSAPIGatewayV2AuthorizerDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_api_gateway_v2_authorizer" { + if rs.Type != "aws_apigatewayv2_authorizer" { continue } @@ -126,7 +153,20 @@ func testAccCheckAWSAPIGateway2AuthorizerDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSAPIGateway2AuthorizerExists(n string) resource.TestCheckFunc { +func testAccCheckAWSAPIGatewayV2AuthorizerDisappears(apiId *string, v *apigatewayv2.GetAuthorizerOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + _, err := conn.DeleteAuthorizer(&apigatewayv2.DeleteAuthorizerInput{ + ApiId: apiId, + AuthorizerId: v.AuthorizerId, + }) + + return err + } +} + +func testAccCheckAWSAPIGatewayV2AuthorizerExists(n string, vApiId *string, v *apigatewayv2.GetAuthorizerOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -139,19 +179,23 @@ func testAccCheckAWSAPIGateway2AuthorizerExists(n string) resource.TestCheckFunc conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn - _, err := conn.GetAuthorizer(&apigatewayv2.GetAuthorizerInput{ - ApiId: aws.String(rs.Primary.Attributes["api_id"]), + apiId := aws.String(rs.Primary.Attributes["api_id"]) + resp, err := conn.GetAuthorizer(&apigatewayv2.GetAuthorizerInput{ + ApiId: apiId, AuthorizerId: aws.String(rs.Primary.ID), }) if err != nil { return err } + *vApiId = *apiId + *v = *resp + return nil } } -func testAccAWSAPIGateway2AuthorizerImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { +func testAccAWSAPIGatewayV2AuthorizerImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { return func(s *terraform.State) (string, error) { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -162,7 +206,7 @@ func testAccAWSAPIGateway2AuthorizerImportStateIdFunc(resourceName string) resou } } -func testAccAWSAPIGateway2AuthorizerConfig_base(rName string) string { +func testAccAWSAPIGatewayV2AuthorizerConfig_base(rName string) string { return baseAccAWSLambdaConfig(rName, rName, rName) + fmt.Sprintf(` resource "aws_lambda_function" "test" { filename = "test-fixtures/lambdatest.zip" @@ -172,7 +216,7 @@ resource "aws_lambda_function" "test" { runtime = "nodejs10.x" } -resource "aws_api_gateway_v2_api" "test" { +resource "aws_apigatewayv2_api" "test" { name = %[1]q protocol_type = "WEBSOCKET" route_selection_expression = "$request.body.action" @@ -196,10 +240,10 @@ EOF `, rName) } -func testAccAWSAPIGateway2AuthorizerConfig_basic(rName string) string { - return testAccAWSAPIGateway2AuthorizerConfig_base(rName) + fmt.Sprintf(` -resource "aws_api_gateway_v2_authorizer" "test" { - api_id = "${aws_api_gateway_v2_api.test.id}" +func testAccAWSAPIGatewayV2AuthorizerConfig_basic(rName string) string { + return testAccAWSAPIGatewayV2AuthorizerConfig_base(rName) + fmt.Sprintf(` +resource "aws_apigatewayv2_authorizer" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" authorizer_type = "REQUEST" authorizer_uri = "${aws_lambda_function.test.invoke_arn}" identity_sources = ["route.request.header.Auth"] @@ -208,10 +252,10 @@ resource "aws_api_gateway_v2_authorizer" "test" { `, rName) } -func testAccAWSAPIGateway2AuthorizerConfig_credentials(rName string) string { - return testAccAWSAPIGateway2AuthorizerConfig_base(rName) + fmt.Sprintf(` -resource "aws_api_gateway_v2_authorizer" "test" { - api_id = "${aws_api_gateway_v2_api.test.id}" +func testAccAWSAPIGatewayV2AuthorizerConfig_credentials(rName string) string { + return testAccAWSAPIGatewayV2AuthorizerConfig_base(rName) + fmt.Sprintf(` +resource "aws_apigatewayv2_authorizer" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" authorizer_type = "REQUEST" authorizer_uri = "${aws_lambda_function.test.invoke_arn}" identity_sources = ["route.request.header.Auth"] @@ -222,10 +266,10 @@ resource "aws_api_gateway_v2_authorizer" "test" { `, rName) } -func testAccAWSAPIGateway2AuthorizerConfig_credentialsUpdated(rName string) string { - return testAccAWSAPIGateway2AuthorizerConfig_base(rName) + fmt.Sprintf(` -resource "aws_api_gateway_v2_authorizer" "test" { - api_id = "${aws_api_gateway_v2_api.test.id}" +func testAccAWSAPIGatewayV2AuthorizerConfig_credentialsUpdated(rName string) string { + return testAccAWSAPIGatewayV2AuthorizerConfig_base(rName) + fmt.Sprintf(` +resource "aws_apigatewayv2_authorizer" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" authorizer_type = "REQUEST" authorizer_uri = "${aws_lambda_function.test.invoke_arn}" identity_sources = ["route.request.header.Auth", "route.request.querystring.Name"] diff --git a/website/aws.erb b/website/aws.erb index 331dc1132d9..54455c4f84f 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -219,7 +219,7 @@ aws_apigatewayv2_api
  • - aws_api_gateway_v2_authorizer + aws_apigatewayv2_authorizer
  • diff --git a/website/docs/r/api_gateway_v2_authorizer.html.markdown b/website/docs/r/apigatewayv2_authorizer.html.markdown similarity index 77% rename from website/docs/r/api_gateway_v2_authorizer.html.markdown rename to website/docs/r/apigatewayv2_authorizer.html.markdown index ca10461a9e5..47019886b1d 100644 --- a/website/docs/r/api_gateway_v2_authorizer.html.markdown +++ b/website/docs/r/apigatewayv2_authorizer.html.markdown @@ -1,12 +1,12 @@ --- +subcategory: "API Gateway v2 (WebSocket and HTTP APIs)" layout: "aws" -page_title: "AWS: aws_api_gateway_v2_authorizer" -sidebar_current: "docs-aws-resource-api-gateway-v2-authorizer" +page_title: "AWS: aws_apigatewayv2_authorizer" description: |- Manages an Amazon API Gateway Version 2 authorizer. --- -# Resource: aws_api_gateway_v2_authorizer +# Resource: aws_apigatewayv2_authorizer Manages an Amazon API Gateway Version 2 authorizer. More information can be found in the [Amazon API Gateway Developer Guide](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html). @@ -16,8 +16,8 @@ More information can be found in the [Amazon API Gateway Developer Guide](https: ### Basic ```hcl -resource "aws_api_gateway_v2_authorizer" "example" { - api_id = "${aws_api_gateway_v2_api.example.id}" +resource "aws_apigatewayv2_authorizer" "example" { + api_id = "${aws_apigatewayv2_api.example.id}" authorizer_type = "REQUEST" authorizer_uri = "${aws_lambda_function.example.invoke_arn}" identity_sources = ["route.request.header.Auth"] @@ -46,8 +46,8 @@ In addition to all arguments above, the following attributes are exported: ## Import -`aws_api_gateway_v2_authorizer` can be imported by using the API identifier and authorizer identifier, e.g. +`aws_apigatewayv2_authorizer` can be imported by using the API identifier and authorizer identifier, e.g. ``` -$ terraform import aws_api_gateway_v2_authorizer.example aabbccddee/1122334 +$ terraform import aws_apigatewayv2_authorizer.example aabbccddee/1122334 ``` From 4c27f541ac3710fe260347fbefe08e79765c8469 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 15 Mar 2020 18:41:06 -0400 Subject: [PATCH 053/684] r/aws_apigatewayv2_authorizer: Add support for JWT. --- aws/resource_aws_apigatewayv2_authorizer.go | 64 +++++++++- ...source_aws_apigatewayv2_authorizer_test.go | 109 +++++++++++++++++- .../r/apigatewayv2_authorizer.html.markdown | 36 +++++- 3 files changed, 199 insertions(+), 10 deletions(-) diff --git a/aws/resource_aws_apigatewayv2_authorizer.go b/aws/resource_aws_apigatewayv2_authorizer.go index c1a1bf7bbda..e761cbf2ca6 100644 --- a/aws/resource_aws_apigatewayv2_authorizer.go +++ b/aws/resource_aws_apigatewayv2_authorizer.go @@ -36,12 +36,13 @@ func resourceAwsApiGatewayV2Authorizer() *schema.Resource { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ + apigatewayv2.AuthorizerTypeJwt, apigatewayv2.AuthorizerTypeRequest, }, false), }, "authorizer_uri": { Type: schema.TypeString, - Required: true, + Optional: true, ValidateFunc: validation.StringLenBetween(1, 2048), }, "identity_sources": { @@ -50,6 +51,25 @@ func resourceAwsApiGatewayV2Authorizer() *schema.Resource { MinItems: 1, Elem: &schema.Schema{Type: schema.TypeString}, }, + "jwt_configuration": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "audience": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "issuer": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, "name": { Type: schema.TypeString, Required: true, @@ -65,13 +85,18 @@ func resourceAwsApiGatewayV2AuthorizerCreate(d *schema.ResourceData, meta interf req := &apigatewayv2.CreateAuthorizerInput{ ApiId: aws.String(d.Get("api_id").(string)), AuthorizerType: aws.String(d.Get("authorizer_type").(string)), - AuthorizerUri: aws.String(d.Get("authorizer_uri").(string)), IdentitySource: expandStringSet(d.Get("identity_sources").(*schema.Set)), Name: aws.String(d.Get("name").(string)), } if v, ok := d.GetOk("authorizer_credentials_arn"); ok { req.AuthorizerCredentialsArn = aws.String(v.(string)) } + if v, ok := d.GetOk("authorizer_uri"); ok { + req.AuthorizerUri = aws.String(v.(string)) + } + if v, ok := d.GetOk("jwt_configuration"); ok { + req.JwtConfiguration = expandApiGateway2JwtConfiguration(v.([]interface{})) + } log.Printf("[DEBUG] Creating API Gateway v2 authorizer: %s", req) resp, err := conn.CreateAuthorizer(req) @@ -106,6 +131,9 @@ func resourceAwsApiGatewayV2AuthorizerRead(d *schema.ResourceData, meta interfac if err := d.Set("identity_sources", flattenStringSet(resp.IdentitySource)); err != nil { return fmt.Errorf("error setting identity_sources: %s", err) } + if err := d.Set("jwt_configuration", flattenApiGateway2JwtConfiguration(resp.JwtConfiguration)); err != nil { + return fmt.Errorf("error setting jwt_configuration: %s", err) + } d.Set("name", resp.Name) return nil @@ -133,6 +161,9 @@ func resourceAwsApiGatewayV2AuthorizerUpdate(d *schema.ResourceData, meta interf if d.HasChange("name") { req.Name = aws.String(d.Get("name").(string)) } + if d.HasChange("jwt_configuration") { + req.JwtConfiguration = expandApiGateway2JwtConfiguration(d.Get("jwt_configuration").([]interface{})) + } log.Printf("[DEBUG] Updating API Gateway v2 authorizer: %s", req) _, err := conn.UpdateAuthorizer(req) @@ -172,3 +203,32 @@ func resourceAwsApiGatewayV2AuthorizerImport(d *schema.ResourceData, meta interf return []*schema.ResourceData{d}, nil } + +func expandApiGateway2JwtConfiguration(vConfiguration []interface{}) *apigatewayv2.JWTConfiguration { + configuration := &apigatewayv2.JWTConfiguration{} + + if len(vConfiguration) == 0 || vConfiguration[0] == nil { + return configuration + } + mConfiguration := vConfiguration[0].(map[string]interface{}) + + if vAudience, ok := mConfiguration["audience"].(*schema.Set); ok && vAudience.Len() > 0 { + configuration.Audience = expandStringSet(vAudience) + } + if vIssuer, ok := mConfiguration["issuer"].(string); ok && vIssuer != "" { + configuration.Issuer = aws.String(vIssuer) + } + + return configuration +} + +func flattenApiGateway2JwtConfiguration(configuration *apigatewayv2.JWTConfiguration) []interface{} { + if configuration == nil { + return []interface{}{} + } + + return []interface{}{map[string]interface{}{ + "audience": flattenStringSet(configuration.Audience), + "issuer": aws.StringValue(configuration.Issuer), + }} +} diff --git a/aws/resource_aws_apigatewayv2_authorizer_test.go b/aws/resource_aws_apigatewayv2_authorizer_test.go index adafc4710db..37ae39ce3f9 100644 --- a/aws/resource_aws_apigatewayv2_authorizer_test.go +++ b/aws/resource_aws_apigatewayv2_authorizer_test.go @@ -32,6 +32,7 @@ func TestAccAWSAPIGatewayV2Authorizer_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "authorizer_uri", lambdaResourceName, "invoke_arn"), resource.TestCheckResourceAttr(resourceName, "identity_sources.#", "1"), resource.TestCheckResourceAttr(resourceName, "identity_sources.645907014", "route.request.header.Auth"), + resource.TestCheckResourceAttr(resourceName, "jwt_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "name", rName), ), }, @@ -90,6 +91,7 @@ func TestAccAWSAPIGatewayV2Authorizer_Credentials(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "authorizer_uri", lambdaResourceName, "invoke_arn"), resource.TestCheckResourceAttr(resourceName, "identity_sources.#", "1"), resource.TestCheckResourceAttr(resourceName, "identity_sources.645907014", "route.request.header.Auth"), + resource.TestCheckResourceAttr(resourceName, "jwt_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "name", rName), ), }, @@ -109,6 +111,7 @@ func TestAccAWSAPIGatewayV2Authorizer_Credentials(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "identity_sources.#", "2"), resource.TestCheckResourceAttr(resourceName, "identity_sources.645907014", "route.request.header.Auth"), resource.TestCheckResourceAttr(resourceName, "identity_sources.4138478046", "route.request.querystring.Name"), + resource.TestCheckResourceAttr(resourceName, "jwt_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("%s-updated", rName)), ), }, @@ -121,6 +124,59 @@ func TestAccAWSAPIGatewayV2Authorizer_Credentials(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "authorizer_uri", lambdaResourceName, "invoke_arn"), resource.TestCheckResourceAttr(resourceName, "identity_sources.#", "1"), resource.TestCheckResourceAttr(resourceName, "identity_sources.645907014", "route.request.header.Auth"), + resource.TestCheckResourceAttr(resourceName, "jwt_configuration.#", "0"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + ), + }, + }, + }) +} + +func TestAccAWSAPIGatewayV2Authorizer_JWT(t *testing.T) { + var apiId string + var v apigatewayv2.GetAuthorizerOutput + resourceName := "aws_apigatewayv2_authorizer.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGatewayV2AuthorizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2AuthorizerConfig_jwt(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayV2AuthorizerExists(resourceName, &apiId, &v), + resource.TestCheckResourceAttr(resourceName, "authorizer_credentials_arn", ""), + resource.TestCheckResourceAttr(resourceName, "authorizer_type", "JWT"), + resource.TestCheckResourceAttr(resourceName, "authorizer_uri", ""), + resource.TestCheckResourceAttr(resourceName, "identity_sources.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_sources.2786136151", "$request.header.Authorization"), + resource.TestCheckResourceAttr(resourceName, "jwt_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "jwt_configuration.0.audience.#", "1"), + resource.TestCheckResourceAttr(resourceName, "jwt_configuration.0.audience.1785148924", "test"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAPIGatewayV2AuthorizerImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAPIGatewayV2AuthorizerConfig_jwtUpdated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayV2AuthorizerExists(resourceName, &apiId, &v), + resource.TestCheckResourceAttr(resourceName, "authorizer_credentials_arn", ""), + resource.TestCheckResourceAttr(resourceName, "authorizer_type", "JWT"), + resource.TestCheckResourceAttr(resourceName, "authorizer_uri", ""), + resource.TestCheckResourceAttr(resourceName, "identity_sources.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_sources.2786136151", "$request.header.Authorization"), + resource.TestCheckResourceAttr(resourceName, "jwt_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "jwt_configuration.0.audience.#", "2"), + resource.TestCheckResourceAttr(resourceName, "jwt_configuration.0.audience.1785148924", "test"), + resource.TestCheckResourceAttr(resourceName, "jwt_configuration.0.audience.2323796166", "testing"), resource.TestCheckResourceAttr(resourceName, "name", rName), ), }, @@ -206,7 +262,7 @@ func testAccAWSAPIGatewayV2AuthorizerImportStateIdFunc(resourceName string) reso } } -func testAccAWSAPIGatewayV2AuthorizerConfig_base(rName string) string { +func testAccAWSAPIGatewayV2AuthorizerConfig_baseWebSocket(rName string) string { return baseAccAWSLambdaConfig(rName, rName, rName) + fmt.Sprintf(` resource "aws_lambda_function" "test" { filename = "test-fixtures/lambdatest.zip" @@ -240,8 +296,21 @@ EOF `, rName) } +func testAccAWSAPIGatewayV2AuthorizerConfig_baseHttp(rName string) string { + return baseAccAWSLambdaConfig(rName, rName, rName) + fmt.Sprintf(` +resource "aws_apigatewayv2_api" "test" { + name = %[1]q + protocol_type = "HTTP" +} + +resource "aws_cognito_user_pool" "test" { + name = %[1]q +} +`, rName) +} + func testAccAWSAPIGatewayV2AuthorizerConfig_basic(rName string) string { - return testAccAWSAPIGatewayV2AuthorizerConfig_base(rName) + fmt.Sprintf(` + return testAccAWSAPIGatewayV2AuthorizerConfig_baseWebSocket(rName) + fmt.Sprintf(` resource "aws_apigatewayv2_authorizer" "test" { api_id = "${aws_apigatewayv2_api.test.id}" authorizer_type = "REQUEST" @@ -253,7 +322,7 @@ resource "aws_apigatewayv2_authorizer" "test" { } func testAccAWSAPIGatewayV2AuthorizerConfig_credentials(rName string) string { - return testAccAWSAPIGatewayV2AuthorizerConfig_base(rName) + fmt.Sprintf(` + return testAccAWSAPIGatewayV2AuthorizerConfig_baseWebSocket(rName) + fmt.Sprintf(` resource "aws_apigatewayv2_authorizer" "test" { api_id = "${aws_apigatewayv2_api.test.id}" authorizer_type = "REQUEST" @@ -267,7 +336,7 @@ resource "aws_apigatewayv2_authorizer" "test" { } func testAccAWSAPIGatewayV2AuthorizerConfig_credentialsUpdated(rName string) string { - return testAccAWSAPIGatewayV2AuthorizerConfig_base(rName) + fmt.Sprintf(` + return testAccAWSAPIGatewayV2AuthorizerConfig_baseWebSocket(rName) + fmt.Sprintf(` resource "aws_apigatewayv2_authorizer" "test" { api_id = "${aws_apigatewayv2_api.test.id}" authorizer_type = "REQUEST" @@ -279,3 +348,35 @@ resource "aws_apigatewayv2_authorizer" "test" { } `, rName) } + +func testAccAWSAPIGatewayV2AuthorizerConfig_jwt(rName string) string { + return testAccAWSAPIGatewayV2AuthorizerConfig_baseHttp(rName) + fmt.Sprintf(` +resource "aws_apigatewayv2_authorizer" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" + authorizer_type = "JWT" + identity_sources = ["$request.header.Authorization"] + name = %[1]q + + jwt_configuration { + audience = ["test"] + issuer = "https://${aws_cognito_user_pool.test.endpoint}" + } +} +`, rName) +} + +func testAccAWSAPIGatewayV2AuthorizerConfig_jwtUpdated(rName string) string { + return testAccAWSAPIGatewayV2AuthorizerConfig_baseHttp(rName) + fmt.Sprintf(` +resource "aws_apigatewayv2_authorizer" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" + authorizer_type = "JWT" + identity_sources = ["$request.header.Authorization"] + name = %[1]q + + jwt_configuration { + audience = ["test", "testing"] + issuer = "https://${aws_cognito_user_pool.test.endpoint}" + } +} +`, rName) +} diff --git a/website/docs/r/apigatewayv2_authorizer.html.markdown b/website/docs/r/apigatewayv2_authorizer.html.markdown index 47019886b1d..f8321b4e102 100644 --- a/website/docs/r/apigatewayv2_authorizer.html.markdown +++ b/website/docs/r/apigatewayv2_authorizer.html.markdown @@ -13,7 +13,7 @@ More information can be found in the [Amazon API Gateway Developer Guide](https: ## Example Usage -### Basic +### Basic WebSocket API ```hcl resource "aws_apigatewayv2_authorizer" "example" { @@ -25,18 +25,46 @@ resource "aws_apigatewayv2_authorizer" "example" { } ``` +### Basic HTTP API + +```hcl +resource "aws_apigatewayv2_authorizer" "example" { + api_id = "${aws_apigatewayv2_api.example.id}" + authorizer_type = "JWT" + identity_sources = ["$request.header.Authorization"] + name = "example-authorizer" + + jwt_configuration { + audience = ["example"] + issuer = "https://${aws_cognito_user_pool.example.endpoint}" + } +} +``` + ## Argument Reference The following arguments are supported: * `api_id` - (Required) The API identifier. -* `authorizer_type` - (Required) The authorizer type. Valid values: `REQUEST`. -* `authorizer_uri` - (Required) The authorizer's Uniform Resource Identifier (URI). -For `REQUEST` authorizers this must be a well-formed Lambda function URI, such as the `invoke_arn` attribute of the [`aws_lambda_function`](/docs/providers/aws/r/lambda_function.html) resource. +* `authorizer_type` - (Required) The authorizer type. Valid values: `JWT`, `REQUEST`. +For WebSocket APIs, specify `REQUEST` for a Lambda function using incoming request parameters. + For HTTP APIs, specify `JWT` to use JSON Web Tokens. * `identity_sources` - (Required) The identity sources for which authorization is requested. For `REQUEST` authorizers the value is a list of one or more mapping expressions of the specified request parameters. +For `JWT` authorizers the single entry specifies where to extract the JSON Web Token (JWT) from inbound requests. * `name` - (Required) The name of the authorizer. * `authorizer_credentials_arn` - (Optional) The required credentials as an IAM role for API Gateway to invoke the authorizer. +Supported only for `REQUEST` authorizers. +* `authorizer_uri` - (Optional) The authorizer's Uniform Resource Identifier (URI). +For `REQUEST` authorizers this must be a well-formed Lambda function URI, such as the `invoke_arn` attribute of the [`aws_lambda_function`](/docs/providers/aws/r/lambda_function.html) resource. +Supported only for `REQUEST` authorizers. +* `jwt_configuration` - (Optional) The configuration of a JWT authorizer. Required for the `JWT` authorizer type. +Supported only for HTTP APIs. + +The `jwt_configuration` object supports the following: + +* `audience` - (Optional) A list of the intended recipients of the JWT. A valid JWT must provide an aud that matches at least one entry in this list. +* `issuer` - (Optional) The base domain of the identity provider that issues JSON Web Tokens, such as the `endpoint` attribute of the [`aws_cognito_user_pool`](/docs/providers/aws/r/cognito_user_pool.html) resource. ## Attribute Reference From f2cca86ee1759e79e4dc8f7d93190a884b477bd7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 3 Jun 2019 09:40:32 -0400 Subject: [PATCH 054/684] Add 'aws_api_gateway_v2_domain_name' resource. --- aws/provider.go | 1 + aws/resource_aws_api_gateway2_domain_name.go | 259 ++++++++++++++ ...ource_aws_api_gateway2_domain_name_test.go | 315 ++++++++++++++++++ website/aws.erb | 3 + .../api_gateway_v2_domain_name.html.markdown | 70 ++++ 5 files changed, 648 insertions(+) create mode 100644 aws/resource_aws_api_gateway2_domain_name.go create mode 100644 aws/resource_aws_api_gateway2_domain_name_test.go create mode 100644 website/docs/r/api_gateway_v2_domain_name.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 7de35b36bd8..5895aa46674 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -355,6 +355,7 @@ func Provider() terraform.ResourceProvider { "aws_api_gateway_usage_plan_key": resourceAwsApiGatewayUsagePlanKey(), "aws_api_gateway_vpc_link": resourceAwsApiGatewayVpcLink(), "aws_apigatewayv2_api": resourceAwsApiGatewayV2Api(), + "aws_api_gateway_v2_domain_name": resourceAwsApiGateway2DomainName(), "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), "aws_appautoscaling_target": resourceAwsAppautoscalingTarget(), "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), diff --git a/aws/resource_aws_api_gateway2_domain_name.go b/aws/resource_aws_api_gateway2_domain_name.go new file mode 100644 index 00000000000..53e867661b4 --- /dev/null +++ b/aws/resource_aws_api_gateway2_domain_name.go @@ -0,0 +1,259 @@ +package aws + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "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" +) + +const ( + apiGateway2DomainNameStatusDeleted = "DELETED" +) + +func resourceAwsApiGateway2DomainName() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsApiGateway2DomainNameCreate, + Read: resourceAwsApiGateway2DomainNameRead, + Update: resourceAwsApiGateway2DomainNameUpdate, + Delete: resourceAwsApiGateway2DomainNameDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Update: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "api_mapping_selection_expression": { + Type: schema.TypeString, + Computed: true, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "domain_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 512), + }, + "domain_name_configuration": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + "endpoint_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + apigatewayv2.EndpointTypeRegional, + }, true), + }, + "hosted_zone_id": { + Type: schema.TypeString, + Computed: true, + }, + "security_policy": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + apigatewayv2.SecurityPolicyTls12, + }, true), + }, + "target_domain_name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "tags": tagsSchema(), + }, + } +} + +func resourceAwsApiGateway2DomainNameCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + req := &apigatewayv2.CreateDomainNameInput{ + DomainName: aws.String(d.Get("domain_name").(string)), + DomainNameConfigurations: expandApiGateway2DomainNameConfiguration(d.Get("domain_name_configuration").([]interface{})), + Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().Apigatewayv2Tags(), + } + + log.Printf("[DEBUG] Creating API Gateway v2 domain name: %s", req) + resp, err := conn.CreateDomainName(req) + if err != nil { + return fmt.Errorf("error creating API Gateway v2 domain name: %s", err) + } + + d.SetId(aws.StringValue(resp.DomainName)) + + return resourceAwsApiGateway2DomainNameRead(d, meta) +} + +func resourceAwsApiGateway2DomainNameRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + respRaw, state, err := apiGateway2DomainNameRefresh(conn, d.Id())() + if err != nil { + return fmt.Errorf("error reading API Gateway v2 domain name (%s): %s", d.Id(), err) + } + + if state == apiGateway2DomainNameStatusDeleted { + log.Printf("[WARN] API Gateway v2 domain name (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + resp := respRaw.(*apigatewayv2.GetDomainNameOutput) + d.Set("api_mapping_selection_expression", resp.ApiMappingSelectionExpression) + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "apigateway", + Region: meta.(*AWSClient).region, + Resource: fmt.Sprintf("/domainnames/%s", d.Id()), + }.String() + d.Set("arn", arn) + d.Set("domain_name", resp.DomainName) + err = d.Set("domain_name_configuration", flattenApiGateway2DomainNameConfiguration(resp.DomainNameConfigurations[0])) + if err != nil { + return fmt.Errorf("error setting domain_name_configuration: %s", err) + } + if err := d.Set("tags", keyvaluetags.Apigatewayv2KeyValueTags(resp.Tags).IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} + +func resourceAwsApiGateway2DomainNameUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + if d.HasChange("domain_name_configuration") { + req := &apigatewayv2.UpdateDomainNameInput{ + DomainName: aws.String(d.Id()), + DomainNameConfigurations: expandApiGateway2DomainNameConfiguration(d.Get("domain_name_configuration").([]interface{})), + } + + log.Printf("[DEBUG] Updating API Gateway v2 domain name: %s", req) + _, err := conn.UpdateDomainName(req) + if err != nil { + return fmt.Errorf("error updating API Gateway v2 domain name (%s): %s", d.Id(), err) + } + + if err := waitForApiGateway2DomainNameAvailabilityOnUpdate(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { + return fmt.Errorf("error waiting for API Gateway v2 domain name (%s) to become available: %s", d.Id(), err) + } + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.Apigatewayv2UpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating API Gateway v2 domain name (%s) tags: %s", d.Id(), err) + } + } + + return resourceAwsApiGateway2DomainNameRead(d, meta) +} + +func resourceAwsApiGateway2DomainNameDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + log.Printf("[DEBUG] Deleting API Gateway v2 domain name (%s)", d.Id()) + _, err := conn.DeleteDomainName(&apigatewayv2.DeleteDomainNameInput{ + DomainName: aws.String(d.Id()), + }) + if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") { + return nil + } + if err != nil { + return fmt.Errorf("error deleting API Gateway v2 domain name (%s): %s", d.Id(), err) + } + + return nil +} + +func apiGateway2DomainNameRefresh(conn *apigatewayv2.ApiGatewayV2, domainName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + resp, err := conn.GetDomainName(&apigatewayv2.GetDomainNameInput{ + DomainName: aws.String(domainName), + }) + if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") { + return "", apiGateway2DomainNameStatusDeleted, nil + } + if err != nil { + return nil, "", err + } + + if n := len(resp.DomainNameConfigurations); n != 1 { + return nil, "", fmt.Errorf("Found %d domain name configurations for %s, expected 1", n, domainName) + } + + domainNameConfiguration := resp.DomainNameConfigurations[0] + if statusMessage := aws.StringValue(domainNameConfiguration.DomainNameStatusMessage); statusMessage != "" { + log.Printf("[INFO] Domain name (%s) status message: %s", domainName, statusMessage) + } + + return resp, aws.StringValue(domainNameConfiguration.DomainNameStatus), nil + } +} + +func waitForApiGateway2DomainNameAvailabilityOnUpdate(conn *apigatewayv2.ApiGatewayV2, domainName string, timeout time.Duration) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{apigatewayv2.DomainNameStatusUpdating}, + Target: []string{apigatewayv2.DomainNameStatusAvailable}, + Refresh: apiGateway2DomainNameRefresh(conn, domainName), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 5 * time.Second, + } + + _, err := stateConf.WaitForState() + + return err +} + +func expandApiGateway2DomainNameConfiguration(vDomainNameConfiguration []interface{}) []*apigatewayv2.DomainNameConfiguration { + if len(vDomainNameConfiguration) == 0 || vDomainNameConfiguration[0] == nil { + return nil + } + mDomainNameConfiguration := vDomainNameConfiguration[0].(map[string]interface{}) + + return []*apigatewayv2.DomainNameConfiguration{{ + CertificateArn: aws.String(mDomainNameConfiguration["certificate_arn"].(string)), + EndpointType: aws.String(mDomainNameConfiguration["endpoint_type"].(string)), + SecurityPolicy: aws.String(mDomainNameConfiguration["security_policy"].(string)), + }} +} + +func flattenApiGateway2DomainNameConfiguration(domainNameConfiguration *apigatewayv2.DomainNameConfiguration) []interface{} { + if domainNameConfiguration == nil { + return []interface{}{} + } + + return []interface{}{map[string]interface{}{ + "certificate_arn": aws.StringValue(domainNameConfiguration.CertificateArn), + "endpoint_type": aws.StringValue(domainNameConfiguration.EndpointType), + "hosted_zone_id": aws.StringValue(domainNameConfiguration.HostedZoneId), + "security_policy": aws.StringValue(domainNameConfiguration.SecurityPolicy), + "target_domain_name": aws.StringValue(domainNameConfiguration.ApiGatewayDomainName), + }} +} diff --git a/aws/resource_aws_api_gateway2_domain_name_test.go b/aws/resource_aws_api_gateway2_domain_name_test.go new file mode 100644 index 00000000000..7363080892c --- /dev/null +++ b/aws/resource_aws_api_gateway2_domain_name_test.go @@ -0,0 +1,315 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func init() { + resource.AddTestSweepers("aws_api_gateway_v2_domain_name", &resource.Sweeper{ + Name: "aws_api_gateway_v2_domain_name", + F: testSweepAPIGateway2DomainNames, + }) +} + +func testSweepAPIGateway2DomainNames(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).apigatewayv2conn + input := &apigatewayv2.GetDomainNamesInput{} + + for { + output, err := conn.GetDomainNames(input) + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping API Gateway v2 domain names sweep for %s: %s", region, err) + return nil + } + if err != nil { + return fmt.Errorf("error retrieving API Gateway v2 domain names: %s", err) + } + + for _, domainName := range output.Items { + log.Printf("[INFO] Deleting API Gateway v2 domain name: %s", aws.StringValue(domainName.DomainName)) + _, err := conn.DeleteDomainName(&apigatewayv2.DeleteDomainNameInput{ + DomainName: domainName.DomainName, + }) + if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") { + continue + } + if err != nil { + return fmt.Errorf("error deleting API Gateway v2 domain name (%s): %s", aws.StringValue(domainName.DomainName), err) + } + } + + if aws.StringValue(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + return nil +} + +func TestAccAWSAPIGateway2DomainName_basic(t *testing.T) { + resourceName := "aws_api_gateway_v2_domain_name.test" + certResourceName := "aws_acm_certificate.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + key := tlsRsaPrivateKeyPem(2048) + certificate := tlsRsaX509SelfSignedCertificatePem(key, fmt.Sprintf("%s.example.com", rName)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGateway2DomainNameDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGateway2DomainNameConfig_basic(rName, certificate, key, 1, 0), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), + resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "domain_name_configuration.0.certificate_arn", certResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.endpoint_type", "REGIONAL"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.hosted_zone_id"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.security_policy", "TLS_1_2"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.target_domain_name"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAPIGateway2DomainName_Tags(t *testing.T) { + resourceName := "aws_api_gateway_v2_domain_name.test" + certResourceName := "aws_acm_certificate.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + key := tlsRsaPrivateKeyPem(2048) + certificate := tlsRsaX509SelfSignedCertificatePem(key, fmt.Sprintf("%s.example.com", rName)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGateway2DomainNameDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGateway2DomainNameConfig_tags(rName, certificate, key, 1, 0), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), + resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "domain_name_configuration.0.certificate_arn", certResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.endpoint_type", "REGIONAL"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.hosted_zone_id"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.security_policy", "TLS_1_2"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.target_domain_name"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.Key1", "Value1"), + resource.TestCheckResourceAttr(resourceName, "tags.Key2", "Value2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAPIGateway2DomainNameConfig_basic(rName, certificate, key, 1, 0), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), + resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "domain_name_configuration.0.certificate_arn", certResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.endpoint_type", "REGIONAL"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.hosted_zone_id"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.security_policy", "TLS_1_2"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.target_domain_name"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + }, + }) +} + +func TestAccAWSAPIGateway2DomainName_UpdateCertificate(t *testing.T) { + resourceName := "aws_api_gateway_v2_domain_name.test" + certResourceName0 := "aws_acm_certificate.test.0" + certResourceName1 := "aws_acm_certificate.test.1" + rName := acctest.RandomWithPrefix("tf-acc-test") + key := tlsRsaPrivateKeyPem(2048) + certificate := tlsRsaX509SelfSignedCertificatePem(key, fmt.Sprintf("%s.example.com", rName)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGateway2DomainNameDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGateway2DomainNameConfig_basic(rName, certificate, key, 2, 0), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), + resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "domain_name_configuration.0.certificate_arn", certResourceName0, "arn"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.endpoint_type", "REGIONAL"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.hosted_zone_id"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.security_policy", "TLS_1_2"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.target_domain_name"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + Config: testAccAWSAPIGateway2DomainNameConfig_basic(rName, certificate, key, 2, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), + resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "domain_name_configuration.0.certificate_arn", certResourceName1, "arn"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.endpoint_type", "REGIONAL"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.hosted_zone_id"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.security_policy", "TLS_1_2"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.target_domain_name"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + Config: testAccAWSAPIGateway2DomainNameConfig_tags(rName, certificate, key, 2, 0), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), + resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "domain_name_configuration.0.certificate_arn", certResourceName0, "arn"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.endpoint_type", "REGIONAL"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.hosted_zone_id"), + resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.0.security_policy", "TLS_1_2"), + resource.TestCheckResourceAttrSet(resourceName, "domain_name_configuration.0.target_domain_name"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.Key1", "Value1"), + resource.TestCheckResourceAttr(resourceName, "tags.Key2", "Value2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckAWSAPIGateway2DomainNameDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_api_gateway_v2_domain_name" { + continue + } + + _, err := conn.GetDomainName(&apigatewayv2.GetDomainNameInput{ + DomainName: aws.String(rs.Primary.ID), + }) + if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") { + continue + } + if err != nil { + return err + } + + return fmt.Errorf("API Gateway v2 domain name %s still exists", rs.Primary.ID) + } + + return nil +} + +func testAccCheckAWSAPIGateway2DomainNameExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No API Gateway v2 domain name ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + _, err := conn.GetDomainName(&apigatewayv2.GetDomainNameInput{ + DomainName: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + + return nil + } +} + +func testAccAWSAPIGateway2DomainNameConfig_base(rName, certificate, key string, count int) string { + return fmt.Sprintf(` +resource "aws_acm_certificate" "test" { + count = %[4]d + + certificate_body = %[2]q + private_key = %[3]q + + tags = { + Name = %[1]q + } +} +`, rName, certificate, key, count) +} + +func testAccAWSAPIGateway2DomainNameConfig_basic(rName, certificate, key string, count, index int) string { + return testAccAWSAPIGateway2DomainNameConfig_base(rName, certificate, key, count) + fmt.Sprintf(` +resource "aws_api_gateway_v2_domain_name" "test" { + domain_name = "%[1]s.example.com" + + domain_name_configuration { + certificate_arn = "${aws_acm_certificate.test.*.arn[%[2]d]}" + endpoint_type = "REGIONAL" + security_policy = "TLS_1_2" + } +} +`, rName, index) +} + +func testAccAWSAPIGateway2DomainNameConfig_tags(rName, certificate, key string, count, index int) string { + return testAccAWSAPIGateway2DomainNameConfig_base(rName, certificate, key, count) + fmt.Sprintf(` +resource "aws_api_gateway_v2_domain_name" "test" { + domain_name = "%[1]s.example.com" + + domain_name_configuration { + certificate_arn = "${aws_acm_certificate.test.*.arn[%[2]d]}" + endpoint_type = "REGIONAL" + security_policy = "TLS_1_2" + } + + tags = { + Key1 = "Value1" + Key2 = "Value2" + } +} +`, rName, index) +} diff --git a/website/aws.erb b/website/aws.erb index db4bcbbd8ef..38184c9d0ea 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -218,6 +218,9 @@
  • aws_apigatewayv2_api
  • +
  • + aws_api_gateway_v2_domain_name +
  • diff --git a/website/docs/r/api_gateway_v2_domain_name.html.markdown b/website/docs/r/api_gateway_v2_domain_name.html.markdown new file mode 100644 index 00000000000..a7cc23f7f00 --- /dev/null +++ b/website/docs/r/api_gateway_v2_domain_name.html.markdown @@ -0,0 +1,70 @@ +--- +layout: "aws" +page_title: "AWS: aws_api_gateway_v2_domain_name" +sidebar_current: "docs-aws-resource-api-gateway-v2-domain-name" +description: |- + Manages an Amazon API Gateway Version 2 domain name. +--- + +# Resource: aws_api_gateway_v2_domain_name + +Manages an Amazon API Gateway Version 2 domain name. +More information can be found in the [Amazon API Gateway Developer Guide](https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-custom-domains.html). + +-> **Note:** This resource establishes ownership of and the TLS settings for +a particular domain name. An API stage can be associated with the domain name using the `aws_api_gateway_v2_api_mapping` resource. + +## Example Usage + +### Basic + +```hcl +resource "aws_api_gateway_v2_domain_name" "example" { + domain_name = "ws-api.example.com" + + domain_name_configuration { + certificate_arn = "${aws_acm_certificate.example.arn}" + endpoint_type = "REGIONAL" + security_policy = "TLS_1_2" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `domain_name` - (Required) The domain name. +* `domain_name_configuration` - (Required) The domain name configuration. +* `tags` - (Optional) A mapping of tags to assign to the domain name. + +The `domain_name_configuration` object supports the following: + +* `certificate_arn` - (Required) The ARN of an AWS-managed certificate that will be used by the endpoint for the domain name. AWS Certificate Manager is the only supported source. +Use the [`aws_acm_certificate`](/docs/providers/aws/r/acm_certificate.html) resource to configure an ACM certificate. +* `endpoint_type` - (Required) The endpoint type. Valid values: `REGIONAL`. +* `security_policy` - (Required) The Transport Layer Security (TLS) version of the [security policy](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-custom-domain-tls-version.html) for the domain name. Valid values: `TLS_1_2`. +* `hosted_zone_id` - (Computed) The Amazon Route 53 Hosted Zone ID of the endpoint. +* `target_domain_name` - (Computed) The target domain name. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The domain name identifier. +* `api_mapping_selection_expression` - The [API mapping selection expression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-mapping-selection-expressions) for the domain name. +* `arn` - The ARN of the domain name. + +## Timeouts + +`aws_api_gateway_v2_domain_name` provides the following [Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `update` - (Default `60 minutes`) Used for updating the domain name + +## Import + +`aws_api_gateway_v2_domain_name` can be imported by using the domain name, e.g. + +``` +$ terraform import aws_api_gateway_v2_domain_name.example ws-api.example.com +``` From f5c038d8cf7cf72b9fe88723cff41c05cf318b66 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 13 Mar 2020 18:25:54 -0400 Subject: [PATCH 055/684] 'aws_api_gateway2_domain_name' -> 'aws_apigatewayv2_domain_name'. --- aws/provider.go | 2 +- ... resource_aws_apigatewayv2_domain_name.go} | 48 +++---- ...urce_aws_apigatewayv2_domain_name_test.go} | 122 ++++++++++++------ website/aws.erb | 2 +- ...=> apigatewayv2_domain_name.html.markdown} | 16 +-- 5 files changed, 118 insertions(+), 72 deletions(-) rename aws/{resource_aws_api_gateway2_domain_name.go => resource_aws_apigatewayv2_domain_name.go} (77%) rename aws/{resource_aws_api_gateway2_domain_name_test.go => resource_aws_apigatewayv2_domain_name_test.go} (71%) rename website/docs/r/{api_gateway_v2_domain_name.html.markdown => apigatewayv2_domain_name.html.markdown} (80%) diff --git a/aws/provider.go b/aws/provider.go index 5895aa46674..35200ee54d9 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -355,7 +355,7 @@ func Provider() terraform.ResourceProvider { "aws_api_gateway_usage_plan_key": resourceAwsApiGatewayUsagePlanKey(), "aws_api_gateway_vpc_link": resourceAwsApiGatewayVpcLink(), "aws_apigatewayv2_api": resourceAwsApiGatewayV2Api(), - "aws_api_gateway_v2_domain_name": resourceAwsApiGateway2DomainName(), + "aws_apigatewayv2_domain_name": resourceAwsApiGatewayV2DomainName(), "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), "aws_appautoscaling_target": resourceAwsAppautoscalingTarget(), "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), diff --git a/aws/resource_aws_api_gateway2_domain_name.go b/aws/resource_aws_apigatewayv2_domain_name.go similarity index 77% rename from aws/resource_aws_api_gateway2_domain_name.go rename to aws/resource_aws_apigatewayv2_domain_name.go index 53e867661b4..9ae3e799683 100644 --- a/aws/resource_aws_api_gateway2_domain_name.go +++ b/aws/resource_aws_apigatewayv2_domain_name.go @@ -15,15 +15,15 @@ import ( ) const ( - apiGateway2DomainNameStatusDeleted = "DELETED" + apiGatewayV2DomainNameStatusDeleted = "DELETED" ) -func resourceAwsApiGateway2DomainName() *schema.Resource { +func resourceAwsApiGatewayV2DomainName() *schema.Resource { return &schema.Resource{ - Create: resourceAwsApiGateway2DomainNameCreate, - Read: resourceAwsApiGateway2DomainNameRead, - Update: resourceAwsApiGateway2DomainNameUpdate, - Delete: resourceAwsApiGateway2DomainNameDelete, + Create: resourceAwsApiGatewayV2DomainNameCreate, + Read: resourceAwsApiGatewayV2DomainNameRead, + Update: resourceAwsApiGatewayV2DomainNameUpdate, + Delete: resourceAwsApiGatewayV2DomainNameDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, @@ -89,12 +89,12 @@ func resourceAwsApiGateway2DomainName() *schema.Resource { } } -func resourceAwsApiGateway2DomainNameCreate(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2DomainNameCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn req := &apigatewayv2.CreateDomainNameInput{ DomainName: aws.String(d.Get("domain_name").(string)), - DomainNameConfigurations: expandApiGateway2DomainNameConfiguration(d.Get("domain_name_configuration").([]interface{})), + DomainNameConfigurations: expandApiGatewayV2DomainNameConfiguration(d.Get("domain_name_configuration").([]interface{})), Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().Apigatewayv2Tags(), } @@ -106,18 +106,18 @@ func resourceAwsApiGateway2DomainNameCreate(d *schema.ResourceData, meta interfa d.SetId(aws.StringValue(resp.DomainName)) - return resourceAwsApiGateway2DomainNameRead(d, meta) + return resourceAwsApiGatewayV2DomainNameRead(d, meta) } -func resourceAwsApiGateway2DomainNameRead(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2DomainNameRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn - respRaw, state, err := apiGateway2DomainNameRefresh(conn, d.Id())() + respRaw, state, err := apiGatewayV2DomainNameRefresh(conn, d.Id())() if err != nil { return fmt.Errorf("error reading API Gateway v2 domain name (%s): %s", d.Id(), err) } - if state == apiGateway2DomainNameStatusDeleted { + if state == apiGatewayV2DomainNameStatusDeleted { log.Printf("[WARN] API Gateway v2 domain name (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -133,7 +133,7 @@ func resourceAwsApiGateway2DomainNameRead(d *schema.ResourceData, meta interface }.String() d.Set("arn", arn) d.Set("domain_name", resp.DomainName) - err = d.Set("domain_name_configuration", flattenApiGateway2DomainNameConfiguration(resp.DomainNameConfigurations[0])) + err = d.Set("domain_name_configuration", flattenApiGatewayV2DomainNameConfiguration(resp.DomainNameConfigurations[0])) if err != nil { return fmt.Errorf("error setting domain_name_configuration: %s", err) } @@ -144,13 +144,13 @@ func resourceAwsApiGateway2DomainNameRead(d *schema.ResourceData, meta interface return nil } -func resourceAwsApiGateway2DomainNameUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2DomainNameUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn if d.HasChange("domain_name_configuration") { req := &apigatewayv2.UpdateDomainNameInput{ DomainName: aws.String(d.Id()), - DomainNameConfigurations: expandApiGateway2DomainNameConfiguration(d.Get("domain_name_configuration").([]interface{})), + DomainNameConfigurations: expandApiGatewayV2DomainNameConfiguration(d.Get("domain_name_configuration").([]interface{})), } log.Printf("[DEBUG] Updating API Gateway v2 domain name: %s", req) @@ -159,7 +159,7 @@ func resourceAwsApiGateway2DomainNameUpdate(d *schema.ResourceData, meta interfa return fmt.Errorf("error updating API Gateway v2 domain name (%s): %s", d.Id(), err) } - if err := waitForApiGateway2DomainNameAvailabilityOnUpdate(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { + if err := waitForApiGatewayV2DomainNameAvailabilityOnUpdate(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { return fmt.Errorf("error waiting for API Gateway v2 domain name (%s) to become available: %s", d.Id(), err) } } @@ -171,10 +171,10 @@ func resourceAwsApiGateway2DomainNameUpdate(d *schema.ResourceData, meta interfa } } - return resourceAwsApiGateway2DomainNameRead(d, meta) + return resourceAwsApiGatewayV2DomainNameRead(d, meta) } -func resourceAwsApiGateway2DomainNameDelete(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2DomainNameDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn log.Printf("[DEBUG] Deleting API Gateway v2 domain name (%s)", d.Id()) @@ -191,13 +191,13 @@ func resourceAwsApiGateway2DomainNameDelete(d *schema.ResourceData, meta interfa return nil } -func apiGateway2DomainNameRefresh(conn *apigatewayv2.ApiGatewayV2, domainName string) resource.StateRefreshFunc { +func apiGatewayV2DomainNameRefresh(conn *apigatewayv2.ApiGatewayV2, domainName string) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.GetDomainName(&apigatewayv2.GetDomainNameInput{ DomainName: aws.String(domainName), }) if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") { - return "", apiGateway2DomainNameStatusDeleted, nil + return "", apiGatewayV2DomainNameStatusDeleted, nil } if err != nil { return nil, "", err @@ -216,11 +216,11 @@ func apiGateway2DomainNameRefresh(conn *apigatewayv2.ApiGatewayV2, domainName st } } -func waitForApiGateway2DomainNameAvailabilityOnUpdate(conn *apigatewayv2.ApiGatewayV2, domainName string, timeout time.Duration) error { +func waitForApiGatewayV2DomainNameAvailabilityOnUpdate(conn *apigatewayv2.ApiGatewayV2, domainName string, timeout time.Duration) error { stateConf := &resource.StateChangeConf{ Pending: []string{apigatewayv2.DomainNameStatusUpdating}, Target: []string{apigatewayv2.DomainNameStatusAvailable}, - Refresh: apiGateway2DomainNameRefresh(conn, domainName), + Refresh: apiGatewayV2DomainNameRefresh(conn, domainName), Timeout: timeout, Delay: 10 * time.Second, MinTimeout: 5 * time.Second, @@ -231,7 +231,7 @@ func waitForApiGateway2DomainNameAvailabilityOnUpdate(conn *apigatewayv2.ApiGate return err } -func expandApiGateway2DomainNameConfiguration(vDomainNameConfiguration []interface{}) []*apigatewayv2.DomainNameConfiguration { +func expandApiGatewayV2DomainNameConfiguration(vDomainNameConfiguration []interface{}) []*apigatewayv2.DomainNameConfiguration { if len(vDomainNameConfiguration) == 0 || vDomainNameConfiguration[0] == nil { return nil } @@ -244,7 +244,7 @@ func expandApiGateway2DomainNameConfiguration(vDomainNameConfiguration []interfa }} } -func flattenApiGateway2DomainNameConfiguration(domainNameConfiguration *apigatewayv2.DomainNameConfiguration) []interface{} { +func flattenApiGatewayV2DomainNameConfiguration(domainNameConfiguration *apigatewayv2.DomainNameConfiguration) []interface{} { if domainNameConfiguration == nil { return []interface{}{} } diff --git a/aws/resource_aws_api_gateway2_domain_name_test.go b/aws/resource_aws_apigatewayv2_domain_name_test.go similarity index 71% rename from aws/resource_aws_api_gateway2_domain_name_test.go rename to aws/resource_aws_apigatewayv2_domain_name_test.go index 7363080892c..3c1f504166a 100644 --- a/aws/resource_aws_api_gateway2_domain_name_test.go +++ b/aws/resource_aws_apigatewayv2_domain_name_test.go @@ -8,25 +8,27 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" ) func init() { - resource.AddTestSweepers("aws_api_gateway_v2_domain_name", &resource.Sweeper{ - Name: "aws_api_gateway_v2_domain_name", - F: testSweepAPIGateway2DomainNames, + resource.AddTestSweepers("aws_apigatewayv2_domain_name", &resource.Sweeper{ + Name: "aws_apigatewayv2_domain_name", + F: testSweepAPIGatewayV2DomainNames, }) } -func testSweepAPIGateway2DomainNames(region string) error { +func testSweepAPIGatewayV2DomainNames(region string) error { client, err := sharedClientForRegion(region) if err != nil { return fmt.Errorf("error getting client: %s", err) } conn := client.(*AWSClient).apigatewayv2conn input := &apigatewayv2.GetDomainNamesInput{} + var sweeperErrs *multierror.Error for { output, err := conn.GetDomainNames(input) @@ -47,7 +49,10 @@ func testSweepAPIGateway2DomainNames(region string) error { continue } if err != nil { - return fmt.Errorf("error deleting API Gateway v2 domain name (%s): %s", aws.StringValue(domainName.DomainName), err) + sweeperErr := fmt.Errorf("error deleting API Gateway v2 domain name (%s): %s", aws.StringValue(domainName.DomainName), err) + log.Printf("[ERROR] %s", sweeperErr) + sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) + continue } } @@ -57,11 +62,12 @@ func testSweepAPIGateway2DomainNames(region string) error { input.NextToken = output.NextToken } - return nil + return sweeperErrs.ErrorOrNil() } -func TestAccAWSAPIGateway2DomainName_basic(t *testing.T) { - resourceName := "aws_api_gateway_v2_domain_name.test" +func TestAccAWSAPIGatewayV2DomainName_basic(t *testing.T) { + var v apigatewayv2.GetDomainNameOutput + resourceName := "aws_apigatewayv2_domain_name.test" certResourceName := "aws_acm_certificate.test" rName := acctest.RandomWithPrefix("tf-acc-test") key := tlsRsaPrivateKeyPem(2048) @@ -70,12 +76,12 @@ func TestAccAWSAPIGateway2DomainName_basic(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAPIGateway2DomainNameDestroy, + CheckDestroy: testAccCheckAWSAPIGatewayV2DomainNameDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAPIGateway2DomainNameConfig_basic(rName, certificate, key, 1, 0), + Config: testAccAWSAPIGatewayV2DomainNameConfig_basic(rName, certificate, key, 1, 0), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccCheckAWSAPIGatewayV2DomainNameExists(resourceName, &v), testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), @@ -96,8 +102,33 @@ func TestAccAWSAPIGateway2DomainName_basic(t *testing.T) { }) } -func TestAccAWSAPIGateway2DomainName_Tags(t *testing.T) { - resourceName := "aws_api_gateway_v2_domain_name.test" +func TestAccAWSAPIGatewayV2DomainName_disappears(t *testing.T) { + var v apigatewayv2.GetDomainNameOutput + resourceName := "aws_apigatewayv2_domain_name.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + key := tlsRsaPrivateKeyPem(2048) + certificate := tlsRsaX509SelfSignedCertificatePem(key, fmt.Sprintf("%s.example.com", rName)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGatewayV2DomainNameDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2DomainNameConfig_basic(rName, certificate, key, 1, 0), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayV2DomainNameExists(resourceName, &v), + testAccCheckAWSAPIGatewayV2DomainNameDisappears(&v), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSAPIGatewayV2DomainName_Tags(t *testing.T) { + var v apigatewayv2.GetDomainNameOutput + resourceName := "aws_apigatewayv2_domain_name.test" certResourceName := "aws_acm_certificate.test" rName := acctest.RandomWithPrefix("tf-acc-test") key := tlsRsaPrivateKeyPem(2048) @@ -106,12 +137,12 @@ func TestAccAWSAPIGateway2DomainName_Tags(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAPIGateway2DomainNameDestroy, + CheckDestroy: testAccCheckAWSAPIGatewayV2DomainNameDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAPIGateway2DomainNameConfig_tags(rName, certificate, key, 1, 0), + Config: testAccAWSAPIGatewayV2DomainNameConfig_tags(rName, certificate, key, 1, 0), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccCheckAWSAPIGatewayV2DomainNameExists(resourceName, &v), testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), @@ -131,9 +162,9 @@ func TestAccAWSAPIGateway2DomainName_Tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAPIGateway2DomainNameConfig_basic(rName, certificate, key, 1, 0), + Config: testAccAWSAPIGatewayV2DomainNameConfig_basic(rName, certificate, key, 1, 0), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccCheckAWSAPIGatewayV2DomainNameExists(resourceName, &v), testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), @@ -149,8 +180,9 @@ func TestAccAWSAPIGateway2DomainName_Tags(t *testing.T) { }) } -func TestAccAWSAPIGateway2DomainName_UpdateCertificate(t *testing.T) { - resourceName := "aws_api_gateway_v2_domain_name.test" +func TestAccAWSAPIGatewayV2DomainName_UpdateCertificate(t *testing.T) { + var v apigatewayv2.GetDomainNameOutput + resourceName := "aws_apigatewayv2_domain_name.test" certResourceName0 := "aws_acm_certificate.test.0" certResourceName1 := "aws_acm_certificate.test.1" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -160,12 +192,12 @@ func TestAccAWSAPIGateway2DomainName_UpdateCertificate(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAPIGateway2DomainNameDestroy, + CheckDestroy: testAccCheckAWSAPIGatewayV2DomainNameDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAPIGateway2DomainNameConfig_basic(rName, certificate, key, 2, 0), + Config: testAccAWSAPIGatewayV2DomainNameConfig_basic(rName, certificate, key, 2, 0), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccCheckAWSAPIGatewayV2DomainNameExists(resourceName, &v), testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), @@ -178,9 +210,9 @@ func TestAccAWSAPIGateway2DomainName_UpdateCertificate(t *testing.T) { ), }, { - Config: testAccAWSAPIGateway2DomainNameConfig_basic(rName, certificate, key, 2, 1), + Config: testAccAWSAPIGatewayV2DomainNameConfig_basic(rName, certificate, key, 2, 1), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccCheckAWSAPIGatewayV2DomainNameExists(resourceName, &v), testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), @@ -193,9 +225,9 @@ func TestAccAWSAPIGateway2DomainName_UpdateCertificate(t *testing.T) { ), }, { - Config: testAccAWSAPIGateway2DomainNameConfig_tags(rName, certificate, key, 2, 0), + Config: testAccAWSAPIGatewayV2DomainNameConfig_tags(rName, certificate, key, 2, 0), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2DomainNameExists(resourceName), + testAccCheckAWSAPIGatewayV2DomainNameExists(resourceName, &v), testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/.+`)), resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.example.com", rName)), resource.TestCheckResourceAttr(resourceName, "domain_name_configuration.#", "1"), @@ -218,11 +250,11 @@ func TestAccAWSAPIGateway2DomainName_UpdateCertificate(t *testing.T) { }) } -func testAccCheckAWSAPIGateway2DomainNameDestroy(s *terraform.State) error { +func testAccCheckAWSAPIGatewayV2DomainNameDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_api_gateway_v2_domain_name" { + if rs.Type != "aws_apigatewayv2_domain_name" { continue } @@ -242,7 +274,19 @@ func testAccCheckAWSAPIGateway2DomainNameDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSAPIGateway2DomainNameExists(n string) resource.TestCheckFunc { +func testAccCheckAWSAPIGatewayV2DomainNameDisappears(v *apigatewayv2.GetDomainNameOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + _, err := conn.DeleteDomainName(&apigatewayv2.DeleteDomainNameInput{ + DomainName: v.DomainName, + }) + + return err + } +} + +func testAccCheckAWSAPIGatewayV2DomainNameExists(n string, v *apigatewayv2.GetDomainNameOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -255,18 +299,20 @@ func testAccCheckAWSAPIGateway2DomainNameExists(n string) resource.TestCheckFunc conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn - _, err := conn.GetDomainName(&apigatewayv2.GetDomainNameInput{ + resp, err := conn.GetDomainName(&apigatewayv2.GetDomainNameInput{ DomainName: aws.String(rs.Primary.ID), }) if err != nil { return err } + *v = *resp + return nil } } -func testAccAWSAPIGateway2DomainNameConfig_base(rName, certificate, key string, count int) string { +func testAccAWSAPIGatewayV2DomainNameConfig_base(rName, certificate, key string, count int) string { return fmt.Sprintf(` resource "aws_acm_certificate" "test" { count = %[4]d @@ -281,9 +327,9 @@ resource "aws_acm_certificate" "test" { `, rName, certificate, key, count) } -func testAccAWSAPIGateway2DomainNameConfig_basic(rName, certificate, key string, count, index int) string { - return testAccAWSAPIGateway2DomainNameConfig_base(rName, certificate, key, count) + fmt.Sprintf(` -resource "aws_api_gateway_v2_domain_name" "test" { +func testAccAWSAPIGatewayV2DomainNameConfig_basic(rName, certificate, key string, count, index int) string { + return testAccAWSAPIGatewayV2DomainNameConfig_base(rName, certificate, key, count) + fmt.Sprintf(` +resource "aws_apigatewayv2_domain_name" "test" { domain_name = "%[1]s.example.com" domain_name_configuration { @@ -295,9 +341,9 @@ resource "aws_api_gateway_v2_domain_name" "test" { `, rName, index) } -func testAccAWSAPIGateway2DomainNameConfig_tags(rName, certificate, key string, count, index int) string { - return testAccAWSAPIGateway2DomainNameConfig_base(rName, certificate, key, count) + fmt.Sprintf(` -resource "aws_api_gateway_v2_domain_name" "test" { +func testAccAWSAPIGatewayV2DomainNameConfig_tags(rName, certificate, key string, count, index int) string { + return testAccAWSAPIGatewayV2DomainNameConfig_base(rName, certificate, key, count) + fmt.Sprintf(` +resource "aws_apigatewayv2_domain_name" "test" { domain_name = "%[1]s.example.com" domain_name_configuration { diff --git a/website/aws.erb b/website/aws.erb index 38184c9d0ea..dce3c91d799 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -219,7 +219,7 @@ aws_apigatewayv2_api
  • - aws_api_gateway_v2_domain_name + aws_apigatewayv2_domain_name
  • diff --git a/website/docs/r/api_gateway_v2_domain_name.html.markdown b/website/docs/r/apigatewayv2_domain_name.html.markdown similarity index 80% rename from website/docs/r/api_gateway_v2_domain_name.html.markdown rename to website/docs/r/apigatewayv2_domain_name.html.markdown index a7cc23f7f00..951f0f78525 100644 --- a/website/docs/r/api_gateway_v2_domain_name.html.markdown +++ b/website/docs/r/apigatewayv2_domain_name.html.markdown @@ -1,25 +1,25 @@ --- +subcategory: "API Gateway v2 (WebSocket and HTTP APIs)" layout: "aws" -page_title: "AWS: aws_api_gateway_v2_domain_name" -sidebar_current: "docs-aws-resource-api-gateway-v2-domain-name" +page_title: "AWS: aws_apigatewayv2_domain_name" description: |- Manages an Amazon API Gateway Version 2 domain name. --- -# Resource: aws_api_gateway_v2_domain_name +# Resource: aws_apigatewayv2_domain_name Manages an Amazon API Gateway Version 2 domain name. More information can be found in the [Amazon API Gateway Developer Guide](https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-custom-domains.html). -> **Note:** This resource establishes ownership of and the TLS settings for -a particular domain name. An API stage can be associated with the domain name using the `aws_api_gateway_v2_api_mapping` resource. +a particular domain name. An API stage can be associated with the domain name using the `aws_apigatewayv2_api_mapping` resource. ## Example Usage ### Basic ```hcl -resource "aws_api_gateway_v2_domain_name" "example" { +resource "aws_apigatewayv2_domain_name" "example" { domain_name = "ws-api.example.com" domain_name_configuration { @@ -57,14 +57,14 @@ In addition to all arguments above, the following attributes are exported: ## Timeouts -`aws_api_gateway_v2_domain_name` provides the following [Timeouts](/docs/configuration/resources.html#timeouts) configuration options: +`aws_apigatewayv2_domain_name` provides the following [Timeouts](/docs/configuration/resources.html#timeouts) configuration options: - `update` - (Default `60 minutes`) Used for updating the domain name ## Import -`aws_api_gateway_v2_domain_name` can be imported by using the domain name, e.g. +`aws_apigatewayv2_domain_name` can be imported by using the domain name, e.g. ``` -$ terraform import aws_api_gateway_v2_domain_name.example ws-api.example.com +$ terraform import aws_apigatewayv2_domain_name.example ws-api.example.com ``` From 1df2b1e7a06429bdb7235b70b1fe4c66b35f99c0 Mon Sep 17 00:00:00 2001 From: cory Date: Tue, 17 Mar 2020 14:25:26 +0000 Subject: [PATCH 056/684] Moves `replica` to `aws_dynamodb_table`. --- aws/provider.go | 1 - aws/resource_aws_dynamodb_table.go | 301 +++++++++++++- aws/resource_aws_dynamodb_table_2019.go | 409 ------------------- aws/resource_aws_dynamodb_table_2019_test.go | 129 ------ aws/resource_aws_dynamodb_table_test.go | 81 ++++ aws/structure.go | 37 +- 6 files changed, 395 insertions(+), 563 deletions(-) delete mode 100644 aws/resource_aws_dynamodb_table_2019.go delete mode 100644 aws/resource_aws_dynamodb_table_2019_test.go diff --git a/aws/provider.go b/aws/provider.go index 71087b6eb83..c7c84fd1b01 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -483,7 +483,6 @@ func Provider() terraform.ResourceProvider { "aws_dx_public_virtual_interface": resourceAwsDxPublicVirtualInterface(), "aws_dx_transit_virtual_interface": resourceAwsDxTransitVirtualInterface(), "aws_dynamodb_table": resourceAwsDynamoDbTable(), - "aws_dynamodb_table_2019": resourceAwsDynamoDbTable2019(), "aws_dynamodb_table_item": resourceAwsDynamoDbTableItem(), "aws_dynamodb_global_table": resourceAwsDynamoDbGlobalTable(), "aws_ebs_default_kms_key": resourceAwsEbsDefaultKmsKey(), diff --git a/aws/resource_aws_dynamodb_table.go b/aws/resource_aws_dynamodb_table.go index 83e71b6b9a3..14c8d1cf8f7 100644 --- a/aws/resource_aws_dynamodb_table.go +++ b/aws/resource_aws_dynamodb_table.go @@ -279,6 +279,58 @@ func resourceAwsDynamoDbTable() *schema.Resource { }, }, }, + "replica": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region_name": { + Type: schema.TypeString, + Required: true, + }, + "kms_master_key_id": { + Type: schema.TypeString, + Optional: true, + }, + "provision_capacity_override": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "read_capacity": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + "global_secondary_index": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "provisioned_capacity_override": { + Type: schema.TypeMap, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "read_capacity": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, }, } } @@ -418,6 +470,12 @@ func resourceAwsDynamoDbTableCreate(d *schema.ResourceData, meta interface{}) er } } + if _, ok := d.GetOk("replica"); ok { + if err := createDynamoDbReplicas(d.Id(), d.Get("replica").([]interface{}), conn); err != nil { + return fmt.Errorf("error enabled DynamoDB Table (%s) replicas: %s", d.Id(), err) + } + } + return resourceAwsDynamoDbTableRead(d, meta) } @@ -595,9 +653,54 @@ func resourceAwsDynamoDbTableUpdate(d *schema.ResourceData, meta interface{}) er } } + if d.HasChange("replica") { + if err := updateDynamoDbReplica(d, conn); err != nil { + return fmt.Errorf("error updating DynamoDB Table (%s) replica: %s", d.Id(), err) + } + } + return resourceAwsDynamoDbTableRead(d, meta) } +func updateDynamoDbReplica(d *schema.ResourceData, conn *dynamodb.DynamoDB) error { + var err error + var replicaUpdates []*dynamodb.ReplicationGroupUpdate + o, n := d.GetChange("replica") + + replicaUpdates, _ = diffDynamoDbReplicas(o.([]interface{}), n.([]interface{})) + log.Printf("[DEBUG] replica updates %s", replicaUpdates) + for _, replicaUpdate := range replicaUpdates { + var ops []*dynamodb.ReplicationGroupUpdate + ops = append(ops, replicaUpdate) + + replicaInput := &dynamodb.UpdateTableInput{ + TableName: aws.String(d.Id()), + ReplicaUpdates: ops, + } + replicaInput.ReplicaUpdates = replicaUpdates + _, replicaErr := conn.UpdateTable(replicaInput) + if replicaErr == nil { + if replicaUpdate.Delete == nil { + log.Printf("[DEBUG] waiting for replica to be updated") + err = waitForDynamoDbReplicaUpdateToBeCompleted(d.Id(), aws.StringValue(replicaUpdate.Update.RegionName), 20*time.Minute, conn) + if err != nil { + return fmt.Errorf("error waiting for DynamoDB Table Replicas to update (%s): %s", d.Id(), err) + } + } else { + log.Printf("[DEBUG] waiting for replica to be deleted") + err = waitForDynamoDbReplicaDeleteToBeCompleted(d.Id(), aws.StringValue(replicaUpdate.Delete.RegionName), 20*time.Minute, conn) + if err != nil { + return fmt.Errorf("error waiting for DynamoDB Table Replicas to delete (%s): %s", d.Id(), err) + } + } + } else { + return fmt.Errorf("error updating DynamoDB Table (%s): %s", d.Id(), replicaErr) + } + } + + return nil +} + func resourceAwsDynamoDbTableRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).dynamodbconn @@ -652,7 +755,23 @@ func resourceAwsDynamoDbTableDelete(d *schema.ResourceData, meta interface{}) er log.Printf("[DEBUG] DynamoDB delete table: %s", d.Id()) - err := deleteAwsDynamoDbTable(d.Id(), conn) + input := &dynamodb.DescribeTableInput{ + TableName: aws.String(d.Id()), + } + + output, err := conn.DescribeTable(input) + log.Printf("[DEBUG] DynamoDB delete describe: %s", output) + if err != nil { + return fmt.Errorf("error describing DynamoDB Table (%s): %s", d.Id(), err) + } + + if len(output.Table.Replicas) > 0 { + if err := deleteDynamoDbReplicas(d.Id(), d.Get("replica").([]interface{}), conn); err != nil { + return fmt.Errorf("error deleting DynamoDB Table (%s) replicas: %s", d.Id(), err) + } + } + + err = deleteAwsDynamoDbTable(d.Id(), conn) if err != nil { if isAWSErr(err, dynamodb.ErrCodeResourceNotFoundException, "Requested resource not found: Table: ") { return nil @@ -702,6 +821,52 @@ func deleteAwsDynamoDbTable(tableName string, conn *dynamodb.DynamoDB) error { return err } +func deleteDynamoDbReplicas(tableName string, replicas []interface{}, conn *dynamodb.DynamoDB) error { + for _, replica := range replicas { + var ops []*dynamodb.ReplicationGroupUpdate + if regionName, ok := replica.(map[string]interface{})["region_name"]; ok { + ops = append(ops, &dynamodb.ReplicationGroupUpdate{ + Delete: &dynamodb.DeleteReplicationGroupMemberAction{ + RegionName: aws.String(regionName.(string)), + }, + }) + + input := &dynamodb.UpdateTableInput{ + TableName: aws.String(tableName), + ReplicaUpdates: ops, + } + + log.Printf("[DEBUG] Deleting DynamoDB Replicas to %v", input) + + err := resource.Retry(20*time.Minute, func() *resource.RetryError { + _, err := conn.UpdateTable(input) + if err != nil { + if isAWSErr(err, "ThrottlingException", "") { + return resource.RetryableError(err) + } + if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "can be created, updated, or deleted simultaneously") { + return resource.RetryableError(err) + } + + return resource.NonRetryableError(err) + } + return nil + }) + if isResourceTimeoutError(err) { + _, err = conn.UpdateTable(input) + } + if err != nil { + return fmt.Errorf("Error deleting DynamoDB Replicas status: %s", err) + } + + if err := waitForDynamoDbReplicaDeleteToBeCompleted(tableName, regionName.(string), 20*time.Minute, conn); err != nil { + return fmt.Errorf("Error waiting for DynamoDB replica delete: %s", err) + } + } + } + return nil +} + func waitForDynamodbTableDeletion(conn *dynamodb.DynamoDB, tableName string, timeout time.Duration) error { stateConf := &resource.StateChangeConf{ Pending: []string{ @@ -738,6 +903,140 @@ func waitForDynamodbTableDeletion(conn *dynamodb.DynamoDB, tableName string, tim return err } +func waitForDynamoDbReplicaUpdateToBeCompleted(tableName string, region string, timeout time.Duration, conn *dynamodb.DynamoDB) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + dynamodb.ReplicaStatusCreating, + dynamodb.ReplicaStatusUpdating, + dynamodb.ReplicaStatusDeleting, + }, + Target: []string{ + dynamodb.ReplicaStatusActive, + }, + Timeout: timeout, + Refresh: func() (interface{}, string, error) { + result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ + TableName: aws.String(tableName), + }) + if err != nil { + return 42, "", err + } + log.Printf("[DEBUG] DynamoDB replicas: %s", result.Table.Replicas) + + if len(result.Table.Replicas) == 0 { + return result, dynamodb.ReplicaStatusCreating, nil + } + // Find replica + var targetReplica *dynamodb.ReplicaDescription + for _, replica := range result.Table.Replicas { + if *replica.RegionName == region { + targetReplica = replica + } + } + + if targetReplica == nil { + return nil, "", nil + } + + return result, aws.StringValue(targetReplica.ReplicaStatus), nil + }, + } + _, err := stateConf.WaitForState() + + return err +} + +func waitForDynamoDbReplicaDeleteToBeCompleted(tableName string, region string, timeout time.Duration, conn *dynamodb.DynamoDB) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + dynamodb.ReplicaStatusCreating, + dynamodb.ReplicaStatusUpdating, + dynamodb.ReplicaStatusDeleting, + dynamodb.ReplicaStatusActive, + }, + Target: []string{""}, + Timeout: timeout, + Refresh: func() (interface{}, string, error) { + result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ + TableName: aws.String(tableName), + }) + if err != nil { + return 42, "", err + } + + log.Printf("[DEBUG] all replicas for waiting: %s", result.Table.Replicas) + if len(result.Table.Replicas) == 0 { + log.Printf("[DEBUG] all replicas deleted: %s", result.Table.Replicas) + return result, "", nil + } + + // Find replica + var targetReplica *dynamodb.ReplicaDescription + for _, replica := range result.Table.Replicas { + if *replica.RegionName == region { + targetReplica = replica + } + } + log.Printf("[DEBUG] targetReplica: %s", targetReplica) + + if targetReplica == nil { + return result, "", nil + } + + return result, aws.StringValue(targetReplica.ReplicaStatus), nil + }, + } + _, err := stateConf.WaitForState() + + return err +} + +func createDynamoDbReplicas(tableName string, replicas []interface{}, conn *dynamodb.DynamoDB) error { + for _, replica := range replicas { + var ops []*dynamodb.ReplicationGroupUpdate + if regionName, ok := replica.(map[string]interface{})["region_name"]; ok { + ops = append(ops, &dynamodb.ReplicationGroupUpdate{ + Create: &dynamodb.CreateReplicationGroupMemberAction{ + RegionName: aws.String(regionName.(string)), + }, + }) + + input := &dynamodb.UpdateTableInput{ + TableName: aws.String(tableName), + ReplicaUpdates: ops, + } + + log.Printf("[DEBUG] Updating DynamoDB Replicas to %v", input) + + err := resource.Retry(20*time.Minute, func() *resource.RetryError { + _, err := conn.UpdateTable(input) + if err != nil { + if isAWSErr(err, "ThrottlingException", "") { + return resource.RetryableError(err) + } + if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "can be created, updated, or deleted simultaneously") { + return resource.RetryableError(err) + } + + return resource.NonRetryableError(err) + } + return nil + }) + if isResourceTimeoutError(err) { + _, err = conn.UpdateTable(input) + } + if err != nil { + return fmt.Errorf("Error updating DynamoDB Replicas status: %s", err) + } + + if err := waitForDynamoDbReplicaUpdateToBeCompleted(tableName, regionName.(string), 20*time.Minute, conn); err != nil { + return fmt.Errorf("Error waiting for DynamoDB replica update: %s", err) + } + } + } + return nil +} + func updateDynamoDbTimeToLive(tableName string, ttlList []interface{}, conn *dynamodb.DynamoDB) error { ttlMap := ttlList[0].(map[string]interface{}) diff --git a/aws/resource_aws_dynamodb_table_2019.go b/aws/resource_aws_dynamodb_table_2019.go deleted file mode 100644 index be55f366f17..00000000000 --- a/aws/resource_aws_dynamodb_table_2019.go +++ /dev/null @@ -1,409 +0,0 @@ -package aws - -import ( - "fmt" - "log" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/dynamodb" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" -) - -func replicaSchema() *schema.Schema { - return &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "region_name": { - Type: schema.TypeString, - Required: true, - }, - "kms_master_key_id": { - Type: schema.TypeString, - Optional: true, - }, - "provision_capacity_override": { - Type: schema.TypeMap, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "read_capacity": { - Type: schema.TypeInt, - Required: true, - }, - }, - }, - }, - "global_secondary_index": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - "provisioned_capacity_override": { - Type: schema.TypeMap, - Required: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "read_capacity": { - Type: schema.TypeInt, - Required: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func resourceAwsDynamoDbTable2019() *schema.Resource { - schema := resourceAwsDynamoDbTable() - schema.Create = resourceAwsDynamoDbTable2019Create - schema.Read = resourceAwsDynamoDbTable2019Read - schema.Update = resourceAwsDynamoDbTable2019Update - schema.Delete = resourceAwsDynamoDbTable2019Delete - schema.Schema["replica"] = replicaSchema() - - return schema -} - -func resourceAwsDynamoDbTable2019Create(d *schema.ResourceData, meta interface{}) error { - err := resourceAwsDynamoDbTableCreate(d, meta) - if err != nil { - return fmt.Errorf("error creating DynamoDB Table (%s) %s", d.Id(), err) - } - conn := meta.(*AWSClient).dynamodbconn - - if _, ok := d.GetOk("replica"); ok { - if err := createDynamoDbReplicas(d.Id(), d.Get("replica").([]interface{}), conn); err != nil { - return fmt.Errorf("error enabled DynamoDB Table (%s) replicas: %s", d.Id(), err) - } - } - - if err := waitForDynamoDbTableToBeActive(d.Id(), d.Timeout(schema.TimeoutCreate), conn); err != nil { - return err - } - - return resourceAwsDynamoDbTable2019Read(d, meta) -} - -func createDynamoDbReplicas(tableName string, replicas []interface{}, conn *dynamodb.DynamoDB) error { - for _, replica := range replicas { - var ops []*dynamodb.ReplicationGroupUpdate - if regionName, ok := replica.(map[string]interface{})["region_name"]; ok { - ops = append(ops, &dynamodb.ReplicationGroupUpdate{ - Create: &dynamodb.CreateReplicationGroupMemberAction{ - RegionName: aws.String(regionName.(string)), - }, - }) - - input := &dynamodb.UpdateTableInput{ - TableName: aws.String(tableName), - ReplicaUpdates: ops, - } - - log.Printf("[DEBUG] Updating DynamoDB Replicas to %v", input) - - err := resource.Retry(20*time.Minute, func() *resource.RetryError { - _, err := conn.UpdateTable(input) - if err != nil { - if isAWSErr(err, "ThrottlingException", "") { - return resource.RetryableError(err) - } - if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "can be created, updated, or deleted simultaneously") { - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) - } - return nil - }) - if isResourceTimeoutError(err) { - _, err = conn.UpdateTable(input) - } - if err != nil { - return fmt.Errorf("Error updating DynamoDB Replicas status: %s", err) - } - - if err := waitForDynamoDbReplicaUpdateToBeCompleted(tableName, regionName.(string), 20*time.Minute, conn); err != nil { - return fmt.Errorf("Error waiting for DynamoDB replica update: %s", err) - } - } - } - return nil -} - -func deleteDynamoDbReplicas(tableName string, replicas []interface{}, conn *dynamodb.DynamoDB) error { - for _, replica := range replicas { - var ops []*dynamodb.ReplicationGroupUpdate - if regionName, ok := replica.(map[string]interface{})["region_name"]; ok { - ops = append(ops, &dynamodb.ReplicationGroupUpdate{ - Delete: &dynamodb.DeleteReplicationGroupMemberAction{ - RegionName: aws.String(regionName.(string)), - }, - }) - - input := &dynamodb.UpdateTableInput{ - TableName: aws.String(tableName), - ReplicaUpdates: ops, - } - - log.Printf("[DEBUG] Deleting DynamoDB Replicas to %v", input) - - err := resource.Retry(20*time.Minute, func() *resource.RetryError { - _, err := conn.UpdateTable(input) - if err != nil { - if isAWSErr(err, "ThrottlingException", "") { - return resource.RetryableError(err) - } - if isAWSErr(err, dynamodb.ErrCodeLimitExceededException, "can be created, updated, or deleted simultaneously") { - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) - } - return nil - }) - if isResourceTimeoutError(err) { - _, err = conn.UpdateTable(input) - } - if err != nil { - return fmt.Errorf("Error deleting DynamoDB Replicas status: %s", err) - } - - if err := waitForDynamoDbReplicaDeleteToBeCompleted(tableName, regionName.(string), 20*time.Minute, conn); err != nil { - return fmt.Errorf("Error waiting for DynamoDB replica delete: %s", err) - } - } - } - return nil -} - -func resourceAwsDynamoDbTable2019Update(d *schema.ResourceData, meta interface{}) error { - err := resourceAwsDynamoDbTableUpdate(d, meta) - if err != nil { - return fmt.Errorf("error updating DynamoDB Table (%s) %s", d.Id(), err) - } - - conn := meta.(*AWSClient).dynamodbconn - - if d.HasChange("replica") { - var replicaUpdates []*dynamodb.ReplicationGroupUpdate - o, n := d.GetChange("replica") - - replicaUpdates, _ = diffDynamoDbReplicas(o.([]interface{}), n.([]interface{})) - log.Printf("[DEBUG] replica updates %s", replicaUpdates) - for _, replicaUpdate := range replicaUpdates { - var ops []*dynamodb.ReplicationGroupUpdate - ops = append(ops, replicaUpdate) - - replicaInput := &dynamodb.UpdateTableInput{ - TableName: aws.String(d.Id()), - ReplicaUpdates: ops, - } - replicaInput.ReplicaUpdates = replicaUpdates - _, replicaErr := conn.UpdateTable(replicaInput) - if replicaErr == nil { - if replicaUpdate.Delete == nil { - log.Printf("[DEBUG] waiting for replica to be updated") - err = waitForDynamoDbReplicaUpdateToBeCompleted(d.Id(), aws.StringValue(replicaUpdate.Update.RegionName), 20*time.Minute, conn) - if err != nil { - return fmt.Errorf("error waiting for DynamoDB Table Replicas to update (%s): %s", d.Id(), err) - } - } else { - log.Printf("[DEBUG] waiting for replica to be deleted") - err = waitForDynamoDbReplicaDeleteToBeCompleted(d.Id(), aws.StringValue(replicaUpdate.Delete.RegionName), 20*time.Minute, conn) - if err != nil { - return fmt.Errorf("error waiting for DynamoDB Table Replicas to delete (%s): %s", d.Id(), err) - } - } - } else { - return fmt.Errorf("error updating DynamoDB Table (%s): %s", d.Id(), replicaErr) - } - } - } - - return resourceAwsDynamoDbTable2019Read(d, meta) -} - -func resourceAwsDynamoDbTable2019Read(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).dynamodbconn - - result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ - TableName: aws.String(d.Id()), - }) - - if err != nil { - if isAWSErr(err, dynamodb.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] Dynamodb Table (%s) not found, error code (404)", d.Id()) - d.SetId("") - return nil - } - return err - } - - err = flattenAwsDynamoDbTableResource_2019(d, result.Table) - if err != nil { - return err - } - - ttlOut, err := conn.DescribeTimeToLive(&dynamodb.DescribeTimeToLiveInput{ - TableName: aws.String(d.Id()), - }) - if err != nil { - return fmt.Errorf("error describing DynamoDB Table (%s) Time to Live: %s", d.Id(), err) - } - if err := d.Set("ttl", flattenDynamoDbTtl(ttlOut)); err != nil { - return fmt.Errorf("error setting ttl: %s", err) - } - - tags, err := readDynamoDbTableTags(d.Get("arn").(string), conn) - if err != nil { - return err - } - - d.Set("tags", tags) - - pitrOut, err := conn.DescribeContinuousBackups(&dynamodb.DescribeContinuousBackupsInput{ - TableName: aws.String(d.Id()), - }) - if err != nil && !isAWSErr(err, "UnknownOperationException", "") { - return err - } - d.Set("point_in_time_recovery", flattenDynamoDbPitr(pitrOut)) - - return nil -} - -func resourceAwsDynamoDbTable2019Delete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).dynamodbconn - - log.Printf("[DEBUG] DynamoDB delete table: %s", d.Id()) - - input := &dynamodb.DescribeTableInput{ - TableName: aws.String(d.Id()), - } - - output, err := conn.DescribeTable(input) - log.Printf("[DEBUG] DynamoDB delete describe: %s", output) - if err != nil { - return fmt.Errorf("error describing DynamoDB Table (%s): %s", d.Id(), err) - } - - if len(output.Table.Replicas) > 0 { - if err := deleteDynamoDbReplicas(d.Id(), d.Get("replica").([]interface{}), conn); err != nil { - return fmt.Errorf("error deleting DynamoDB Table (%s) replicas: %s", d.Id(), err) - } - } - - err = deleteAwsDynamoDbTable(d.Id(), conn) - if err != nil { - if isAWSErr(err, dynamodb.ErrCodeResourceNotFoundException, "Requested resource not found: Table: ") { - return nil - } - return fmt.Errorf("error deleting DynamoDB Table (%s): %s", d.Id(), err) - } - - if err := waitForDynamodbTableDeletion(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("error waiting for DynamoDB Table (%s) deletion: %s", d.Id(), err) - } - - return nil -} - -func waitForDynamoDbReplicaUpdateToBeCompleted(tableName string, region string, timeout time.Duration, conn *dynamodb.DynamoDB) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{ - dynamodb.ReplicaStatusCreating, - dynamodb.ReplicaStatusUpdating, - dynamodb.ReplicaStatusDeleting, - }, - Target: []string{ - dynamodb.ReplicaStatusActive, - }, - Timeout: timeout, - Refresh: func() (interface{}, string, error) { - result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ - TableName: aws.String(tableName), - }) - if err != nil { - return 42, "", err - } - log.Printf("[DEBUG] DynamoDB replicas: %s", result.Table.Replicas) - - if len(result.Table.Replicas) == 0 { - return result, dynamodb.ReplicaStatusCreating, nil - } - // Find replica - var targetReplica *dynamodb.ReplicaDescription - for _, replica := range result.Table.Replicas { - if *replica.RegionName == region { - targetReplica = replica - } - } - - if targetReplica == nil { - return nil, "", nil - } - - return result, aws.StringValue(targetReplica.ReplicaStatus), nil - }, - } - _, err := stateConf.WaitForState() - - return err -} - -func waitForDynamoDbReplicaDeleteToBeCompleted(tableName string, region string, timeout time.Duration, conn *dynamodb.DynamoDB) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{ - dynamodb.ReplicaStatusCreating, - dynamodb.ReplicaStatusUpdating, - dynamodb.ReplicaStatusDeleting, - dynamodb.ReplicaStatusActive, - }, - Target: []string{}, - Timeout: timeout, - Refresh: func() (interface{}, string, error) { - result, err := conn.DescribeTable(&dynamodb.DescribeTableInput{ - TableName: aws.String(tableName), - }) - if err != nil { - return 42, "", err - } - - log.Printf("[DEBUG] all replicas for waiting: %s", result.Table.Replicas) - if len(result.Table.Replicas) == 0 { - return result, "", nil - } - - // Find replica - var targetReplica *dynamodb.ReplicaDescription - for _, replica := range result.Table.Replicas { - if *replica.RegionName == region { - targetReplica = replica - } - } - log.Printf("[DEBUG] targetReplica: %s", targetReplica) - - if targetReplica == nil { - return result, "", nil - } - - return result, aws.StringValue(targetReplica.ReplicaStatus), nil - }, - } - _, err := stateConf.WaitForState() - - return err -} diff --git a/aws/resource_aws_dynamodb_table_2019_test.go b/aws/resource_aws_dynamodb_table_2019_test.go deleted file mode 100644 index 216364744fd..00000000000 --- a/aws/resource_aws_dynamodb_table_2019_test.go +++ /dev/null @@ -1,129 +0,0 @@ -package aws - -import ( - "fmt" - "log" - "testing" - - "github.com/aws/aws-sdk-go/service/dynamodb" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" -) - -func init() { - resource.AddTestSweepers("aws_dynamodb_table_2019", &resource.Sweeper{ - Name: "aws_dynamodb_table_2019", - F: testSweepDynamoDbTables2019, - }) -} - -func testSweepDynamoDbTables2019(region string) error { - client, err := sharedClientForRegion(region) - if err != nil { - return fmt.Errorf("error getting client: %s", err) - } - conn := client.(*AWSClient).dynamodbconn - - err = conn.ListTablesPages(&dynamodb.ListTablesInput{}, func(out *dynamodb.ListTablesOutput, lastPage bool) bool { - for _, tableName := range out.TableNames { - log.Printf("[INFO] Deleting DynamoDB Table: %s", *tableName) - - err := deleteAwsDynamoDbTable(*tableName, conn) - if err != nil { - log.Printf("[ERROR] Failed to delete DynamoDB Table %s: %s", *tableName, err) - continue - } - } - return !lastPage - }) - if err != nil { - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping DynamoDB Table sweep for %s: %s", region, err) - return nil - } - return fmt.Errorf("Error retrieving DynamoDB Tables: %s", err) - } - - return nil -} - -func TestAccAWSDynamoDbTable2019_basic(t *testing.T) { - var conf dynamodb.DescribeTableOutput - resourceName := "aws_dynamodb_table_2019.test" - tableName := acctest.RandomWithPrefix("TerraformTestTable2019-") - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSDynamoDbTableDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSDynamoDbReplicaUpdates(tableName), - Check: resource.ComposeTestCheckFunc( - testAccCheckInitialAWSDynamoDbTableExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "name", tableName), - resource.TestCheckResourceAttr(resourceName, "hash_key", "TestTableHashKey"), - resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.name", "TestTableHashKey"), - resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.type", "S"), - resource.TestCheckResourceAttr(resourceName, "replica.#", "1"), - resource.TestCheckResourceAttr(resourceName, "replica.0.region_name", "us-west-1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccAWSDynamoDbReplicaDeletes(tableName), - Check: resource.ComposeTestCheckFunc( - testAccCheckInitialAWSDynamoDbTableExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "name", tableName), - resource.TestCheckResourceAttr(resourceName, "hash_key", "TestTableHashKey"), - resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.name", "TestTableHashKey"), - resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.type", "S"), - resource.TestCheckResourceAttr(resourceName, "hash_key", "TestTableHashKey"), - resource.TestCheckResourceAttr(resourceName, "replica.#", "0"), - ), - }, - }, - }) -} - -func testAccAWSDynamoDbReplicaUpdates(rName string) string { - return fmt.Sprintf(` -resource "aws_dynamodb_table_2019" "test" { - name = "%s" - hash_key = "TestTableHashKey" - billing_mode = "PAY_PER_REQUEST" - stream_enabled = true - stream_view_type = "NEW_AND_OLD_IMAGES" - - attribute { - name = "TestTableHashKey" - type = "S" - } - - replica { - region_name = "us-west-1" - } -} -`, rName) -} - -func testAccAWSDynamoDbReplicaDeletes(rName string) string { - return fmt.Sprintf(` -resource "aws_dynamodb_table_2019" "test" { - name = "%s" - hash_key = "TestTableHashKey" - billing_mode = "PAY_PER_REQUEST" - stream_enabled = true - stream_view_type = "NEW_AND_OLD_IMAGES" - - attribute { - name = "TestTableHashKey" - type = "S" - } -} -`, rName) -} diff --git a/aws/resource_aws_dynamodb_table_test.go b/aws/resource_aws_dynamodb_table_test.go index 21b37ad009e..d7c7627f5ef 100644 --- a/aws/resource_aws_dynamodb_table_test.go +++ b/aws/resource_aws_dynamodb_table_test.go @@ -1382,6 +1382,87 @@ func testAccCheckAWSDynamoDbTableDisappears(table *dynamodb.DescribeTableOutput) } } +func TestAccAWSDynamoDbTable2019_basic(t *testing.T) { + var conf dynamodb.DescribeTableOutput + resourceName := "aws_dynamodb_table.test" + tableName := acctest.RandomWithPrefix("TerraformTestTable-") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDynamoDbTableDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDynamoDbReplicaUpdates(tableName), + Check: resource.ComposeTestCheckFunc( + testAccCheckInitialAWSDynamoDbTableExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "name", tableName), + resource.TestCheckResourceAttr(resourceName, "hash_key", "TestTableHashKey"), + resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.name", "TestTableHashKey"), + resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.type", "S"), + resource.TestCheckResourceAttr(resourceName, "replica.#", "1"), + resource.TestCheckResourceAttr(resourceName, "replica.0.region_name", "us-west-1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSDynamoDbReplicaDeletes(tableName), + Check: resource.ComposeTestCheckFunc( + testAccCheckInitialAWSDynamoDbTableExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "name", tableName), + resource.TestCheckResourceAttr(resourceName, "hash_key", "TestTableHashKey"), + resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.name", "TestTableHashKey"), + resource.TestCheckResourceAttr(resourceName, "attribute.2990477658.type", "S"), + resource.TestCheckResourceAttr(resourceName, "hash_key", "TestTableHashKey"), + resource.TestCheckResourceAttr(resourceName, "replica.#", "0"), + ), + }, + }, + }) +} + +func testAccAWSDynamoDbReplicaUpdates(rName string) string { + return fmt.Sprintf(` +resource "aws_dynamodb_table" "test" { + name = "%s" + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = "us-west-1" + } +} +`, rName) +} + +func testAccAWSDynamoDbReplicaDeletes(rName string) string { + return fmt.Sprintf(` +resource "aws_dynamodb_table" "test" { + name = "%s" + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } +} +`, rName) +} + func dynamoDbGetGSIIndex(gsiList *[]*dynamodb.GlobalSecondaryIndexDescription, target string) int { for idx, gsiObject := range *gsiList { if *gsiObject.IndexName == target { diff --git a/aws/structure.go b/aws/structure.go index c2112cd7459..a4d2146993a 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -4357,29 +4357,6 @@ func flattenDynamoDbPitr(pitrDesc *dynamodb.DescribeContinuousBackupsOutput) []i return []interface{}{m} } -func flattenAwsDynamoDbTableResource_2019(d *schema.ResourceData, table *dynamodb.TableDescription) error { - err := flattenAwsDynamoDbTableResource(d, table) - if err != nil { - return err - } - - replicaList := make([]map[string]interface{}, 0, len(table.Replicas)) - for _, replicaObject := range table.Replicas { - replica := map[string]interface{}{ - "region_name": aws.StringValue(replicaObject.RegionName), - } - - replicaList = append(replicaList, replica) - } - - err = d.Set("replica", replicaList) - if err != nil { - return err - } - - return nil -} - func flattenAwsDynamoDbTableResource(d *schema.ResourceData, table *dynamodb.TableDescription) error { d.Set("billing_mode", dynamodb.BillingModeProvisioned) if table.BillingModeSummary != nil { @@ -4495,6 +4472,20 @@ func flattenAwsDynamoDbTableResource(d *schema.ResourceData, table *dynamodb.Tab return err } + replicaList := make([]map[string]interface{}, 0, len(table.Replicas)) + for _, replicaObject := range table.Replicas { + replica := map[string]interface{}{ + "region_name": aws.StringValue(replicaObject.RegionName), + } + + replicaList = append(replicaList, replica) + } + + err = d.Set("replica", replicaList) + if err != nil { + return err + } + d.Set("arn", table.TableArn) return nil From 0082f7e22c848600649089028c4bddeba4fbb18d Mon Sep 17 00:00:00 2001 From: Daniel Linhart Date: Wed, 18 Mar 2020 16:07:02 +0100 Subject: [PATCH 057/684] Moved VPC SGs from ModifyDB to RestoreDB API Call --- aws/resource_aws_db_instance.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index 8cdfef1f3e2..98dc765ba29 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -1008,8 +1008,11 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error } if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { - modifyDbInstanceInput.VpcSecurityGroupIds = expandStringSet(attr) - requiresModifyDbInstance = true + var s []*string + for _, v := range attr.List() { + s = append(s, aws.String(v.(string))) + } + opts.VpcSecurityGroupIds = s } if attr, ok := d.GetOk("performance_insights_enabled"); ok { From c75a5895ff33efb237c016146b952d0aad2cab4d Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 19 Mar 2020 02:19:12 -0400 Subject: [PATCH 058/684] service/neptune: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_neptune_cluster.go:597:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_cluster.go:684:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_cluster_instance.go:384:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_cluster_instance.go:390:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_cluster_instance.go:396:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_cluster_instance.go:402:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_cluster_instance.go:451:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_cluster_parameter_group.go:185:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_neptune_cluster_parameter_group.go:226:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_cluster_parameter_group.go:237:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_cluster_parameter_group.go:240:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_neptune_event_subscription.go:209:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_neptune_event_subscription.go:265:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_event_subscription.go:266:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_event_subscription.go:267:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_event_subscription.go:268:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_event_subscription.go:278:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_event_subscription.go:320:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_event_subscription.go:323:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_neptune_parameter_group.go:100:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_neptune_parameter_group.go:101:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_parameter_group.go:102:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_parameter_group.go:103:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_parameter_group.go:104:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_neptune_parameter_group.go:181:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_neptune_parameter_group.go:259:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_parameter_group.go:269:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_neptune_parameter_group.go:272:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_neptune_subnet_group.go:195:3: R008: deprecated (schema.ResourceData).SetPartial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSNeptuneCluster_backupsUpdate (297.92s) --- PASS: TestAccAWSNeptuneCluster_basic (168.78s) --- PASS: TestAccAWSNeptuneCluster_deleteProtection (212.60s) --- PASS: TestAccAWSNeptuneCluster_encrypted (175.61s) --- PASS: TestAccAWSNeptuneCluster_iamAuth (193.62s) --- PASS: TestAccAWSNeptuneCluster_kmsKey (195.57s) --- PASS: TestAccAWSNeptuneCluster_namePrefix (154.44s) --- PASS: TestAccAWSNeptuneCluster_tags (209.12s) --- PASS: TestAccAWSNeptuneCluster_takeFinalSnapshot (254.53s) --- PASS: TestAccAWSNeptuneCluster_updateCloudwatchLogsExports (233.15s) --- PASS: TestAccAWSNeptuneCluster_updateIamRoles (195.20s) --- PASS: TestAccAWSNeptuneClusterInstance_basic (1755.23s) --- PASS: TestAccAWSNeptuneClusterInstance_generatedName (785.56s) --- PASS: TestAccAWSNeptuneClusterInstance_kmsKey (835.57s) --- PASS: TestAccAWSNeptuneClusterInstance_namePrefix (807.49s) --- PASS: TestAccAWSNeptuneClusterInstance_withaz (925.05s) --- PASS: TestAccAWSNeptuneClusterInstance_withSubnetGroup (783.88s) --- PASS: TestAccAWSNeptuneClusterParameterGroup_basic (17.40s) --- PASS: TestAccAWSNeptuneClusterParameterGroup_Description (17.46s) --- PASS: TestAccAWSNeptuneClusterParameterGroup_generatedName (17.68s) --- PASS: TestAccAWSNeptuneClusterParameterGroup_namePrefix (20.77s) --- PASS: TestAccAWSNeptuneClusterParameterGroup_Parameter (31.24s) --- PASS: TestAccAWSNeptuneClusterParameterGroup_Tags (64.82s) --- PASS: TestAccAWSNeptuneEventSubscription_basic (150.00s) --- PASS: TestAccAWSNeptuneEventSubscription_withCategories (124.64s) --- PASS: TestAccAWSNeptuneEventSubscription_withPrefix (123.58s) --- PASS: TestAccAWSNeptuneEventSubscription_withSourceIds (97.81s) --- PASS: TestAccAWSNeptuneParameterGroup_basic (28.51s) --- PASS: TestAccAWSNeptuneParameterGroup_Description (22.30s) --- PASS: TestAccAWSNeptuneParameterGroup_Parameter (114.91s) --- PASS: TestAccAWSNeptuneParameterGroup_Tags (60.91s) --- PASS: TestAccAWSNeptuneSubnetGroup_basic (46.02s) --- PASS: TestAccAWSNeptuneSubnetGroup_generatedName (49.96s) --- PASS: TestAccAWSNeptuneSubnetGroup_namePrefix (48.39s) --- PASS: TestAccAWSNeptuneSubnetGroup_updateDescription (76.13s) ``` --- aws/resource_aws_neptune_cluster.go | 2 -- aws/resource_aws_neptune_cluster_instance.go | 6 ------ ...resource_aws_neptune_cluster_parameter_group.go | 7 ------- aws/resource_aws_neptune_event_subscription.go | 10 ---------- aws/resource_aws_neptune_parameter_group.go | 14 -------------- aws/resource_aws_neptune_subnet_group.go | 2 -- 6 files changed, 41 deletions(-) diff --git a/aws/resource_aws_neptune_cluster.go b/aws/resource_aws_neptune_cluster.go index 4283fe4e548..59d960501b5 100644 --- a/aws/resource_aws_neptune_cluster.go +++ b/aws/resource_aws_neptune_cluster.go @@ -594,7 +594,6 @@ func resourceAwsNeptuneClusterUpdate(d *schema.ResourceData, meta interface{}) e } if d.HasChange("neptune_cluster_parameter_group_name") { - d.SetPartial("neptune_cluster_parameter_group_name") req.DBClusterParameterGroupName = aws.String(d.Get("neptune_cluster_parameter_group_name").(string)) requestUpdate = true } @@ -681,7 +680,6 @@ func resourceAwsNeptuneClusterUpdate(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("error updating Neptune Cluster (%s) tags: %s", d.Get("arn").(string), err) } - d.SetPartial("tags") } return resourceAwsNeptuneClusterRead(d, meta) diff --git a/aws/resource_aws_neptune_cluster_instance.go b/aws/resource_aws_neptune_cluster_instance.go index 0db3d20cc49..5cb9484c725 100644 --- a/aws/resource_aws_neptune_cluster_instance.go +++ b/aws/resource_aws_neptune_cluster_instance.go @@ -381,25 +381,21 @@ func resourceAwsNeptuneClusterInstanceUpdate(d *schema.ResourceData, meta interf } if d.HasChange("preferred_backup_window") { - d.SetPartial("preferred_backup_window") req.PreferredBackupWindow = aws.String(d.Get("preferred_backup_window").(string)) requestUpdate = true } if d.HasChange("preferred_maintenance_window") { - d.SetPartial("preferred_maintenance_window") req.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintenance_window").(string)) requestUpdate = true } if d.HasChange("auto_minor_version_upgrade") { - d.SetPartial("auto_minor_version_upgrade") req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) requestUpdate = true } if d.HasChange("promotion_tier") { - d.SetPartial("promotion_tier") req.PromotionTier = aws.Int64(int64(d.Get("promotion_tier").(int))) requestUpdate = true } @@ -447,8 +443,6 @@ func resourceAwsNeptuneClusterInstanceUpdate(d *schema.ResourceData, meta interf if err := keyvaluetags.NeptuneUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Neptune Cluster Instance (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } return resourceAwsNeptuneClusterInstanceRead(d, meta) diff --git a/aws/resource_aws_neptune_cluster_parameter_group.go b/aws/resource_aws_neptune_cluster_parameter_group.go index bc03251088e..a67f741c2a5 100644 --- a/aws/resource_aws_neptune_cluster_parameter_group.go +++ b/aws/resource_aws_neptune_cluster_parameter_group.go @@ -182,8 +182,6 @@ func resourceAwsNeptuneClusterParameterGroupRead(d *schema.ResourceData, meta in func resourceAwsNeptuneClusterParameterGroupUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).neptuneconn - d.Partial(true) - if d.HasChange("parameter") { o, n := d.GetChange("parameter") if o == nil { @@ -223,7 +221,6 @@ func resourceAwsNeptuneClusterParameterGroupUpdate(d *schema.ResourceData, meta return fmt.Errorf("Error modifying Neptune Cluster Parameter Group: %s", err) } } - d.SetPartial("parameter") } } @@ -233,12 +230,8 @@ func resourceAwsNeptuneClusterParameterGroupUpdate(d *schema.ResourceData, meta if err := keyvaluetags.NeptuneUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Neptune Cluster Parameter Group (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } - d.Partial(false) - return resourceAwsNeptuneClusterParameterGroupRead(d, meta) } diff --git a/aws/resource_aws_neptune_event_subscription.go b/aws/resource_aws_neptune_event_subscription.go index 2a1723acfd5..4a3d3b66367 100644 --- a/aws/resource_aws_neptune_event_subscription.go +++ b/aws/resource_aws_neptune_event_subscription.go @@ -206,7 +206,6 @@ func resourceAwsNeptuneEventSubscriptionRead(d *schema.ResourceData, meta interf func resourceAwsNeptuneEventSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).neptuneconn - d.Partial(true) requestUpdate := false req := &neptune.ModifyEventSubscriptionInput{ @@ -262,10 +261,6 @@ func resourceAwsNeptuneEventSubscriptionUpdate(d *schema.ResourceData, meta inte if err != nil { return err } - d.SetPartial("event_categories") - d.SetPartial("enabled") - d.SetPartial("sns_topic_arn") - d.SetPartial("source_type") } if d.HasChange("tags") { @@ -274,8 +269,6 @@ func resourceAwsNeptuneEventSubscriptionUpdate(d *schema.ResourceData, meta inte if err := keyvaluetags.NeptuneUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Neptune Cluster Event Subscription (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } if d.HasChange("source_ids") { @@ -317,11 +310,8 @@ func resourceAwsNeptuneEventSubscriptionUpdate(d *schema.ResourceData, meta inte } } } - d.SetPartial("source_ids") } - d.Partial(false) - return resourceAwsNeptuneEventSubscriptionRead(d, meta) } diff --git a/aws/resource_aws_neptune_parameter_group.go b/aws/resource_aws_neptune_parameter_group.go index 3274658a3bf..117312f0907 100644 --- a/aws/resource_aws_neptune_parameter_group.go +++ b/aws/resource_aws_neptune_parameter_group.go @@ -97,12 +97,6 @@ func resourceAwsNeptuneParameterGroupCreate(d *schema.ResourceData, meta interfa return fmt.Errorf("Error creating Neptune Parameter Group: %s", err) } - d.Partial(true) - d.SetPartial("name") - d.SetPartial("family") - d.SetPartial("description") - d.Partial(false) - d.SetId(*resp.DBParameterGroup.DBParameterGroupName) d.Set("arn", resp.DBParameterGroup.DBParameterGroupArn) log.Printf("[INFO] Neptune Parameter Group ID: %s", d.Id()) @@ -178,8 +172,6 @@ func resourceAwsNeptuneParameterGroupRead(d *schema.ResourceData, meta interface func resourceAwsNeptuneParameterGroupUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).neptuneconn - d.Partial(true) - if d.HasChange("parameter") { o, n := d.GetChange("parameter") if o == nil { @@ -255,8 +247,6 @@ func resourceAwsNeptuneParameterGroupUpdate(d *schema.ResourceData, meta interfa return fmt.Errorf("Error modifying Neptune Parameter Group: %s", err) } } - - d.SetPartial("parameter") } if !d.IsNewResource() && d.HasChange("tags") { @@ -265,12 +255,8 @@ func resourceAwsNeptuneParameterGroupUpdate(d *schema.ResourceData, meta interfa if err := keyvaluetags.NeptuneUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Neptune Parameter Group (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } - d.Partial(false) - return resourceAwsNeptuneParameterGroupRead(d, meta) } diff --git a/aws/resource_aws_neptune_subnet_group.go b/aws/resource_aws_neptune_subnet_group.go index 9f0d19dde5c..a3faef9f38e 100644 --- a/aws/resource_aws_neptune_subnet_group.go +++ b/aws/resource_aws_neptune_subnet_group.go @@ -191,8 +191,6 @@ func resourceAwsNeptuneSubnetGroupUpdate(d *schema.ResourceData, meta interface{ if err := keyvaluetags.NeptuneUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Neptune Subnet Group (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } return resourceAwsNeptuneSubnetGroupRead(d, meta) From 9f43805807eafbfba7646f3282f8abcfa553a06f Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 19 Mar 2020 04:49:08 -0400 Subject: [PATCH 059/684] resource/aws_iam_instance_profile: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_iam_instance_profile.go:200:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_iam_instance_profile.go:209:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_iam_instance_profile.go:219:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_iam_instance_profile.go:222:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_iam_instance_profile.go:249:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_iam_instance_profile.go:268:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_iam_instance_profile.go:275:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSIAMInstanceProfile_withoutRole (13.88s) --- PASS: TestAccAWSIAMInstanceProfile_basic (14.58s) --- PASS: TestAccAWSIAMInstanceProfile_withRoleNotRoles (14.64s) --- PASS: TestAccAWSIAMInstanceProfile_namePrefix (14.70s) ``` --- aws/resource_aws_iam_instance_profile.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/aws/resource_aws_iam_instance_profile.go b/aws/resource_aws_iam_instance_profile.go index 1dbd2ebe371..af183db58f4 100644 --- a/aws/resource_aws_iam_instance_profile.go +++ b/aws/resource_aws_iam_instance_profile.go @@ -197,8 +197,6 @@ func instanceProfileSetRoles(d *schema.ResourceData, iamconn *iam.IAM) error { currentRoles := schema.CopySet(oldRoles) - d.Partial(true) - for _, role := range oldRoles.Difference(newRoles).List() { err := instanceProfileRemoveRole(iamconn, d.Id(), role.(string)) if err != nil { @@ -206,7 +204,6 @@ func instanceProfileSetRoles(d *schema.ResourceData, iamconn *iam.IAM) error { } currentRoles.Remove(role) d.Set("roles", currentRoles) - d.SetPartial("roles") } for _, role := range newRoles.Difference(oldRoles).List() { @@ -216,11 +213,8 @@ func instanceProfileSetRoles(d *schema.ResourceData, iamconn *iam.IAM) error { } currentRoles.Add(role) d.Set("roles", currentRoles) - d.SetPartial("roles") } - d.Partial(false) - return nil } @@ -246,8 +240,6 @@ func instanceProfileRemoveAllRoles(d *schema.ResourceData, iamconn *iam.IAM) err func resourceAwsIamInstanceProfileUpdate(d *schema.ResourceData, meta interface{}) error { iamconn := meta.(*AWSClient).iamconn - d.Partial(true) - if d.HasChange("role") { oldRole, newRole := d.GetChange("role") @@ -264,16 +256,12 @@ func resourceAwsIamInstanceProfileUpdate(d *schema.ResourceData, meta interface{ return fmt.Errorf("Error adding role %s to IAM instance profile %s: %s", newRole.(string), d.Id(), err) } } - - d.SetPartial("role") } if d.HasChange("roles") { return instanceProfileSetRoles(d, iamconn) } - d.Partial(false) - return nil } From a2373c1b81023e2b3c329905bb0f409c6d63c540 Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Thu, 19 Mar 2020 15:50:16 +0000 Subject: [PATCH 060/684] Cleanup after v2.54.0 release --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 524758f5b53..cbaa62a8afe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +## 2.55.0 (Unreleased) ## 2.54.0 (March 19, 2020) FEATURES: From 2c724d929f400f2fb39d91662727eec5be9b7cdf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 18 Mar 2020 18:39:39 -0400 Subject: [PATCH 061/684] r/aws_apigatewayv2_api: Add CORS configuration and quick start attributes. --- aws/resource_aws_apigatewayv2_api.go | 139 ++++++++- aws/resource_aws_apigatewayv2_api_test.go | 289 ++++++++++++++++++ aws/structure.go | 11 + website/docs/r/apigatewayv2_api.html.markdown | 15 + 4 files changed, 453 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_apigatewayv2_api.go b/aws/resource_aws_apigatewayv2_api.go index 995997f9036..415f1b144a8 100644 --- a/aws/resource_aws_apigatewayv2_api.go +++ b/aws/resource_aws_apigatewayv2_api.go @@ -40,6 +40,53 @@ func resourceAwsApiGatewayV2Api() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "cors_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allow_credentials": { + Type: schema.TypeBool, + Optional: true, + }, + "allow_headers": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: hashStringCaseInsensitive, + }, + "allow_methods": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: hashStringCaseInsensitive, + }, + "allow_origins": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: hashStringCaseInsensitive, + }, + "expose_headers": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: hashStringCaseInsensitive, + }, + "max_age": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + "credentials_arn": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validateArn, + }, "description": { Type: schema.TypeString, Optional: true, @@ -63,12 +110,22 @@ func resourceAwsApiGatewayV2Api() *schema.Resource { apigatewayv2.ProtocolTypeWebsocket, }, false), }, + "route_key": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, "route_selection_expression": { Type: schema.TypeString, Optional: true, Default: "$request.method $request.path", }, "tags": tagsSchema(), + "target": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, "version": { Type: schema.TypeString, Optional: true, @@ -90,12 +147,24 @@ func resourceAwsApiGatewayV2ApiCreate(d *schema.ResourceData, meta interface{}) if v, ok := d.GetOk("api_key_selection_expression"); ok { req.ApiKeySelectionExpression = aws.String(v.(string)) } + if v, ok := d.GetOk("cors_configuration"); ok { + req.CorsConfiguration = expandApiGateway2CorsConfiguration(v.([]interface{})) + } + if v, ok := d.GetOk("credentials_arn"); ok { + req.CredentialsArn = aws.String(v.(string)) + } if v, ok := d.GetOk("description"); ok { req.Description = aws.String(v.(string)) } + if v, ok := d.GetOk("route_key"); ok { + req.RouteKey = aws.String(v.(string)) + } if v, ok := d.GetOk("route_selection_expression"); ok { req.RouteSelectionExpression = aws.String(v.(string)) } + if v, ok := d.GetOk("target"); ok { + req.Target = aws.String(v.(string)) + } if v, ok := d.GetOk("version"); ok { req.Version = aws.String(v.(string)) } @@ -135,6 +204,9 @@ func resourceAwsApiGatewayV2ApiRead(d *schema.ResourceData, meta interface{}) er Resource: fmt.Sprintf("/apis/%s", d.Id()), }.String() d.Set("arn", apiArn) + if err := d.Set("cors_configuration", flattenApiGateway2CorsConfiguration(resp.CorsConfiguration)); err != nil { + return fmt.Errorf("error setting cors_configuration: %s", err) + } d.Set("description", resp.Description) executionArn := arn.ARN{ Partition: meta.(*AWSClient).partition, @@ -158,7 +230,24 @@ func resourceAwsApiGatewayV2ApiRead(d *schema.ResourceData, meta interface{}) er func resourceAwsApiGatewayV2ApiUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn - if d.HasChanges("api_key_selection_expression", "description", "name", "route_selection_expression", "version") { + deleteCorsConfiguration := false + if d.HasChange("cors_configuration") { + v := d.Get("cors_configuration") + if len(v.([]interface{})) == 0 { + deleteCorsConfiguration = true + + log.Printf("[DEBUG] Deleting CORS configuration for API Gateway v2 API (%s)", d.Id()) + _, err := conn.DeleteCorsConfiguration(&apigatewayv2.DeleteCorsConfigurationInput{ + ApiId: aws.String(d.Id()), + }) + if err != nil { + return fmt.Errorf("error deleting CORS configuration for API Gateway v2 API (%s): %s", d.Id(), err) + } + } + } + + if d.HasChanges("api_key_selection_expression", "description", "name", "route_selection_expression", "version") || + (d.HasChange("cors_configuration") && !deleteCorsConfiguration) { req := &apigatewayv2.UpdateApiInput{ ApiId: aws.String(d.Id()), } @@ -166,6 +255,9 @@ func resourceAwsApiGatewayV2ApiUpdate(d *schema.ResourceData, meta interface{}) if d.HasChange("api_key_selection_expression") { req.ApiKeySelectionExpression = aws.String(d.Get("api_key_selection_expression").(string)) } + if d.HasChange("cors_configuration") { + req.CorsConfiguration = expandApiGateway2CorsConfiguration(d.Get("cors_configuration").([]interface{})) + } if d.HasChange("description") { req.Description = aws.String(d.Get("description").(string)) } @@ -212,3 +304,48 @@ func resourceAwsApiGatewayV2ApiDelete(d *schema.ResourceData, meta interface{}) return nil } + +func expandApiGateway2CorsConfiguration(vConfiguration []interface{}) *apigatewayv2.Cors { + configuration := &apigatewayv2.Cors{} + + if len(vConfiguration) == 0 || vConfiguration[0] == nil { + return configuration + } + mConfiguration := vConfiguration[0].(map[string]interface{}) + + if vAllowCredentials, ok := mConfiguration["allow_credentials"].(bool); ok { + configuration.AllowCredentials = aws.Bool(vAllowCredentials) + } + if vAllowHeaders, ok := mConfiguration["allow_headers"].(*schema.Set); ok { + configuration.AllowHeaders = expandStringSet(vAllowHeaders) + } + if vAllowMethods, ok := mConfiguration["allow_methods"].(*schema.Set); ok { + configuration.AllowMethods = expandStringSet(vAllowMethods) + } + if vAllowOrigins, ok := mConfiguration["allow_origins"].(*schema.Set); ok { + configuration.AllowOrigins = expandStringSet(vAllowOrigins) + } + if vExposeHeaders, ok := mConfiguration["expose_headers"].(*schema.Set); ok { + configuration.ExposeHeaders = expandStringSet(vExposeHeaders) + } + if vMaxAge, ok := mConfiguration["max_age"].(int); ok { + configuration.MaxAge = aws.Int64(int64(vMaxAge)) + } + + return configuration +} + +func flattenApiGateway2CorsConfiguration(configuration *apigatewayv2.Cors) []interface{} { + if configuration == nil { + return []interface{}{} + } + + return []interface{}{map[string]interface{}{ + "allow_credentials": aws.BoolValue(configuration.AllowCredentials), + "allow_headers": flattenCaseInsensitiveStringSet(configuration.AllowHeaders), + "allow_methods": flattenCaseInsensitiveStringSet(configuration.AllowMethods), + "allow_origins": flattenCaseInsensitiveStringSet(configuration.AllowOrigins), + "expose_headers": flattenCaseInsensitiveStringSet(configuration.ExposeHeaders), + "max_age": int(aws.Int64Value(configuration.MaxAge)), + }} +} diff --git a/aws/resource_aws_apigatewayv2_api_test.go b/aws/resource_aws_apigatewayv2_api_test.go index d3de86eead7..9de345466e5 100644 --- a/aws/resource_aws_apigatewayv2_api_test.go +++ b/aws/resource_aws_apigatewayv2_api_test.go @@ -82,6 +82,7 @@ func TestAccAWSAPIGatewayV2Api_basicWebSocket(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/apis/.+`)), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", ""), testAccMatchResourceAttrRegionalARN(resourceName, "execution_arn", "execute-api", regexp.MustCompile(`.+`)), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -117,6 +118,7 @@ func TestAccAWSAPIGatewayV2Api_basicHttp(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/apis/.+`)), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", ""), testAccMatchResourceAttrRegionalARN(resourceName, "execution_arn", "execute-api", regexp.MustCompile(`.+`)), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -175,6 +177,7 @@ func TestAccAWSAPIGatewayV2Api_AllAttributesWebSocket(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$context.authorizer.usageIdentifierKey"), testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/apis/.+`)), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", "test description"), testAccMatchResourceAttrRegionalARN(resourceName, "execution_arn", "execute-api", regexp.MustCompile(`.+`)), resource.TestCheckResourceAttr(resourceName, "name", rName1), @@ -189,6 +192,7 @@ func TestAccAWSAPIGatewayV2Api_AllAttributesWebSocket(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSAPIGatewayV2ApiExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", ""), resource.TestCheckResourceAttr(resourceName, "name", rName1), resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeWebsocket), @@ -202,6 +206,7 @@ func TestAccAWSAPIGatewayV2Api_AllAttributesWebSocket(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSAPIGatewayV2ApiExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$context.authorizer.usageIdentifierKey"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", "test description"), resource.TestCheckResourceAttr(resourceName, "name", rName2), resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.body.service"), @@ -214,6 +219,7 @@ func TestAccAWSAPIGatewayV2Api_AllAttributesWebSocket(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSAPIGatewayV2ApiExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$context.authorizer.usageIdentifierKey"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", "test description"), resource.TestCheckResourceAttr(resourceName, "name", rName1), resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.body.service"), @@ -248,6 +254,7 @@ func TestAccAWSAPIGatewayV2Api_AllAttributesHttp(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/apis/.+`)), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", "test description"), testAccMatchResourceAttrRegionalARN(resourceName, "execution_arn", "execute-api", regexp.MustCompile(`.+`)), resource.TestCheckResourceAttr(resourceName, "name", rName1), @@ -262,6 +269,7 @@ func TestAccAWSAPIGatewayV2Api_AllAttributesHttp(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSAPIGatewayV2ApiExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", ""), resource.TestCheckResourceAttr(resourceName, "name", rName1), resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeHttp), @@ -275,6 +283,7 @@ func TestAccAWSAPIGatewayV2Api_AllAttributesHttp(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSAPIGatewayV2ApiExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", "test description"), resource.TestCheckResourceAttr(resourceName, "name", rName2), resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.method $request.path"), @@ -287,6 +296,7 @@ func TestAccAWSAPIGatewayV2Api_AllAttributesHttp(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSAPIGatewayV2ApiExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", "test description"), resource.TestCheckResourceAttr(resourceName, "name", rName1), resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.method $request.path"), @@ -320,6 +330,7 @@ func TestAccAWSAPIGatewayV2Api_Tags(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/apis/.+`)), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", ""), testAccMatchResourceAttrRegionalARN(resourceName, "execution_arn", "execute-api", regexp.MustCompile(`.+`)), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -341,6 +352,7 @@ func TestAccAWSAPIGatewayV2Api_Tags(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSAPIGatewayV2ApiExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", ""), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeWebsocket), @@ -353,6 +365,141 @@ func TestAccAWSAPIGatewayV2Api_Tags(t *testing.T) { }) } +func TestAccAWSAPIGatewayV2Api_CorsConfiguration(t *testing.T) { + var v apigatewayv2.GetApiOutput + resourceName := "aws_apigatewayv2_api.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGatewayV2ApiDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2ApiConfig_corsConfiguration(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayV2ApiExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"), + resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/apis/.+`)), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_credentials", "false"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_headers.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_headers.2053999599", "Authorization"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_methods.#", "2"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_methods.4248514160", "GET"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_methods.2928708052", "put"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_origins.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_origins.89023941", "https://www.example.com"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.expose_headers.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.max_age", "0"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + testAccMatchResourceAttrRegionalARN(resourceName, "execution_arn", "execute-api", regexp.MustCompile(`.+`)), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeHttp), + resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.method $request.path"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "version", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAPIGatewayV2ApiConfig_corsConfigurationUpdated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayV2ApiExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"), + resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/apis/.+`)), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_credentials", "true"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_headers.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_methods.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_methods.163128923", "*"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_origins.#", "2"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_origins.1868318776", "HTTP://WWW.EXAMPLE.ORG"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_origins.3551736600", "https://example.io"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.expose_headers.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.expose_headers.115091893", "X-Api-Id"), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.max_age", "500"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + testAccMatchResourceAttrRegionalARN(resourceName, "execution_arn", "execute-api", regexp.MustCompile(`.+`)), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeHttp), + resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.method $request.path"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "version", ""), + ), + }, + { + Config: testAccAWSAPIGatewayV2ApiConfig_basicHttp(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayV2ApiExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"), + resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/apis/.+`)), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + testAccMatchResourceAttrRegionalARN(resourceName, "execution_arn", "execute-api", regexp.MustCompile(`.+`)), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeHttp), + resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.method $request.path"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "version", ""), + ), + }, + }, + }) +} + +func TestAccAWSAPIGatewayV2Api_QuickCreate(t *testing.T) { + var v apigatewayv2.GetApiOutput + resourceName := "aws_apigatewayv2_api.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGatewayV2ApiDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2ApiConfig_quickCreate(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayV2ApiExists(resourceName, &v), + testAccCheckAWSAPIGatewayV2ApiQuickCreateIntegration(resourceName, "HTTP_PROXY", "http://www.example.com/"), + testAccCheckAWSAPIGatewayV2ApiQuickCreateRoute(resourceName, "GET /pets"), + testAccCheckAWSAPIGatewayV2ApiQuickCreateStage(resourceName, "$default"), + resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"), + resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/apis/.+`)), + resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "0"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + testAccMatchResourceAttrRegionalARN(resourceName, "execution_arn", "execute-api", regexp.MustCompile(`.+`)), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeHttp), + resource.TestCheckResourceAttr(resourceName, "route_key", "GET /pets"), + resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.method $request.path"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "target", "http://www.example.com/"), + resource.TestCheckResourceAttr(resourceName, "version", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "route_key", + "target", + }, + }, + }, + }) +} + func testAccCheckAWSAPIGatewayV2ApiDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn @@ -415,6 +562,105 @@ func testAccCheckAWSAPIGatewayV2ApiExists(n string, v *apigatewayv2.GetApiOutput } } +func testAccCheckAWSAPIGatewayV2ApiQuickCreateIntegration(n, expectedType, expectedUri string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No API Gateway v2 API ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + resp, err := conn.GetIntegrations(&apigatewayv2.GetIntegrationsInput{ + ApiId: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + + if got := len(resp.Items); got != 1 { + return fmt.Errorf("Incorrect number of integrations: %d", got) + } + + if got := aws.StringValue(resp.Items[0].IntegrationType); got != expectedType { + return fmt.Errorf("Incorrect integration type. Expected: %s, got: %s", expectedType, got) + } + if got := aws.StringValue(resp.Items[0].IntegrationUri); got != expectedUri { + return fmt.Errorf("Incorrect integration URI. Expected: %s, got: %s", expectedUri, got) + } + + return nil + } +} + +func testAccCheckAWSAPIGatewayV2ApiQuickCreateRoute(n, expectedRouteKey string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No API Gateway v2 API ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + resp, err := conn.GetRoutes(&apigatewayv2.GetRoutesInput{ + ApiId: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + + if got := len(resp.Items); got != 1 { + return fmt.Errorf("Incorrect number of routes: %d", got) + } + + if got := aws.StringValue(resp.Items[0].RouteKey); got != expectedRouteKey { + return fmt.Errorf("Incorrect route key. Expected: %s, got: %s", expectedRouteKey, got) + } + + return nil + } +} + +func testAccCheckAWSAPIGatewayV2ApiQuickCreateStage(n, expectedName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No API Gateway v2 API ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + resp, err := conn.GetStages(&apigatewayv2.GetStagesInput{ + ApiId: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + + if got := len(resp.Items); got != 1 { + return fmt.Errorf("Incorrect number of stages: %d", got) + } + + if got := aws.StringValue(resp.Items[0].StageName); got != expectedName { + return fmt.Errorf("Incorrect stage name. Expected: %s, got: %s", expectedName, got) + } + + return nil + } +} + func testAccAWSAPIGatewayV2ApiConfig_basicWebSocket(rName string) string { return fmt.Sprintf(` resource "aws_apigatewayv2_api" "test" { @@ -472,3 +718,46 @@ resource "aws_apigatewayv2_api" "test" { } `, rName) } + +func testAccAWSAPIGatewayV2ApiConfig_corsConfiguration(rName string) string { + return fmt.Sprintf(` +resource "aws_apigatewayv2_api" "test" { + name = %[1]q + protocol_type = "HTTP" + + cors_configuration { + allow_headers = ["Authorization"] + allow_methods = ["GET", "put"] + allow_origins = ["https://www.example.com"] + } +} +`, rName) +} + +func testAccAWSAPIGatewayV2ApiConfig_corsConfigurationUpdated(rName string) string { + return fmt.Sprintf(` +resource "aws_apigatewayv2_api" "test" { + name = %[1]q + protocol_type = "HTTP" + + cors_configuration { + allow_credentials = true + allow_methods = ["*"] + allow_origins = ["HTTP://WWW.EXAMPLE.ORG", "https://example.io"] + expose_headers = ["X-Api-Id"] + max_age = 500 + } +} +`, rName) +} + +func testAccAWSAPIGatewayV2ApiConfig_quickCreate(rName string) string { + return fmt.Sprintf(` +resource "aws_apigatewayv2_api" "test" { + name = %[1]q + protocol_type = "HTTP" + target = "http://www.example.com/" + route_key = "GET /pets" +} +`, rName) +} diff --git a/aws/structure.go b/aws/structure.go index 378aa7754c8..3a7690e6c05 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -46,6 +46,7 @@ import ( "github.com/aws/aws-sdk-go/service/waf" "github.com/aws/aws-sdk-go/service/worklink" "github.com/beevik/etree" + "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/structure" "github.com/mitchellh/copystructure" @@ -999,6 +1000,16 @@ func flattenStringSet(list []*string) *schema.Set { return schema.NewSet(schema.HashString, flattenStringList(list)) } +// hashStringCaseInsensitive hashes strings in a case insensitive manner. +// If you want a Set of strings and are case inensitive, this is the SchemaSetFunc you want. +func hashStringCaseInsensitive(v interface{}) int { + return hashcode.String(strings.ToLower(v.(string))) +} + +func flattenCaseInsensitiveStringSet(list []*string) *schema.Set { + return schema.NewSet(hashStringCaseInsensitive, flattenStringList(list)) +} + //Flattens an array of private ip addresses into a []string, where the elements returned are the IP strings e.g. "192.168.0.0" func flattenNetworkInterfacesPrivateIPAddresses(dtos []*ec2.NetworkInterfacePrivateIpAddress) []string { ips := make([]string, 0, len(dtos)) diff --git a/website/docs/r/apigatewayv2_api.html.markdown b/website/docs/r/apigatewayv2_api.html.markdown index f6da35d340f..ee7d2ba43c6 100644 --- a/website/docs/r/apigatewayv2_api.html.markdown +++ b/website/docs/r/apigatewayv2_api.html.markdown @@ -42,12 +42,27 @@ The following arguments are supported: * `api_key_selection_expression` - (Optional) An [API key selection expression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-apikey-selection-expressions). Valid values: `$context.authorizer.usageIdentifierKey`, `$request.header.x-api-key`. Defaults to `$request.header.x-api-key`. Applicable for WebSocket APIs. +* `cors_configuration` - (Optional) The cross-origin resource sharing (CORS) [configuration](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html). Applicable for HTTP APIs. +* `credentials_arn` - (Optional) Part of _quick create_. Specifies any credentials required for the integration. Applicable for HTTP APIs. * `description` - (Optional) The description of the API. +* `route_key` - (Optional) Part of _quick create_. Specifies any [route key](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html). Applicable for HTTP APIs. * `route_selection_expression` - (Optional) The [route selection expression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-route-selection-expressions) for the API. Defaults to `$request.method $request.path`. * `tags` - (Optional) A mapping of tags to assign to the API. +* `target` - (Optional) Part of _quick create_. Quick create produces an API with an integration, a default catch-all route, and a default stage which is configured to automatically deploy changes. +For HTTP integrations, specify a fully qualified URL. For Lambda integrations, specify a function ARN. +The type of the integration will be `HTTP_PROXY` or `AWS_PROXY`, respectively. Applicable for HTTP APIs. * `version` - (Optional) A version identifier for the API. +The `cors_configuration` object supports the following: + +* `allow_credentials` - (Optional) Whether credentials are included in the CORS request. +* `allow_headers` - (Optional) The set of allowed HTTP headers. +* `allow_methods` - (Optional) The set of allowed HTTP methods. +* `allow_origins` - (Optional) The set of allowed origins. +* `expose_headers` - (Optional) The set of exposed HTTP headers. +* `max_age` - (Optional) The number of seconds that the browser should cache preflight request results. + ## Attribute Reference In addition to all arguments above, the following attributes are exported: From 5efe7cfd048286d9cae088553812b34ecdf55489 Mon Sep 17 00:00:00 2001 From: Stefan Sundin Date: Fri, 20 Mar 2020 20:31:59 -0700 Subject: [PATCH 062/684] Rename test. --- aws/resource_aws_egress_only_internet_gateway_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_egress_only_internet_gateway_test.go b/aws/resource_aws_egress_only_internet_gateway_test.go index 96f8534816b..1e8d734aa72 100644 --- a/aws/resource_aws_egress_only_internet_gateway_test.go +++ b/aws/resource_aws_egress_only_internet_gateway_test.go @@ -85,7 +85,7 @@ func TestAccAWSEgressOnlyInternetGateway_basic(t *testing.T) { }) } -func TestAccCheckAWSEgressOnlyInternetGateway_tags(t *testing.T) { +func TestAccAWSEgressOnlyInternetGateway_tags(t *testing.T) { var v ec2.EgressOnlyInternetGateway resourceName := "aws_egress_only_internet_gateway.test" From 24fecc62812aa5369713d90438a02dcbab3491f3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2020 15:29:14 -0400 Subject: [PATCH 063/684] Update module bflad/tfproviderlint to v0.14.0 (#12505) Co-authored-by: Renovate Bot --- go.mod | 2 +- go.sum | 4 +- .../helper/analysisutils/analyzers.go | 87 +++- .../helper/analysisutils/runners.go | 377 +++++++++++++++++- .../helper/astutils/basiclit.go | 11 +- .../tfproviderlint/helper/astutils/expr.go | 14 + .../helper/astutils/fieldlist.go | 10 + .../tfproviderlint/helper/astutils/package.go | 2 + .../helper/schema/type_customizedifffunc.go | 87 ++++ .../helper/schema/type_provider.go | 26 ++ .../helper/schema/type_resourcediff.go | 21 + .../helper/schema/type_stateupgradefunc.go | 91 +++++ .../bflad/tfproviderlint/passes/R007/R007.go | 4 +- .../bflad/tfproviderlint/passes/R008/R008.go | 4 +- .../bflad/tfproviderlint/passes/V002/V002.go | 4 +- .../bflad/tfproviderlint/passes/V003/V003.go | 8 +- .../bflad/tfproviderlint/passes/V004/V004.go | 8 +- .../bflad/tfproviderlint/passes/V005/V005.go | 4 +- .../bflad/tfproviderlint/passes/V006/V006.go | 4 +- .../bflad/tfproviderlint/passes/V007/V007.go | 4 +- .../bflad/tfproviderlint/passes/V008/V008.go | 4 +- .../resourcedatapartialcallexpr.go | 14 + .../resourcedatasetpartialcallexpr.go | 14 + .../iprangecallexpr/iprangecallexpr.go | 13 + .../singleipcallexpr/singleipcallexpr.go | 13 + .../bflad/tfproviderlint/version/version.go | 2 +- vendor/modules.txt | 6 +- 27 files changed, 800 insertions(+), 38 deletions(-) create mode 100644 vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_customizedifffunc.go create mode 100644 vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_provider.go create mode 100644 vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_resourcediff.go create mode 100644 vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_stateupgradefunc.go create mode 100644 vendor/github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatapartialcallexpr/resourcedatapartialcallexpr.go create mode 100644 vendor/github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatasetpartialcallexpr/resourcedatasetpartialcallexpr.go create mode 100644 vendor/github.com/bflad/tfproviderlint/passes/helper/validation/iprangecallexpr/iprangecallexpr.go create mode 100644 vendor/github.com/bflad/tfproviderlint/passes/helper/validation/singleipcallexpr/singleipcallexpr.go diff --git a/go.mod b/go.mod index 9632ceb12c7..c945d1fc97e 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/aws/aws-sdk-go v1.29.24 github.com/beevik/etree v1.1.0 github.com/bflad/tfproviderdocs v0.5.0 - github.com/bflad/tfproviderlint v0.12.0 + github.com/bflad/tfproviderlint v0.14.0 github.com/client9/misspell v0.3.4 github.com/golangci/golangci-lint v1.23.8 github.com/hashicorp/aws-sdk-go-base v0.4.0 diff --git a/go.sum b/go.sum index fa3ca95338d..ac7b9ce9f78 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,8 @@ github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderdocs v0.5.0 h1:FzT4hEtKX1WcrLmZSRB83kFdzRmkqu7kS9RHn5oKAuA= github.com/bflad/tfproviderdocs v0.5.0/go.mod h1:d0k1fQLEu1pdeORxozwuwmvauFaEmMBREQ1fw3J+pPc= -github.com/bflad/tfproviderlint v0.12.0 h1:vAl/8VOk/o3jEBbyMkWHrkCa6sisT4INDMCkXu0GNDw= -github.com/bflad/tfproviderlint v0.12.0/go.mod h1:MsNI3eEj7uC7P/h7XmGvzMLtsotLkrvB+NF2/w3RZGc= +github.com/bflad/tfproviderlint v0.14.0 h1:iki5tDr4l0jp0zEL0chZylptMT5QdE09E60cziFQNZA= +github.com/bflad/tfproviderlint v0.14.0/go.mod h1:1Jtjs6DPKoyqPrbPyMiy33h0ViO2h831uzoOuikCA60= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= diff --git a/vendor/github.com/bflad/tfproviderlint/helper/analysisutils/analyzers.go b/vendor/github.com/bflad/tfproviderlint/helper/analysisutils/analyzers.go index 0041b098bdf..b5fcb049387 100644 --- a/vendor/github.com/bflad/tfproviderlint/helper/analysisutils/analyzers.go +++ b/vendor/github.com/bflad/tfproviderlint/helper/analysisutils/analyzers.go @@ -12,27 +12,77 @@ import ( ) // DeprecatedReceiverMethodSelectorExprAnalyzer returns an Analyzer for deprecated *ast.SelectorExpr -func DeprecatedReceiverMethodSelectorExprAnalyzer(analyzerName string, selectorExprAnalyzer *analysis.Analyzer, packageName, typeName, methodName string) *analysis.Analyzer { +func DeprecatedReceiverMethodSelectorExprAnalyzer(analyzerName string, callExprAnalyzer, selectorExprAnalyzer *analysis.Analyzer, packagePath, typeName, methodName string) *analysis.Analyzer { doc := fmt.Sprintf(`check for deprecated %[2]s.%[3]s usage The %[1]s analyzer reports usage of the deprecated: %[2]s.%[3]s -`, analyzerName, packageName, typeName, methodName) +`, analyzerName, packagePath, typeName, methodName) return &analysis.Analyzer{ Name: analyzerName, Doc: doc, Requires: []*analysis.Analyzer{ + callExprAnalyzer, commentignore.Analyzer, selectorExprAnalyzer, }, - Run: DeprecatedReceiverMethodSelectorExprRunner(analyzerName, selectorExprAnalyzer, packageName, typeName, methodName), + Run: DeprecatedReceiverMethodSelectorExprRunner(analyzerName, callExprAnalyzer, selectorExprAnalyzer, packagePath, typeName, methodName), + } +} + +// DeprecatedEmptyCallExprWithReplacementSelectorExprAnalyzer returns an Analyzer for deprecated *ast.SelectorExpr with replacement +func DeprecatedEmptyCallExprWithReplacementSelectorExprAnalyzer(analyzerName string, callExprAnalyzer, selectorExprAnalyzer *analysis.Analyzer, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName string) *analysis.Analyzer { + doc := fmt.Sprintf(`check for deprecated %[2]s.%[3]s usage + +The %[1]s analyzer reports usage of the deprecated: + +%[2]s.%[3]s + +That should be replaced with: + +%[4]s.%[5]s +`, analyzerName, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName) + + return &analysis.Analyzer{ + Name: analyzerName, + Doc: doc, + Requires: []*analysis.Analyzer{ + callExprAnalyzer, + commentignore.Analyzer, + selectorExprAnalyzer, + }, + Run: DeprecatedEmptyCallExprWithReplacementSelectorExprRunner(analyzerName, callExprAnalyzer, selectorExprAnalyzer, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName), + } +} + +// DeprecatedWithReplacementPointerSelectorExprAnalyzer returns an Analyzer for deprecated *ast.SelectorExpr with replacement +func DeprecatedWithReplacementPointerSelectorExprAnalyzer(analyzerName string, selectorExprAnalyzer *analysis.Analyzer, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName string) *analysis.Analyzer { + doc := fmt.Sprintf(`check for deprecated %[2]s.%[3]s usage + +The %[1]s analyzer reports usage of the deprecated: + +%[2]s.%[3]s + +That should be replaced with: + +*%[4]s.%[5]s +`, analyzerName, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName) + + return &analysis.Analyzer{ + Name: analyzerName, + Doc: doc, + Requires: []*analysis.Analyzer{ + commentignore.Analyzer, + selectorExprAnalyzer, + }, + Run: DeprecatedWithReplacementPointerSelectorExprRunner(analyzerName, selectorExprAnalyzer, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName), } } // DeprecatedWithReplacementSelectorExprAnalyzer returns an Analyzer for deprecated *ast.SelectorExpr with replacement -func DeprecatedWithReplacementSelectorExprAnalyzer(analyzerName string, selectorExprAnalyzer *analysis.Analyzer, oldPackageName, oldSelectorName, newPackageName, newSelectorName string) *analysis.Analyzer { +func DeprecatedWithReplacementSelectorExprAnalyzer(analyzerName string, selectorExprAnalyzer *analysis.Analyzer, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName string) *analysis.Analyzer { doc := fmt.Sprintf(`check for deprecated %[2]s.%[3]s usage The %[1]s analyzer reports usage of the deprecated: @@ -42,7 +92,7 @@ The %[1]s analyzer reports usage of the deprecated: That should be replaced with: %[4]s.%[5]s -`, analyzerName, oldPackageName, oldSelectorName, newPackageName, newSelectorName) +`, analyzerName, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName) return &analysis.Analyzer{ Name: analyzerName, @@ -51,7 +101,7 @@ That should be replaced with: commentignore.Analyzer, selectorExprAnalyzer, }, - Run: DeprecatedWithReplacementSelectorExprRunner(analyzerName, selectorExprAnalyzer, oldPackageName, oldSelectorName, newPackageName, newSelectorName), + Run: DeprecatedWithReplacementSelectorExprRunner(analyzerName, selectorExprAnalyzer, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName), } } @@ -119,3 +169,28 @@ func SelectorExprAnalyzer(analyzerName string, packageFunc func(ast.Expr, *types ResultType: reflect.TypeOf([]*ast.SelectorExpr{}), } } + +// TypeAssertExprRemovalAnalyzer returns an Analyzer for *ast.TypeAssertExpr +func TypeAssertExprRemovalAnalyzer(analyzerName string, typeAssertExprAnalyzer *analysis.Analyzer, packagePath string, selectorName string) *analysis.Analyzer { + return &analysis.Analyzer{ + Name: analyzerName, + Doc: fmt.Sprintf("remove %s.%s type assertions", packagePath, selectorName), + Requires: []*analysis.Analyzer{ + typeAssertExprAnalyzer, + }, + Run: TypeAssertExprRemovalRunner(analyzerName, typeAssertExprAnalyzer), + } +} + +// TypeAssertExprAnalyzer returns an Analyzer for *ast.TypeAssertExpr +func TypeAssertExprAnalyzer(analyzerName string, packageFunc func(ast.Expr, *types.Info, string) bool, packagePath string, selectorName string) *analysis.Analyzer { + return &analysis.Analyzer{ + Name: analyzerName, + Doc: fmt.Sprintf("find %s.%s type assertions for later passes", packagePath, selectorName), + Requires: []*analysis.Analyzer{ + inspect.Analyzer, + }, + Run: TypeAssertExprRunner(packageFunc, selectorName), + ResultType: reflect.TypeOf([]*ast.TypeAssertExpr{}), + } +} diff --git a/vendor/github.com/bflad/tfproviderlint/helper/analysisutils/runners.go b/vendor/github.com/bflad/tfproviderlint/helper/analysisutils/runners.go index dc95ca5c91e..50b44083efe 100644 --- a/vendor/github.com/bflad/tfproviderlint/helper/analysisutils/runners.go +++ b/vendor/github.com/bflad/tfproviderlint/helper/analysisutils/runners.go @@ -1,8 +1,13 @@ package analysisutils import ( + "bytes" + "fmt" "go/ast" + "go/format" + "go/token" "go/types" + "path/filepath" "github.com/bflad/tfproviderlint/passes/commentignore" "golang.org/x/tools/go/analysis" @@ -11,17 +16,276 @@ import ( ) // DeprecatedReceiverMethodSelectorExprRunner returns an Analyzer runner for deprecated *ast.SelectorExpr -func DeprecatedReceiverMethodSelectorExprRunner(analyzerName string, selectorExprAnalyzer *analysis.Analyzer, packageName, typeName, methodName string) func(*analysis.Pass) (interface{}, error) { +func DeprecatedReceiverMethodSelectorExprRunner(analyzerName string, callExprAnalyzer, selectorExprAnalyzer *analysis.Analyzer, packagePath, typeName, methodName string) func(*analysis.Pass) (interface{}, error) { return func(pass *analysis.Pass) (interface{}, error) { + callExprs := pass.ResultOf[callExprAnalyzer].([]*ast.CallExpr) selectorExprs := pass.ResultOf[selectorExprAnalyzer].([]*ast.SelectorExpr) ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + // CallExpr and SelectorExpr will overlap, so only perform one report/fix + reported := make(map[token.Pos]struct{}) + + for _, callExpr := range callExprs { + if ignorer.ShouldIgnore(analyzerName, callExpr) { + continue + } + + var callExprBuf bytes.Buffer + + if err := format.Node(&callExprBuf, pass.Fset, callExpr); err != nil { + return nil, fmt.Errorf("error formatting original: %s", err) + } + + pass.Report(analysis.Diagnostic{ + Pos: callExpr.Pos(), + End: callExpr.End(), + Message: fmt.Sprintf("%s: deprecated %s", analyzerName, callExprBuf.String()), + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "Remove", + TextEdits: []analysis.TextEdit{ + { + Pos: callExpr.Pos(), + End: callExpr.End(), + NewText: []byte{}, + }, + }, + }, + }, + }) + + reported[callExpr.Pos()] = struct{}{} + } + for _, selectorExpr := range selectorExprs { if ignorer.ShouldIgnore(analyzerName, selectorExpr) { continue } - pass.Reportf(selectorExpr.Pos(), "%s: deprecated (%s.%s).%s", analyzerName, packageName, typeName, methodName) + if _, ok := reported[selectorExpr.Pos()]; ok { + continue + } + + var selectorExprBuf bytes.Buffer + + if err := format.Node(&selectorExprBuf, pass.Fset, selectorExpr); err != nil { + return nil, fmt.Errorf("error formatting original: %s", err) + } + + pass.Report(analysis.Diagnostic{ + Pos: selectorExpr.Pos(), + End: selectorExpr.End(), + Message: fmt.Sprintf("%s: deprecated %s", analyzerName, selectorExprBuf.String()), + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "Remove", + TextEdits: []analysis.TextEdit{ + { + Pos: selectorExpr.Pos(), + End: selectorExpr.End(), + NewText: []byte{}, + }, + }, + }, + }, + }) + } + + return nil, nil + } +} + +// DeprecatedEmptyCallExprWithReplacementSelectorExprRunner returns an Analyzer runner for deprecated *ast.SelectorExpr with replacement +func DeprecatedEmptyCallExprWithReplacementSelectorExprRunner(analyzerName string, callExprAnalyzer *analysis.Analyzer, selectorExprAnalyzer *analysis.Analyzer, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName string) func(*analysis.Pass) (interface{}, error) { + return func(pass *analysis.Pass) (interface{}, error) { + callExprs := pass.ResultOf[callExprAnalyzer].([]*ast.CallExpr) + selectorExprs := pass.ResultOf[selectorExprAnalyzer].([]*ast.SelectorExpr) + ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + + // CallExpr and SelectorExpr will overlap, so only perform one report/fix + reported := make(map[token.Pos]struct{}) + + for _, callExpr := range callExprs { + if ignorer.ShouldIgnore(analyzerName, callExpr) { + continue + } + + if len(callExpr.Args) != 0 { + continue + } + + selectorExpr, ok := callExpr.Fun.(*ast.SelectorExpr) + + if !ok { + continue + } + + newSelectorExpr := &ast.SelectorExpr{ + Sel: selectorExpr.Sel, + X: selectorExpr.X, + } + + if oldPackagePath != newPackagePath { + newSelectorExpr.X = &ast.Ident{ + Name: filepath.Base(newPackagePath), + } + } + + if oldSelectorName != newSelectorName { + newSelectorExpr.Sel = &ast.Ident{ + Name: newSelectorName, + } + } + + var callExprBuf, newSelectorExprBuf bytes.Buffer + + if err := format.Node(&callExprBuf, pass.Fset, selectorExpr); err != nil { + return nil, fmt.Errorf("error formatting original: %s", err) + } + + if err := format.Node(&newSelectorExprBuf, pass.Fset, newSelectorExpr); err != nil { + return nil, fmt.Errorf("error formatting new: %s", err) + } + + pass.Report(analysis.Diagnostic{ + Pos: callExpr.Pos(), + End: callExpr.End(), + Message: fmt.Sprintf("%s: deprecated %s should be replaced with %s", analyzerName, callExprBuf.String(), newSelectorExprBuf.String()), + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "Replace", + TextEdits: []analysis.TextEdit{ + { + Pos: callExpr.Pos(), + End: callExpr.End(), + NewText: newSelectorExprBuf.Bytes(), + }, + }, + }, + }, + }) + + reported[callExpr.Pos()] = struct{}{} + } + + for _, selectorExpr := range selectorExprs { + if ignorer.ShouldIgnore(analyzerName, selectorExpr) { + continue + } + + if _, ok := reported[selectorExpr.Pos()]; ok { + continue + } + + newSelectorExpr := &ast.SelectorExpr{ + Sel: selectorExpr.Sel, + X: selectorExpr.X, + } + + if oldPackagePath != newPackagePath { + newSelectorExpr.X = &ast.Ident{ + Name: filepath.Base(newPackagePath), + } + } + + if oldSelectorName != newSelectorName { + newSelectorExpr.Sel = &ast.Ident{ + Name: newSelectorName, + } + } + + var selectorExprBuf, newSelectorExprBuf bytes.Buffer + + if err := format.Node(&selectorExprBuf, pass.Fset, selectorExpr); err != nil { + return nil, fmt.Errorf("error formatting original: %s", err) + } + + if err := format.Node(&newSelectorExprBuf, pass.Fset, newSelectorExpr); err != nil { + return nil, fmt.Errorf("error formatting new: %s", err) + } + + pass.Report(analysis.Diagnostic{ + Pos: selectorExpr.Pos(), + End: selectorExpr.End(), + Message: fmt.Sprintf("%s: deprecated %s should be replaced with %s", analyzerName, selectorExprBuf.String(), newSelectorExprBuf.String()), + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "Replace", + TextEdits: []analysis.TextEdit{ + { + Pos: selectorExpr.Pos(), + End: selectorExpr.End(), + NewText: newSelectorExprBuf.Bytes(), + }, + }, + }, + }, + }) + } + + return nil, nil + } +} + +// DeprecatedWithReplacementPointerSelectorExprRunner returns an Analyzer runner for deprecated *ast.SelectorExpr with replacement +func DeprecatedWithReplacementPointerSelectorExprRunner(analyzerName string, selectorExprAnalyzer *analysis.Analyzer, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName string) func(*analysis.Pass) (interface{}, error) { + return func(pass *analysis.Pass) (interface{}, error) { + ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + selectorExprs := pass.ResultOf[selectorExprAnalyzer].([]*ast.SelectorExpr) + + for _, selectorExpr := range selectorExprs { + if ignorer.ShouldIgnore(analyzerName, selectorExpr) { + continue + } + + newSelectorExpr := &ast.SelectorExpr{ + Sel: selectorExpr.Sel, + X: selectorExpr.X, + } + + if oldPackagePath != newPackagePath { + newSelectorExpr.X = &ast.Ident{ + Name: filepath.Base(newPackagePath), + } + } + + if oldSelectorName != newSelectorName { + newSelectorExpr.Sel = &ast.Ident{ + Name: newSelectorName, + } + } + + newStarExpr := &ast.StarExpr{ + X: newSelectorExpr, + } + + var selectorExprBuf, newStarExprBuf bytes.Buffer + + if err := format.Node(&selectorExprBuf, pass.Fset, selectorExpr); err != nil { + return nil, fmt.Errorf("error formatting original: %s", err) + } + + if err := format.Node(&newStarExprBuf, pass.Fset, newStarExpr); err != nil { + return nil, fmt.Errorf("error formatting new: %s", err) + } + + pass.Report(analysis.Diagnostic{ + Pos: selectorExpr.Pos(), + End: selectorExpr.End(), + Message: fmt.Sprintf("%s: deprecated %s should be replaced with %s", analyzerName, selectorExprBuf.String(), newStarExprBuf.String()), + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "Replace", + TextEdits: []analysis.TextEdit{ + { + Pos: selectorExpr.Pos(), + End: selectorExpr.End(), + NewText: newStarExprBuf.Bytes(), + }, + }, + }, + }, + }) } return nil, nil @@ -29,7 +293,7 @@ func DeprecatedReceiverMethodSelectorExprRunner(analyzerName string, selectorExp } // DeprecatedWithReplacementSelectorExprRunner returns an Analyzer runner for deprecated *ast.SelectorExpr with replacement -func DeprecatedWithReplacementSelectorExprRunner(analyzerName string, selectorExprAnalyzer *analysis.Analyzer, oldPackageName, oldSelectorName, newPackageName, newSelectorName string) func(*analysis.Pass) (interface{}, error) { +func DeprecatedWithReplacementSelectorExprRunner(analyzerName string, selectorExprAnalyzer *analysis.Analyzer, oldPackagePath, oldSelectorName, newPackagePath, newSelectorName string) func(*analysis.Pass) (interface{}, error) { return func(pass *analysis.Pass) (interface{}, error) { selectorExprs := pass.ResultOf[selectorExprAnalyzer].([]*ast.SelectorExpr) ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) @@ -39,7 +303,50 @@ func DeprecatedWithReplacementSelectorExprRunner(analyzerName string, selectorEx continue } - pass.Reportf(selectorExpr.Pos(), "%s: deprecated %s.%s should be replaced with %s.%s", analyzerName, oldPackageName, oldSelectorName, newPackageName, newSelectorName) + newSelectorExpr := &ast.SelectorExpr{ + Sel: selectorExpr.Sel, + X: selectorExpr.X, + } + + if oldPackagePath != newPackagePath { + newSelectorExpr.X = &ast.Ident{ + Name: filepath.Base(newPackagePath), + } + } + + if oldSelectorName != newSelectorName { + newSelectorExpr.Sel = &ast.Ident{ + Name: newSelectorName, + } + } + + var selectorExprBuf, newSelectorExprBuf bytes.Buffer + + if err := format.Node(&selectorExprBuf, pass.Fset, selectorExpr); err != nil { + return nil, fmt.Errorf("error formatting original: %s", err) + } + + if err := format.Node(&newSelectorExprBuf, pass.Fset, newSelectorExpr); err != nil { + return nil, fmt.Errorf("error formatting new: %s", err) + } + + pass.Report(analysis.Diagnostic{ + Pos: selectorExpr.Pos(), + End: selectorExpr.End(), + Message: fmt.Sprintf("%s: deprecated %s should be replaced with %s", analyzerName, selectorExprBuf.String(), newSelectorExprBuf.String()), + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "Replace", + TextEdits: []analysis.TextEdit{ + { + Pos: selectorExpr.Pos(), + End: selectorExpr.End(), + NewText: newSelectorExprBuf.Bytes(), + }, + }, + }, + }, + }) } return nil, nil @@ -170,3 +477,65 @@ func SelectorExprRunner(packageFunc func(ast.Expr, *types.Info, string) bool, se return result, nil } } + +// TypeAssertExprRemovalRunner returns an Analyzer runner for removing *ast.TypeAssertExpr +func TypeAssertExprRemovalRunner(analyzerName string, typeAssertExprAnalyzer *analysis.Analyzer) func(*analysis.Pass) (interface{}, error) { + return func(pass *analysis.Pass) (interface{}, error) { + typeAssertExprs := pass.ResultOf[typeAssertExprAnalyzer].([]*ast.TypeAssertExpr) + + for _, typeAssertExpr := range typeAssertExprs { + var typeAssertExprBuf, xBuf bytes.Buffer + + if err := format.Node(&typeAssertExprBuf, pass.Fset, typeAssertExpr); err != nil { + return nil, fmt.Errorf("error formatting original: %s", err) + } + + if err := format.Node(&xBuf, pass.Fset, typeAssertExpr.X); err != nil { + return nil, fmt.Errorf("error formatting new: %s", err) + } + + pass.Report(analysis.Diagnostic{ + Pos: typeAssertExpr.Pos(), + End: typeAssertExpr.End(), + Message: fmt.Sprintf("%s: %s type assertion should be removed", analyzerName, typeAssertExprBuf.String()), + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "Remove", + TextEdits: []analysis.TextEdit{ + { + Pos: typeAssertExpr.Pos(), + End: typeAssertExpr.End(), + NewText: xBuf.Bytes(), + }, + }, + }, + }, + }) + } + + return nil, nil + } +} + +// TypeAssertExprRunner returns an Analyzer runner for *ast.TypeAssertExpr +func TypeAssertExprRunner(packageFunc func(ast.Expr, *types.Info, string) bool, selectorName string) func(*analysis.Pass) (interface{}, error) { + return func(pass *analysis.Pass) (interface{}, error) { + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + nodeFilter := []ast.Node{ + (*ast.TypeAssertExpr)(nil), + } + var result []*ast.TypeAssertExpr + + inspect.Preorder(nodeFilter, func(n ast.Node) { + typeAssertExpr := n.(*ast.TypeAssertExpr) + + if !packageFunc(typeAssertExpr.Type, pass.TypesInfo, selectorName) { + return + } + + result = append(result, typeAssertExpr) + }) + + return result, nil + } +} diff --git a/vendor/github.com/bflad/tfproviderlint/helper/astutils/basiclit.go b/vendor/github.com/bflad/tfproviderlint/helper/astutils/basiclit.go index 94cee53a9a7..8fa6c327237 100644 --- a/vendor/github.com/bflad/tfproviderlint/helper/astutils/basiclit.go +++ b/vendor/github.com/bflad/tfproviderlint/helper/astutils/basiclit.go @@ -2,8 +2,8 @@ package astutils import ( "go/ast" + "go/token" "strconv" - "strings" ) // ExprBoolValue fetches a bool value from the Expr @@ -29,8 +29,7 @@ func ExprBoolValue(e ast.Expr) *bool { func ExprIntValue(e ast.Expr) *int { switch v := e.(type) { case *ast.BasicLit: - stringValue := strings.Trim(v.Value, `"`) - intValue, err := strconv.Atoi(stringValue) + intValue, err := strconv.Atoi(v.Value) if err != nil { return nil @@ -47,8 +46,10 @@ func ExprIntValue(e ast.Expr) *int { func ExprStringValue(e ast.Expr) *string { switch v := e.(type) { case *ast.BasicLit: - stringValue := strings.Trim(v.Value, `"`) - + if v.Kind != token.STRING { + return nil + } + stringValue, _ := strconv.Unquote(v.Value) // can assume well-formed Go return &stringValue } diff --git a/vendor/github.com/bflad/tfproviderlint/helper/astutils/expr.go b/vendor/github.com/bflad/tfproviderlint/helper/astutils/expr.go index ebd012d0398..b82499b1512 100644 --- a/vendor/github.com/bflad/tfproviderlint/helper/astutils/expr.go +++ b/vendor/github.com/bflad/tfproviderlint/helper/astutils/expr.go @@ -18,6 +18,13 @@ func IsExprTypeArrayError(e ast.Expr) bool { return ok && IsExprTypeError(arrayType.Elt) } +// IsExprTypeString returns true if the expression matches bool +func IsExprTypeBool(e ast.Expr) bool { + ident, ok := e.(*ast.Ident) + + return ok && ident.Name == "bool" +} + // IsExprTypeError returns true if the expression matches string func IsExprTypeError(e ast.Expr) bool { ident, ok := e.(*ast.Ident) @@ -32,6 +39,13 @@ func IsExprTypeInterface(e ast.Expr) bool { return ok } +// IsExprTypeMapStringInterface returns true if the expression matches []string +func IsExprTypeMapStringInterface(e ast.Expr) bool { + mapType, ok := e.(*ast.MapType) + + return ok && IsExprTypeString(mapType.Key) && IsExprTypeInterface(mapType.Value) +} + // IsExprTypeString returns true if the expression matches string func IsExprTypeString(e ast.Expr) bool { ident, ok := e.(*ast.Ident) diff --git a/vendor/github.com/bflad/tfproviderlint/helper/astutils/fieldlist.go b/vendor/github.com/bflad/tfproviderlint/helper/astutils/fieldlist.go index 81e19bab279..4b6c45802e5 100644 --- a/vendor/github.com/bflad/tfproviderlint/helper/astutils/fieldlist.go +++ b/vendor/github.com/bflad/tfproviderlint/helper/astutils/fieldlist.go @@ -60,6 +60,16 @@ func FieldListType(fieldList *ast.FieldList, position int) *ast.Expr { return &field.Type } +// HasFieldListLength returns true if the FieldList has the expected length +// If FieldList is nil, checks against expected length of 0. +func HasFieldListLength(fieldList *ast.FieldList, expectedLength int) bool { + if fieldList == nil { + return expectedLength == 0 + } + + return len(fieldList.List) == expectedLength +} + // IsFieldListType returns true if the field at position is present and matches expected ast.Expr func IsFieldListType(fieldList *ast.FieldList, position int, exprFunc func(ast.Expr) bool) bool { t := FieldListType(fieldList, position) diff --git a/vendor/github.com/bflad/tfproviderlint/helper/astutils/package.go b/vendor/github.com/bflad/tfproviderlint/helper/astutils/package.go index e983b9d6bdf..00eaa78a787 100644 --- a/vendor/github.com/bflad/tfproviderlint/helper/astutils/package.go +++ b/vendor/github.com/bflad/tfproviderlint/helper/astutils/package.go @@ -32,6 +32,8 @@ func IsPackageFunc(e ast.Expr, info *types.Info, packageSuffix string, funcName case *ast.Ident: return strings.HasSuffix(info.ObjectOf(x).(*types.PkgName).Imported().Path(), packageSuffix) } + case *ast.StarExpr: + return IsPackageFunc(e.X, info, packageSuffix, funcName) } return false diff --git a/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_customizedifffunc.go b/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_customizedifffunc.go new file mode 100644 index 00000000000..c90186db149 --- /dev/null +++ b/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_customizedifffunc.go @@ -0,0 +1,87 @@ +package schema + +import ( + "go/ast" + "go/token" + "go/types" + + "github.com/bflad/tfproviderlint/helper/astutils" +) + +const ( + TypeNameCustomizeDiffFunc = `CustomizeDiffFunc` +) + +// IsFuncTypeCustomizeDiffFunc returns true if the FuncType matches expected parameters and results types +func IsFuncTypeCustomizeDiffFunc(node ast.Node, info *types.Info) bool { + funcType := astutils.FuncTypeFromNode(node) + + if funcType == nil { + return false + } + + if !astutils.HasFieldListLength(funcType.Params, 2) { + return false + } + + if !astutils.IsFieldListTypePackageType(funcType.Params, 0, info, PackagePath, TypeNameResourceDiff) { + return false + } + + if !astutils.IsFieldListType(funcType.Params, 1, astutils.IsExprTypeInterface) { + return false + } + + if !astutils.HasFieldListLength(funcType.Results, 1) { + return false + } + + return astutils.IsFieldListType(funcType.Results, 0, astutils.IsExprTypeError) +} + +// IsTypeCustomizeDiffFunc returns if the type is CustomizeDiffFunc from the customdiff package +func IsTypeCustomizeDiffFunc(t types.Type) bool { + switch t := t.(type) { + case *types.Named: + return IsNamedType(t, TypeNameCustomizeDiffFunc) + case *types.Pointer: + return IsTypeCustomizeDiffFunc(t.Elem()) + default: + return false + } +} + +// CustomizeDiffFuncInfo represents all gathered CustomizeDiffFunc data for easier access +type CustomizeDiffFuncInfo struct { + AstFuncDecl *ast.FuncDecl + AstFuncLit *ast.FuncLit + Body *ast.BlockStmt + Node ast.Node + Pos token.Pos + Type *ast.FuncType + TypesInfo *types.Info +} + +// NewCustomizeDiffFuncInfo instantiates a CustomizeDiffFuncInfo +func NewCustomizeDiffFuncInfo(node ast.Node, info *types.Info) *CustomizeDiffFuncInfo { + result := &CustomizeDiffFuncInfo{ + TypesInfo: info, + } + + switch node := node.(type) { + case *ast.FuncDecl: + result.AstFuncDecl = node + result.Body = node.Body + result.Node = node + result.Pos = node.Pos() + result.Type = node.Type + case *ast.FuncLit: + result.AstFuncLit = node + result.Body = node.Body + result.Node = node + result.Pos = node.Pos() + result.Type = node.Type + } + + return result +} diff --git a/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_provider.go b/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_provider.go new file mode 100644 index 00000000000..4aabc603ccd --- /dev/null +++ b/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_provider.go @@ -0,0 +1,26 @@ +package schema + +import "go/types" + +const ( + ProviderFieldConfigureFunc = `ConfigureFunc` + ProviderFieldDataSourcesMap = `DataSourcesMap` + ProviderFieldMetaReset = `MetaReset` + ProviderFieldResourcesMap = `ResourcesMap` + ProviderFieldSchema = `Schema` + ProviderFieldTerraformVersion = `TerraformVersion` + + TypeNameProvider = `Provider` +) + +// IsTypeProvider returns if the type is Provider from the schema package +func IsTypeProvider(t types.Type) bool { + switch t := t.(type) { + case *types.Named: + return IsNamedType(t, TypeNameProvider) + case *types.Pointer: + return IsTypeProvider(t.Elem()) + default: + return false + } +} diff --git a/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_resourcediff.go b/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_resourcediff.go new file mode 100644 index 00000000000..4d14e2a656a --- /dev/null +++ b/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_resourcediff.go @@ -0,0 +1,21 @@ +package schema + +import ( + "go/types" +) + +const ( + TypeNameResourceDiff = `ResourceDiff` +) + +// IsTypeResourceDiff returns if the type is ResourceDiff from the schema package +func IsTypeResourceDiff(t types.Type) bool { + switch t := t.(type) { + case *types.Named: + return IsNamedType(t, TypeNameResourceDiff) + case *types.Pointer: + return IsTypeResourceDiff(t.Elem()) + default: + return false + } +} diff --git a/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_stateupgradefunc.go b/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_stateupgradefunc.go new file mode 100644 index 00000000000..fc86c07d0f3 --- /dev/null +++ b/vendor/github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema/type_stateupgradefunc.go @@ -0,0 +1,91 @@ +package schema + +import ( + "go/ast" + "go/token" + "go/types" + + "github.com/bflad/tfproviderlint/helper/astutils" +) + +const ( + TypeNameStateUpgradeFunc = `StateUpgradeFunc` +) + +// IsFuncTypeStateUpgradeFunc returns true if the FuncType matches expected parameters and results types +func IsFuncTypeStateUpgradeFunc(node ast.Node, info *types.Info) bool { + funcType := astutils.FuncTypeFromNode(node) + + if funcType == nil { + return false + } + + if !astutils.HasFieldListLength(funcType.Params, 2) { + return false + } + + if !astutils.IsFieldListType(funcType.Params, 0, astutils.IsExprTypeMapStringInterface) { + return false + } + + if !astutils.IsFieldListType(funcType.Params, 1, astutils.IsExprTypeInterface) { + return false + } + + if !astutils.HasFieldListLength(funcType.Results, 2) { + return false + } + + if !astutils.IsFieldListType(funcType.Results, 0, astutils.IsExprTypeMapStringInterface) { + return false + } + + return astutils.IsFieldListType(funcType.Results, 1, astutils.IsExprTypeError) +} + +// IsTypeStateUpgradeFunc returns if the type is StateUpgradeFunc from the schema package +func IsTypeStateUpgradeFunc(t types.Type) bool { + switch t := t.(type) { + case *types.Named: + return IsNamedType(t, TypeNameStateUpgradeFunc) + case *types.Pointer: + return IsTypeStateUpgradeFunc(t.Elem()) + default: + return false + } +} + +// StateUpgradeFuncInfo represents all gathered StateUpgradeFunc data for easier access +type StateUpgradeFuncInfo struct { + AstFuncDecl *ast.FuncDecl + AstFuncLit *ast.FuncLit + Body *ast.BlockStmt + Node ast.Node + Pos token.Pos + Type *ast.FuncType + TypesInfo *types.Info +} + +// NewStateUpgradeFuncInfo instantiates a StateUpgradeFuncInfo +func NewStateUpgradeFuncInfo(node ast.Node, info *types.Info) *StateUpgradeFuncInfo { + result := &StateUpgradeFuncInfo{ + TypesInfo: info, + } + + switch node := node.(type) { + case *ast.FuncDecl: + result.AstFuncDecl = node + result.Body = node.Body + result.Node = node + result.Pos = node.Pos() + result.Type = node.Type + case *ast.FuncLit: + result.AstFuncLit = node + result.Body = node.Body + result.Node = node + result.Pos = node.Pos() + result.Type = node.Type + } + + return result +} diff --git a/vendor/github.com/bflad/tfproviderlint/passes/R007/R007.go b/vendor/github.com/bflad/tfproviderlint/passes/R007/R007.go index 1060470e9ed..e59f6f5bd01 100644 --- a/vendor/github.com/bflad/tfproviderlint/passes/R007/R007.go +++ b/vendor/github.com/bflad/tfproviderlint/passes/R007/R007.go @@ -3,13 +3,15 @@ package R007 import ( "github.com/bflad/tfproviderlint/helper/analysisutils" "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatapartialcallexpr" "github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatapartialselectorexpr" ) var Analyzer = analysisutils.DeprecatedReceiverMethodSelectorExprAnalyzer( "R007", + resourcedatapartialcallexpr.Analyzer, resourcedatapartialselectorexpr.Analyzer, - schema.PackageName, + schema.PackagePath, schema.TypeNameResourceData, "Partial", ) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/R008/R008.go b/vendor/github.com/bflad/tfproviderlint/passes/R008/R008.go index 46cd3b1feb3..2eaac056f04 100644 --- a/vendor/github.com/bflad/tfproviderlint/passes/R008/R008.go +++ b/vendor/github.com/bflad/tfproviderlint/passes/R008/R008.go @@ -3,13 +3,15 @@ package R008 import ( "github.com/bflad/tfproviderlint/helper/analysisutils" "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatasetpartialcallexpr" "github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatasetpartialselectorexpr" ) var Analyzer = analysisutils.DeprecatedReceiverMethodSelectorExprAnalyzer( "R008", + resourcedatasetpartialcallexpr.Analyzer, resourcedatasetpartialselectorexpr.Analyzer, - schema.PackageName, + schema.PackagePath, schema.TypeNameResourceData, "SetPartial", ) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/V002/V002.go b/vendor/github.com/bflad/tfproviderlint/passes/V002/V002.go index 31ba026efb2..24aaec9e898 100644 --- a/vendor/github.com/bflad/tfproviderlint/passes/V002/V002.go +++ b/vendor/github.com/bflad/tfproviderlint/passes/V002/V002.go @@ -9,8 +9,8 @@ import ( var Analyzer = analysisutils.DeprecatedWithReplacementSelectorExprAnalyzer( "V002", cidrnetworkselectorexpr.Analyzer, - validation.PackageName, + validation.PackagePath, validation.FuncNameCIDRNetwork, - validation.PackageName, + validation.PackagePath, validation.FuncNameIsCIDRNetwork, ) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/V003/V003.go b/vendor/github.com/bflad/tfproviderlint/passes/V003/V003.go index 30e13cc4e2c..75b361e3894 100644 --- a/vendor/github.com/bflad/tfproviderlint/passes/V003/V003.go +++ b/vendor/github.com/bflad/tfproviderlint/passes/V003/V003.go @@ -3,14 +3,16 @@ package V003 import ( "github.com/bflad/tfproviderlint/helper/analysisutils" "github.com/bflad/tfproviderlint/helper/terraformtype/helper/validation" + "github.com/bflad/tfproviderlint/passes/helper/validation/iprangecallexpr" "github.com/bflad/tfproviderlint/passes/helper/validation/iprangeselectorexpr" ) -var Analyzer = analysisutils.DeprecatedWithReplacementSelectorExprAnalyzer( +var Analyzer = analysisutils.DeprecatedEmptyCallExprWithReplacementSelectorExprAnalyzer( "V003", + iprangecallexpr.Analyzer, iprangeselectorexpr.Analyzer, - validation.PackageName, + validation.PackagePath, validation.FuncNameIPRange, - validation.PackageName, + validation.PackagePath, validation.FuncNameIsIPv4Range, ) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/V004/V004.go b/vendor/github.com/bflad/tfproviderlint/passes/V004/V004.go index b06d59e9194..50b1a20da02 100644 --- a/vendor/github.com/bflad/tfproviderlint/passes/V004/V004.go +++ b/vendor/github.com/bflad/tfproviderlint/passes/V004/V004.go @@ -3,14 +3,16 @@ package V004 import ( "github.com/bflad/tfproviderlint/helper/analysisutils" "github.com/bflad/tfproviderlint/helper/terraformtype/helper/validation" + "github.com/bflad/tfproviderlint/passes/helper/validation/singleipcallexpr" "github.com/bflad/tfproviderlint/passes/helper/validation/singleipselectorexpr" ) -var Analyzer = analysisutils.DeprecatedWithReplacementSelectorExprAnalyzer( +var Analyzer = analysisutils.DeprecatedEmptyCallExprWithReplacementSelectorExprAnalyzer( "V004", + singleipcallexpr.Analyzer, singleipselectorexpr.Analyzer, - validation.PackageName, + validation.PackagePath, validation.FuncNameSingleIP, - validation.PackageName, + validation.PackagePath, validation.FuncNameIsIPAddress, ) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/V005/V005.go b/vendor/github.com/bflad/tfproviderlint/passes/V005/V005.go index 8483ed115ef..1336a2faef3 100644 --- a/vendor/github.com/bflad/tfproviderlint/passes/V005/V005.go +++ b/vendor/github.com/bflad/tfproviderlint/passes/V005/V005.go @@ -9,8 +9,8 @@ import ( var Analyzer = analysisutils.DeprecatedWithReplacementSelectorExprAnalyzer( "V005", validatejsonstringselectorexpr.Analyzer, - validation.PackageName, + validation.PackagePath, validation.FuncNameValidateJsonString, - validation.PackageName, + validation.PackagePath, validation.FuncNameStringIsJSON, ) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/V006/V006.go b/vendor/github.com/bflad/tfproviderlint/passes/V006/V006.go index 1e1ae4e2940..96f54bf8c62 100644 --- a/vendor/github.com/bflad/tfproviderlint/passes/V006/V006.go +++ b/vendor/github.com/bflad/tfproviderlint/passes/V006/V006.go @@ -9,8 +9,8 @@ import ( var Analyzer = analysisutils.DeprecatedWithReplacementSelectorExprAnalyzer( "V006", validatelistuniquestringsselectorexpr.Analyzer, - validation.PackageName, + validation.PackagePath, validation.FuncNameValidateListUniqueStrings, - validation.PackageName, + validation.PackagePath, validation.FuncNameListOfUniqueStrings, ) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/V007/V007.go b/vendor/github.com/bflad/tfproviderlint/passes/V007/V007.go index 1fc49fc4801..da36c8e601e 100644 --- a/vendor/github.com/bflad/tfproviderlint/passes/V007/V007.go +++ b/vendor/github.com/bflad/tfproviderlint/passes/V007/V007.go @@ -9,8 +9,8 @@ import ( var Analyzer = analysisutils.DeprecatedWithReplacementSelectorExprAnalyzer( "V007", validateregexpselectorexpr.Analyzer, - validation.PackageName, + validation.PackagePath, validation.FuncNameValidateRegexp, - validation.PackageName, + validation.PackagePath, validation.FuncNameStringIsValidRegExp, ) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/V008/V008.go b/vendor/github.com/bflad/tfproviderlint/passes/V008/V008.go index 0644b8a5f1a..4a925a19a32 100644 --- a/vendor/github.com/bflad/tfproviderlint/passes/V008/V008.go +++ b/vendor/github.com/bflad/tfproviderlint/passes/V008/V008.go @@ -9,8 +9,8 @@ import ( var Analyzer = analysisutils.DeprecatedWithReplacementSelectorExprAnalyzer( "V008", validaterfc3339timestringselectorexpr.Analyzer, - validation.PackageName, + validation.PackagePath, validation.FuncNameValidateRFC3339TimeString, - validation.PackageName, + validation.PackagePath, validation.FuncNameIsRFC3339Time, ) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatapartialcallexpr/resourcedatapartialcallexpr.go b/vendor/github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatapartialcallexpr/resourcedatapartialcallexpr.go new file mode 100644 index 00000000000..6129b217472 --- /dev/null +++ b/vendor/github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatapartialcallexpr/resourcedatapartialcallexpr.go @@ -0,0 +1,14 @@ +package resourcedatapartialcallexpr + +import ( + "github.com/bflad/tfproviderlint/helper/analysisutils" + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" +) + +var Analyzer = analysisutils.ReceiverMethodCallExprAnalyzer( + "resourcedatapartialcallexpr", + schema.IsReceiverMethod, + schema.PackagePath, + schema.TypeNameResourceData, + "Partial", +) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatasetpartialcallexpr/resourcedatasetpartialcallexpr.go b/vendor/github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatasetpartialcallexpr/resourcedatasetpartialcallexpr.go new file mode 100644 index 00000000000..e01d742eab2 --- /dev/null +++ b/vendor/github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatasetpartialcallexpr/resourcedatasetpartialcallexpr.go @@ -0,0 +1,14 @@ +package resourcedatasetpartialcallexpr + +import ( + "github.com/bflad/tfproviderlint/helper/analysisutils" + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" +) + +var Analyzer = analysisutils.ReceiverMethodCallExprAnalyzer( + "resourcedatasetpartialcallexpr", + schema.IsReceiverMethod, + schema.PackagePath, + schema.TypeNameResourceData, + "SetPartial", +) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/helper/validation/iprangecallexpr/iprangecallexpr.go b/vendor/github.com/bflad/tfproviderlint/passes/helper/validation/iprangecallexpr/iprangecallexpr.go new file mode 100644 index 00000000000..5f2f556173a --- /dev/null +++ b/vendor/github.com/bflad/tfproviderlint/passes/helper/validation/iprangecallexpr/iprangecallexpr.go @@ -0,0 +1,13 @@ +package iprangecallexpr + +import ( + "github.com/bflad/tfproviderlint/helper/analysisutils" + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/validation" +) + +var Analyzer = analysisutils.FunctionCallExprAnalyzer( + "iprangecallexpr", + validation.IsFunc, + validation.PackagePath, + validation.FuncNameIPRange, +) diff --git a/vendor/github.com/bflad/tfproviderlint/passes/helper/validation/singleipcallexpr/singleipcallexpr.go b/vendor/github.com/bflad/tfproviderlint/passes/helper/validation/singleipcallexpr/singleipcallexpr.go new file mode 100644 index 00000000000..6ddd27af991 --- /dev/null +++ b/vendor/github.com/bflad/tfproviderlint/passes/helper/validation/singleipcallexpr/singleipcallexpr.go @@ -0,0 +1,13 @@ +package singleipcallexpr + +import ( + "github.com/bflad/tfproviderlint/helper/analysisutils" + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/validation" +) + +var Analyzer = analysisutils.FunctionCallExprAnalyzer( + "singleipcallexpr", + validation.IsFunc, + validation.PackagePath, + validation.FuncNameSingleIP, +) diff --git a/vendor/github.com/bflad/tfproviderlint/version/version.go b/vendor/github.com/bflad/tfproviderlint/version/version.go index 1b0a8292d07..e167f14be56 100644 --- a/vendor/github.com/bflad/tfproviderlint/version/version.go +++ b/vendor/github.com/bflad/tfproviderlint/version/version.go @@ -10,7 +10,7 @@ var ( GitCommit string // The main version number that is being run at the moment. - Version = "0.12.0" + Version = "0.13.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release diff --git a/vendor/modules.txt b/vendor/modules.txt index b5dc39a9a50..31399007989 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -218,7 +218,7 @@ github.com/bflad/tfproviderdocs/check github.com/bflad/tfproviderdocs/check/sidenavigation github.com/bflad/tfproviderdocs/command github.com/bflad/tfproviderdocs/version -# github.com/bflad/tfproviderlint v0.12.0 +# github.com/bflad/tfproviderlint v0.14.0 github.com/bflad/tfproviderlint/cmd/tfproviderlint github.com/bflad/tfproviderlint/helper/analysisutils github.com/bflad/tfproviderlint/helper/astutils @@ -301,8 +301,10 @@ github.com/bflad/tfproviderlint/passes/helper/resource/testmatchresourceattrcall github.com/bflad/tfproviderlint/passes/helper/schema/crudfuncinfo github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatagetchangeassignstmt github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatagetokexistscallexpr +github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatapartialcallexpr github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatapartialselectorexpr github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatasetcallexpr +github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatasetpartialcallexpr github.com/bflad/tfproviderlint/passes/helper/schema/resourcedatasetpartialselectorexpr github.com/bflad/tfproviderlint/passes/helper/schema/resourceinfo github.com/bflad/tfproviderlint/passes/helper/schema/resourceinfodatasourceonly @@ -313,7 +315,9 @@ github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly github.com/bflad/tfproviderlint/passes/helper/schema/schemamapcompositelit github.com/bflad/tfproviderlint/passes/helper/schema/schemavalidatefuncinfo github.com/bflad/tfproviderlint/passes/helper/validation/cidrnetworkselectorexpr +github.com/bflad/tfproviderlint/passes/helper/validation/iprangecallexpr github.com/bflad/tfproviderlint/passes/helper/validation/iprangeselectorexpr +github.com/bflad/tfproviderlint/passes/helper/validation/singleipcallexpr github.com/bflad/tfproviderlint/passes/helper/validation/singleipselectorexpr github.com/bflad/tfproviderlint/passes/helper/validation/validatejsonstringselectorexpr github.com/bflad/tfproviderlint/passes/helper/validation/validatelistuniquestringsselectorexpr From cb72b1f24c1344533c32f421263db84e39bdd824 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 24 Mar 2020 16:04:15 -0400 Subject: [PATCH 064/684] service/ec2: Initial support for Local Zones (#12400) * service/ec2: Initial support for Local Zones Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/11136 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/11994 Changes: * New Resource: `aws_ec2_availability_zone_group` * data-source/aws_availability_zone: Add `all_availability_zones` and `filter` arguments * data-source/aws_availability_zone: Add `group_name`, `network_border_group`, and `opt_in_status` attributes * data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments * data-source/aws_availability_zones: Add `group_names` attribute ``` --- PASS: TestAccDataSourceAwsAvailabilityZone_Filter (17.53s) --- PASS: TestAccDataSourceAwsAvailabilityZone_ZoneId (17.74s) --- PASS: TestAccDataSourceAwsAvailabilityZone_AllAvailabilityZones (17.74s) --- PASS: TestAccDataSourceAwsAvailabilityZone_Name (17.79s) --- PASS: TestAccAWSAvailabilityZones_Filter (15.46s) --- PASS: TestAccAWSAvailabilityZones_stateFilter (15.87s) --- PASS: TestAccAWSAvailabilityZones_basic (16.60s) --- PASS: TestAccAWSAvailabilityZones_AllAvailabilityZones (16.70s) --- PASS: TestAccAWSAvailabilityZones_BlacklistedNames (17.00s) --- PASS: TestAccAWSAvailabilityZones_BlacklistedZoneIds (17.14s) --- PASS: TestAccAWSEc2AvailabilityZoneGroup_OptInStatus (37.67s) ``` --- aws/data_source_aws_availability_zone.go | 39 +++- aws/data_source_aws_availability_zone_test.go | 144 ++++++++++++-- aws/data_source_aws_availability_zones.go | 34 ++++ ...data_source_aws_availability_zones_test.go | 69 +++++++ aws/provider.go | 1 + ...esource_aws_ec2_availability_zone_group.go | 188 ++++++++++++++++++ ...ce_aws_ec2_availability_zone_group_test.go | 102 ++++++++++ website/aws.erb | 3 + .../docs/d/availability_zone.html.markdown | 30 ++- .../docs/d/availability_zones.html.markdown | 40 ++++ .../ec2_availability_zone_group.html.markdown | 43 ++++ 11 files changed, 651 insertions(+), 42 deletions(-) create mode 100644 aws/resource_aws_ec2_availability_zone_group.go create mode 100644 aws/resource_aws_ec2_availability_zone_group_test.go create mode 100644 website/docs/r/ec2_availability_zone_group.html.markdown diff --git a/aws/data_source_aws_availability_zone.go b/aws/data_source_aws_availability_zone.go index 3878aa75d34..15db6af609c 100644 --- a/aws/data_source_aws_availability_zone.go +++ b/aws/data_source_aws_availability_zone.go @@ -14,28 +14,41 @@ func dataSourceAwsAvailabilityZone() *schema.Resource { Read: dataSourceAwsAvailabilityZoneRead, Schema: map[string]*schema.Schema{ + "all_availability_zones": { + Type: schema.TypeBool, + Optional: true, + }, + "filter": ec2CustomFiltersSchema(), + "group_name": { + Type: schema.TypeString, + Computed: true, + }, "name": { Type: schema.TypeString, Optional: true, Computed: true, }, - - "region": { + "name_suffix": { Type: schema.TypeString, Computed: true, }, - - "name_suffix": { + "network_border_group": { + Type: schema.TypeString, + Computed: true, + }, + "opt_in_status": { + Type: schema.TypeString, + Computed: true, + }, + "region": { Type: schema.TypeString, Computed: true, }, - "state": { Type: schema.TypeString, Optional: true, Computed: true, }, - "zone_id": { Type: schema.TypeString, Optional: true, @@ -50,6 +63,10 @@ func dataSourceAwsAvailabilityZoneRead(d *schema.ResourceData, meta interface{}) req := &ec2.DescribeAvailabilityZonesInput{} + if v, ok := d.GetOk("all_availability_zones"); ok { + req.AllAvailabilityZones = aws.Bool(v.(bool)) + } + if v := d.Get("name").(string); v != "" { req.ZoneNames = []*string{aws.String(v)} } @@ -61,6 +78,13 @@ func dataSourceAwsAvailabilityZoneRead(d *schema.ResourceData, meta interface{}) "state": d.Get("state").(string), }, ) + + if filters, filtersOk := d.GetOk("filter"); filtersOk { + req.Filters = append(req.Filters, buildEC2CustomFilterList( + filters.(*schema.Set), + )...) + } + if len(req.Filters) == 0 { // Don't send an empty filters list; the EC2 API won't accept it. req.Filters = nil @@ -87,8 +111,11 @@ func dataSourceAwsAvailabilityZoneRead(d *schema.ResourceData, meta interface{}) nameSuffix := (*az.ZoneName)[len(*az.RegionName):] d.SetId(aws.StringValue(az.ZoneName)) + d.Set("group_name", az.GroupName) d.Set("name", az.ZoneName) d.Set("name_suffix", nameSuffix) + d.Set("network_border_group", az.NetworkBorderGroup) + d.Set("opt_in_status", az.OptInStatus) d.Set("region", az.RegionName) d.Set("state", az.State) d.Set("zone_id", az.ZoneId) diff --git a/aws/data_source_aws_availability_zone_test.go b/aws/data_source_aws_availability_zone_test.go index 10f63470d3b..327e72e566a 100644 --- a/aws/data_source_aws_availability_zone_test.go +++ b/aws/data_source_aws_availability_zone_test.go @@ -1,43 +1,149 @@ package aws import ( + "fmt" + "regexp" "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" ) -func TestAccDataSourceAwsAvailabilityZone(t *testing.T) { - ds1ResourceName := "data.aws_availability_zone.by_name" - ds2ResourceName := "data.aws_availability_zone.by_zone_id" +func TestAccDataSourceAwsAvailabilityZone_AllAvailabilityZones(t *testing.T) { + availabilityZonesDataSourceName := "data.aws_availability_zones.test" + dataSourceName := "data.aws_availability_zone.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsAvailabilityZoneConfig, + Config: testAccDataSourceAwsAvailabilityZoneConfigAllAvailabilityZones(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(ds1ResourceName, "name", "us-west-2a"), - resource.TestCheckResourceAttr(ds1ResourceName, "name_suffix", "a"), - resource.TestCheckResourceAttr(ds1ResourceName, "region", "us-west-2"), - resource.TestCheckResourceAttrSet(ds1ResourceName, "zone_id"), - - resource.TestCheckResourceAttr(ds2ResourceName, "name", "us-west-2a"), - resource.TestCheckResourceAttr(ds2ResourceName, "name_suffix", "a"), - resource.TestCheckResourceAttr(ds2ResourceName, "region", "us-west-2"), - resource.TestCheckResourceAttrPair(ds2ResourceName, "zone_id", ds1ResourceName, "zone_id"), + resource.TestCheckResourceAttr(dataSourceName, "group_name", testAccGetRegion()), + resource.TestCheckResourceAttrPair(dataSourceName, "name", availabilityZonesDataSourceName, "names.0"), + resource.TestMatchResourceAttr(dataSourceName, "name_suffix", regexp.MustCompile(`^[a-z]$`)), + resource.TestCheckResourceAttr(dataSourceName, "network_border_group", testAccGetRegion()), + resource.TestCheckResourceAttr(dataSourceName, "opt_in_status", "opt-in-not-required"), + resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()), + resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"), ), }, }, }) } -const testAccDataSourceAwsAvailabilityZoneConfig = ` -data "aws_availability_zone" "by_name" { - name = "us-west-2a" +func TestAccDataSourceAwsAvailabilityZone_Filter(t *testing.T) { + availabilityZonesDataSourceName := "data.aws_availability_zones.test" + dataSourceName := "data.aws_availability_zone.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsAvailabilityZoneConfigFilter(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "group_name", testAccGetRegion()), + resource.TestCheckResourceAttrPair(dataSourceName, "name", availabilityZonesDataSourceName, "names.0"), + resource.TestMatchResourceAttr(dataSourceName, "name_suffix", regexp.MustCompile(`^[a-z]$`)), + resource.TestCheckResourceAttr(dataSourceName, "network_border_group", testAccGetRegion()), + resource.TestCheckResourceAttr(dataSourceName, "opt_in_status", "opt-in-not-required"), + resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()), + resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"), + ), + }, + }, + }) +} + +func TestAccDataSourceAwsAvailabilityZone_Name(t *testing.T) { + availabilityZonesDataSourceName := "data.aws_availability_zones.test" + dataSourceName := "data.aws_availability_zone.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsAvailabilityZoneConfigName(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "group_name", testAccGetRegion()), + resource.TestCheckResourceAttrPair(dataSourceName, "name", availabilityZonesDataSourceName, "names.0"), + resource.TestMatchResourceAttr(dataSourceName, "name_suffix", regexp.MustCompile(`^[a-z]$`)), + resource.TestCheckResourceAttr(dataSourceName, "network_border_group", testAccGetRegion()), + resource.TestCheckResourceAttr(dataSourceName, "opt_in_status", "opt-in-not-required"), + resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()), + resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"), + ), + }, + }, + }) } -data "aws_availability_zone" "by_zone_id" { - zone_id = "${data.aws_availability_zone.by_name.zone_id}" +func TestAccDataSourceAwsAvailabilityZone_ZoneId(t *testing.T) { + availabilityZonesDataSourceName := "data.aws_availability_zones.test" + dataSourceName := "data.aws_availability_zone.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsAvailabilityZoneConfigZoneId(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "group_name", testAccGetRegion()), + resource.TestCheckResourceAttrPair(dataSourceName, "name", availabilityZonesDataSourceName, "names.0"), + resource.TestMatchResourceAttr(dataSourceName, "name_suffix", regexp.MustCompile(`^[a-z]$`)), + resource.TestCheckResourceAttr(dataSourceName, "network_border_group", testAccGetRegion()), + resource.TestCheckResourceAttr(dataSourceName, "opt_in_status", "opt-in-not-required"), + resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()), + resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"), + ), + }, + }, + }) +} + +func testAccDataSourceAwsAvailabilityZoneConfigAllAvailabilityZones() string { + return fmt.Sprintf(` +data "aws_availability_zones" "test" {} + +data "aws_availability_zone" "test" { + all_availability_zones = true + name = data.aws_availability_zones.test.names[0] +} +`) +} + +func testAccDataSourceAwsAvailabilityZoneConfigFilter() string { + return fmt.Sprintf(` +data "aws_availability_zones" "test" {} + +data "aws_availability_zone" "test" { + filter { + name = "zone-name" + values = [data.aws_availability_zones.test.names[0]] + } +} +`) +} + +func testAccDataSourceAwsAvailabilityZoneConfigName() string { + return fmt.Sprintf(` +data "aws_availability_zones" "test" {} + +data "aws_availability_zone" "test" { + name = data.aws_availability_zones.test.names[0] +} +`) +} + +func testAccDataSourceAwsAvailabilityZoneConfigZoneId() string { + return fmt.Sprintf(` +data "aws_availability_zones" "test" {} + +data "aws_availability_zone" "test" { + zone_id = data.aws_availability_zones.test.zone_ids[0] +} +`) } -` diff --git a/aws/data_source_aws_availability_zones.go b/aws/data_source_aws_availability_zones.go index b9e9526afea..bee053e1d9a 100644 --- a/aws/data_source_aws_availability_zones.go +++ b/aws/data_source_aws_availability_zones.go @@ -17,6 +17,10 @@ func dataSourceAwsAvailabilityZones() *schema.Resource { Read: dataSourceAwsAvailabilityZonesRead, Schema: map[string]*schema.Schema{ + "all_availability_zones": { + Type: schema.TypeBool, + Optional: true, + }, "blacklisted_names": { Type: schema.TypeSet, Optional: true, @@ -27,6 +31,12 @@ func dataSourceAwsAvailabilityZones() *schema.Resource { Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "filter": ec2CustomFiltersSchema(), + "group_names": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "names": { Type: schema.TypeList, Computed: true, @@ -59,6 +69,10 @@ func dataSourceAwsAvailabilityZonesRead(d *schema.ResourceData, meta interface{} request := &ec2.DescribeAvailabilityZonesInput{} + if v, ok := d.GetOk("all_availability_zones"); ok { + request.AllAvailabilityZones = aws.Bool(v.(bool)) + } + if v, ok := d.GetOk("state"); ok { request.Filters = []*ec2.Filter{ { @@ -68,6 +82,17 @@ func dataSourceAwsAvailabilityZonesRead(d *schema.ResourceData, meta interface{} } } + if filters, filtersOk := d.GetOk("filter"); filtersOk { + request.Filters = append(request.Filters, buildEC2CustomFilterList( + filters.(*schema.Set), + )...) + } + + if len(request.Filters) == 0 { + // Don't send an empty filters list; the EC2 API won't accept it. + request.Filters = nil + } + log.Printf("[DEBUG] Reading Availability Zones: %s", request) resp, err := conn.DescribeAvailabilityZones(request) if err != nil { @@ -80,9 +105,11 @@ func dataSourceAwsAvailabilityZonesRead(d *schema.ResourceData, meta interface{} blacklistedNames := d.Get("blacklisted_names").(*schema.Set) blacklistedZoneIDs := d.Get("blacklisted_zone_ids").(*schema.Set) + groupNames := schema.NewSet(schema.HashString, nil) names := []string{} zoneIds := []string{} for _, v := range resp.AvailabilityZones { + groupName := aws.StringValue(v.GroupName) name := aws.StringValue(v.ZoneName) zoneID := aws.StringValue(v.ZoneId) @@ -94,10 +121,17 @@ func dataSourceAwsAvailabilityZonesRead(d *schema.ResourceData, meta interface{} continue } + if !groupNames.Contains(groupName) { + groupNames.Add(groupName) + } + names = append(names, name) zoneIds = append(zoneIds, zoneID) } + if err := d.Set("group_names", groupNames); err != nil { + return fmt.Errorf("error setting group_names: %s", err) + } if err := d.Set("names", names); err != nil { return fmt.Errorf("Error setting Availability Zone names: %s", err) } diff --git a/aws/data_source_aws_availability_zones_test.go b/aws/data_source_aws_availability_zones_test.go index e5edde63fda..00877f12593 100644 --- a/aws/data_source_aws_availability_zones_test.go +++ b/aws/data_source_aws_availability_zones_test.go @@ -88,6 +88,23 @@ func TestAccAWSAvailabilityZones_basic(t *testing.T) { }) } +func TestAccAWSAvailabilityZones_AllAvailabilityZones(t *testing.T) { + dataSourceName := "data.aws_availability_zones.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckAwsAvailabilityZonesConfigAllAvailabilityZones(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAvailabilityZonesMeta(dataSourceName), + ), + }, + }, + }) +} + func TestAccAWSAvailabilityZones_BlacklistedNames(t *testing.T) { allDataSourceName := "data.aws_availability_zones.all" blacklistedDataSourceName := "data.aws_availability_zones.test" @@ -124,6 +141,23 @@ func TestAccAWSAvailabilityZones_BlacklistedZoneIds(t *testing.T) { }) } +func TestAccAWSAvailabilityZones_Filter(t *testing.T) { + dataSourceName := "data.aws_availability_zones.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckAwsAvailabilityZonesConfigFilter(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAvailabilityZonesMeta(dataSourceName), + ), + }, + }, + }) +} + func TestAccAWSAvailabilityZones_stateFilter(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -219,6 +253,22 @@ func testAccCheckAwsAvailabilityZoneState(n string) resource.TestCheckFunc { } func testAccCheckAwsAvailabilityZonesBuildAvailable(attrs map[string]string) ([]string, error) { + groupNames, groupNamesOk := attrs["group_names.#"] + + if !groupNamesOk { + return nil, fmt.Errorf("Availability Zone Group names list is missing.") + } + + groupNamesQty, err := strconv.Atoi(groupNames) + + if err != nil { + return nil, err + } + + if groupNamesQty < 1 { + return nil, fmt.Errorf("No Availability Zone Groups found in region, this is probably a bug.") + } + v, ok := attrs["names.#"] if !ok { return nil, fmt.Errorf("Available AZ name list is missing.") @@ -249,6 +299,14 @@ const testAccCheckAwsAvailabilityZonesConfig = ` data "aws_availability_zones" "availability_zones" { } ` +func testAccCheckAwsAvailabilityZonesConfigAllAvailabilityZones() string { + return fmt.Sprintf(` +data "aws_availability_zones" "test" { + all_availability_zones = true +} +`) +} + func testAccCheckAwsAvailabilityZonesConfigBlacklistedNames() string { return fmt.Sprintf(` data "aws_availability_zones" "all" {} @@ -269,6 +327,17 @@ data "aws_availability_zones" "test" { `) } +func testAccCheckAwsAvailabilityZonesConfigFilter() string { + return fmt.Sprintf(` +data "aws_availability_zones" "test" { + filter { + name = "state" + values = ["available"] + } +} +`) +} + const testAccCheckAwsAvailabilityZonesStateConfig = ` data "aws_availability_zones" "state_filter" { state = "available" diff --git a/aws/provider.go b/aws/provider.go index 3758c3ae6e2..be386f16d6b 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -491,6 +491,7 @@ func Provider() terraform.ResourceProvider { "aws_ebs_snapshot": resourceAwsEbsSnapshot(), "aws_ebs_snapshot_copy": resourceAwsEbsSnapshotCopy(), "aws_ebs_volume": resourceAwsEbsVolume(), + "aws_ec2_availability_zone_group": resourceAwsEc2AvailabilityZoneGroup(), "aws_ec2_capacity_reservation": resourceAwsEc2CapacityReservation(), "aws_ec2_client_vpn_endpoint": resourceAwsEc2ClientVpnEndpoint(), "aws_ec2_client_vpn_network_association": resourceAwsEc2ClientVpnNetworkAssociation(), diff --git a/aws/resource_aws_ec2_availability_zone_group.go b/aws/resource_aws_ec2_availability_zone_group.go new file mode 100644 index 00000000000..afa320795ee --- /dev/null +++ b/aws/resource_aws_ec2_availability_zone_group.go @@ -0,0 +1,188 @@ +package aws + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func resourceAwsEc2AvailabilityZoneGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsEc2AvailabilityZoneGroupCreate, + Read: resourceAwsEc2AvailabilityZoneGroupRead, + Update: resourceAwsEc2AvailabilityZoneGroupUpdate, + Delete: schema.Noop, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + d.Set("group_name", d.Id()) + + return []*schema.ResourceData{d}, nil + }, + }, + + Schema: map[string]*schema.Schema{ + "group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "opt_in_status": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + ec2.AvailabilityZoneOptInStatusOptedIn, + ec2.AvailabilityZoneOptInStatusNotOptedIn, + }, false), + }, + }, + } +} + +func resourceAwsEc2AvailabilityZoneGroupCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + configurationOptInStatus := d.Get("opt_in_status").(string) + + d.SetId(d.Get("group_name").(string)) + + if err := resourceAwsEc2AvailabilityZoneGroupRead(d, meta); err != nil { + return err + } + + apiOptInStatus := d.Get("opt_in_status").(string) + + if apiOptInStatus != configurationOptInStatus { + input := &ec2.ModifyAvailabilityZoneGroupInput{ + GroupName: aws.String(d.Id()), + OptInStatus: aws.String(configurationOptInStatus), + } + + if _, err := conn.ModifyAvailabilityZoneGroup(input); err != nil { + return fmt.Errorf("error modifying EC2 Availability Zone Group (%s): %w", d.Id(), err) + } + + if err := waitForEc2AvailabilityZoneGroupOptInStatus(conn, d.Id(), configurationOptInStatus); err != nil { + return fmt.Errorf("error waiting for EC2 Availability Zone Group (%s) opt-in status update: %w", d.Id(), err) + } + } + + return resourceAwsEc2AvailabilityZoneGroupRead(d, meta) +} + +func resourceAwsEc2AvailabilityZoneGroupRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + availabilityZone, err := ec2DescribeAvailabilityZoneGroup(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error describing EC2 Availability Zone Group (%s): %w", d.Id(), err) + } + + if aws.StringValue(availabilityZone.OptInStatus) == ec2.AvailabilityZoneOptInStatusOptInNotRequired { + return fmt.Errorf("unnecessary handling of EC2 Availability Zone Group (%s), status: %s", d.Id(), ec2.AvailabilityZoneOptInStatusOptInNotRequired) + } + + d.Set("group_name", availabilityZone.GroupName) + d.Set("opt_in_status", availabilityZone.OptInStatus) + + return nil +} + +func resourceAwsEc2AvailabilityZoneGroupUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + optInStatus := d.Get("opt_in_status").(string) + + input := &ec2.ModifyAvailabilityZoneGroupInput{ + GroupName: aws.String(d.Id()), + OptInStatus: aws.String(optInStatus), + } + + if _, err := conn.ModifyAvailabilityZoneGroup(input); err != nil { + return fmt.Errorf("error modifying EC2 Availability Zone Group (%s): %w", d.Id(), err) + } + + if err := waitForEc2AvailabilityZoneGroupOptInStatus(conn, d.Id(), optInStatus); err != nil { + return fmt.Errorf("error waiting for EC2 Availability Zone Group (%s) opt-in status update: %w", d.Id(), err) + } + + return resourceAwsEc2AvailabilityZoneGroupRead(d, meta) +} + +func ec2DescribeAvailabilityZoneGroup(conn *ec2.EC2, groupName string) (*ec2.AvailabilityZone, error) { + input := &ec2.DescribeAvailabilityZonesInput{ + AllAvailabilityZones: aws.Bool(true), + Filters: []*ec2.Filter{ + { + Name: aws.String("group-name"), + Values: aws.StringSlice([]string{groupName}), + }, + }, + } + + output, err := conn.DescribeAvailabilityZones(input) + + if err != nil { + return nil, err + } + + if output == nil || len(output.AvailabilityZones) == 0 { + return nil, nil + } + + for _, availabilityZone := range output.AvailabilityZones { + if availabilityZone == nil { + continue + } + + if aws.StringValue(availabilityZone.GroupName) == groupName { + return availabilityZone, nil + } + } + + return nil, nil +} + +func ec2AvailabilityZoneGroupOptInStatusRefreshFunc(conn *ec2.EC2, groupName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + availabilityZone, err := ec2DescribeAvailabilityZoneGroup(conn, groupName) + + if err != nil { + return nil, "", fmt.Errorf("error describing EC2 Availability Zone Group (%s): %w", groupName, err) + } + + if availabilityZone == nil { + return nil, "", fmt.Errorf("error describing EC2 Availability Zone Group (%s): not found", groupName) + } + + return availabilityZone, aws.StringValue(availabilityZone.OptInStatus), nil + } +} + +func waitForEc2AvailabilityZoneGroupOptInStatus(conn *ec2.EC2, groupName string, optInStatus string) error { + pending := ec2.AvailabilityZoneOptInStatusNotOptedIn + + if optInStatus == ec2.AvailabilityZoneOptInStatusNotOptedIn { + pending = ec2.AvailabilityZoneOptInStatusOptedIn + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{pending}, + Target: []string{optInStatus}, + Refresh: ec2AvailabilityZoneGroupOptInStatusRefreshFunc(conn, groupName), + Timeout: 10 * time.Minute, + Delay: 10 * time.Second, + MinTimeout: 2 * time.Second, + ContinuousTargetOccurence: 3, + } + + log.Printf("[DEBUG] Waiting for EC2 Availability Zone Group (%s) opt-in status update", groupName) + _, err := stateConf.WaitForState() + + return err +} diff --git a/aws/resource_aws_ec2_availability_zone_group_test.go b/aws/resource_aws_ec2_availability_zone_group_test.go new file mode 100644 index 00000000000..4bb8bfe1ce1 --- /dev/null +++ b/aws/resource_aws_ec2_availability_zone_group_test.go @@ -0,0 +1,102 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccAWSEc2AvailabilityZoneGroup_OptInStatus(t *testing.T) { + resourceName := "aws_ec2_availability_zone_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEc2AvailabilityZoneGroup(t) }, + Providers: testAccProviders, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccEc2AvailabilityZoneGroupConfigOptInStatus(ec2.AvailabilityZoneOptInStatusOptedIn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "opt_in_status", ec2.AvailabilityZoneOptInStatusOptedIn), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + // InvalidOptInStatus: Opting out of Local Zones is not currently supported. Contact AWS Support for additional assistance. + /* + { + Config: testAccEc2AvailabilityZoneGroupConfigOptInStatus(ec2.AvailabilityZoneOptInStatusNotOptedIn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "opt_in_status", ec2.AvailabilityZoneOptInStatusNotOptedIn), + ), + }, + { + Config: testAccEc2AvailabilityZoneGroupConfigOptInStatus(ec2.AvailabilityZoneOptInStatusOptedIn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "opt_in_status", ec2.AvailabilityZoneOptInStatusOptedIn), + ), + }, + */ + }, + }) +} + +func testAccPreCheckAWSEc2AvailabilityZoneGroup(t *testing.T) { + conn := testAccProvider.Meta().(*AWSClient).ec2conn + + input := &ec2.DescribeAvailabilityZonesInput{ + AllAvailabilityZones: aws.Bool(true), + Filters: []*ec2.Filter{ + { + Name: aws.String("opt-in-status"), + Values: aws.StringSlice([]string{ + ec2.AvailabilityZoneOptInStatusNotOptedIn, + ec2.AvailabilityZoneOptInStatusOptedIn, + }), + }, + }, + } + + output, err := conn.DescribeAvailabilityZones(input) + + if testAccPreCheckSkipError(err) { + t.Skipf("skipping acceptance testing: %s", err) + } + + if err != nil { + t.Fatalf("unexpected PreCheck error: %s", err) + } + + if output == nil || len(output.AvailabilityZones) == 0 || output.AvailabilityZones[0] == nil { + t.Skipf("skipping acceptance testing: no opt-in EC2 Availability Zone Groups found") + } +} + +func testAccEc2AvailabilityZoneGroupConfigOptInStatus(optInStatus string) string { + return fmt.Sprintf(` +data "aws_availability_zones" "test" { + all_availability_zones = true + + # Filter to one Availability Zone Group per Region as Local Zones become available + # e.g. ensure there are not two us-west-2-XXX when adding to this list + filter { + name = "group-name" + values = [ + "us-west-2-lax-1", + ] + } +} + +resource "aws_ec2_availability_zone_group" "test" { + # The above group-name filter should ensure one Availability Zone Group per Region + group_name = tolist(data.aws_availability_zones.test.group_names)[0] + opt_in_status = %[1]q +} +`, optInStatus) +} diff --git a/website/aws.erb b/website/aws.erb index b338883522c..b5b8540d4c4 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -1113,6 +1113,9 @@
  • aws_ebs_volume
  • +
  • + aws_ec2_availability_zone_group +
  • aws_ec2_capacity_reservation
  • diff --git a/website/docs/d/availability_zone.html.markdown b/website/docs/d/availability_zone.html.markdown index eb6fcd1b0d6..b4be1d4fe6a 100644 --- a/website/docs/d/availability_zone.html.markdown +++ b/website/docs/d/availability_zone.html.markdown @@ -74,29 +74,25 @@ The arguments of this data source act as filters for querying the available availability zones. The given filters must match exactly one availability zone whose data will be exported as attributes. +* `all_availability_zones` - (Optional) Set to `true` to include all Availability Zones and Local Zones regardless of your opt in status. +* `filter` - (Optional) Configuration block(s) for filtering. Detailed below. * `name` - (Optional) The full name of the availability zone to select. +* `state` - (Optional) A specific availability zone state to require. May be any of `"available"`, `"information"` or `"impaired"`. +* `zone_id` - (Optional) The zone ID of the availability zone to select. -* `state` - (Optional) A specific availability zone state to require. May - be any of `"available"`, `"information"` or `"impaired"`. +### filter Configuration Block -* `zone_id` - (Optional) The zone ID of the availability zone to select. +The following arguments are supported by the `filter` configuration block: -All reasonable uses of this data source will specify `name`, since `state` -alone would match a single AZ only in a region that itself has only one AZ. +* `name` - (Required) The name of the filter field. Valid values can be found in the [EC2 DescribeAvailabilityZones API Reference](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeAvailabilityZones.html). +* `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. ## Attributes Reference In addition to all arguments above, the following attributes are exported: -* `name` - The name of the selected availability zone. - -* `region` - The region where the selected availability zone resides. - This is always the region selected on the provider, since this data source - searches only within that region. - -* `name_suffix` - The part of the AZ name that appears after the region name, - uniquely identifying the AZ within its region. - -* `state` - The current state of the AZ. - -* `zone_id` - (Optional) The zone ID of the selected availability zone. +* `group_name` - For Availability Zones, this is the same value as the Region name. For Local Zones, the name of the associated group, for example `us-west-2-lax-1`. +* `name_suffix` - The part of the AZ name that appears after the region name, uniquely identifying the AZ within its region. +* `network_border_group` - The name of the location from which the address is advertised. +* `opt_in_status` - For Availability Zones, this always has the value of `opt-in-not-required`. For Local Zones, this is the opt in status. The possible values are `opted-in` and `not-opted-in`. +* `region` - The region where the selected availability zone resides. This is always the region selected on the provider, since this data source searches only within that region. diff --git a/website/docs/d/availability_zones.html.markdown b/website/docs/d/availability_zones.html.markdown index 8f025764aef..5939110abe4 100644 --- a/website/docs/d/availability_zones.html.markdown +++ b/website/docs/d/availability_zones.html.markdown @@ -15,8 +15,12 @@ configured in the provider. This is different from the `aws_availability_zone` (singular) data source, which provides some details about a specific availability zone. +-> When [Local Zones](https://aws.amazon.com/about-aws/global-infrastructure/localzones/) are enabled in a region, by default the API and this data source include both Local Zones and Availability Zones. To return only Availability Zones, see the example section below. + ## Example Usage +### By State + ```hcl # Declare the data source data "aws_availability_zones" "available" { @@ -38,21 +42,57 @@ resource "aws_subnet" "secondary" { } ``` +### By Filter + +All Local Zones (regardless of opt-in status): + +```hcl +data "aws_availability_zones" "example" { + all_availability_zones = true + + filter { + name = "opt-in-status" + values = ["not-opted-in", "opted-in"] + } +} +``` + +Only Availability Zones (no Local Zones): + +``` +data "aws_availability_zones" "example" { + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} +``` + ## Argument Reference The following arguments are supported: +* `all_availability_zones` - (Optional) Set to `true` to include all Availability Zones and Local Zones regardless of your opt in status. * `blacklisted_names` - (Optional) List of blacklisted Availability Zone names. * `blacklisted_zone_ids` - (Optional) List of blacklisted Availability Zone IDs. +* `filter` - (Optional) Configuration block(s) for filtering. Detailed below. * `state` - (Optional) Allows to filter list of Availability Zones based on their current state. Can be either `"available"`, `"information"`, `"impaired"` or `"unavailable"`. By default the list includes a complete set of Availability Zones to which the underlying AWS account has access, regardless of their state. +### filter Configuration Block + +The following arguments are supported by the `filter` configuration block: + +* `name` - (Required) The name of the filter field. Valid values can be found in the [EC2 DescribeAvailabilityZones API Reference](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeAvailabilityZones.html). +* `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: +* `group_names` A set of the Availability Zone Group names. For Availability Zones, this is the same value as the Region name. For Local Zones, the name of the associated group, for example `us-west-2-lax-1`. * `names` - A list of the Availability Zone names available to the account. * `zone_ids` - A list of the Availability Zone IDs available to the account. diff --git a/website/docs/r/ec2_availability_zone_group.html.markdown b/website/docs/r/ec2_availability_zone_group.html.markdown new file mode 100644 index 00000000000..76b9e2dd27d --- /dev/null +++ b/website/docs/r/ec2_availability_zone_group.html.markdown @@ -0,0 +1,43 @@ +--- +subcategory: "EC2" +layout: "aws" +page_title: "AWS: aws_ec2_availability_zone_group" +description: |- + Manages an EC2 Availability Zone Group. +--- + +# Resource: aws_ec2_availability_zone_group + +Manages an EC2 Availability Zone Group, such as updating its opt-in status. + +~> **NOTE:** This is an advanced Terraform resource. Terraform will automatically assume management of the EC2 Availability Zone Group without import and perform no actions on removal from configuration. + +## Example Usage + +```hcl +resource "aws_ec2_availability_zone_group" "example" { + group_name = "us-west-2-lax-1" + opt_in_status = "opted-in" +} +``` + +## Argument Reference + +The following arguments are required: + +* `group_name` - (Required) Name of the Availability Zone Group. +* `opt_in_status` - (Required) Indicates whether to enable or disable Availability Zone Group. Valid values: `opted-in` or `not-opted-in`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - Name of the Availability Zone Group. + +## Import + +EC2 Availability Zone Groups can be imported using the group name, e.g. + +``` +$ terraform import aws_ec2_availability_zone_group.example us-west-2-lax-1 +``` From 81c55de44d67ad4515e615b9a5992a65be06bff6 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 24 Mar 2020 16:06:16 -0400 Subject: [PATCH 065/684] Update CHANGELOG for #12400 --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbaa62a8afe..4e1b9d7dc1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,16 @@ ## 2.55.0 (Unreleased) + +FEATURES: + +* **New Resource:** `aws_ec2_availability_zone_group` [GH-12400] + +ENHANCEMENTS: + +* data-source/aws_availability_zone: Add `all_availability_zones` and `filter` arguments [GH-12400] +* data-source/aws_availability_zone: Add `group_name`, `network_border_group`, and `opt_in_status` attributes [GH-12400] +* data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments [GH-12400] +* data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] + ## 2.54.0 (March 19, 2020) FEATURES: From 913a1162ce9fdb400a62d0bdb7afa34803190df3 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Tue, 24 Mar 2020 22:12:39 +0200 Subject: [PATCH 066/684] Update launch_template.html.markdown --- website/docs/d/launch_template.html.markdown | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/website/docs/d/launch_template.html.markdown b/website/docs/d/launch_template.html.markdown index 52512bd210f..c8ce035bea7 100644 --- a/website/docs/d/launch_template.html.markdown +++ b/website/docs/d/launch_template.html.markdown @@ -18,7 +18,7 @@ data "aws_launch_template" "default" { } ``` -Filter usage: +### Filter ```hcl data "aws_launch_template" "test" { @@ -34,9 +34,14 @@ data "aws_launch_template" "test" { The following arguments are supported: * `name` - (Optional) The name of the launch template. -* `filter` - (Optional) One or more name/value pairs to use as filters. There are -several valid keys, for a full reference, check out -[describe-launch-templates in the AWS CLI reference][1]. +* `filter` - (Optional) Configuration block(s) for filtering. Detailed below. + +### filter Configuration Block + +The following arguments are supported by the `filter` configuration block: + +* `name` - (Required) The name of the filter field. Valid values can be found in the [EC2 DescribeLaunchTemplates API Reference](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeLaunchTemplates.html). +* `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. ## Attributes Reference @@ -76,5 +81,3 @@ In addition to all arguments above, the following attributes are exported: * `tag_specifications` - The tags to apply to the resources during launch. * `tags` - (Optional) A mapping of tags to assign to the launch template. * `user_data` - The Base64-encoded user data to provide when launching the instance. - -[1]: https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-launch-templates.html From 724da0e021dd58e28324234e2efc73b07bb03acd Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 23 Mar 2020 14:48:08 -0700 Subject: [PATCH 067/684] No longer stops sweepers for Elastic Beanstalk Applications and Environments on the first error --- ..._aws_elastic_beanstalk_application_test.go | 26 ++++----- ..._aws_elastic_beanstalk_environment_test.go | 54 +++++++++---------- 2 files changed, 34 insertions(+), 46 deletions(-) diff --git a/aws/resource_aws_elastic_beanstalk_application_test.go b/aws/resource_aws_elastic_beanstalk_application_test.go index 258adb0f2b0..217eded6849 100644 --- a/aws/resource_aws_elastic_beanstalk_application_test.go +++ b/aws/resource_aws_elastic_beanstalk_application_test.go @@ -6,14 +6,13 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/elasticbeanstalk" + multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" ) -// initialize sweeper func init() { resource.AddTestSweepers("aws_elastic_beanstalk_application", &resource.Sweeper{ Name: "aws_elastic_beanstalk_application", @@ -35,7 +34,7 @@ func testSweepElasticBeanstalkApplications(region string) error { log.Printf("[WARN] Skipping Elastic Beanstalk Application sweep for %s: %s", region, err) return nil } - return fmt.Errorf("Error retrieving beanstalk application: %s", err) + return fmt.Errorf("error retrieving beanstalk application: %w", err) } if len(resp.Applications) == 0 { @@ -43,23 +42,24 @@ func testSweepElasticBeanstalkApplications(region string) error { return nil } + var errors error for _, bsa := range resp.Applications { + applicationName := aws.StringValue(bsa.ApplicationName) _, err := beanstalkconn.DeleteApplication( &elasticbeanstalk.DeleteApplicationInput{ ApplicationName: bsa.ApplicationName, }) if err != nil { - elasticbeanstalkerr, ok := err.(awserr.Error) - if ok && (elasticbeanstalkerr.Code() == "InvalidConfiguration.NotFound" || elasticbeanstalkerr.Code() == "ValidationError") { - log.Printf("[DEBUG] beanstalk application (%s) not found", *bsa.ApplicationName) - return nil + if isAWSErr(err, "InvalidConfiguration.NotFound", "") || isAWSErr(err, "ValidationError", "") { + log.Printf("[DEBUG] beanstalk application %q not found", applicationName) + continue } - return err + errors = multierror.Append(fmt.Errorf("error deleting Elastic Beanstalk Application %q: %w", applicationName, err)) } } - return nil + return errors } func TestAccAWSElasticBeanstalkApplication_basic(t *testing.T) { @@ -243,16 +243,10 @@ func testAccCheckBeanstalkAppDestroy(s *terraform.State) error { if len(resp.Applications) > 0 { return fmt.Errorf("Elastic Beanstalk Application still exists.") } - return nil } - // Verify the error is what we want - ec2err, ok := err.(awserr.Error) - if !ok { - return err - } - if ec2err.Code() != "InvalidBeanstalkAppID.NotFound" { + if !isAWSErr(err, "InvalidBeanstalkAppID.NotFound", "") { return err } } diff --git a/aws/resource_aws_elastic_beanstalk_environment_test.go b/aws/resource_aws_elastic_beanstalk_environment_test.go index 8c30d5acbe6..e02e655691e 100644 --- a/aws/resource_aws_elastic_beanstalk_environment_test.go +++ b/aws/resource_aws_elastic_beanstalk_environment_test.go @@ -10,15 +10,14 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/elasticbeanstalk" + multierror "github.com/hashicorp/go-multierror" "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/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) -// initialize sweeper func init() { resource.AddTestSweepers("aws_elastic_beanstalk_environment", &resource.Sweeper{ Name: "aws_elastic_beanstalk_environment", @@ -29,7 +28,7 @@ func init() { func testSweepElasticBeanstalkEnvironments(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } beanstalkconn := client.(*AWSClient).elasticbeanstalkconn @@ -42,7 +41,7 @@ func testSweepElasticBeanstalkEnvironments(region string) error { log.Printf("[WARN] Skipping Elastic Beanstalk Environment sweep for %s: %s", region, err) return nil } - return fmt.Errorf("Error retrieving beanstalk environment: %s", err) + return fmt.Errorf("error retrieving beanstalk environment: %w", err) } if len(resp.Environments) == 0 { @@ -50,8 +49,11 @@ func testSweepElasticBeanstalkEnvironments(region string) error { return nil } + var errors error for _, bse := range resp.Environments { - log.Printf("Trying to terminate (%s) (%s)", *bse.EnvironmentName, *bse.EnvironmentId) + environmentName := aws.StringValue(bse.EnvironmentName) + environmentID := aws.StringValue(bse.EnvironmentId) + log.Printf("Trying to terminate (%s) (%s)", environmentName, environmentID) _, err := beanstalkconn.TerminateEnvironment( &elasticbeanstalk.TerminateEnvironmentInput{ @@ -60,13 +62,11 @@ func testSweepElasticBeanstalkEnvironments(region string) error { }) if err != nil { - elasticbeanstalkerr, ok := err.(awserr.Error) - if ok && (elasticbeanstalkerr.Code() == "InvalidConfiguration.NotFound" || elasticbeanstalkerr.Code() == "ValidationError") { - log.Printf("[DEBUG] beanstalk environment (%s) not found", *bse.EnvironmentName) - return nil + if isAWSErr(err, "InvalidConfiguration.NotFound", "") || isAWSErr(err, "ValidationError", "") { + log.Printf("[DEBUG] Elastic Beanstalk Environment %q not found", environmentName) + continue } - - return err + errors = multierror.Append(fmt.Errorf("error terminating Elastic Beanstalk Environment %q: %w", environmentName, err)) } waitForReadyTimeOut, _ := time.ParseDuration("5m") @@ -77,7 +77,7 @@ func testSweepElasticBeanstalkEnvironments(region string) error { stateConf := &resource.StateChangeConf{ Pending: []string{"Terminating"}, Target: []string{"Terminated"}, - Refresh: environmentStateRefreshFunc(beanstalkconn, *bse.EnvironmentId, t), + Refresh: environmentStateRefreshFunc(beanstalkconn, environmentID, t), Timeout: waitForReadyTimeOut, Delay: 10 * time.Second, PollInterval: pollInterval, @@ -86,14 +86,13 @@ func testSweepElasticBeanstalkEnvironments(region string) error { _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf( - "Error waiting for Elastic Beanstalk Environment (%s) to become terminated: %s", - *bse.EnvironmentId, err) + errors = multierror.Append(fmt.Errorf("Error waiting for Elastic Beanstalk Environment %q to become terminated: %w", environmentID, err)) + continue } - log.Printf("> Terminated (%s) (%s)", *bse.EnvironmentName, *bse.EnvironmentId) + log.Printf("> Terminated (%s) (%s)", environmentName, environmentID) } - return nil + return errors } func TestAccAWSBeanstalkEnv_basic(t *testing.T) { @@ -106,7 +105,7 @@ func TestAccAWSBeanstalkEnv_basic(t *testing.T) { beanstalkElbNameRegexp := regexp.MustCompile("awseb.+?EBLoa[^,]+") beanstalkInstancesNameRegexp := regexp.MustCompile("i-([0-9a-fA-F]{8}|[0-9a-fA-F]{17})") beanstalkLcNameRegexp := regexp.MustCompile("awseb.+?AutoScalingLaunch[^,]+") - beanstalkEndpointUrl := regexp.MustCompile("awseb.+?EBLoa[^,].+?elb.amazonaws.com") + beanstalkEndpointURL := regexp.MustCompile("awseb.+?EBLoa[^,].+?elb.amazonaws.com") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -119,7 +118,7 @@ func TestAccAWSBeanstalkEnv_basic(t *testing.T) { testAccCheckBeanstalkEnvExists(resourceName, &app), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "elasticbeanstalk", fmt.Sprintf("environment/%s/%s", rName, rName)), resource.TestMatchResourceAttr(resourceName, "autoscaling_groups.0", beanstalkAsgNameRegexp), - resource.TestMatchResourceAttr(resourceName, "endpoint_url", beanstalkEndpointUrl), + resource.TestMatchResourceAttr(resourceName, "endpoint_url", beanstalkEndpointURL), resource.TestMatchResourceAttr(resourceName, "instances.0", beanstalkInstancesNameRegexp), resource.TestMatchResourceAttr(resourceName, "launch_configurations.0", beanstalkLcNameRegexp), resource.TestMatchResourceAttr(resourceName, "load_balancers.0", beanstalkElbNameRegexp), @@ -544,7 +543,7 @@ func testAccVerifyBeanstalkConfig(env *elasticbeanstalk.EnvironmentDescription, sort.Strings(testStrings) sort.Strings(expected) if !reflect.DeepEqual(testStrings, expected) { - return fmt.Errorf("Error matching strings, expected:\n\n%#v\n\ngot:\n\n%#v\n", testStrings, foundEnvs) + return fmt.Errorf("error matching strings, expected:\n\n%#v\n\ngot:\n\n%#v", testStrings, foundEnvs) } return nil @@ -567,23 +566,18 @@ func testAccCheckBeanstalkEnvDestroy(s *terraform.State) error { if err == nil { switch { case len(resp.Environments) > 1: - return fmt.Errorf("Error %d environments match, expected 1", len(resp.Environments)) + return fmt.Errorf("error %d environments match, expected 1", len(resp.Environments)) case len(resp.Environments) == 1: if *resp.Environments[0].Status == "Terminated" { return nil } - return fmt.Errorf("Elastic Beanstalk ENV still exists.") + return fmt.Errorf("Elastic Beanstalk ENV still exists") default: return nil } } - // Verify the error is what we want - ec2err, ok := err.(awserr.Error) - if !ok { - return err - } - if ec2err.Code() != "InvalidBeanstalkEnvID.NotFound" { + if !isAWSErr(err, "InvalidBeanstalkEnvID.NotFound", "") { return err } } @@ -746,10 +740,10 @@ func describeBeanstalkEnv(conn *elasticbeanstalk.ElasticBeanstalk, return &elasticbeanstalk.EnvironmentDescription{}, err } if len(resp.Environments) == 0 { - return &elasticbeanstalk.EnvironmentDescription{}, fmt.Errorf("Elastic Beanstalk ENV not found.") + return &elasticbeanstalk.EnvironmentDescription{}, fmt.Errorf("Elastic Beanstalk ENV not found") } if len(resp.Environments) > 1 { - return &elasticbeanstalk.EnvironmentDescription{}, fmt.Errorf("Found %d environments, expected 1.", len(resp.Environments)) + return &elasticbeanstalk.EnvironmentDescription{}, fmt.Errorf("found %d environments, expected 1", len(resp.Environments)) } return resp.Environments[0], nil } From 46474871ac6590458012d89aca0a9f71bc5f7f3f Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 23 Mar 2020 14:51:50 -0700 Subject: [PATCH 068/684] Updates Elastic Beanstalk Platform ARN to supported platform version --- aws/resource_aws_elastic_beanstalk_environment_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_elastic_beanstalk_environment_test.go b/aws/resource_aws_elastic_beanstalk_environment_test.go index e02e655691e..469aa80d5ce 100644 --- a/aws/resource_aws_elastic_beanstalk_environment_test.go +++ b/aws/resource_aws_elastic_beanstalk_environment_test.go @@ -846,7 +846,7 @@ func testAccBeanstalkEnvConfig_platform_arn(rName string) string { resource "aws_elastic_beanstalk_environment" "test" { application = aws_elastic_beanstalk_application.test.name name = %[1]q - platform_arn = "arn:${data.aws_partition.current.partition}:elasticbeanstalk:${data.aws_region.current.name}::platform/Python 3.6 running on 64bit Amazon Linux/2.9.4" + platform_arn = "arn:${data.aws_partition.current.partition}:elasticbeanstalk:${data.aws_region.current.name}::platform/Python 3.6 running on 64bit Amazon Linux/2.9.6" setting { namespace = "aws:ec2:vpc" From 1d40e91794981b672fc260f24b898ff6611479e2 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 23 Mar 2020 14:53:33 -0700 Subject: [PATCH 069/684] Formatting fixes --- aws/resource_aws_elastic_beanstalk_environment.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_elastic_beanstalk_environment.go b/aws/resource_aws_elastic_beanstalk_environment.go index 64daf5cf60b..65d9f09e77e 100644 --- a/aws/resource_aws_elastic_beanstalk_environment.go +++ b/aws/resource_aws_elastic_beanstalk_environment.go @@ -237,7 +237,7 @@ func resourceAwsElasticBeanstalkEnvironmentCreate(d *schema.ResourceData, meta i if cnamePrefix != "" { if tier != "WebServer" { - return fmt.Errorf("Cannot set cname_prefix for tier: %s.", tier) + return fmt.Errorf("cannot set cname_prefix for tier: %s", tier) } createOpts.CNAMEPrefix = aws.String(cnamePrefix) } @@ -308,9 +308,7 @@ func resourceAwsElasticBeanstalkEnvironmentCreate(d *schema.ResourceData, meta i _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf( - "Error waiting for Elastic Beanstalk Environment (%s) to become ready: %s", - d.Id(), err) + return fmt.Errorf("Error waiting for Elastic Beanstalk Environment (%s) to become ready: %w", d.Id(), err) } envErrors, err := getBeanstalkEnvironmentErrors(conn, d.Id(), t) @@ -792,9 +790,7 @@ func resourceAwsElasticBeanstalkEnvironmentDelete(d *schema.ResourceData, meta i _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf( - "Error waiting for Elastic Beanstalk Environment (%s) to become terminated: %s", - d.Id(), err) + return fmt.Errorf("Error waiting for Elastic Beanstalk Environment (%s) to become terminated: %w", d.Id(), err) } envErrors, err := getBeanstalkEnvironmentErrors(conn, d.Id(), t) @@ -984,7 +980,7 @@ func getBeanstalkEnvironmentErrors(conn *elasticbeanstalk.ElasticBeanstalk, envi }) if err != nil { - return nil, fmt.Errorf("Unable to get Elastic Beanstalk Evironment events: %s", err) + return nil, fmt.Errorf("unable to get Elastic Beanstalk Environment events: %w", err) } var events beanstalkEnvironmentErrors From 6c8020ea68f6d4ec1b8dd2c29ef7a78586908e3b Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 23 Mar 2020 16:19:55 -0700 Subject: [PATCH 070/684] Adds option to ignore error events when terminating Elastic Beanstalk Environment --- ...ource_aws_elastic_beanstalk_environment.go | 144 +++++++++++------- ..._aws_elastic_beanstalk_environment_test.go | 6 +- 2 files changed, 88 insertions(+), 62 deletions(-) diff --git a/aws/resource_aws_elastic_beanstalk_environment.go b/aws/resource_aws_elastic_beanstalk_environment.go index 65d9f09e77e..901c0bb637c 100644 --- a/aws/resource_aws_elastic_beanstalk_environment.go +++ b/aws/resource_aws_elastic_beanstalk_environment.go @@ -296,17 +296,7 @@ func resourceAwsElasticBeanstalkEnvironmentCreate(d *schema.ResourceData, meta i log.Printf("[WARN] Error parsing poll_interval, using default backoff") } - stateConf := &resource.StateChangeConf{ - Pending: []string{"Launching", "Updating"}, - Target: []string{"Ready"}, - Refresh: environmentStateRefreshFunc(conn, d.Id(), t), - Timeout: waitForReadyTimeOut, - Delay: 10 * time.Second, - PollInterval: pollInterval, - MinTimeout: 3 * time.Second, - } - - _, err = stateConf.WaitForState() + err = waitForElasticBeanstalkEnvironmentReady(conn, d.Id(), waitForReadyTimeOut, pollInterval, t) if err != nil { return fmt.Errorf("Error waiting for Elastic Beanstalk Environment (%s) to become ready: %w", d.Id(), err) } @@ -448,17 +438,7 @@ func resourceAwsElasticBeanstalkEnvironmentUpdate(d *schema.ResourceData, meta i log.Printf("[WARN] Error parsing poll_interval, using default backoff") } - stateConf := &resource.StateChangeConf{ - Pending: []string{"Launching", "Updating"}, - Target: []string{"Ready"}, - Refresh: environmentStateRefreshFunc(conn, d.Id(), t), - Timeout: waitForReadyTimeOut, - Delay: 10 * time.Second, - PollInterval: pollInterval, - MinTimeout: 3 * time.Second, - } - - _, err = stateConf.WaitForState() + err = waitForElasticBeanstalkEnvironmentReady(conn, d.Id(), waitForReadyTimeOut, pollInterval, t) if err != nil { return fmt.Errorf( "Error waiting for Elastic Beanstalk Environment (%s) to become ready: %s", @@ -494,17 +474,7 @@ func resourceAwsElasticBeanstalkEnvironmentUpdate(d *schema.ResourceData, meta i log.Printf("[WARN] Error parsing poll_interval, using default backoff") } - stateConf := &resource.StateChangeConf{ - Pending: []string{"Launching", "Updating"}, - Target: []string{"Ready"}, - Refresh: environmentStateRefreshFunc(conn, d.Id(), t), - Timeout: waitForReadyTimeOut, - Delay: 10 * time.Second, - PollInterval: pollInterval, - MinTimeout: 3 * time.Second, - } - - _, err = stateConf.WaitForState() + err = waitForElasticBeanstalkEnvironmentReady(conn, d.Id(), waitForReadyTimeOut, pollInterval, t) if err != nil { return fmt.Errorf( "Error waiting for Elastic Beanstalk Environment (%s) to become ready: %s", @@ -754,34 +724,39 @@ func resourceAwsElasticBeanstalkEnvironmentSettingsRead(d *schema.ResourceData, func resourceAwsElasticBeanstalkEnvironmentDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).elasticbeanstalkconn + waitForReadyTimeOut, err := time.ParseDuration(d.Get("wait_for_ready_timeout").(string)) + if err != nil { + return err + } + pollInterval, err := time.ParseDuration(d.Get("poll_interval").(string)) + if err != nil { + pollInterval = 0 + log.Printf("[WARN] Error parsing poll_interval, using default backoff") + } + + // The Environment needs to be in a Ready state before it can be terminated + err = waitForElasticBeanstalkEnvironmentReadyIgnoreErrorEvents(conn, d.Id(), waitForReadyTimeOut, pollInterval) + if err != nil { + return fmt.Errorf("error waiting for Elastic Beanstalk Environment %q to be ready before terminating: %w", d.Id(), err) + } + opts := elasticbeanstalk.TerminateEnvironmentInput{ EnvironmentId: aws.String(d.Id()), TerminateResources: aws.Bool(true), } // Get the current time to filter getBeanstalkEnvironmentErrors messages - t := time.Now() log.Printf("[DEBUG] Elastic Beanstalk Environment terminate opts: %s", opts) - _, err := conn.TerminateEnvironment(&opts) + _, err = conn.TerminateEnvironment(&opts) if err != nil { return err } - waitForReadyTimeOut, err := time.ParseDuration(d.Get("wait_for_ready_timeout").(string)) - if err != nil { - return err - } - pollInterval, err := time.ParseDuration(d.Get("poll_interval").(string)) - if err != nil { - pollInterval = 0 - log.Printf("[WARN] Error parsing poll_interval, using default backoff") - } - stateConf := &resource.StateChangeConf{ Pending: []string{"Terminating"}, Target: []string{"Terminated"}, - Refresh: environmentStateRefreshFunc(conn, d.Id(), t), + Refresh: elasticBeanstalkEnvironmentStateIgnoreErrorEventsRefreshFunc(conn, d.Id()), Timeout: waitForReadyTimeOut, Delay: 10 * time.Second, PollInterval: pollInterval, @@ -790,30 +765,52 @@ func resourceAwsElasticBeanstalkEnvironmentDelete(d *schema.ResourceData, meta i _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf("Error waiting for Elastic Beanstalk Environment (%s) to become terminated: %w", d.Id(), err) + return fmt.Errorf("Error waiting for Elastic Beanstalk Environment %q to become terminated: %w", d.Id(), err) } - envErrors, err := getBeanstalkEnvironmentErrors(conn, d.Id(), t) - if err != nil { - return err + return nil +} + +func waitForElasticBeanstalkEnvironmentReady(conn *elasticbeanstalk.ElasticBeanstalk, id string, timeout, pollInterval time.Duration, startTime time.Time) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{"Launching", "Updating"}, + Target: []string{"Ready"}, + Refresh: elasticBeanstalkEnvironmentStateRefreshFunc(conn, id, startTime), + Timeout: timeout, + Delay: 10 * time.Second, + PollInterval: pollInterval, + MinTimeout: 3 * time.Second, } - if envErrors != nil { - return envErrors + + _, err := stateConf.WaitForState() + return err +} + +func waitForElasticBeanstalkEnvironmentReadyIgnoreErrorEvents(conn *elasticbeanstalk.ElasticBeanstalk, id string, timeout, pollInterval time.Duration) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{"Launching", "Updating"}, + Target: []string{"Ready"}, + Refresh: elasticBeanstalkEnvironmentStateIgnoreErrorEventsRefreshFunc(conn, id), + Timeout: timeout, + Delay: 10 * time.Second, + PollInterval: pollInterval, + MinTimeout: 3 * time.Second, } - return nil + _, err := stateConf.WaitForState() + return err } -// environmentStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch +// elasticBeanstalkEnvironmentStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // the creation of the Beanstalk Environment -func environmentStateRefreshFunc(conn *elasticbeanstalk.ElasticBeanstalk, environmentId string, t time.Time) resource.StateRefreshFunc { +func elasticBeanstalkEnvironmentStateRefreshFunc(conn *elasticbeanstalk.ElasticBeanstalk, environmentID string, t time.Time) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeEnvironments(&elasticbeanstalk.DescribeEnvironmentsInput{ - EnvironmentIds: []*string{aws.String(environmentId)}, + EnvironmentIds: []*string{aws.String(environmentID)}, }) if err != nil { log.Printf("[Err] Error waiting for Elastic Beanstalk Environment state: %s", err) - return -1, "failed", fmt.Errorf("Error waiting for Elastic Beanstalk Environment state: %s", err) + return -1, "failed", fmt.Errorf("error waiting for Elastic Beanstalk Environment state: %w", err) } if resp == nil || len(resp.Environments) == 0 { @@ -841,7 +838,38 @@ func environmentStateRefreshFunc(conn *elasticbeanstalk.ElasticBeanstalk, enviro return -1, "failed", envErrors } - return env, *env.Status, nil + return env, aws.StringValue(env.Status), nil + } +} + +func elasticBeanstalkEnvironmentStateIgnoreErrorEventsRefreshFunc(conn *elasticbeanstalk.ElasticBeanstalk, environmentID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + resp, err := conn.DescribeEnvironments(&elasticbeanstalk.DescribeEnvironmentsInput{ + EnvironmentIds: []*string{aws.String(environmentID)}, + }) + if err != nil { + log.Printf("[Err] Error waiting for Elastic Beanstalk Environment state: %s", err) + return -1, "failed", fmt.Errorf("error waiting for Elastic Beanstalk Environment state: %w", err) + } + + if resp == nil || len(resp.Environments) == 0 { + // Sometimes AWS just has consistency issues and doesn't see + // our instance yet. Return an empty state. + return nil, "", nil + } + + var env *elasticbeanstalk.EnvironmentDescription + for _, e := range resp.Environments { + if environmentID == aws.StringValue(e.EnvironmentId) { + env = e + } + } + + if env == nil { + return -1, "failed", fmt.Errorf("Error finding Elastic Beanstalk Environment, environment not found") + } + + return env, aws.StringValue(env.Status), nil } } diff --git a/aws/resource_aws_elastic_beanstalk_environment_test.go b/aws/resource_aws_elastic_beanstalk_environment_test.go index 469aa80d5ce..ae51127f72d 100644 --- a/aws/resource_aws_elastic_beanstalk_environment_test.go +++ b/aws/resource_aws_elastic_beanstalk_environment_test.go @@ -73,20 +73,18 @@ func testSweepElasticBeanstalkEnvironments(region string) error { pollInterval, _ := time.ParseDuration("10s") // poll for deletion - t := time.Now() stateConf := &resource.StateChangeConf{ Pending: []string{"Terminating"}, Target: []string{"Terminated"}, - Refresh: environmentStateRefreshFunc(beanstalkconn, environmentID, t), + Refresh: elasticBeanstalkEnvironmentStateIgnoreErrorEventsRefreshFunc(beanstalkconn, environmentID), Timeout: waitForReadyTimeOut, Delay: 10 * time.Second, PollInterval: pollInterval, MinTimeout: 3 * time.Second, } - _, err = stateConf.WaitForState() if err != nil { - errors = multierror.Append(fmt.Errorf("Error waiting for Elastic Beanstalk Environment %q to become terminated: %w", environmentID, err)) + errors = multierror.Append(fmt.Errorf("error waiting for Elastic Beanstalk Environment %q to become terminated: %w", environmentID, err)) continue } log.Printf("> Terminated (%s) (%s)", environmentName, environmentID) From b877854a003b1661f4f240d63be02940436d855b Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 23 Mar 2020 16:44:37 -0700 Subject: [PATCH 071/684] Consolidates Elastic Beanstalk Environment deletion --- ...ource_aws_elastic_beanstalk_environment.go | 18 +++++++---- ..._aws_elastic_beanstalk_environment_test.go | 31 ++----------------- 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/aws/resource_aws_elastic_beanstalk_environment.go b/aws/resource_aws_elastic_beanstalk_environment.go index 901c0bb637c..441052c7f50 100644 --- a/aws/resource_aws_elastic_beanstalk_environment.go +++ b/aws/resource_aws_elastic_beanstalk_environment.go @@ -740,24 +740,30 @@ func resourceAwsElasticBeanstalkEnvironmentDelete(d *schema.ResourceData, meta i return fmt.Errorf("error waiting for Elastic Beanstalk Environment %q to be ready before terminating: %w", d.Id(), err) } + return deleteElasticBeanstalkEnvironment(conn, d.Id(), waitForReadyTimeOut, pollInterval) +} + +func deleteElasticBeanstalkEnvironment(conn *elasticbeanstalk.ElasticBeanstalk, id string, timeout, pollInterval time.Duration) error { opts := elasticbeanstalk.TerminateEnvironmentInput{ - EnvironmentId: aws.String(d.Id()), + EnvironmentId: aws.String(id), TerminateResources: aws.Bool(true), } - - // Get the current time to filter getBeanstalkEnvironmentErrors messages log.Printf("[DEBUG] Elastic Beanstalk Environment terminate opts: %s", opts) - _, err = conn.TerminateEnvironment(&opts) + _, err := conn.TerminateEnvironment(&opts) if err != nil { + if isAWSErr(err, "InvalidConfiguration.NotFound", "") || isAWSErr(err, "ValidationError", "") { + log.Printf("[DEBUG] Elastic Beanstalk Environment %q not found", id) + return nil + } return err } stateConf := &resource.StateChangeConf{ Pending: []string{"Terminating"}, Target: []string{"Terminated"}, - Refresh: elasticBeanstalkEnvironmentStateIgnoreErrorEventsRefreshFunc(conn, d.Id()), - Timeout: waitForReadyTimeOut, + Refresh: elasticBeanstalkEnvironmentStateIgnoreErrorEventsRefreshFunc(conn, id), + Timeout: timeout, Delay: 10 * time.Second, PollInterval: pollInterval, MinTimeout: 3 * time.Second, diff --git a/aws/resource_aws_elastic_beanstalk_environment_test.go b/aws/resource_aws_elastic_beanstalk_environment_test.go index ae51127f72d..3feeca529fe 100644 --- a/aws/resource_aws_elastic_beanstalk_environment_test.go +++ b/aws/resource_aws_elastic_beanstalk_environment_test.go @@ -55,38 +55,11 @@ func testSweepElasticBeanstalkEnvironments(region string) error { environmentID := aws.StringValue(bse.EnvironmentId) log.Printf("Trying to terminate (%s) (%s)", environmentName, environmentID) - _, err := beanstalkconn.TerminateEnvironment( - &elasticbeanstalk.TerminateEnvironmentInput{ - EnvironmentId: bse.EnvironmentId, - TerminateResources: aws.Bool(true), - }) - + err := deleteElasticBeanstalkEnvironment(beanstalkconn, environmentID, 5*time.Minute, 10*time.Second) if err != nil { - if isAWSErr(err, "InvalidConfiguration.NotFound", "") || isAWSErr(err, "ValidationError", "") { - log.Printf("[DEBUG] Elastic Beanstalk Environment %q not found", environmentName) - continue - } - errors = multierror.Append(fmt.Errorf("error terminating Elastic Beanstalk Environment %q: %w", environmentName, err)) + errors = multierror.Append(fmt.Errorf("error deleting Elastic Beanstalk Environment %q: %w", environmentID, err)) } - waitForReadyTimeOut, _ := time.ParseDuration("5m") - pollInterval, _ := time.ParseDuration("10s") - - // poll for deletion - stateConf := &resource.StateChangeConf{ - Pending: []string{"Terminating"}, - Target: []string{"Terminated"}, - Refresh: elasticBeanstalkEnvironmentStateIgnoreErrorEventsRefreshFunc(beanstalkconn, environmentID), - Timeout: waitForReadyTimeOut, - Delay: 10 * time.Second, - PollInterval: pollInterval, - MinTimeout: 3 * time.Second, - } - _, err = stateConf.WaitForState() - if err != nil { - errors = multierror.Append(fmt.Errorf("error waiting for Elastic Beanstalk Environment %q to become terminated: %w", environmentID, err)) - continue - } log.Printf("> Terminated (%s) (%s)", environmentName, environmentID) } From b623e4ba713f575de7ea630696410530dd8fb699 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 23 Mar 2020 16:45:10 -0700 Subject: [PATCH 072/684] Formatting fixes --- ...ource_aws_elastic_beanstalk_environment.go | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/aws/resource_aws_elastic_beanstalk_environment.go b/aws/resource_aws_elastic_beanstalk_environment.go index 441052c7f50..331d169581c 100644 --- a/aws/resource_aws_elastic_beanstalk_environment.go +++ b/aws/resource_aws_elastic_beanstalk_environment.go @@ -315,12 +315,12 @@ func resourceAwsElasticBeanstalkEnvironmentCreate(d *schema.ResourceData, meta i func resourceAwsElasticBeanstalkEnvironmentUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).elasticbeanstalkconn - envId := d.Id() + envID := d.Id() var hasChange bool updateOpts := elasticbeanstalk.UpdateEnvironmentInput{ - EnvironmentId: aws.String(envId), + EnvironmentId: aws.String(envID), } if d.HasChange("description") { @@ -476,9 +476,7 @@ func resourceAwsElasticBeanstalkEnvironmentUpdate(d *schema.ResourceData, meta i err = waitForElasticBeanstalkEnvironmentReady(conn, d.Id(), waitForReadyTimeOut, pollInterval, t) if err != nil { - return fmt.Errorf( - "Error waiting for Elastic Beanstalk Environment (%s) to become ready: %s", - d.Id(), err) + return fmt.Errorf("error waiting for Elastic Beanstalk Environment %q to become ready: %w", d.Id(), err) } envErrors, err := getBeanstalkEnvironmentErrors(conn, d.Id(), t) @@ -496,12 +494,12 @@ func resourceAwsElasticBeanstalkEnvironmentUpdate(d *schema.ResourceData, meta i func resourceAwsElasticBeanstalkEnvironmentRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).elasticbeanstalkconn - envId := d.Id() + envID := d.Id() log.Printf("[DEBUG] Elastic Beanstalk environment read %s: id %s", d.Get("name").(string), d.Id()) resp, err := conn.DescribeEnvironments(&elasticbeanstalk.DescribeEnvironmentsInput{ - EnvironmentIds: []*string{aws.String(envId)}, + EnvironmentIds: []*string{aws.String(envID)}, }) if err != nil { @@ -527,7 +525,7 @@ func resourceAwsElasticBeanstalkEnvironmentRead(d *schema.ResourceData, meta int } resources, err := conn.DescribeEnvironmentResources(&elasticbeanstalk.DescribeEnvironmentResourcesInput{ - EnvironmentId: aws.String(envId), + EnvironmentId: aws.String(envID), }) if err != nil { @@ -771,7 +769,7 @@ func deleteElasticBeanstalkEnvironment(conn *elasticbeanstalk.ElasticBeanstalk, _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf("Error waiting for Elastic Beanstalk Environment %q to become terminated: %w", d.Id(), err) + return fmt.Errorf("error waiting for Elastic Beanstalk Environment %q to become terminated: %w", id, err) } return nil @@ -827,7 +825,7 @@ func elasticBeanstalkEnvironmentStateRefreshFunc(conn *elasticbeanstalk.ElasticB var env *elasticbeanstalk.EnvironmentDescription for _, e := range resp.Environments { - if environmentId == *e.EnvironmentId { + if environmentID == aws.StringValue(e.EnvironmentId) { env = e } } @@ -836,7 +834,7 @@ func elasticBeanstalkEnvironmentStateRefreshFunc(conn *elasticbeanstalk.ElasticB return -1, "failed", fmt.Errorf("Error finding Elastic Beanstalk Environment, environment not found") } - envErrors, err := getBeanstalkEnvironmentErrors(conn, environmentId, t) + envErrors, err := getBeanstalkEnvironmentErrors(conn, environmentID, t) if err != nil { return -1, "failed", err } From 1a6e477482f7593d98e834c0ef55a2a9a3e95995 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 23 Mar 2020 22:33:39 -0700 Subject: [PATCH 073/684] Corrects test for Elastic Beanstalk Platform ARN --- aws/resource_aws_elastic_beanstalk_environment_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_elastic_beanstalk_environment_test.go b/aws/resource_aws_elastic_beanstalk_environment_test.go index 3feeca529fe..c5cec7b2b02 100644 --- a/aws/resource_aws_elastic_beanstalk_environment_test.go +++ b/aws/resource_aws_elastic_beanstalk_environment_test.go @@ -453,7 +453,7 @@ func TestAccAWSBeanstalkEnv_platformArn(t *testing.T) { Config: testAccBeanstalkEnvConfig_platform_arn(rName), Check: resource.ComposeTestCheckFunc( testAccCheckBeanstalkEnvExists(resourceName, &app), - testAccCheckResourceAttrRegionalARNNoAccount(resourceName, "platform_arn", "elasticbeanstalk", "platform/Python 3.6 running on 64bit Amazon Linux/2.9.4"), + testAccCheckResourceAttrRegionalARNNoAccount(resourceName, "platform_arn", "elasticbeanstalk", "platform/Python 3.6 running on 64bit Amazon Linux/2.9.6"), ), }, { From f0ef35b387d91bb9732838e8c6c7f7a3bb8cdda0 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 23 Mar 2020 22:45:55 -0700 Subject: [PATCH 074/684] Terraform formatting fixes --- aws/resource_aws_elastic_beanstalk_application_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_elastic_beanstalk_application_test.go b/aws/resource_aws_elastic_beanstalk_application_test.go index 217eded6849..a7485c58f39 100644 --- a/aws/resource_aws_elastic_beanstalk_application_test.go +++ b/aws/resource_aws_elastic_beanstalk_application_test.go @@ -87,9 +87,10 @@ func TestAccAWSElasticBeanstalkApplication_basic(t *testing.T) { func testAccBeanstalkAppImportConfig(name string) string { return fmt.Sprintf(` resource "aws_elastic_beanstalk_application" "tftest" { - name = "%s" - description = "tf-test-desc" - }`, name) + name = "%s" + description = "tf-test-desc" +} +`, name) } func TestAccAWSBeanstalkApp_basic(t *testing.T) { @@ -286,7 +287,7 @@ func testAccCheckBeanstalkAppExists(n string, app *elasticbeanstalk.ApplicationD func testAccBeanstalkAppConfig(rName string) string { return fmt.Sprintf(` resource "aws_elastic_beanstalk_application" "tftest" { - name = "%s" + name = "%s" description = "tf-test-desc" } `, rName) From 505b7d06582fff04589a64d912c6726d13c8ce83 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 23 Mar 2020 23:13:22 -0700 Subject: [PATCH 075/684] Corrects function name --- aws/resource_aws_elastic_beanstalk_environment.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_elastic_beanstalk_environment.go b/aws/resource_aws_elastic_beanstalk_environment.go index 331d169581c..2ae60ab1ad0 100644 --- a/aws/resource_aws_elastic_beanstalk_environment.go +++ b/aws/resource_aws_elastic_beanstalk_environment.go @@ -760,7 +760,7 @@ func deleteElasticBeanstalkEnvironment(conn *elasticbeanstalk.ElasticBeanstalk, stateConf := &resource.StateChangeConf{ Pending: []string{"Terminating"}, Target: []string{"Terminated"}, - Refresh: elasticBeanstalkEnvironmentStateIgnoreErrorEventsRefreshFunc(conn, id), + Refresh: elasticBeanstalkEnvironmentIgnoreErrorEventsStateRefreshFunc(conn, id), Timeout: timeout, Delay: 10 * time.Second, PollInterval: pollInterval, @@ -794,7 +794,7 @@ func waitForElasticBeanstalkEnvironmentReadyIgnoreErrorEvents(conn *elasticbeans stateConf := &resource.StateChangeConf{ Pending: []string{"Launching", "Updating"}, Target: []string{"Ready"}, - Refresh: elasticBeanstalkEnvironmentStateIgnoreErrorEventsRefreshFunc(conn, id), + Refresh: elasticBeanstalkEnvironmentIgnoreErrorEventsStateRefreshFunc(conn, id), Timeout: timeout, Delay: 10 * time.Second, PollInterval: pollInterval, @@ -846,7 +846,7 @@ func elasticBeanstalkEnvironmentStateRefreshFunc(conn *elasticbeanstalk.ElasticB } } -func elasticBeanstalkEnvironmentStateIgnoreErrorEventsRefreshFunc(conn *elasticbeanstalk.ElasticBeanstalk, environmentID string) resource.StateRefreshFunc { +func elasticBeanstalkEnvironmentIgnoreErrorEventsStateRefreshFunc(conn *elasticbeanstalk.ElasticBeanstalk, environmentID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeEnvironments(&elasticbeanstalk.DescribeEnvironmentsInput{ EnvironmentIds: []*string{aws.String(environmentID)}, From 2191252e203401efdbaacded77dd7fe698a3c36c Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 24 Mar 2020 13:47:40 -0700 Subject: [PATCH 076/684] Adds fix to filter out Local Zones from list of Availability Zones --- aws/resource_aws_elastic_beanstalk_environment_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws/resource_aws_elastic_beanstalk_environment_test.go b/aws/resource_aws_elastic_beanstalk_environment_test.go index c5cec7b2b02..de598b6f483 100644 --- a/aws/resource_aws_elastic_beanstalk_environment_test.go +++ b/aws/resource_aws_elastic_beanstalk_environment_test.go @@ -727,6 +727,10 @@ data "aws_availability_zones" "available" { # after waiting upwards of one hour to initialize the Auto Scaling Group. blacklisted_zone_ids = ["usw2-az4"] state = "available" + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_elastic_beanstalk_solution_stack" "test" { From 563ed4ded07cc89d60182983e38be075aa8f89d6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 3 Jun 2019 09:40:32 -0400 Subject: [PATCH 077/684] Add 'aws_api_gateway_v2_integration' resource. --- aws/provider.go | 1 + aws/resource_aws_api_gateway2_integration.go | 299 ++++++++++++++ ...ource_aws_api_gateway2_integration_test.go | 390 ++++++++++++++++++ website/aws.erb | 3 + .../api_gateway_v2_integration.html.markdown | 81 ++++ 5 files changed, 774 insertions(+) create mode 100644 aws/resource_aws_api_gateway2_integration.go create mode 100644 aws/resource_aws_api_gateway2_integration_test.go create mode 100644 website/docs/r/api_gateway_v2_integration.html.markdown diff --git a/aws/provider.go b/aws/provider.go index be386f16d6b..02357170970 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -355,6 +355,7 @@ func Provider() terraform.ResourceProvider { "aws_api_gateway_usage_plan_key": resourceAwsApiGatewayUsagePlanKey(), "aws_api_gateway_vpc_link": resourceAwsApiGatewayVpcLink(), "aws_apigatewayv2_api": resourceAwsApiGatewayV2Api(), + "aws_api_gateway_v2_integration": resourceAwsApiGateway2Integration(), "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), "aws_appautoscaling_target": resourceAwsAppautoscalingTarget(), "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), diff --git a/aws/resource_aws_api_gateway2_integration.go b/aws/resource_aws_api_gateway2_integration.go new file mode 100644 index 00000000000..87645ef11c9 --- /dev/null +++ b/aws/resource_aws_api_gateway2_integration.go @@ -0,0 +1,299 @@ +package aws + +import ( + "fmt" + "log" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func resourceAwsApiGateway2Integration() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsApiGateway2IntegrationCreate, + Read: resourceAwsApiGateway2IntegrationRead, + Update: resourceAwsApiGateway2IntegrationUpdate, + Delete: resourceAwsApiGateway2IntegrationDelete, + Importer: &schema.ResourceImporter{ + State: resourceAwsApiGateway2IntegrationImport, + }, + CustomizeDiff: resourceAwsApiGateway2IntegrationCustomizeDiff, + + Schema: map[string]*schema.Schema{ + "api_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "connection_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "connection_type": { + Type: schema.TypeString, + Optional: true, + Default: apigatewayv2.ConnectionTypeInternet, + ValidateFunc: validation.StringInSlice([]string{ + apigatewayv2.ConnectionTypeInternet, + apigatewayv2.ConnectionTypeVpcLink, + }, false), + }, + "content_handling_strategy": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + apigatewayv2.ContentHandlingStrategyConvertToBinary, + apigatewayv2.ContentHandlingStrategyConvertToText, + }, false), + }, + "credentials_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "integration_method": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateHTTPMethod(), + }, + "integration_response_selection_expression": { + Type: schema.TypeString, + Computed: true, + }, + "integration_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + apigatewayv2.IntegrationTypeAws, + apigatewayv2.IntegrationTypeAwsProxy, + apigatewayv2.IntegrationTypeHttp, + apigatewayv2.IntegrationTypeHttpProxy, + apigatewayv2.IntegrationTypeMock, + }, false), + }, + "integration_uri": { + Type: schema.TypeString, + Optional: true, + }, + "passthrough_behavior": { + Type: schema.TypeString, + Optional: true, + Default: apigatewayv2.PassthroughBehaviorWhenNoMatch, + ValidateFunc: validation.StringInSlice([]string{ + apigatewayv2.PassthroughBehaviorWhenNoMatch, + apigatewayv2.PassthroughBehaviorNever, + apigatewayv2.PassthroughBehaviorWhenNoTemplates, + }, false), + }, + "request_templates": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "template_selection_expression": { + Type: schema.TypeString, + Optional: true, + }, + "timeout_milliseconds": { + Type: schema.TypeInt, + Optional: true, + Default: 29000, + ValidateFunc: validation.IntBetween(50, 29000), + }, + }, + } +} + +func resourceAwsApiGateway2IntegrationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + req := &apigatewayv2.CreateIntegrationInput{ + ApiId: aws.String(d.Get("api_id").(string)), + IntegrationType: aws.String(d.Get("integration_type").(string)), + } + if v, ok := d.GetOk("connection_id"); ok { + req.ConnectionId = aws.String(v.(string)) + } + if v, ok := d.GetOk("connection_type"); ok { + req.ConnectionType = aws.String(v.(string)) + } + if v, ok := d.GetOk("content_handling_strategy"); ok { + req.ContentHandlingStrategy = aws.String(v.(string)) + } + if v, ok := d.GetOk("credentials_arn"); ok { + req.CredentialsArn = aws.String(v.(string)) + } + if v, ok := d.GetOk("description"); ok { + req.Description = aws.String(v.(string)) + } + if v, ok := d.GetOk("integration_method"); ok { + req.IntegrationMethod = aws.String(v.(string)) + } + if v, ok := d.GetOk("integration_uri"); ok { + req.IntegrationUri = aws.String(v.(string)) + } + if v, ok := d.GetOk("passthrough_behavior"); ok { + req.PassthroughBehavior = aws.String(v.(string)) + } + if v, ok := d.GetOk("request_templates"); ok { + req.RequestTemplates = stringMapToPointers(v.(map[string]interface{})) + } + if v, ok := d.GetOk("template_selection_expression"); ok { + req.TemplateSelectionExpression = aws.String(v.(string)) + } + if v, ok := d.GetOk("timeout_milliseconds"); ok { + req.TimeoutInMillis = aws.Int64(int64(v.(int))) + } + + log.Printf("[DEBUG] Creating API Gateway v2 integration: %s", req) + resp, err := conn.CreateIntegration(req) + if err != nil { + return fmt.Errorf("error creating API Gateway v2 integration: %s", err) + } + + d.SetId(aws.StringValue(resp.IntegrationId)) + + return resourceAwsApiGateway2IntegrationRead(d, meta) +} + +func resourceAwsApiGateway2IntegrationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + resp, err := conn.GetIntegration(&apigatewayv2.GetIntegrationInput{ + ApiId: aws.String(d.Get("api_id").(string)), + IntegrationId: aws.String(d.Id()), + }) + if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") { + log.Printf("[WARN] API Gateway v2 integration (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("error reading API Gateway v2 integration: %s", err) + } + + d.Set("connection_id", resp.ConnectionId) + d.Set("connection_type", resp.ConnectionType) + d.Set("content_handling_strategy", resp.ContentHandlingStrategy) + d.Set("credentials_arn", resp.CredentialsArn) + d.Set("description", resp.Description) + d.Set("integration_method", resp.IntegrationMethod) + d.Set("integration_response_selection_expression", resp.IntegrationResponseSelectionExpression) + d.Set("integration_type", resp.IntegrationType) + d.Set("integration_uri", resp.IntegrationUri) + d.Set("passthrough_behavior", resp.PassthroughBehavior) + err = d.Set("request_templates", pointersMapToStringList(resp.RequestTemplates)) + if err != nil { + return fmt.Errorf("error setting request_templates: %s", err) + } + d.Set("template_selection_expression", resp.TemplateSelectionExpression) + d.Set("timeout_milliseconds", resp.TimeoutInMillis) + + return nil +} + +func resourceAwsApiGateway2IntegrationUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + req := &apigatewayv2.UpdateIntegrationInput{ + ApiId: aws.String(d.Get("api_id").(string)), + IntegrationId: aws.String(d.Id()), + } + if d.HasChange("connection_id") { + req.ConnectionId = aws.String(d.Get("connection_id").(string)) + } + if d.HasChange("connection_type") { + req.ConnectionType = aws.String(d.Get("connection_type").(string)) + } + if d.HasChange("content_handling_strategy") { + req.ContentHandlingStrategy = aws.String(d.Get("content_handling_strategy").(string)) + } + if d.HasChange("credentials_arn") { + req.CredentialsArn = aws.String(d.Get("credentials_arn").(string)) + } + if d.HasChange("description") { + req.Description = aws.String(d.Get("description").(string)) + } + if d.HasChange("integration_method") { + req.IntegrationMethod = aws.String(d.Get("integration_method").(string)) + } + if d.HasChange("integration_uri") { + req.IntegrationUri = aws.String(d.Get("integration_uri").(string)) + } + if d.HasChange("passthrough_behavior") { + req.PassthroughBehavior = aws.String(d.Get("passthrough_behavior").(string)) + } + if d.HasChange("request_templates") { + req.RequestTemplates = stringMapToPointers(d.Get("request_templates").(map[string]interface{})) + } + if d.HasChange("template_selection_expression") { + req.TemplateSelectionExpression = aws.String(d.Get("template_selection_expression").(string)) + } + if d.HasChange("timeout_milliseconds") { + req.TimeoutInMillis = aws.Int64(int64(d.Get("timeout_milliseconds").(int))) + } + + log.Printf("[DEBUG] Updating API Gateway v2 integration: %s", req) + _, err := conn.UpdateIntegration(req) + if err != nil { + return fmt.Errorf("error updating API Gateway v2 integration: %s", err) + } + + return resourceAwsApiGateway2IntegrationRead(d, meta) +} + +func resourceAwsApiGateway2IntegrationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).apigatewayv2conn + + log.Printf("[DEBUG] Deleting API Gateway v2 integration (%s)", d.Id()) + _, err := conn.DeleteIntegration(&apigatewayv2.DeleteIntegrationInput{ + ApiId: aws.String(d.Get("api_id").(string)), + IntegrationId: aws.String(d.Id()), + }) + if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") { + return nil + } + if err != nil { + return fmt.Errorf("error deleting API Gateway v2 integration: %s", err) + } + + return nil +} + +func resourceAwsApiGateway2IntegrationImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + parts := strings.Split(d.Id(), "/") + if len(parts) != 2 { + return []*schema.ResourceData{}, fmt.Errorf("Wrong format of resource: %s. Please follow 'api-id/integration-id'", d.Id()) + } + + d.SetId(parts[1]) + d.Set("api_id", parts[0]) + + return []*schema.ResourceData{d}, nil +} + +func resourceAwsApiGateway2IntegrationCustomizeDiff(diff *schema.ResourceDiff, meta interface{}) error { + if diff.Id() == "" { + // New resource. + integrationMethod := diff.Get("integration_method").(string) + integrationType := diff.Get("integration_type").(string) + if integrationType == apigatewayv2.IntegrationTypeMock { + if integrationMethod != "" { + return fmt.Errorf("'integration_method' must not be set when 'integration_type' is '%s'", integrationType) + } + } else if integrationMethod == "" { + return fmt.Errorf("'integration_method' must be set when 'integration_type' is '%s'", integrationType) + } + } + + return nil +} diff --git a/aws/resource_aws_api_gateway2_integration_test.go b/aws/resource_aws_api_gateway2_integration_test.go new file mode 100644 index 00000000000..ac37b93b8b9 --- /dev/null +++ b/aws/resource_aws_api_gateway2_integration_test.go @@ -0,0 +1,390 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccAWSAPIGateway2Integration_basic(t *testing.T) { + resourceName := "aws_api_gateway_v2_integration.test" + rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGateway2IntegrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGateway2IntegrationConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2IntegrationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "connection_id", ""), + resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), + resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", ""), + resource.TestCheckResourceAttr(resourceName, "credentials_arn", ""), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "integration_method", ""), + resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", "${integration.response.statuscode}"), + resource.TestCheckResourceAttr(resourceName, "integration_type", "MOCK"), + resource.TestCheckResourceAttr(resourceName, "integration_uri", ""), + resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", "WHEN_NO_MATCH"), + resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), + resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), + resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "29000"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAPIGateway2IntegrationImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAPIGateway2Integration_IntegrationTypeHttp(t *testing.T) { + resourceName := "aws_api_gateway_v2_integration.test" + rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGateway2IntegrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGateway2IntegrationConfig_integrationTypeHttp(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2IntegrationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "connection_id", ""), + resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), + resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", "CONVERT_TO_TEXT"), + resource.TestCheckResourceAttr(resourceName, "credentials_arn", ""), + resource.TestCheckResourceAttr(resourceName, "description", "Test HTTP"), + resource.TestCheckResourceAttr(resourceName, "integration_method", "GET"), + resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", "${integration.response.statuscode}"), + resource.TestCheckResourceAttr(resourceName, "integration_type", "HTTP"), + resource.TestCheckResourceAttr(resourceName, "integration_uri", "http://www.example.com"), + resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", "WHEN_NO_MATCH"), + resource.TestCheckResourceAttr(resourceName, "request_templates.%", "1"), + resource.TestCheckResourceAttr(resourceName, "request_templates.application/json", ""), + resource.TestCheckResourceAttr(resourceName, "template_selection_expression", "$request.body.name"), + resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "28999"), + ), + }, + { + Config: testAccAWSAPIGateway2IntegrationConfig_integrationTypeHttpUpdated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2IntegrationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "connection_id", ""), + resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), + resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", "CONVERT_TO_BINARY"), + resource.TestCheckResourceAttr(resourceName, "credentials_arn", ""), + resource.TestCheckResourceAttr(resourceName, "description", "Test HTTP updated"), + resource.TestCheckResourceAttr(resourceName, "integration_method", "POST"), + resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", "${integration.response.statuscode}"), + resource.TestCheckResourceAttr(resourceName, "integration_type", "HTTP"), + resource.TestCheckResourceAttr(resourceName, "integration_uri", "http://www.example.org"), + resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", "WHEN_NO_TEMPLATES"), + resource.TestCheckResourceAttr(resourceName, "request_templates.%", "2"), + resource.TestCheckResourceAttr(resourceName, "request_templates.application/json", "#set($number=42)"), + resource.TestCheckResourceAttr(resourceName, "request_templates.application/xml", "#set($percent=$number/100)"), + resource.TestCheckResourceAttr(resourceName, "template_selection_expression", "$request.body.id"), + resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "51"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAPIGateway2IntegrationImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAPIGateway2Integration_Lambda(t *testing.T) { + resourceName := "aws_api_gateway_v2_integration.test" + callerIdentityDatasourceName := "data.aws_caller_identity.current" + lambdaResourceName := "aws_lambda_function.test" + rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGateway2IntegrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGateway2IntegrationConfig_lambda(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2IntegrationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), + resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", "CONVERT_TO_TEXT"), + resource.TestCheckResourceAttrPair(resourceName, "credentials_arn", callerIdentityDatasourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "description", "Test Lambda"), + resource.TestCheckResourceAttr(resourceName, "integration_method", "POST"), + resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", "${integration.response.body.errorMessage}"), + resource.TestCheckResourceAttr(resourceName, "integration_type", "AWS"), + resource.TestCheckResourceAttrPair(resourceName, "integration_uri", lambdaResourceName, "invoke_arn"), + resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", "WHEN_NO_MATCH"), + resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), + resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), + resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "29000"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAPIGateway2IntegrationImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAPIGateway2Integration_VpcLink(t *testing.T) { + resourceName := "aws_api_gateway_v2_integration.test" + vpcLinkResourceName := "aws_api_gateway_vpc_link.test" + rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGateway2IntegrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGateway2IntegrationConfig_vpcLink(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGateway2IntegrationExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "connection_id", vpcLinkResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "connection_type", "VPC_LINK"), + resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", "CONVERT_TO_TEXT"), + resource.TestCheckResourceAttr(resourceName, "credentials_arn", ""), + resource.TestCheckResourceAttr(resourceName, "description", "Test VPC Link"), + resource.TestCheckResourceAttr(resourceName, "integration_method", "PUT"), + resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", ""), + resource.TestCheckResourceAttr(resourceName, "integration_type", "HTTP_PROXY"), + resource.TestCheckResourceAttr(resourceName, "integration_uri", "http://www.example.net"), + resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", "NEVER"), + resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), + resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), + resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "12345"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAPIGateway2IntegrationImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckAWSAPIGateway2IntegrationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_api_gateway_v2_integration" { + continue + } + + _, err := conn.GetIntegration(&apigatewayv2.GetIntegrationInput{ + ApiId: aws.String(rs.Primary.Attributes["api_id"]), + IntegrationId: aws.String(rs.Primary.ID), + }) + if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") { + continue + } + if err != nil { + return err + } + + return fmt.Errorf("API Gateway v2 integration %s still exists", rs.Primary.ID) + } + + return nil +} + +func testAccCheckAWSAPIGateway2IntegrationExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No API Gateway v2 integration ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + _, err := conn.GetIntegration(&apigatewayv2.GetIntegrationInput{ + ApiId: aws.String(rs.Primary.Attributes["api_id"]), + IntegrationId: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + + return nil + } +} + +func testAccAWSAPIGateway2IntegrationImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("Not Found: %s", resourceName) + } + + return fmt.Sprintf("%s/%s", rs.Primary.Attributes["api_id"], rs.Primary.ID), nil + } +} + +func testAccAWSAPIGateway2IntegrationConfig_api(rName string) string { + return fmt.Sprintf(` +resource "aws_api_gateway_v2_api" "test" { + name = %[1]q + protocol_type = "WEBSOCKET" + route_selection_expression = "$request.body.action" +} +`, rName) +} + +func testAccAWSAPIGateway2IntegrationConfig_basic(rName string) string { + return testAccAWSAPIGateway2IntegrationConfig_api(rName) + fmt.Sprintf(` +resource "aws_api_gateway_v2_integration" "test" { + api_id = "${aws_api_gateway_v2_api.test.id}" + integration_type = "MOCK" +} +`) +} + +func testAccAWSAPIGateway2IntegrationConfig_integrationTypeHttp(rName string) string { + return testAccAWSAPIGateway2IntegrationConfig_api(rName) + fmt.Sprintf(` +resource "aws_api_gateway_v2_integration" "test" { + api_id = "${aws_api_gateway_v2_api.test.id}" + integration_type = "HTTP" + + connection_type = "INTERNET" + content_handling_strategy = "CONVERT_TO_TEXT" + description = "Test HTTP" + integration_method = "GET" + integration_uri = "http://www.example.com" + passthrough_behavior = "WHEN_NO_MATCH" + template_selection_expression = "$request.body.name" + timeout_milliseconds = 28999 + + request_templates = { + "application/json" = "" + } +} +`) +} + +func testAccAWSAPIGateway2IntegrationConfig_integrationTypeHttpUpdated(rName string) string { + return testAccAWSAPIGateway2IntegrationConfig_api(rName) + fmt.Sprintf(` +resource "aws_api_gateway_v2_integration" "test" { + api_id = "${aws_api_gateway_v2_api.test.id}" + integration_type = "HTTP" + + connection_type = "INTERNET" + content_handling_strategy = "CONVERT_TO_BINARY" + description = "Test HTTP updated" + integration_method = "POST" + integration_uri = "http://www.example.org" + passthrough_behavior = "WHEN_NO_TEMPLATES" + template_selection_expression = "$request.body.id" + timeout_milliseconds = 51 + + request_templates = { + "application/json" = "#set($number=42)" + "application/xml" = "#set($percent=$number/100)" + } +} +`) +} + +func testAccAWSAPIGateway2IntegrationConfig_lambda(rName string) string { + return testAccAWSAPIGateway2IntegrationConfig_api(rName) + baseAccAWSLambdaConfig(rName, rName, rName) + fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +resource "aws_lambda_function" "test" { + filename = "test-fixtures/lambdatest.zip" + function_name = %[1]q + role = "${aws_iam_role.iam_for_lambda.arn}" + handler = "index.handler" + runtime = "nodejs10.x" +} + +resource "aws_api_gateway_v2_integration" "test" { + api_id = "${aws_api_gateway_v2_api.test.id}" + integration_type = "AWS" + + connection_type = "INTERNET" + content_handling_strategy = "CONVERT_TO_TEXT" + credentials_arn = "${data.aws_caller_identity.current.arn}" + description = "Test Lambda" + integration_method = "POST" + integration_uri = "${aws_lambda_function.test.invoke_arn}" + passthrough_behavior = "WHEN_NO_MATCH" +} +`, rName) +} + +func testAccAWSAPIGateway2IntegrationConfig_vpcLink(rName string) string { + return testAccAWSAPIGateway2IntegrationConfig_api(rName) + fmt.Sprintf(` +data "aws_availability_zones" "available" {} + +resource "aws_vpc" "test" { + cidr_block = "10.10.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "test" { + vpc_id = "${aws_vpc.test.id}" + cidr_block = "10.10.0.0/24" + availability_zone = "${data.aws_availability_zones.available.names[0]}" + + tags = { + Name = %[1]q + } +} + +resource "aws_lb" "test" { + name = %[1]q + internal = true + load_balancer_type = "network" + subnets = ["${aws_subnet.test.id}"] +} + +resource "aws_api_gateway_vpc_link" "test" { + name = %[1]q + target_arns = ["${aws_lb.test.arn}"] +} + +resource "aws_api_gateway_v2_integration" "test" { + api_id = "${aws_api_gateway_v2_api.test.id}" + integration_type = "HTTP_PROXY" + + connection_id = "${aws_api_gateway_vpc_link.test.id}" + connection_type = "VPC_LINK" + content_handling_strategy = "CONVERT_TO_TEXT" + description = "Test VPC Link" + integration_method = "PUT" + integration_uri = "http://www.example.net" + passthrough_behavior = "NEVER" + timeout_milliseconds = 12345 +} +`, rName) +} diff --git a/website/aws.erb b/website/aws.erb index b5b8540d4c4..c8d1250f864 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -218,6 +218,9 @@
  • aws_apigatewayv2_api
  • +
  • + aws_api_gateway_v2_integration +
  • diff --git a/website/docs/r/api_gateway_v2_integration.html.markdown b/website/docs/r/api_gateway_v2_integration.html.markdown new file mode 100644 index 00000000000..6a7157655cf --- /dev/null +++ b/website/docs/r/api_gateway_v2_integration.html.markdown @@ -0,0 +1,81 @@ +--- +layout: "aws" +page_title: "AWS: aws_api_gateway_v2_integration" +sidebar_current: "docs-aws-resource-api-gateway-v2-integration" +description: |- + Manages an Amazon API Gateway Version 2 integration. +--- + +# Resource: aws_api_gateway_v2_integration + +Manages an Amazon API Gateway Version 2 integration. +More information can be found in the [Amazon API Gateway Developer Guide](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html). + +## Example Usage + +### Basic + +```hcl +resource "aws_api_gateway_v2_integration" "example" { + api_id = "${aws_api_gateway_v2_api.example.id}" + integration_type = "MOCK" +} +``` + +### Lambda Integration + +```hcl +resource "aws_lambda_function" "example" { + filename = "example.zip" + function_name = "Example" + role = "${aws_iam_role.example.arn}" + handler = "index.handler" + runtime = "nodejs10.x" +} + +resource "aws_api_gateway_v2_integration" "example" { + api_id = "${aws_api_gateway_v2_api.example.id}" + integration_type = "AWS" + + connection_type = "INTERNET" + content_handling_strategy = "CONVERT_TO_TEXT" + description = "Lambda example" + integration_method = "POST" + integration_uri = "${aws_lambda_function.example.invoke_arn}" + passthrough_behavior = "WHEN_NO_MATCH" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `api_id` - (Required) The API identifier. +* `integration_type` - (Required) The integration type of an integration. +Valid values: `AWS`, `AWS_PROXY`, `HTTP`, `HTTP_PROXY`, `MOCK`. +* `connection_id` - (Optional) The connection ID. +* `connection_type` - (Optional) The type of the network connection to the integration endpoint. Valid values: `INTERNET`, `VPC_LINK`. Default is `INTERNET`. +* `content_handling_strategy` - (Optional) How to handle response payload content type conversions. Valid values: `CONVERT_TO_BINARY`, `CONVERT_TO_TEXT`. +* `credentials_arn` - (Optional) The credentials required for the integration, if any. +* `description` - (Optional) The description of the integration. +* `integration_method` - (Optional) The integration's HTTP method. Must be specified if `integration_type` is not `MOCK`. +* `integration_uri` - (Optional) The URI of the Lambda function for a Lambda proxy integration, where `integration_type` is `AWS_PROXY`. +* `passthrough_behavior` - (Optional) The pass-through behavior for incoming requests based on the Content-Type header in the request, and the available mapping templates specified as the `request_templates` attribute. Valid values: `WHEN_NO_MATCH`, `WHEN_NO_TEMPLATES`, `NEVER`. Default is `WHEN_NO_MATCH`. +* `request_templates` - (Optional) A map of Velocity templates that are applied on the request payload based on the value of the Content-Type header sent by the client. +* `template_selection_expression` - (Optional) The [template selection expression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-template-selection-expressions) for the integration. +* `timeout_milliseconds` - (Optional) Custom timeout between 50 and 29,000 milliseconds. The default value is 29,000 milliseconds or 29 seconds. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The integration identifier. +* `integration_response_selection_expression` - The [integration response selection expression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-integration-response-selection-expressions) for the integration. + +## Import + +`aws_api_gateway_v2_integration` can be imported by using the API identifier and integration identifier, e.g. + +``` +$ terraform import aws_api_gateway_v2_integration.example aabbccddee/1122334 +``` From ad89102b9226e2fabfd477eaedba112045793d2d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 13 Mar 2020 11:23:35 -0400 Subject: [PATCH 078/684] 'aws_api_gateway2_integration' -> 'aws_apigatewayv2_integration'. --- aws/provider.go | 2 +- ... resource_aws_apigatewayv2_integration.go} | 44 ++--- ...urce_aws_apigatewayv2_integration_test.go} | 164 +++++++++++------- website/aws.erb | 2 +- ...=> apigatewayv2_integration.html.markdown} | 30 ++-- 5 files changed, 136 insertions(+), 106 deletions(-) rename aws/{resource_aws_api_gateway2_integration.go => resource_aws_apigatewayv2_integration.go} (83%) rename aws/{resource_aws_api_gateway2_integration_test.go => resource_aws_apigatewayv2_integration_test.go} (69%) rename website/docs/r/{api_gateway_v2_integration.html.markdown => apigatewayv2_integration.html.markdown} (77%) diff --git a/aws/provider.go b/aws/provider.go index 02357170970..4fc1ea6db77 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -355,7 +355,7 @@ func Provider() terraform.ResourceProvider { "aws_api_gateway_usage_plan_key": resourceAwsApiGatewayUsagePlanKey(), "aws_api_gateway_vpc_link": resourceAwsApiGatewayVpcLink(), "aws_apigatewayv2_api": resourceAwsApiGatewayV2Api(), - "aws_api_gateway_v2_integration": resourceAwsApiGateway2Integration(), + "aws_apigatewayv2_integration": resourceAwsApiGatewayV2Integration(), "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), "aws_appautoscaling_target": resourceAwsAppautoscalingTarget(), "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), diff --git a/aws/resource_aws_api_gateway2_integration.go b/aws/resource_aws_apigatewayv2_integration.go similarity index 83% rename from aws/resource_aws_api_gateway2_integration.go rename to aws/resource_aws_apigatewayv2_integration.go index 87645ef11c9..829b1942a32 100644 --- a/aws/resource_aws_api_gateway2_integration.go +++ b/aws/resource_aws_apigatewayv2_integration.go @@ -11,16 +11,15 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) -func resourceAwsApiGateway2Integration() *schema.Resource { +func resourceAwsApiGatewayV2Integration() *schema.Resource { return &schema.Resource{ - Create: resourceAwsApiGateway2IntegrationCreate, - Read: resourceAwsApiGateway2IntegrationRead, - Update: resourceAwsApiGateway2IntegrationUpdate, - Delete: resourceAwsApiGateway2IntegrationDelete, + Create: resourceAwsApiGatewayV2IntegrationCreate, + Read: resourceAwsApiGatewayV2IntegrationRead, + Update: resourceAwsApiGatewayV2IntegrationUpdate, + Delete: resourceAwsApiGatewayV2IntegrationDelete, Importer: &schema.ResourceImporter{ - State: resourceAwsApiGateway2IntegrationImport, + State: resourceAwsApiGatewayV2IntegrationImport, }, - CustomizeDiff: resourceAwsApiGateway2IntegrationCustomizeDiff, Schema: map[string]*schema.Schema{ "api_id": { @@ -113,7 +112,7 @@ func resourceAwsApiGateway2Integration() *schema.Resource { } } -func resourceAwsApiGateway2IntegrationCreate(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2IntegrationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn req := &apigatewayv2.CreateIntegrationInput{ @@ -162,10 +161,10 @@ func resourceAwsApiGateway2IntegrationCreate(d *schema.ResourceData, meta interf d.SetId(aws.StringValue(resp.IntegrationId)) - return resourceAwsApiGateway2IntegrationRead(d, meta) + return resourceAwsApiGatewayV2IntegrationRead(d, meta) } -func resourceAwsApiGateway2IntegrationRead(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2IntegrationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn resp, err := conn.GetIntegration(&apigatewayv2.GetIntegrationInput{ @@ -201,7 +200,7 @@ func resourceAwsApiGateway2IntegrationRead(d *schema.ResourceData, meta interfac return nil } -func resourceAwsApiGateway2IntegrationUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2IntegrationUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn req := &apigatewayv2.UpdateIntegrationInput{ @@ -248,10 +247,10 @@ func resourceAwsApiGateway2IntegrationUpdate(d *schema.ResourceData, meta interf return fmt.Errorf("error updating API Gateway v2 integration: %s", err) } - return resourceAwsApiGateway2IntegrationRead(d, meta) + return resourceAwsApiGatewayV2IntegrationRead(d, meta) } -func resourceAwsApiGateway2IntegrationDelete(d *schema.ResourceData, meta interface{}) error { +func resourceAwsApiGatewayV2IntegrationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayv2conn log.Printf("[DEBUG] Deleting API Gateway v2 integration (%s)", d.Id()) @@ -269,7 +268,7 @@ func resourceAwsApiGateway2IntegrationDelete(d *schema.ResourceData, meta interf return nil } -func resourceAwsApiGateway2IntegrationImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { +func resourceAwsApiGatewayV2IntegrationImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { parts := strings.Split(d.Id(), "/") if len(parts) != 2 { return []*schema.ResourceData{}, fmt.Errorf("Wrong format of resource: %s. Please follow 'api-id/integration-id'", d.Id()) @@ -280,20 +279,3 @@ func resourceAwsApiGateway2IntegrationImport(d *schema.ResourceData, meta interf return []*schema.ResourceData{d}, nil } - -func resourceAwsApiGateway2IntegrationCustomizeDiff(diff *schema.ResourceDiff, meta interface{}) error { - if diff.Id() == "" { - // New resource. - integrationMethod := diff.Get("integration_method").(string) - integrationType := diff.Get("integration_type").(string) - if integrationType == apigatewayv2.IntegrationTypeMock { - if integrationMethod != "" { - return fmt.Errorf("'integration_method' must not be set when 'integration_type' is '%s'", integrationType) - } - } else if integrationMethod == "" { - return fmt.Errorf("'integration_method' must be set when 'integration_type' is '%s'", integrationType) - } - } - - return nil -} diff --git a/aws/resource_aws_api_gateway2_integration_test.go b/aws/resource_aws_apigatewayv2_integration_test.go similarity index 69% rename from aws/resource_aws_api_gateway2_integration_test.go rename to aws/resource_aws_apigatewayv2_integration_test.go index ac37b93b8b9..d5760a40860 100644 --- a/aws/resource_aws_api_gateway2_integration_test.go +++ b/aws/resource_aws_apigatewayv2_integration_test.go @@ -11,19 +11,21 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/terraform" ) -func TestAccAWSAPIGateway2Integration_basic(t *testing.T) { - resourceName := "aws_api_gateway_v2_integration.test" - rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) +func TestAccAWSAPIGatewayV2Integration_basic(t *testing.T) { + var apiId string + var v apigatewayv2.GetIntegrationOutput + resourceName := "aws_apigatewayv2_integration.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAPIGateway2IntegrationDestroy, + CheckDestroy: testAccCheckAWSAPIGatewayV2IntegrationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAPIGateway2IntegrationConfig_basic(rName), + Config: testAccAWSAPIGatewayV2IntegrationConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2IntegrationExists(resourceName), + testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v), resource.TestCheckResourceAttr(resourceName, "connection_id", ""), resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", ""), @@ -41,7 +43,7 @@ func TestAccAWSAPIGateway2Integration_basic(t *testing.T) { }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAPIGateway2IntegrationImportStateIdFunc(resourceName), + ImportStateIdFunc: testAccAWSAPIGatewayV2IntegrationImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -49,19 +51,44 @@ func TestAccAWSAPIGateway2Integration_basic(t *testing.T) { }) } -func TestAccAWSAPIGateway2Integration_IntegrationTypeHttp(t *testing.T) { - resourceName := "aws_api_gateway_v2_integration.test" - rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) +func TestAccAWSAPIGatewayV2Integration_disappears(t *testing.T) { + var apiId string + var v apigatewayv2.GetIntegrationOutput + resourceName := "aws_apigatewayv2_integration.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAPIGateway2IntegrationDestroy, + CheckDestroy: testAccCheckAWSAPIGatewayV2IntegrationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAPIGateway2IntegrationConfig_integrationTypeHttp(rName), + Config: testAccAWSAPIGatewayV2IntegrationConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2IntegrationExists(resourceName), + testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v), + testAccCheckAWSAPIGatewayV2IntegrationDisappears(&apiId, &v), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSAPIGatewayV2Integration_IntegrationTypeHttp(t *testing.T) { + var apiId string + var v apigatewayv2.GetIntegrationOutput + resourceName := "aws_apigatewayv2_integration.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGatewayV2IntegrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2IntegrationConfig_integrationTypeHttp(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v), resource.TestCheckResourceAttr(resourceName, "connection_id", ""), resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", "CONVERT_TO_TEXT"), @@ -79,9 +106,9 @@ func TestAccAWSAPIGateway2Integration_IntegrationTypeHttp(t *testing.T) { ), }, { - Config: testAccAWSAPIGateway2IntegrationConfig_integrationTypeHttpUpdated(rName), + Config: testAccAWSAPIGatewayV2IntegrationConfig_integrationTypeHttpUpdated(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2IntegrationExists(resourceName), + testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v), resource.TestCheckResourceAttr(resourceName, "connection_id", ""), resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", "CONVERT_TO_BINARY"), @@ -101,7 +128,7 @@ func TestAccAWSAPIGateway2Integration_IntegrationTypeHttp(t *testing.T) { }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAPIGateway2IntegrationImportStateIdFunc(resourceName), + ImportStateIdFunc: testAccAWSAPIGatewayV2IntegrationImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -109,21 +136,23 @@ func TestAccAWSAPIGateway2Integration_IntegrationTypeHttp(t *testing.T) { }) } -func TestAccAWSAPIGateway2Integration_Lambda(t *testing.T) { - resourceName := "aws_api_gateway_v2_integration.test" +func TestAccAWSAPIGatewayV2Integration_Lambda(t *testing.T) { + var apiId string + var v apigatewayv2.GetIntegrationOutput + resourceName := "aws_apigatewayv2_integration.test" callerIdentityDatasourceName := "data.aws_caller_identity.current" lambdaResourceName := "aws_lambda_function.test" - rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAPIGateway2IntegrationDestroy, + CheckDestroy: testAccCheckAWSAPIGatewayV2IntegrationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAPIGateway2IntegrationConfig_lambda(rName), + Config: testAccAWSAPIGatewayV2IntegrationConfig_lambda(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2IntegrationExists(resourceName), + testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v), resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", "CONVERT_TO_TEXT"), resource.TestCheckResourceAttrPair(resourceName, "credentials_arn", callerIdentityDatasourceName, "arn"), @@ -140,7 +169,7 @@ func TestAccAWSAPIGateway2Integration_Lambda(t *testing.T) { }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAPIGateway2IntegrationImportStateIdFunc(resourceName), + ImportStateIdFunc: testAccAWSAPIGatewayV2IntegrationImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -148,20 +177,22 @@ func TestAccAWSAPIGateway2Integration_Lambda(t *testing.T) { }) } -func TestAccAWSAPIGateway2Integration_VpcLink(t *testing.T) { - resourceName := "aws_api_gateway_v2_integration.test" +func TestAccAWSAPIGatewayV2Integration_VpcLink(t *testing.T) { + var apiId string + var v apigatewayv2.GetIntegrationOutput + resourceName := "aws_apigatewayv2_integration.test" vpcLinkResourceName := "aws_api_gateway_vpc_link.test" - rName := fmt.Sprintf("tf-testacc-apigwv2-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAPIGateway2IntegrationDestroy, + CheckDestroy: testAccCheckAWSAPIGatewayV2IntegrationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAPIGateway2IntegrationConfig_vpcLink(rName), + Config: testAccAWSAPIGatewayV2IntegrationConfig_vpcLink(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGateway2IntegrationExists(resourceName), + testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v), resource.TestCheckResourceAttrPair(resourceName, "connection_id", vpcLinkResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "connection_type", "VPC_LINK"), resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", "CONVERT_TO_TEXT"), @@ -179,7 +210,7 @@ func TestAccAWSAPIGateway2Integration_VpcLink(t *testing.T) { }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAPIGateway2IntegrationImportStateIdFunc(resourceName), + ImportStateIdFunc: testAccAWSAPIGatewayV2IntegrationImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -187,11 +218,11 @@ func TestAccAWSAPIGateway2Integration_VpcLink(t *testing.T) { }) } -func testAccCheckAWSAPIGateway2IntegrationDestroy(s *terraform.State) error { +func testAccCheckAWSAPIGatewayV2IntegrationDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_api_gateway_v2_integration" { + if rs.Type != "aws_apigatewayv2_integration" { continue } @@ -212,7 +243,20 @@ func testAccCheckAWSAPIGateway2IntegrationDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSAPIGateway2IntegrationExists(n string) resource.TestCheckFunc { +func testAccCheckAWSAPIGatewayV2IntegrationDisappears(apiId *string, v *apigatewayv2.GetIntegrationOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn + + _, err := conn.DeleteIntegration(&apigatewayv2.DeleteIntegrationInput{ + ApiId: apiId, + IntegrationId: v.IntegrationId, + }) + + return err + } +} + +func testAccCheckAWSAPIGatewayV2IntegrationExists(n string, vApiId *string, v *apigatewayv2.GetIntegrationOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -225,19 +269,23 @@ func testAccCheckAWSAPIGateway2IntegrationExists(n string) resource.TestCheckFun conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn - _, err := conn.GetIntegration(&apigatewayv2.GetIntegrationInput{ - ApiId: aws.String(rs.Primary.Attributes["api_id"]), + apiId := aws.String(rs.Primary.Attributes["api_id"]) + resp, err := conn.GetIntegration(&apigatewayv2.GetIntegrationInput{ + ApiId: apiId, IntegrationId: aws.String(rs.Primary.ID), }) if err != nil { return err } + *vApiId = *apiId + *v = *resp + return nil } } -func testAccAWSAPIGateway2IntegrationImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { +func testAccAWSAPIGatewayV2IntegrationImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { return func(s *terraform.State) (string, error) { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -248,9 +296,9 @@ func testAccAWSAPIGateway2IntegrationImportStateIdFunc(resourceName string) reso } } -func testAccAWSAPIGateway2IntegrationConfig_api(rName string) string { +func testAccAWSAPIGatewayV2IntegrationConfig_api(rName string) string { return fmt.Sprintf(` -resource "aws_api_gateway_v2_api" "test" { +resource "aws_apigatewayv2_api" "test" { name = %[1]q protocol_type = "WEBSOCKET" route_selection_expression = "$request.body.action" @@ -258,19 +306,19 @@ resource "aws_api_gateway_v2_api" "test" { `, rName) } -func testAccAWSAPIGateway2IntegrationConfig_basic(rName string) string { - return testAccAWSAPIGateway2IntegrationConfig_api(rName) + fmt.Sprintf(` -resource "aws_api_gateway_v2_integration" "test" { - api_id = "${aws_api_gateway_v2_api.test.id}" +func testAccAWSAPIGatewayV2IntegrationConfig_basic(rName string) string { + return testAccAWSAPIGatewayV2IntegrationConfig_api(rName) + fmt.Sprintf(` +resource "aws_apigatewayv2_integration" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" integration_type = "MOCK" } `) } -func testAccAWSAPIGateway2IntegrationConfig_integrationTypeHttp(rName string) string { - return testAccAWSAPIGateway2IntegrationConfig_api(rName) + fmt.Sprintf(` -resource "aws_api_gateway_v2_integration" "test" { - api_id = "${aws_api_gateway_v2_api.test.id}" +func testAccAWSAPIGatewayV2IntegrationConfig_integrationTypeHttp(rName string) string { + return testAccAWSAPIGatewayV2IntegrationConfig_api(rName) + fmt.Sprintf(` +resource "aws_apigatewayv2_integration" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" integration_type = "HTTP" connection_type = "INTERNET" @@ -289,10 +337,10 @@ resource "aws_api_gateway_v2_integration" "test" { `) } -func testAccAWSAPIGateway2IntegrationConfig_integrationTypeHttpUpdated(rName string) string { - return testAccAWSAPIGateway2IntegrationConfig_api(rName) + fmt.Sprintf(` -resource "aws_api_gateway_v2_integration" "test" { - api_id = "${aws_api_gateway_v2_api.test.id}" +func testAccAWSAPIGatewayV2IntegrationConfig_integrationTypeHttpUpdated(rName string) string { + return testAccAWSAPIGatewayV2IntegrationConfig_api(rName) + fmt.Sprintf(` +resource "aws_apigatewayv2_integration" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" integration_type = "HTTP" connection_type = "INTERNET" @@ -312,8 +360,8 @@ resource "aws_api_gateway_v2_integration" "test" { `) } -func testAccAWSAPIGateway2IntegrationConfig_lambda(rName string) string { - return testAccAWSAPIGateway2IntegrationConfig_api(rName) + baseAccAWSLambdaConfig(rName, rName, rName) + fmt.Sprintf(` +func testAccAWSAPIGatewayV2IntegrationConfig_lambda(rName string) string { + return testAccAWSAPIGatewayV2IntegrationConfig_api(rName) + baseAccAWSLambdaConfig(rName, rName, rName) + fmt.Sprintf(` data "aws_caller_identity" "current" {} resource "aws_lambda_function" "test" { @@ -324,8 +372,8 @@ resource "aws_lambda_function" "test" { runtime = "nodejs10.x" } -resource "aws_api_gateway_v2_integration" "test" { - api_id = "${aws_api_gateway_v2_api.test.id}" +resource "aws_apigatewayv2_integration" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" integration_type = "AWS" connection_type = "INTERNET" @@ -339,8 +387,8 @@ resource "aws_api_gateway_v2_integration" "test" { `, rName) } -func testAccAWSAPIGateway2IntegrationConfig_vpcLink(rName string) string { - return testAccAWSAPIGateway2IntegrationConfig_api(rName) + fmt.Sprintf(` +func testAccAWSAPIGatewayV2IntegrationConfig_vpcLink(rName string) string { + return testAccAWSAPIGatewayV2IntegrationConfig_api(rName) + fmt.Sprintf(` data "aws_availability_zones" "available" {} resource "aws_vpc" "test" { @@ -373,8 +421,8 @@ resource "aws_api_gateway_vpc_link" "test" { target_arns = ["${aws_lb.test.arn}"] } -resource "aws_api_gateway_v2_integration" "test" { - api_id = "${aws_api_gateway_v2_api.test.id}" +resource "aws_apigatewayv2_integration" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" integration_type = "HTTP_PROXY" connection_id = "${aws_api_gateway_vpc_link.test.id}" diff --git a/website/aws.erb b/website/aws.erb index c8d1250f864..181755dbe9e 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -219,7 +219,7 @@ aws_apigatewayv2_api
  • - aws_api_gateway_v2_integration + aws_apigatewayv2_integration
  • diff --git a/website/docs/r/api_gateway_v2_integration.html.markdown b/website/docs/r/apigatewayv2_integration.html.markdown similarity index 77% rename from website/docs/r/api_gateway_v2_integration.html.markdown rename to website/docs/r/apigatewayv2_integration.html.markdown index 6a7157655cf..2949654c515 100644 --- a/website/docs/r/api_gateway_v2_integration.html.markdown +++ b/website/docs/r/apigatewayv2_integration.html.markdown @@ -1,12 +1,12 @@ --- +subcategory: "API Gateway v2 (WebSocket and HTTP APIs)" layout: "aws" -page_title: "AWS: aws_api_gateway_v2_integration" -sidebar_current: "docs-aws-resource-api-gateway-v2-integration" +page_title: "AWS: aws_apigatewayv2_integration" description: |- Manages an Amazon API Gateway Version 2 integration. --- -# Resource: aws_api_gateway_v2_integration +# Resource: aws_apigatewayv2_integration Manages an Amazon API Gateway Version 2 integration. More information can be found in the [Amazon API Gateway Developer Guide](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html). @@ -16,8 +16,8 @@ More information can be found in the [Amazon API Gateway Developer Guide](https: ### Basic ```hcl -resource "aws_api_gateway_v2_integration" "example" { - api_id = "${aws_api_gateway_v2_api.example.id}" +resource "aws_apigatewayv2_integration" "example" { + api_id = "${aws_apigatewayv2_api.example.id}" integration_type = "MOCK" } ``` @@ -33,16 +33,16 @@ resource "aws_lambda_function" "example" { runtime = "nodejs10.x" } -resource "aws_api_gateway_v2_integration" "example" { - api_id = "${aws_api_gateway_v2_api.example.id}" +resource "aws_apigatewayv2_integration" "example" { + api_id = "${aws_apigatewayv2_api.example.id}" integration_type = "AWS" - connection_type = "INTERNET" - content_handling_strategy = "CONVERT_TO_TEXT" - description = "Lambda example" - integration_method = "POST" - integration_uri = "${aws_lambda_function.example.invoke_arn}" - passthrough_behavior = "WHEN_NO_MATCH" + connection_type = "INTERNET" + content_handling_strategy = "CONVERT_TO_TEXT" + description = "Lambda example" + integration_method = "POST" + integration_uri = "${aws_lambda_function.example.invoke_arn}" + passthrough_behavior = "WHEN_NO_MATCH" } ``` @@ -74,8 +74,8 @@ In addition to all arguments above, the following attributes are exported: ## Import -`aws_api_gateway_v2_integration` can be imported by using the API identifier and integration identifier, e.g. +`aws_apigatewayv2_integration` can be imported by using the API identifier and integration identifier, e.g. ``` -$ terraform import aws_api_gateway_v2_integration.example aabbccddee/1122334 +$ terraform import aws_apigatewayv2_integration.example aabbccddee/1122334 ``` From a9ee64c845477e1efc47cac21e110b8096bec4d2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 15 Mar 2020 18:56:45 -0400 Subject: [PATCH 079/684] r/aws_apigatewayv2_integration: Don't import API Gateway managed integrations. --- aws/resource_aws_apigatewayv2_integration.go | 21 ++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_apigatewayv2_integration.go b/aws/resource_aws_apigatewayv2_integration.go index 829b1942a32..e267d5926a4 100644 --- a/aws/resource_aws_apigatewayv2_integration.go +++ b/aws/resource_aws_apigatewayv2_integration.go @@ -274,8 +274,25 @@ func resourceAwsApiGatewayV2IntegrationImport(d *schema.ResourceData, meta inter return []*schema.ResourceData{}, fmt.Errorf("Wrong format of resource: %s. Please follow 'api-id/integration-id'", d.Id()) } - d.SetId(parts[1]) - d.Set("api_id", parts[0]) + apiId := parts[0] + integrationId := parts[1] + + conn := meta.(*AWSClient).apigatewayv2conn + + resp, err := conn.GetIntegration(&apigatewayv2.GetIntegrationInput{ + ApiId: aws.String(apiId), + IntegrationId: aws.String(integrationId), + }) + if err != nil { + return nil, err + } + + if aws.BoolValue(resp.ApiGatewayManaged) { + return nil, fmt.Errorf("API Gateway v2 integration (%s) was created via quick create", integrationId) + } + + d.SetId(integrationId) + d.Set("api_id", apiId) return []*schema.ResourceData{d}, nil } From ac97c9de2c558a26001e621ad4d04ae4f780a146 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 16 Mar 2020 18:02:06 -0400 Subject: [PATCH 080/684] r/aws_apigatewayv2_integration: Add 'payload_format_version' and 'tls_config' attributes. --- aws/resource_aws_apigatewayv2_integration.go | 64 ++++++++ ...ource_aws_apigatewayv2_integration_test.go | 145 +++++++++++++++++- .../r/apigatewayv2_integration.html.markdown | 18 ++- 3 files changed, 215 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_apigatewayv2_integration.go b/aws/resource_aws_apigatewayv2_integration.go index e267d5926a4..53f6073b551 100644 --- a/aws/resource_aws_apigatewayv2_integration.go +++ b/aws/resource_aws_apigatewayv2_integration.go @@ -93,6 +93,15 @@ func resourceAwsApiGatewayV2Integration() *schema.Resource { apigatewayv2.PassthroughBehaviorWhenNoTemplates, }, false), }, + "payload_format_version": { + Type: schema.TypeString, + Optional: true, + Default: "1.0", + ValidateFunc: validation.StringInSlice([]string{ + "1.0", + "2.0", + }, false), + }, "request_templates": { Type: schema.TypeMap, Optional: true, @@ -108,6 +117,20 @@ func resourceAwsApiGatewayV2Integration() *schema.Resource { Default: 29000, ValidateFunc: validation.IntBetween(50, 29000), }, + "tls_config": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "server_name_to_verify": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, }, } } @@ -143,6 +166,9 @@ func resourceAwsApiGatewayV2IntegrationCreate(d *schema.ResourceData, meta inter if v, ok := d.GetOk("passthrough_behavior"); ok { req.PassthroughBehavior = aws.String(v.(string)) } + if v, ok := d.GetOk("payload_format_version"); ok { + req.PayloadFormatVersion = aws.String(v.(string)) + } if v, ok := d.GetOk("request_templates"); ok { req.RequestTemplates = stringMapToPointers(v.(map[string]interface{})) } @@ -152,6 +178,9 @@ func resourceAwsApiGatewayV2IntegrationCreate(d *schema.ResourceData, meta inter if v, ok := d.GetOk("timeout_milliseconds"); ok { req.TimeoutInMillis = aws.Int64(int64(v.(int))) } + if v, ok := d.GetOk("tls_config"); ok { + req.TlsConfig = expandApiGateway2TlsConfig(v.([]interface{})) + } log.Printf("[DEBUG] Creating API Gateway v2 integration: %s", req) resp, err := conn.CreateIntegration(req) @@ -190,12 +219,16 @@ func resourceAwsApiGatewayV2IntegrationRead(d *schema.ResourceData, meta interfa d.Set("integration_type", resp.IntegrationType) d.Set("integration_uri", resp.IntegrationUri) d.Set("passthrough_behavior", resp.PassthroughBehavior) + d.Set("payload_format_version", resp.PayloadFormatVersion) err = d.Set("request_templates", pointersMapToStringList(resp.RequestTemplates)) if err != nil { return fmt.Errorf("error setting request_templates: %s", err) } d.Set("template_selection_expression", resp.TemplateSelectionExpression) d.Set("timeout_milliseconds", resp.TimeoutInMillis) + if err := d.Set("tls_config", flattenApiGateway2TlsConfig(resp.TlsConfig)); err != nil { + return fmt.Errorf("error setting tls_config: %s", err) + } return nil } @@ -231,6 +264,9 @@ func resourceAwsApiGatewayV2IntegrationUpdate(d *schema.ResourceData, meta inter if d.HasChange("passthrough_behavior") { req.PassthroughBehavior = aws.String(d.Get("passthrough_behavior").(string)) } + if d.HasChange("payload_format_version") { + req.PayloadFormatVersion = aws.String(d.Get("payload_format_version").(string)) + } if d.HasChange("request_templates") { req.RequestTemplates = stringMapToPointers(d.Get("request_templates").(map[string]interface{})) } @@ -240,6 +276,9 @@ func resourceAwsApiGatewayV2IntegrationUpdate(d *schema.ResourceData, meta inter if d.HasChange("timeout_milliseconds") { req.TimeoutInMillis = aws.Int64(int64(d.Get("timeout_milliseconds").(int))) } + if d.HasChange("tls_config") { + req.TlsConfig = expandApiGateway2TlsConfig(d.Get("tls_config").([]interface{})) + } log.Printf("[DEBUG] Updating API Gateway v2 integration: %s", req) _, err := conn.UpdateIntegration(req) @@ -296,3 +335,28 @@ func resourceAwsApiGatewayV2IntegrationImport(d *schema.ResourceData, meta inter return []*schema.ResourceData{d}, nil } + +func expandApiGateway2TlsConfig(vConfig []interface{}) *apigatewayv2.TlsConfigInput { + config := &apigatewayv2.TlsConfigInput{} + + if len(vConfig) == 0 || vConfig[0] == nil { + return config + } + mConfig := vConfig[0].(map[string]interface{}) + + if vServerNameToVerify, ok := mConfig["server_name_to_verify"].(string); ok && vServerNameToVerify != "" { + config.ServerNameToVerify = aws.String(vServerNameToVerify) + } + + return config +} + +func flattenApiGateway2TlsConfig(config *apigatewayv2.TlsConfig) []interface{} { + if config == nil { + return []interface{}{} + } + + return []interface{}{map[string]interface{}{ + "server_name_to_verify": aws.StringValue(config.ServerNameToVerify), + }} +} diff --git a/aws/resource_aws_apigatewayv2_integration_test.go b/aws/resource_aws_apigatewayv2_integration_test.go index d5760a40860..7476b4b53a4 100644 --- a/aws/resource_aws_apigatewayv2_integration_test.go +++ b/aws/resource_aws_apigatewayv2_integration_test.go @@ -36,9 +36,11 @@ func TestAccAWSAPIGatewayV2Integration_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "integration_type", "MOCK"), resource.TestCheckResourceAttr(resourceName, "integration_uri", ""), resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", "WHEN_NO_MATCH"), + resource.TestCheckResourceAttr(resourceName, "payload_format_version", "1.0"), resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "29000"), + resource.TestCheckResourceAttr(resourceName, "tls_config.#", "0"), ), }, { @@ -99,10 +101,12 @@ func TestAccAWSAPIGatewayV2Integration_IntegrationTypeHttp(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "integration_type", "HTTP"), resource.TestCheckResourceAttr(resourceName, "integration_uri", "http://www.example.com"), resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", "WHEN_NO_MATCH"), + resource.TestCheckResourceAttr(resourceName, "payload_format_version", "1.0"), resource.TestCheckResourceAttr(resourceName, "request_templates.%", "1"), resource.TestCheckResourceAttr(resourceName, "request_templates.application/json", ""), resource.TestCheckResourceAttr(resourceName, "template_selection_expression", "$request.body.name"), resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "28999"), + resource.TestCheckResourceAttr(resourceName, "tls_config.#", "0"), ), }, { @@ -119,11 +123,13 @@ func TestAccAWSAPIGatewayV2Integration_IntegrationTypeHttp(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "integration_type", "HTTP"), resource.TestCheckResourceAttr(resourceName, "integration_uri", "http://www.example.org"), resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", "WHEN_NO_TEMPLATES"), + resource.TestCheckResourceAttr(resourceName, "payload_format_version", "1.0"), resource.TestCheckResourceAttr(resourceName, "request_templates.%", "2"), resource.TestCheckResourceAttr(resourceName, "request_templates.application/json", "#set($number=42)"), resource.TestCheckResourceAttr(resourceName, "request_templates.application/xml", "#set($percent=$number/100)"), resource.TestCheckResourceAttr(resourceName, "template_selection_expression", "$request.body.id"), resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "51"), + resource.TestCheckResourceAttr(resourceName, "tls_config.#", "0"), ), }, { @@ -162,9 +168,76 @@ func TestAccAWSAPIGatewayV2Integration_Lambda(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "integration_type", "AWS"), resource.TestCheckResourceAttrPair(resourceName, "integration_uri", lambdaResourceName, "invoke_arn"), resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", "WHEN_NO_MATCH"), + resource.TestCheckResourceAttr(resourceName, "payload_format_version", "1.0"), resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "29000"), + resource.TestCheckResourceAttr(resourceName, "tls_config.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAPIGatewayV2IntegrationImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAPIGatewayV2Integration_TlsConfig(t *testing.T) { + var apiId string + var v apigatewayv2.GetIntegrationOutput + resourceName := "aws_apigatewayv2_integration.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGatewayV2IntegrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayV2IntegrationConfig_tlsConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v), + resource.TestCheckResourceAttr(resourceName, "connection_id", ""), + resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), + resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", ""), + resource.TestCheckResourceAttr(resourceName, "credentials_arn", ""), + resource.TestCheckResourceAttr(resourceName, "description", "Test HTTPS"), + resource.TestCheckResourceAttr(resourceName, "integration_method", "GET"), + resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", ""), + resource.TestCheckResourceAttr(resourceName, "integration_type", "HTTP_PROXY"), + resource.TestCheckResourceAttr(resourceName, "integration_uri", "https://www.example.com"), + resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", ""), + resource.TestCheckResourceAttr(resourceName, "payload_format_version", "1.0"), + resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), + resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), + resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "5001"), + resource.TestCheckResourceAttr(resourceName, "tls_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "tls_config.0.server_name_to_verify", "www.example.com"), + ), + }, + { + Config: testAccAWSAPIGatewayV2IntegrationConfig_tlsConfigUpdated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v), + resource.TestCheckResourceAttr(resourceName, "connection_id", ""), + resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), + resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", ""), + resource.TestCheckResourceAttr(resourceName, "credentials_arn", ""), + resource.TestCheckResourceAttr(resourceName, "description", "Test HTTPS updated"), + resource.TestCheckResourceAttr(resourceName, "integration_method", "POST"), + resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", ""), + resource.TestCheckResourceAttr(resourceName, "integration_type", "HTTP_PROXY"), + resource.TestCheckResourceAttr(resourceName, "integration_uri", "https://www.example.org"), + resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", ""), + resource.TestCheckResourceAttr(resourceName, "payload_format_version", "2.0"), + resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), + resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), + resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "4999"), + resource.TestCheckResourceAttr(resourceName, "tls_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "tls_config.0.server_name_to_verify", "www.example.org"), ), }, { @@ -203,9 +276,11 @@ func TestAccAWSAPIGatewayV2Integration_VpcLink(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "integration_type", "HTTP_PROXY"), resource.TestCheckResourceAttr(resourceName, "integration_uri", "http://www.example.net"), resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", "NEVER"), + resource.TestCheckResourceAttr(resourceName, "payload_format_version", "1.0"), resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "12345"), + resource.TestCheckResourceAttr(resourceName, "tls_config.#", "0"), ), }, { @@ -296,7 +371,7 @@ func testAccAWSAPIGatewayV2IntegrationImportStateIdFunc(resourceName string) res } } -func testAccAWSAPIGatewayV2IntegrationConfig_api(rName string) string { +func testAccAWSAPIGatewayV2IntegrationConfig_apiWebSocket(rName string) string { return fmt.Sprintf(` resource "aws_apigatewayv2_api" "test" { name = %[1]q @@ -306,8 +381,17 @@ resource "aws_apigatewayv2_api" "test" { `, rName) } +func testAccAWSAPIGatewayV2IntegrationConfig_apiHttp(rName string) string { + return fmt.Sprintf(` +resource "aws_apigatewayv2_api" "test" { + name = %[1]q + protocol_type = "HTTP" +} +`, rName) +} + func testAccAWSAPIGatewayV2IntegrationConfig_basic(rName string) string { - return testAccAWSAPIGatewayV2IntegrationConfig_api(rName) + fmt.Sprintf(` + return testAccAWSAPIGatewayV2IntegrationConfig_apiWebSocket(rName) + fmt.Sprintf(` resource "aws_apigatewayv2_integration" "test" { api_id = "${aws_apigatewayv2_api.test.id}" integration_type = "MOCK" @@ -316,7 +400,7 @@ resource "aws_apigatewayv2_integration" "test" { } func testAccAWSAPIGatewayV2IntegrationConfig_integrationTypeHttp(rName string) string { - return testAccAWSAPIGatewayV2IntegrationConfig_api(rName) + fmt.Sprintf(` + return testAccAWSAPIGatewayV2IntegrationConfig_apiWebSocket(rName) + fmt.Sprintf(` resource "aws_apigatewayv2_integration" "test" { api_id = "${aws_apigatewayv2_api.test.id}" integration_type = "HTTP" @@ -338,7 +422,7 @@ resource "aws_apigatewayv2_integration" "test" { } func testAccAWSAPIGatewayV2IntegrationConfig_integrationTypeHttpUpdated(rName string) string { - return testAccAWSAPIGatewayV2IntegrationConfig_api(rName) + fmt.Sprintf(` + return testAccAWSAPIGatewayV2IntegrationConfig_apiWebSocket(rName) + fmt.Sprintf(` resource "aws_apigatewayv2_integration" "test" { api_id = "${aws_apigatewayv2_api.test.id}" integration_type = "HTTP" @@ -361,7 +445,7 @@ resource "aws_apigatewayv2_integration" "test" { } func testAccAWSAPIGatewayV2IntegrationConfig_lambda(rName string) string { - return testAccAWSAPIGatewayV2IntegrationConfig_api(rName) + baseAccAWSLambdaConfig(rName, rName, rName) + fmt.Sprintf(` + return testAccAWSAPIGatewayV2IntegrationConfig_apiWebSocket(rName) + baseAccAWSLambdaConfig(rName, rName, rName) + fmt.Sprintf(` data "aws_caller_identity" "current" {} resource "aws_lambda_function" "test" { @@ -387,9 +471,56 @@ resource "aws_apigatewayv2_integration" "test" { `, rName) } +func testAccAWSAPIGatewayV2IntegrationConfig_tlsConfig(rName string) string { + return testAccAWSAPIGatewayV2IntegrationConfig_apiHttp(rName) + fmt.Sprintf(` +resource "aws_apigatewayv2_integration" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" + integration_type = "HTTP_PROXY" + + connection_type = "INTERNET" + description = "Test HTTPS" + integration_method = "GET" + integration_uri = "https://www.example.com" + timeout_milliseconds = 5001 + + tls_config { + server_name_to_verify = "www.example.com" + } +} +`) +} + +func testAccAWSAPIGatewayV2IntegrationConfig_tlsConfigUpdated(rName string) string { + return testAccAWSAPIGatewayV2IntegrationConfig_apiHttp(rName) + fmt.Sprintf(` +resource "aws_apigatewayv2_integration" "test" { + api_id = "${aws_apigatewayv2_api.test.id}" + integration_type = "HTTP_PROXY" + + connection_type = "INTERNET" + description = "Test HTTPS updated" + integration_method = "POST" + integration_uri = "https://www.example.org" + payload_format_version = "2.0" + timeout_milliseconds = 4999 + + tls_config = { + server_name_to_verify = "www.example.org" + } +} +`) +} + func testAccAWSAPIGatewayV2IntegrationConfig_vpcLink(rName string) string { - return testAccAWSAPIGatewayV2IntegrationConfig_api(rName) + fmt.Sprintf(` -data "aws_availability_zones" "available" {} + return testAccAWSAPIGatewayV2IntegrationConfig_apiWebSocket(rName) + fmt.Sprintf(` +data "aws_availability_zones" "available" { + state = "available" + +// https://github.com/terraform-providers/terraform-provider-aws/issues/12412 +// filter { +// name = "opt-in-status" +// values = ["opt-in-not-required"] +// } +} resource "aws_vpc" "test" { cidr_block = "10.10.0.0/16" diff --git a/website/docs/r/apigatewayv2_integration.html.markdown b/website/docs/r/apigatewayv2_integration.html.markdown index 2949654c515..8b59b565061 100644 --- a/website/docs/r/apigatewayv2_integration.html.markdown +++ b/website/docs/r/apigatewayv2_integration.html.markdown @@ -53,17 +53,25 @@ The following arguments are supported: * `api_id` - (Required) The API identifier. * `integration_type` - (Required) The integration type of an integration. Valid values: `AWS`, `AWS_PROXY`, `HTTP`, `HTTP_PROXY`, `MOCK`. -* `connection_id` - (Optional) The connection ID. +* `connection_id` - (Optional) The ID of the VPC link for a private integration. Supported only for HTTP APIs. * `connection_type` - (Optional) The type of the network connection to the integration endpoint. Valid values: `INTERNET`, `VPC_LINK`. Default is `INTERNET`. -* `content_handling_strategy` - (Optional) How to handle response payload content type conversions. Valid values: `CONVERT_TO_BINARY`, `CONVERT_TO_TEXT`. +* `content_handling_strategy` - (Optional) How to handle response payload content type conversions. Valid values: `CONVERT_TO_BINARY`, `CONVERT_TO_TEXT`. Supported only for WebSocket APIs. * `credentials_arn` - (Optional) The credentials required for the integration, if any. * `description` - (Optional) The description of the integration. * `integration_method` - (Optional) The integration's HTTP method. Must be specified if `integration_type` is not `MOCK`. -* `integration_uri` - (Optional) The URI of the Lambda function for a Lambda proxy integration, where `integration_type` is `AWS_PROXY`. -* `passthrough_behavior` - (Optional) The pass-through behavior for incoming requests based on the Content-Type header in the request, and the available mapping templates specified as the `request_templates` attribute. Valid values: `WHEN_NO_MATCH`, `WHEN_NO_TEMPLATES`, `NEVER`. Default is `WHEN_NO_MATCH`. -* `request_templates` - (Optional) A map of Velocity templates that are applied on the request payload based on the value of the Content-Type header sent by the client. +* `integration_uri` - (Optional) The URI of the Lambda function for a Lambda proxy integration, when `integration_type` is `AWS_PROXY`. +For an `HTTP` integration, specify a fully-qualified URL. For an HTTP API private integration, specify the ARN of an Application Load Balancer listener, Network Load Balancer listener, or AWS Cloud Map service. +* `passthrough_behavior` - (Optional) The pass-through behavior for incoming requests based on the Content-Type header in the request, and the available mapping templates specified as the `request_templates` attribute. +Valid values: `WHEN_NO_MATCH`, `WHEN_NO_TEMPLATES`, `NEVER`. Default is `WHEN_NO_MATCH`. Supported only for WebSocket APIs. +* `payload_format_version` - (Optional) The [format of the payload](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.proxy-format) sent to an integration. Valid values: `1.0`, `2.0`. Default is `1.0`. +* `request_templates` - (Optional) A map of Velocity templates that are applied on the request payload based on the value of the Content-Type header sent by the client. Supported only for WebSocket APIs. * `template_selection_expression` - (Optional) The [template selection expression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-template-selection-expressions) for the integration. * `timeout_milliseconds` - (Optional) Custom timeout between 50 and 29,000 milliseconds. The default value is 29,000 milliseconds or 29 seconds. +* `tls_config` - (Optional) The TLS configuration for a private integration. Supported only for HTTP APIs. + +The `tls_config` object supports the following: + +* `server_name_to_verify` - (Optional) If you specify a server name, API Gateway uses it to verify the hostname on the integration's certificate. The server name is also included in the TLS handshake to support Server Name Indication (SNI) or virtual hosting. ## Attribute Reference From ffbce32f931a9b33adc8407a267ba176c510bd44 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 16 Mar 2020 18:19:34 -0400 Subject: [PATCH 081/684] Remove 'tls_config' attribute. It doesn't seem to do anything right now. --- aws/resource_aws_apigatewayv2_integration.go | 48 ------- ...ource_aws_apigatewayv2_integration_test.go | 118 ------------------ .../r/apigatewayv2_integration.html.markdown | 5 - 3 files changed, 171 deletions(-) diff --git a/aws/resource_aws_apigatewayv2_integration.go b/aws/resource_aws_apigatewayv2_integration.go index 53f6073b551..eed4e89d9ec 100644 --- a/aws/resource_aws_apigatewayv2_integration.go +++ b/aws/resource_aws_apigatewayv2_integration.go @@ -117,20 +117,6 @@ func resourceAwsApiGatewayV2Integration() *schema.Resource { Default: 29000, ValidateFunc: validation.IntBetween(50, 29000), }, - "tls_config": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "server_name_to_verify": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, }, } } @@ -178,9 +164,6 @@ func resourceAwsApiGatewayV2IntegrationCreate(d *schema.ResourceData, meta inter if v, ok := d.GetOk("timeout_milliseconds"); ok { req.TimeoutInMillis = aws.Int64(int64(v.(int))) } - if v, ok := d.GetOk("tls_config"); ok { - req.TlsConfig = expandApiGateway2TlsConfig(v.([]interface{})) - } log.Printf("[DEBUG] Creating API Gateway v2 integration: %s", req) resp, err := conn.CreateIntegration(req) @@ -226,9 +209,6 @@ func resourceAwsApiGatewayV2IntegrationRead(d *schema.ResourceData, meta interfa } d.Set("template_selection_expression", resp.TemplateSelectionExpression) d.Set("timeout_milliseconds", resp.TimeoutInMillis) - if err := d.Set("tls_config", flattenApiGateway2TlsConfig(resp.TlsConfig)); err != nil { - return fmt.Errorf("error setting tls_config: %s", err) - } return nil } @@ -276,9 +256,6 @@ func resourceAwsApiGatewayV2IntegrationUpdate(d *schema.ResourceData, meta inter if d.HasChange("timeout_milliseconds") { req.TimeoutInMillis = aws.Int64(int64(d.Get("timeout_milliseconds").(int))) } - if d.HasChange("tls_config") { - req.TlsConfig = expandApiGateway2TlsConfig(d.Get("tls_config").([]interface{})) - } log.Printf("[DEBUG] Updating API Gateway v2 integration: %s", req) _, err := conn.UpdateIntegration(req) @@ -335,28 +312,3 @@ func resourceAwsApiGatewayV2IntegrationImport(d *schema.ResourceData, meta inter return []*schema.ResourceData{d}, nil } - -func expandApiGateway2TlsConfig(vConfig []interface{}) *apigatewayv2.TlsConfigInput { - config := &apigatewayv2.TlsConfigInput{} - - if len(vConfig) == 0 || vConfig[0] == nil { - return config - } - mConfig := vConfig[0].(map[string]interface{}) - - if vServerNameToVerify, ok := mConfig["server_name_to_verify"].(string); ok && vServerNameToVerify != "" { - config.ServerNameToVerify = aws.String(vServerNameToVerify) - } - - return config -} - -func flattenApiGateway2TlsConfig(config *apigatewayv2.TlsConfig) []interface{} { - if config == nil { - return []interface{}{} - } - - return []interface{}{map[string]interface{}{ - "server_name_to_verify": aws.StringValue(config.ServerNameToVerify), - }} -} diff --git a/aws/resource_aws_apigatewayv2_integration_test.go b/aws/resource_aws_apigatewayv2_integration_test.go index 7476b4b53a4..162fcd1ebe0 100644 --- a/aws/resource_aws_apigatewayv2_integration_test.go +++ b/aws/resource_aws_apigatewayv2_integration_test.go @@ -40,7 +40,6 @@ func TestAccAWSAPIGatewayV2Integration_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "29000"), - resource.TestCheckResourceAttr(resourceName, "tls_config.#", "0"), ), }, { @@ -106,7 +105,6 @@ func TestAccAWSAPIGatewayV2Integration_IntegrationTypeHttp(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "request_templates.application/json", ""), resource.TestCheckResourceAttr(resourceName, "template_selection_expression", "$request.body.name"), resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "28999"), - resource.TestCheckResourceAttr(resourceName, "tls_config.#", "0"), ), }, { @@ -129,7 +127,6 @@ func TestAccAWSAPIGatewayV2Integration_IntegrationTypeHttp(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "request_templates.application/xml", "#set($percent=$number/100)"), resource.TestCheckResourceAttr(resourceName, "template_selection_expression", "$request.body.id"), resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "51"), - resource.TestCheckResourceAttr(resourceName, "tls_config.#", "0"), ), }, { @@ -172,72 +169,6 @@ func TestAccAWSAPIGatewayV2Integration_Lambda(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "29000"), - resource.TestCheckResourceAttr(resourceName, "tls_config.#", "0"), - ), - }, - { - ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAPIGatewayV2IntegrationImportStateIdFunc(resourceName), - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccAWSAPIGatewayV2Integration_TlsConfig(t *testing.T) { - var apiId string - var v apigatewayv2.GetIntegrationOutput - resourceName := "aws_apigatewayv2_integration.test" - rName := acctest.RandomWithPrefix("tf-acc-test") - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAPIGatewayV2IntegrationDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAPIGatewayV2IntegrationConfig_tlsConfig(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v), - resource.TestCheckResourceAttr(resourceName, "connection_id", ""), - resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), - resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", ""), - resource.TestCheckResourceAttr(resourceName, "credentials_arn", ""), - resource.TestCheckResourceAttr(resourceName, "description", "Test HTTPS"), - resource.TestCheckResourceAttr(resourceName, "integration_method", "GET"), - resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", ""), - resource.TestCheckResourceAttr(resourceName, "integration_type", "HTTP_PROXY"), - resource.TestCheckResourceAttr(resourceName, "integration_uri", "https://www.example.com"), - resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", ""), - resource.TestCheckResourceAttr(resourceName, "payload_format_version", "1.0"), - resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), - resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), - resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "5001"), - resource.TestCheckResourceAttr(resourceName, "tls_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "tls_config.0.server_name_to_verify", "www.example.com"), - ), - }, - { - Config: testAccAWSAPIGatewayV2IntegrationConfig_tlsConfigUpdated(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v), - resource.TestCheckResourceAttr(resourceName, "connection_id", ""), - resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"), - resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", ""), - resource.TestCheckResourceAttr(resourceName, "credentials_arn", ""), - resource.TestCheckResourceAttr(resourceName, "description", "Test HTTPS updated"), - resource.TestCheckResourceAttr(resourceName, "integration_method", "POST"), - resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", ""), - resource.TestCheckResourceAttr(resourceName, "integration_type", "HTTP_PROXY"), - resource.TestCheckResourceAttr(resourceName, "integration_uri", "https://www.example.org"), - resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", ""), - resource.TestCheckResourceAttr(resourceName, "payload_format_version", "2.0"), - resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), - resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), - resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "4999"), - resource.TestCheckResourceAttr(resourceName, "tls_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "tls_config.0.server_name_to_verify", "www.example.org"), ), }, { @@ -280,7 +211,6 @@ func TestAccAWSAPIGatewayV2Integration_VpcLink(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"), resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""), resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "12345"), - resource.TestCheckResourceAttr(resourceName, "tls_config.#", "0"), ), }, { @@ -381,15 +311,6 @@ resource "aws_apigatewayv2_api" "test" { `, rName) } -func testAccAWSAPIGatewayV2IntegrationConfig_apiHttp(rName string) string { - return fmt.Sprintf(` -resource "aws_apigatewayv2_api" "test" { - name = %[1]q - protocol_type = "HTTP" -} -`, rName) -} - func testAccAWSAPIGatewayV2IntegrationConfig_basic(rName string) string { return testAccAWSAPIGatewayV2IntegrationConfig_apiWebSocket(rName) + fmt.Sprintf(` resource "aws_apigatewayv2_integration" "test" { @@ -471,45 +392,6 @@ resource "aws_apigatewayv2_integration" "test" { `, rName) } -func testAccAWSAPIGatewayV2IntegrationConfig_tlsConfig(rName string) string { - return testAccAWSAPIGatewayV2IntegrationConfig_apiHttp(rName) + fmt.Sprintf(` -resource "aws_apigatewayv2_integration" "test" { - api_id = "${aws_apigatewayv2_api.test.id}" - integration_type = "HTTP_PROXY" - - connection_type = "INTERNET" - description = "Test HTTPS" - integration_method = "GET" - integration_uri = "https://www.example.com" - timeout_milliseconds = 5001 - - tls_config { - server_name_to_verify = "www.example.com" - } -} -`) -} - -func testAccAWSAPIGatewayV2IntegrationConfig_tlsConfigUpdated(rName string) string { - return testAccAWSAPIGatewayV2IntegrationConfig_apiHttp(rName) + fmt.Sprintf(` -resource "aws_apigatewayv2_integration" "test" { - api_id = "${aws_apigatewayv2_api.test.id}" - integration_type = "HTTP_PROXY" - - connection_type = "INTERNET" - description = "Test HTTPS updated" - integration_method = "POST" - integration_uri = "https://www.example.org" - payload_format_version = "2.0" - timeout_milliseconds = 4999 - - tls_config = { - server_name_to_verify = "www.example.org" - } -} -`) -} - func testAccAWSAPIGatewayV2IntegrationConfig_vpcLink(rName string) string { return testAccAWSAPIGatewayV2IntegrationConfig_apiWebSocket(rName) + fmt.Sprintf(` data "aws_availability_zones" "available" { diff --git a/website/docs/r/apigatewayv2_integration.html.markdown b/website/docs/r/apigatewayv2_integration.html.markdown index 8b59b565061..0596f45650d 100644 --- a/website/docs/r/apigatewayv2_integration.html.markdown +++ b/website/docs/r/apigatewayv2_integration.html.markdown @@ -67,11 +67,6 @@ Valid values: `WHEN_NO_MATCH`, `WHEN_NO_TEMPLATES`, `NEVER`. Default is `WHEN_NO * `request_templates` - (Optional) A map of Velocity templates that are applied on the request payload based on the value of the Content-Type header sent by the client. Supported only for WebSocket APIs. * `template_selection_expression` - (Optional) The [template selection expression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-template-selection-expressions) for the integration. * `timeout_milliseconds` - (Optional) Custom timeout between 50 and 29,000 milliseconds. The default value is 29,000 milliseconds or 29 seconds. -* `tls_config` - (Optional) The TLS configuration for a private integration. Supported only for HTTP APIs. - -The `tls_config` object supports the following: - -* `server_name_to_verify` - (Optional) If you specify a server name, API Gateway uses it to verify the hostname on the integration's certificate. The server name is also included in the TLS handshake to support Server Name Indication (SNI) or virtual hosting. ## Attribute Reference From 0c754c52c92f03798fff79eb8500dc1434f2ce90 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 24 Mar 2020 17:51:39 -0400 Subject: [PATCH 082/684] Use availability zone filter (https://github.com/terraform-providers/terraform-provider-aws/pull/12400 merged). --- aws/resource_aws_apigatewayv2_integration_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_apigatewayv2_integration_test.go b/aws/resource_aws_apigatewayv2_integration_test.go index 162fcd1ebe0..38de2e89b1b 100644 --- a/aws/resource_aws_apigatewayv2_integration_test.go +++ b/aws/resource_aws_apigatewayv2_integration_test.go @@ -397,11 +397,10 @@ func testAccAWSAPIGatewayV2IntegrationConfig_vpcLink(rName string) string { data "aws_availability_zones" "available" { state = "available" -// https://github.com/terraform-providers/terraform-provider-aws/issues/12412 -// filter { -// name = "opt-in-status" -// values = ["opt-in-not-required"] -// } + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { From ef337853149f93edd5e92e419edc989a2566b7d3 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 3 Mar 2020 14:12:37 -0800 Subject: [PATCH 083/684] Cleans up some formatting and adds some tests to actually test some cases --- aws/provider_test.go | 29 ++ aws/resource_aws_emr_cluster_test.go | 390 +++++++++++++-------------- 2 files changed, 215 insertions(+), 204 deletions(-) diff --git a/aws/provider_test.go b/aws/provider_test.go index 63b57f08061..df29fb15538 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -14,6 +14,7 @@ import ( "github.com/aws/aws-sdk-go/service/organizations" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/terraform" ) @@ -275,6 +276,34 @@ func testAccCheckListHasSomeElementAttrPair(nameFirst string, resourceAttr strin } } +// testAccCheckResourceAttrEquivalentJSON is a TestCheckFunc that compares a JSON value with an expected value. Both JSON +// values are normalized before being compared. +func testAccCheckResourceAttrEquivalentJSON(resourceName, attributeName, expectedJSON string) resource.TestCheckFunc { + return func(s *terraform.State) error { + is, err := primaryInstanceState(s, resourceName) + + v, ok := is.Attributes[attributeName] + if !ok { + return fmt.Errorf("%s: No attribute %q found", resourceName, attributeName) + } + + vNormal, err := structure.NormalizeJsonString(v) + if err != nil { + return fmt.Errorf("%s: Error normalizing JSON in %q: %w", resourceName, attributeName, err) + } + + expectedNormal, err := structure.NormalizeJsonString(expectedJSON) + if err != nil { + return fmt.Errorf("Error normalizing expected JSON: %w", err) + } + + if vNormal != expectedNormal { + return fmt.Errorf("%s: Attribute %q expected\n%s\ngot\n%s", resourceName, attributeName, expectedJSON, v) + } + return nil + } +} + // Copied and inlined from the SDK testing code func primaryInstanceState(s *terraform.State, name string) (*terraform.InstanceState, error) { rs, ok := s.RootModule().Resources[name] diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index 7b8c0075c05..eb518f929f5 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -79,6 +79,8 @@ func testSweepEmrClusters(region string) error { } func TestAccAWSEMRCluster_basic(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -89,14 +91,16 @@ func TestAccAWSEMRCluster_basic(t *testing.T) { { Config: testAccAWSEmrClusterConfig(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "scale_down_behavior", "TERMINATE_AT_TASK_COMPLETION"), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "step.#", "0"), - resource.TestCheckResourceAttrSet("aws_emr_cluster.tf-test-cluster", "arn"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "scale_down_behavior", "TERMINATE_AT_TASK_COMPLETION"), + resource.TestCheckResourceAttr(resourceName, "step.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckNoResourceAttr(resourceName, "additional_info"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.#", "1"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -106,6 +110,15 @@ func TestAccAWSEMRCluster_basic(t *testing.T) { } func TestAccAWSEMRCluster_additionalInfo(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + expectedJSON := ` +{ + "instanceAwsClientConfiguration": { + "proxyPort": 8099, + "proxyHost": "myproxy.example.com" + } +}` + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -116,13 +129,14 @@ func TestAccAWSEMRCluster_additionalInfo(t *testing.T) { { Config: testAccAWSEmrClusterConfigAdditionalInfo(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "scale_down_behavior", "TERMINATE_AT_TASK_COMPLETION"), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "step.#", "0"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "scale_down_behavior", "TERMINATE_AT_TASK_COMPLETION"), + resource.TestCheckResourceAttr(resourceName, "step.#", "0"), + testAccCheckResourceAttrEquivalentJSON(resourceName, "additional_info", expectedJSON), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps", "additional_info"}, @@ -132,6 +146,8 @@ func TestAccAWSEMRCluster_additionalInfo(t *testing.T) { } func TestAccAWSEMRCluster_disappears(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -142,7 +158,7 @@ func TestAccAWSEMRCluster_disappears(t *testing.T) { { Config: testAccAWSEmrClusterConfig(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), testAccCheckAWSEmrClusterDisappears(&cluster), ), ExpectNonEmptyPlan: true, @@ -152,6 +168,8 @@ func TestAccAWSEMRCluster_disappears(t *testing.T) { } func TestAccAWSEMRCluster_configurationsJson(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -162,13 +180,13 @@ func TestAccAWSEMRCluster_configurationsJson(t *testing.T) { { Config: testAccAWSEmrClusterConfigConfigurationsJson(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestMatchResourceAttr("aws_emr_cluster.tf-test-cluster", "configurations_json", + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestMatchResourceAttr(resourceName, "configurations_json", regexp.MustCompile("{\"JAVA_HOME\":\"/usr/lib/jvm/java-1.8.0\".+")), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -258,17 +276,14 @@ func TestAccAWSEMRCluster_CoreInstanceGroup_AutoscalingPolicy(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster1), resource.TestCheckResourceAttr(resourceName, "core_instance_group.#", "1"), - resource.TestMatchResourceAttr(resourceName, "core_instance_group.0.autoscaling_policy", regexp.MustCompile(`"MaxCapacity": ?2`)), + testAccCheckResourceAttrEquivalentJSON(resourceName, "core_instance_group.0.autoscaling_policy", autoscalingPolicy1), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigCoreInstanceGroupAutoscalingPolicy(rName, autoscalingPolicy2), @@ -276,7 +291,7 @@ func TestAccAWSEMRCluster_CoreInstanceGroup_AutoscalingPolicy(t *testing.T) { testAccCheckAWSEmrClusterExists(resourceName, &cluster2), testAccCheckAWSEmrClusterNotRecreated(&cluster1, &cluster2), resource.TestCheckResourceAttr(resourceName, "core_instance_group.#", "1"), - resource.TestMatchResourceAttr(resourceName, "core_instance_group.0.autoscaling_policy", regexp.MustCompile(`"MaxCapacity": ?3`)), + testAccCheckResourceAttrEquivalentJSON(resourceName, "core_instance_group.0.autoscaling_policy", autoscalingPolicy2), ), }, { @@ -311,13 +326,10 @@ func TestAccAWSEMRCluster_CoreInstanceGroup_BidPrice(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigCoreInstanceGroupBidPrice(rName, "0.51"), @@ -351,13 +363,10 @@ func TestAccAWSEMRCluster_CoreInstanceGroup_InstanceCount(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigCoreInstanceGroupInstanceCount(rName, 1), @@ -400,13 +409,10 @@ func TestAccAWSEMRCluster_CoreInstanceGroup_InstanceType(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigCoreInstanceGroupInstanceType(rName, "m4.xlarge"), @@ -439,13 +445,10 @@ func TestAccAWSEMRCluster_CoreInstanceGroup_Migration_CoreInstanceType(t *testin ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigCoreInstanceGroupInstanceType(rName, "m4.large"), @@ -478,13 +481,10 @@ func TestAccAWSEMRCluster_CoreInstanceGroup_Migration_InstanceGroup(t *testing.T ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigCoreInstanceGroupInstanceType(rName, "m4.large"), @@ -518,13 +518,10 @@ func TestAccAWSEMRCluster_CoreInstanceGroup_Name(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigCoreInstanceGroupName(rName, "name2"), @@ -540,6 +537,8 @@ func TestAccAWSEMRCluster_CoreInstanceGroup_Name(t *testing.T) { } func TestAccAWSEMRCluster_instance_group(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -550,13 +549,12 @@ func TestAccAWSEMRCluster_instance_group(t *testing.T) { { Config: testAccAWSEmrClusterConfigInstanceGroups(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "instance_group.#", "2"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "instance_group.#", "2"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -566,6 +564,8 @@ func TestAccAWSEMRCluster_instance_group(t *testing.T) { } func TestAccAWSEMRCluster_instance_group_names(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -576,13 +576,12 @@ func TestAccAWSEMRCluster_instance_group_names(t *testing.T) { { Config: testAccAWSEmrClusterConfigInstanceGroupsName(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "instance_group.#", "3"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "instance_group.#", "3"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -592,6 +591,8 @@ func TestAccAWSEMRCluster_instance_group_names(t *testing.T) { } func TestAccAWSEMRCluster_instance_group_update(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -602,21 +603,19 @@ func TestAccAWSEMRCluster_instance_group_update(t *testing.T) { { Config: testAccAWSEmrClusterConfigInstanceGroups(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "instance_group.#", "2"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "instance_group.#", "2"), ), }, { Config: testAccAWSEmrClusterConfigInstanceGroupsUpdate(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "instance_group.#", "2"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "instance_group.#", "2"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -626,6 +625,8 @@ func TestAccAWSEMRCluster_instance_group_update(t *testing.T) { } func TestAccAWSEMRCluster_instance_group_EBSVolumeType_st1(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -636,13 +637,12 @@ func TestAccAWSEMRCluster_instance_group_EBSVolumeType_st1(t *testing.T) { { Config: testAccAWSEmrClusterConfigInstanceGroups_st1(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "instance_group.#", "2"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "instance_group.#", "2"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -652,6 +652,8 @@ func TestAccAWSEMRCluster_instance_group_EBSVolumeType_st1(t *testing.T) { } func TestAccAWSEMRCluster_updateAutoScalingPolicy(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -662,17 +664,17 @@ func TestAccAWSEMRCluster_updateAutoScalingPolicy(t *testing.T) { { Config: testAccAWSEmrClusterConfigInstanceGroups_st1(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), ), }, { Config: testAccAWSEmrClusterConfigInstanceGroups_updateAutoScalingPolicy(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -724,6 +726,8 @@ func TestAccAWSEMRCluster_Ec2Attributes_DefaultManagedSecurityGroups(t *testing. } func TestAccAWSEMRCluster_Kerberos_ClusterDedicatedKdc(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() password := fmt.Sprintf("NeverKeepPasswordsInPlainText%d!", r) @@ -736,14 +740,14 @@ func TestAccAWSEMRCluster_Kerberos_ClusterDedicatedKdc(t *testing.T) { { Config: testAccAWSEmrClusterConfig_Kerberos_ClusterDedicatedKdc(r, password), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "kerberos_attributes.#", "1"), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "kerberos_attributes.0.kdc_admin_password", password), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "kerberos_attributes.0.realm", "EC2.INTERNAL"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "kerberos_attributes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "kerberos_attributes.0.kdc_admin_password", password), + resource.TestCheckResourceAttr(resourceName, "kerberos_attributes.0.realm", "EC2.INTERNAL"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps", "kerberos_attributes.0.kdc_admin_password"}, @@ -771,13 +775,10 @@ func TestAccAWSEMRCluster_MasterInstanceGroup_BidPrice(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigMasterInstanceGroupBidPrice(rName, "0.51"), @@ -811,13 +812,10 @@ func TestAccAWSEMRCluster_MasterInstanceGroup_InstanceCount(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigMasterInstanceGroupInstanceCount(rName, 1), @@ -851,13 +849,10 @@ func TestAccAWSEMRCluster_MasterInstanceGroup_InstanceType(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigMasterInstanceGroupInstanceType(rName, "m4.xlarge"), @@ -890,13 +885,10 @@ func TestAccAWSEMRCluster_MasterInstanceGroup_Migration_InstanceGroup(t *testing ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigMasterInstanceGroupInstanceType(rName, "m4.large"), @@ -929,13 +921,10 @@ func TestAccAWSEMRCluster_MasterInstanceGroup_Migration_MasterInstanceType(t *te ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigMasterInstanceGroupInstanceType(rName, "m4.large"), @@ -969,13 +958,10 @@ func TestAccAWSEMRCluster_MasterInstanceGroup_Name(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigMasterInstanceGroupName(rName, "name2"), @@ -991,6 +977,8 @@ func TestAccAWSEMRCluster_MasterInstanceGroup_Name(t *testing.T) { } func TestAccAWSEMRCluster_security_config(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -1000,10 +988,10 @@ func TestAccAWSEMRCluster_security_config(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSEmrClusterConfig_SecurityConfiguration(r), - Check: testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), + Check: testAccCheckAWSEmrClusterExists(resourceName, &cluster), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -1036,7 +1024,7 @@ func TestAccAWSEMRCluster_Step_Basic(t *testing.T) { ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -1126,7 +1114,7 @@ func TestAccAWSEMRCluster_Step_Multiple(t *testing.T) { ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -1167,6 +1155,7 @@ func TestAccAWSEMRCluster_bootstrap_ordering(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), testAccCheck_bootstrap_order(&cluster, argsInts, argsStrings), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.#", "2"), ), }, { @@ -1180,6 +1169,8 @@ func TestAccAWSEMRCluster_bootstrap_ordering(t *testing.T) { } func TestAccAWSEMRCluster_terminationProtected(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -1190,40 +1181,33 @@ func TestAccAWSEMRCluster_terminationProtected(t *testing.T) { { Config: testAccAWSEmrClusterConfigTerminationPolicy(r, "false"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "termination_protection", "false"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "termination_protection", "false"), ), }, { Config: testAccAWSEmrClusterConfigTerminationPolicy(r, "true"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "termination_protection", "true"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "termination_protection", "true"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "kerberos_attributes.0.kdc_admin_password", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { //Need to turn off termination_protection to allow the job to be deleted Config: testAccAWSEmrClusterConfigTerminationPolicy(r, "false"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "termination_protection", "false"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "termination_protection", "false"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -1233,6 +1217,8 @@ func TestAccAWSEMRCluster_terminationProtected(t *testing.T) { } func TestAccAWSEMRCluster_keepJob(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -1243,13 +1229,12 @@ func TestAccAWSEMRCluster_keepJob(t *testing.T) { { Config: testAccAWSEmrClusterConfig_keepJob(r, "false"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "keep_job_flow_alive_when_no_steps", "false"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "keep_job_flow_alive_when_no_steps", "false"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -1259,6 +1244,8 @@ func TestAccAWSEMRCluster_keepJob(t *testing.T) { } func TestAccAWSEMRCluster_visibleToAllUsers(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -1269,31 +1256,25 @@ func TestAccAWSEMRCluster_visibleToAllUsers(t *testing.T) { { Config: testAccAWSEmrClusterConfig(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "visible_to_all_users", "true"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "visible_to_all_users", "true"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "configurations", - "kerberos_attributes.0.kdc_admin_password", - "keep_job_flow_alive_when_no_steps", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { Config: testAccAWSEmrClusterConfigVisibleToAllUsersUpdated(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "visible_to_all_users", "false"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "visible_to_all_users", "false"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -1303,6 +1284,8 @@ func TestAccAWSEMRCluster_visibleToAllUsers(t *testing.T) { } func TestAccAWSEMRCluster_s3Logging(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() bucketName := fmt.Sprintf("s3n://tf-acc-test-%d/", r) @@ -1315,12 +1298,12 @@ func TestAccAWSEMRCluster_s3Logging(t *testing.T) { { Config: testAccAWSEmrClusterConfigS3Logging(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "log_uri", bucketName), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "log_uri", bucketName), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -1330,6 +1313,8 @@ func TestAccAWSEMRCluster_s3Logging(t *testing.T) { } func TestAccAWSEMRCluster_tags(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -1340,32 +1325,25 @@ func TestAccAWSEMRCluster_tags(t *testing.T) { { Config: testAccAWSEmrClusterConfig(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "tags.%", "4"), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "tags.role", "rolename"), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "tags.dns_zone", "env_zone"), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "tags.env", "env"), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "tags.name", "name-env")), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "tags.%", "4"), + resource.TestCheckResourceAttr(resourceName, "tags.role", "rolename"), + resource.TestCheckResourceAttr(resourceName, "tags.dns_zone", "env_zone"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "env"), + resource.TestCheckResourceAttr(resourceName, "tags.name", "name-env")), }, { Config: testAccAWSEmrClusterConfigUpdatedTags(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "tags.%", "3"), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "tags.dns_zone", "new_zone"), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "tags.Env", "production"), - resource.TestCheckResourceAttr( - "aws_emr_cluster.tf-test-cluster", "tags.name", "name-env"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), + resource.TestCheckResourceAttr(resourceName, "tags.dns_zone", "new_zone"), + resource.TestCheckResourceAttr(resourceName, "tags.Env", "production"), + resource.TestCheckResourceAttr(resourceName, "tags.name", "name-env"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -1375,6 +1353,8 @@ func TestAccAWSEMRCluster_tags(t *testing.T) { } func TestAccAWSEMRCluster_root_volume_size(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -1385,19 +1365,19 @@ func TestAccAWSEMRCluster_root_volume_size(t *testing.T) { { Config: testAccAWSEmrClusterConfig(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "ebs_root_volume_size", "21"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "ebs_root_volume_size", "21"), ), }, { Config: testAccAWSEmrClusterConfigUpdatedRootVolumeSize(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttr("aws_emr_cluster.tf-test-cluster", "ebs_root_volume_size", "48"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "ebs_root_volume_size", "48"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, @@ -1440,6 +1420,8 @@ func TestAccAWSEMRCluster_step_concurrency_level(t *testing.T) { } func TestAccAWSEMRCluster_custom_ami_id(t *testing.T) { + resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster r := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ @@ -1450,12 +1432,12 @@ func TestAccAWSEMRCluster_custom_ami_id(t *testing.T) { { Config: testAccAWSEmrClusterConfigCustomAmiID(r), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEmrClusterExists("aws_emr_cluster.tf-test-cluster", &cluster), - resource.TestCheckResourceAttrSet("aws_emr_cluster.tf-test-cluster", "custom_ami_id"), + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttrSet(resourceName, "custom_ami_id"), ), }, { - ResourceName: "aws_emr_cluster.tf-test-cluster", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, From 1c415d159cc80def54be31dcb9c21de621b09494 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 3 Mar 2020 22:47:28 -0800 Subject: [PATCH 084/684] Fixes linting error --- aws/provider_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aws/provider_test.go b/aws/provider_test.go index df29fb15538..e6607b794e0 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -281,6 +281,9 @@ func testAccCheckListHasSomeElementAttrPair(nameFirst string, resourceAttr strin func testAccCheckResourceAttrEquivalentJSON(resourceName, attributeName, expectedJSON string) resource.TestCheckFunc { return func(s *terraform.State) error { is, err := primaryInstanceState(s, resourceName) + if err != nil { + return err + } v, ok := is.Attributes[attributeName] if !ok { From 09d65da271bb2d6fa77c46fd3871b2781a1d0df4 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 4 Mar 2020 13:06:20 -0800 Subject: [PATCH 085/684] Refactors IAM roles and policies --- aws/resource_aws_emr_cluster_test.go | 5076 ++++++-------------------- 1 file changed, 1193 insertions(+), 3883 deletions(-) diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index eb518f929f5..69d900daf04 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -1723,89 +1723,10 @@ func testAccEmrDeleteManagedSecurityGroup(conn *ec2.EC2, securityGroup *ec2.Secu return err } -func testAccAWSEmrClusterConfigBaseVpc(mapPublicIpOnLaunch bool) string { - return fmt.Sprintf(` -data "aws_availability_zones" "available" { - # Many instance types are not available in this availability zone - blacklisted_zone_ids = ["usw2-az4"] - state = "available" -} - -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" - enable_dns_hostnames = true - - tags = { - Name = "tf-acc-test-emr-cluster" - } -} - -resource "aws_internet_gateway" "test" { - vpc_id = "${aws_vpc.test.id}" - - tags = { - Name = "tf-acc-test-emr-cluster" - } -} - -resource "aws_security_group" "test" { - vpc_id = "${aws_vpc.test.id}" - - ingress { - from_port = 0 - protocol = "-1" - self = true - to_port = 0 - } - - egress { - cidr_blocks = ["0.0.0.0/0"] - from_port = 0 - protocol = "-1" - to_port = 0 - } - - tags = { - Name = "tf-acc-test-emr-cluster" - } - - # EMR will modify ingress rules - lifecycle { - ignore_changes = ["ingress"] - } -} - -resource "aws_subnet" "test" { - availability_zone = "${data.aws_availability_zones.available.names[0]}" - cidr_block = "10.0.0.0/24" - map_public_ip_on_launch = %[1]t - vpc_id = "${aws_vpc.test.id}" - - tags = { - Name = "tf-acc-test-emr-cluster" - } -} - -resource "aws_route_table" "test" { - vpc_id = "${aws_vpc.test.id}" - - route { - cidr_block = "0.0.0.0/0" - gateway_id = "${aws_internet_gateway.test.id}" - } -} - -resource "aws_route_table_association" "test" { - route_table_id = "${aws_route_table.test.id}" - subnet_id = "${aws_subnet.test.id}" -} -`, mapPublicIpOnLaunch) -} - func testAccAWSEmrClusterConfig_bootstrap(r string) string { - return testAccAWSEmrClusterConfigBaseVpc(false) + fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_emr_cluster" "test" { - name = "%s" + name = "%[1]s" release_label = "emr-5.0.0" applications = ["Hadoop", "Hive"] log_uri = "s3n://terraform/testlog/" @@ -1846,33 +1767,110 @@ resource "aws_emr_cluster" "test" { } } -resource "aws_iam_instance_profile" "emr_profile" { - name = "%s_profile" - role = "${aws_iam_role.iam_emr_profile_role.name}" +resource "aws_s3_bucket" "tester" { + bucket = "%[1]s" + acl = "public-read" } -resource "aws_iam_role" "iam_emr_default_role" { - name = "%s_default_role" +resource "aws_s3_bucket_object" "testobject" { + bucket = "${aws_s3_bucket.tester.bucket}" + key = "testscript.sh" + content = < Date: Wed, 4 Mar 2020 13:08:06 -0800 Subject: [PATCH 086/684] Removes unneeded `bootstrap_action` arguments from tests. Adds check to `TestAccAWSEMRCluster_security_config` to test `security_configuration` --- aws/resource_aws_emr_cluster_test.go | 103 ++------------------------- 1 file changed, 5 insertions(+), 98 deletions(-) diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index 69d900daf04..cfa54bb98ef 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -96,7 +96,7 @@ func TestAccAWSEMRCluster_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "step.#", "0"), resource.TestCheckResourceAttrSet(resourceName, "arn"), resource.TestCheckNoResourceAttr(resourceName, "additional_info"), - resource.TestCheckResourceAttr(resourceName, "bootstrap_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.#", "0"), ), }, { @@ -988,7 +988,10 @@ func TestAccAWSEMRCluster_security_config(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSEmrClusterConfig_SecurityConfiguration(r), - Check: testAccCheckAWSEmrClusterExists(resourceName, &cluster), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttrPair(resourceName, "security_configuration", "aws_emr_security_configuration.foo", "name"), + ), }, { ResourceName: resourceName, @@ -1816,12 +1819,6 @@ resource "aws_emr_cluster" "tf-test-cluster" { scale_down_behavior = "TERMINATE_AT_TASK_COMPLETION" - bootstrap_action { - path = "s3://elasticmapreduce/bootstrap-actions/run-if" - name = "runif" - args = ["instance.isMaster=true", "echo running on master node"] - } - configurations = "test-fixtures/emr_configurations.json" depends_on = ["aws_route_table_association.test"] @@ -1973,12 +1970,6 @@ EOF scale_down_behavior = "TERMINATE_AT_TASK_COMPLETION" - bootstrap_action { - path = "s3://elasticmapreduce/bootstrap-actions/run-if" - name = "runif" - args = ["instance.isMaster=true", "echo running on master node"] - } - configurations = "test-fixtures/emr_configurations.json" depends_on = ["aws_route_table_association.test"] @@ -2014,12 +2005,6 @@ resource "aws_emr_cluster" "tf-test-cluster" { keep_job_flow_alive_when_no_steps = true termination_protection = false - bootstrap_action { - path = "s3://elasticmapreduce/bootstrap-actions/run-if" - name = "runif" - args = ["instance.isMaster=true", "echo running on master node"] - } - configurations_json = < Date: Thu, 5 Mar 2020 16:11:48 -0800 Subject: [PATCH 087/684] Replaces `RandInt()` with `RandomWithPrefix()` --- aws/resource_aws_emr_cluster_test.go | 620 +++++++++++++-------------- 1 file changed, 309 insertions(+), 311 deletions(-) diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index cfa54bb98ef..9289a00d3ae 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -79,17 +79,17 @@ func testSweepEmrClusters(region string) error { } func TestAccAWSEMRCluster_basic(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfig(r), + Config: testAccAWSEmrClusterConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "scale_down_behavior", "TERMINATE_AT_TASK_COMPLETION"), @@ -110,7 +110,7 @@ func TestAccAWSEMRCluster_basic(t *testing.T) { } func TestAccAWSEMRCluster_additionalInfo(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" + var cluster emr.Cluster expectedJSON := ` { "instanceAwsClientConfiguration": { @@ -119,15 +119,15 @@ func TestAccAWSEMRCluster_additionalInfo(t *testing.T) { } }` - var cluster emr.Cluster - r := acctest.RandInt() + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfigAdditionalInfo(r), + Config: testAccAWSEmrClusterConfigAdditionalInfo(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "scale_down_behavior", "TERMINATE_AT_TASK_COMPLETION"), @@ -146,17 +146,17 @@ func TestAccAWSEMRCluster_additionalInfo(t *testing.T) { } func TestAccAWSEMRCluster_disappears(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfig(r), + Config: testAccAWSEmrClusterConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), testAccCheckAWSEmrClusterDisappears(&cluster), @@ -168,17 +168,17 @@ func TestAccAWSEMRCluster_disappears(t *testing.T) { } func TestAccAWSEMRCluster_configurationsJson(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfigConfigurationsJson(r), + Config: testAccAWSEmrClusterConfigConfigurationsJson(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestMatchResourceAttr(resourceName, "configurations_json", @@ -537,17 +537,17 @@ func TestAccAWSEMRCluster_CoreInstanceGroup_Name(t *testing.T) { } func TestAccAWSEMRCluster_instance_group(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfigInstanceGroups(r), + Config: testAccAWSEmrClusterConfigInstanceGroups(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "instance_group.#", "2"), @@ -564,17 +564,17 @@ func TestAccAWSEMRCluster_instance_group(t *testing.T) { } func TestAccAWSEMRCluster_instance_group_names(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfigInstanceGroupsName(r), + Config: testAccAWSEmrClusterConfigInstanceGroupsName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "instance_group.#", "3"), @@ -591,24 +591,24 @@ func TestAccAWSEMRCluster_instance_group_names(t *testing.T) { } func TestAccAWSEMRCluster_instance_group_update(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfigInstanceGroups(r), + Config: testAccAWSEmrClusterConfigInstanceGroups(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "instance_group.#", "2"), ), }, { - Config: testAccAWSEmrClusterConfigInstanceGroupsUpdate(r), + Config: testAccAWSEmrClusterConfigInstanceGroupsUpdate(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "instance_group.#", "2"), @@ -625,17 +625,17 @@ func TestAccAWSEMRCluster_instance_group_update(t *testing.T) { } func TestAccAWSEMRCluster_instance_group_EBSVolumeType_st1(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfigInstanceGroups_st1(r), + Config: testAccAWSEmrClusterConfigInstanceGroups_st1(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "instance_group.#", "2"), @@ -652,23 +652,23 @@ func TestAccAWSEMRCluster_instance_group_EBSVolumeType_st1(t *testing.T) { } func TestAccAWSEMRCluster_updateAutoScalingPolicy(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfigInstanceGroups_st1(r), + Config: testAccAWSEmrClusterConfigInstanceGroups_st1(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), ), }, { - Config: testAccAWSEmrClusterConfigInstanceGroups_updateAutoScalingPolicy(r), + Config: testAccAWSEmrClusterConfigInstanceGroups_updateAutoScalingPolicy(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), ), @@ -726,19 +726,18 @@ func TestAccAWSEMRCluster_Ec2Attributes_DefaultManagedSecurityGroups(t *testing. } func TestAccAWSEMRCluster_Kerberos_ClusterDedicatedKdc(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() - password := fmt.Sprintf("NeverKeepPasswordsInPlainText%d!", r) + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") + password := fmt.Sprintf("NeverKeepPasswordsInPlainText%s!", rName) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfig_Kerberos_ClusterDedicatedKdc(r, password), + Config: testAccAWSEmrClusterConfig_Kerberos_ClusterDedicatedKdc(rName, password), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "kerberos_attributes.#", "1"), @@ -977,17 +976,17 @@ func TestAccAWSEMRCluster_MasterInstanceGroup_Name(t *testing.T) { } func TestAccAWSEMRCluster_security_config(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfig_SecurityConfiguration(r), + Config: testAccAWSEmrClusterConfig_SecurityConfiguration(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttrPair(resourceName, "security_configuration", "aws_emr_security_configuration.foo", "name"), @@ -1005,16 +1004,16 @@ func TestAccAWSEMRCluster_security_config(t *testing.T) { func TestAccAWSEMRCluster_Step_Basic(t *testing.T) { var cluster emr.Cluster - rInt := acctest.RandInt() - resourceName := "aws_emr_cluster.tf-test-cluster" + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfig_Step_Single(rInt), + Config: testAccAWSEmrClusterConfig_Step_Single(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "step.#", "1"), @@ -1038,16 +1037,16 @@ func TestAccAWSEMRCluster_Step_Basic(t *testing.T) { func TestAccAWSEMRCluster_Step_ConfigMode(t *testing.T) { var cluster1, cluster2, cluster3 emr.Cluster - rInt := acctest.RandInt() - resourceName := "aws_emr_cluster.tf-test-cluster" + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfig_Step_Single(rInt), + Config: testAccAWSEmrClusterConfig_Step_Single(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster1), resource.TestCheckResourceAttr(resourceName, "step.#", "1"), @@ -1060,7 +1059,7 @@ func TestAccAWSEMRCluster_Step_ConfigMode(t *testing.T) { ImportStateVerifyIgnore: []string{"cluster_state", "configurations", "keep_job_flow_alive_when_no_steps"}, }, { - Config: testAccAWSEmrClusterConfig_Step_NoBlocks(rInt), + Config: testAccAWSEmrClusterConfig_Step_NoBlocks(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster2), resource.TestCheckResourceAttr(resourceName, "step.#", "1"), @@ -1073,7 +1072,7 @@ func TestAccAWSEMRCluster_Step_ConfigMode(t *testing.T) { ImportStateVerifyIgnore: []string{"cluster_state", "configurations", "keep_job_flow_alive_when_no_steps"}, }, { - Config: testAccAWSEmrClusterConfig_Step_Zeroed(rInt), + Config: testAccAWSEmrClusterConfig_Step_Zeroed(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster3), resource.TestCheckResourceAttr(resourceName, "step.#", "0"), @@ -1091,16 +1090,16 @@ func TestAccAWSEMRCluster_Step_ConfigMode(t *testing.T) { func TestAccAWSEMRCluster_Step_Multiple(t *testing.T) { var cluster emr.Cluster - rInt := acctest.RandInt() - resourceName := "aws_emr_cluster.tf-test-cluster" + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfig_Step_Multiple(rInt), + Config: testAccAWSEmrClusterConfig_Step_Multiple(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "step.#", "2"), @@ -1172,24 +1171,24 @@ func TestAccAWSEMRCluster_bootstrap_ordering(t *testing.T) { } func TestAccAWSEMRCluster_terminationProtected(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfigTerminationPolicy(r, "false"), + Config: testAccAWSEmrClusterConfigTerminationPolicy(rName, "false"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "termination_protection", "false"), ), }, { - Config: testAccAWSEmrClusterConfigTerminationPolicy(r, "true"), + Config: testAccAWSEmrClusterConfigTerminationPolicy(rName, "true"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "termination_protection", "true"), @@ -1203,7 +1202,7 @@ func TestAccAWSEMRCluster_terminationProtected(t *testing.T) { }, { //Need to turn off termination_protection to allow the job to be deleted - Config: testAccAWSEmrClusterConfigTerminationPolicy(r, "false"), + Config: testAccAWSEmrClusterConfigTerminationPolicy(rName, "false"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "termination_protection", "false"), @@ -1220,17 +1219,17 @@ func TestAccAWSEMRCluster_terminationProtected(t *testing.T) { } func TestAccAWSEMRCluster_keepJob(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfig_keepJob(r, "false"), + Config: testAccAWSEmrClusterConfig_keepJob(rName, "false"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "keep_job_flow_alive_when_no_steps", "false"), @@ -1247,17 +1246,17 @@ func TestAccAWSEMRCluster_keepJob(t *testing.T) { } func TestAccAWSEMRCluster_visibleToAllUsers(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfig(r), + Config: testAccAWSEmrClusterConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "visible_to_all_users", "true"), @@ -1270,7 +1269,7 @@ func TestAccAWSEMRCluster_visibleToAllUsers(t *testing.T) { ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, { - Config: testAccAWSEmrClusterConfigVisibleToAllUsersUpdated(r), + Config: testAccAWSEmrClusterConfigVisibleToAllUsersUpdated(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "visible_to_all_users", "false"), @@ -1287,19 +1286,18 @@ func TestAccAWSEMRCluster_visibleToAllUsers(t *testing.T) { } func TestAccAWSEMRCluster_s3Logging(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() - bucketName := fmt.Sprintf("s3n://tf-acc-test-%d/", r) + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") + bucketName := fmt.Sprintf("s3n://%s/", rName) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfigS3Logging(r), + Config: testAccAWSEmrClusterConfigS3Logging(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "log_uri", bucketName), @@ -1316,17 +1314,17 @@ func TestAccAWSEMRCluster_s3Logging(t *testing.T) { } func TestAccAWSEMRCluster_tags(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfig(r), + Config: testAccAWSEmrClusterConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "tags.%", "4"), @@ -1336,7 +1334,7 @@ func TestAccAWSEMRCluster_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.name", "name-env")), }, { - Config: testAccAWSEmrClusterConfigUpdatedTags(r), + Config: testAccAWSEmrClusterConfigUpdatedTags(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), @@ -1356,24 +1354,24 @@ func TestAccAWSEMRCluster_tags(t *testing.T) { } func TestAccAWSEMRCluster_root_volume_size(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfig(r), + Config: testAccAWSEmrClusterConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "ebs_root_volume_size", "21"), ), }, { - Config: testAccAWSEmrClusterConfigUpdatedRootVolumeSize(r), + Config: testAccAWSEmrClusterConfigUpdatedRootVolumeSize(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "ebs_root_volume_size", "48"), @@ -1423,17 +1421,17 @@ func TestAccAWSEMRCluster_step_concurrency_level(t *testing.T) { } func TestAccAWSEMRCluster_custom_ami_id(t *testing.T) { - resourceName := "aws_emr_cluster.tf-test-cluster" - var cluster emr.Cluster - r := acctest.RandInt() + + resourceName := "aws_emr_cluster.tf-test-cluster" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSEmrDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEmrClusterConfigCustomAmiID(r), + Config: testAccAWSEmrClusterConfigCustomAmiID(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), resource.TestCheckResourceAttrSet(resourceName, "custom_ami_id"), @@ -1789,10 +1787,10 @@ EOF testAccAWSEmrClusterConfigIAMInstanceProfileBase(r) } -func testAccAWSEmrClusterConfig(r int) string { +func testAccAWSEmrClusterConfig(r string) string { return fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { - name = "emr-test-%[1]d" + name = "%[1]s" release_label = "emr-4.6.0" applications = ["Spark"] @@ -1828,113 +1826,15 @@ resource "aws_emr_cluster" "tf-test-cluster" { ebs_root_volume_size = 21 } `, r) + testAccAWSEmrClusterConfigBaseVpc(false) + - testAccAWSEmrClusterConfigIAMServiceRoleBase(fmt.Sprintf("iam_emr_default_%[1]d", r)) + - testAccAWSEmrClusterConfigIAMInstanceProfileBase(fmt.Sprintf("iam_emr_profile_%[1]d", r)) + - testAccAWSEmrClusterConfigIAMAutoscalingRole(fmt.Sprintf("EMR_AutoScaling_DefaultRole_%[1]d", r)) -} - -func testAccAWSEmrClusterConfigIAMAutoscalingRole(r string) string { - return fmt.Sprintf(` -resource "aws_iam_role" "emr-autoscaling-role" { - name = "%[1]s" - assume_role_policy = "${data.aws_iam_policy_document.emr-autoscaling-role-policy.json}" -} - -data "aws_iam_policy_document" "emr-autoscaling-role-policy" { - statement { - effect = "Allow" - actions = ["sts:AssumeRole"] - - principals { - type = "Service" - identifiers = ["elasticmapreduce.amazonaws.com", "application-autoscaling.amazonaws.com"] - } - } -} - -resource "aws_iam_role_policy_attachment" "emr-autoscaling-role" { - role = "${aws_iam_role.emr-autoscaling-role.name}" - policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceforAutoScalingRole" -} -`, r) -} - -func testAccAWSEmrClusterConfigIAMInstanceProfileBase(r string) string { - return fmt.Sprintf(` -resource "aws_iam_instance_profile" "emr_profile" { - name = "%[1]s_profile" - role = "${aws_iam_role.iam_emr_profile_role.name}" -} - -resource "aws_iam_role" "iam_emr_profile_role" { - name = "%[1]s_profile_role" - - assume_role_policy = < Date: Thu, 5 Mar 2020 17:13:04 -0800 Subject: [PATCH 088/684] Adds functions to compose acceptance test configurations --- aws/provider_test.go | 11 ++ aws/resource_aws_emr_cluster_test.go | 269 +++++++++++++++------------ 2 files changed, 164 insertions(+), 116 deletions(-) diff --git a/aws/provider_test.go b/aws/provider_test.go index e6607b794e0..4e6245e7a16 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -1288,3 +1288,14 @@ provider "aws" { } `, os.Getenv("TF_ACC_ASSUME_ROLE_ARN"), policy) } + +// composeConfig can be called to concatenate multiple strings to build test configurations +func composeConfig(config ...string) string { + var str strings.Builder + + for _, conf := range config { + str.WriteString(conf) + } + + return str.String() +} diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index 9289a00d3ae..c62e53fd31f 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -1724,8 +1724,12 @@ func testAccEmrDeleteManagedSecurityGroup(conn *ec2.EC2, securityGroup *ec2.Secu return err } +func testAccAWSEmrComposeConfig(mapPublicIPOnLaunch bool, config ...string) string { + return composeConfig(append(config, testAccAWSEmrClusterConfigBaseVpc(mapPublicIPOnLaunch))...) +} + func testAccAWSEmrClusterConfig_bootstrap(r string) string { - return fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` resource "aws_emr_cluster" "test" { name = "%[1]s" release_label = "emr-5.0.0" @@ -1782,13 +1786,14 @@ echo $@ EOF acl = "public-read" } -`, r) + testAccAWSEmrClusterConfigBaseVpc(false) + - testAccAWSEmrClusterConfigIAMServiceRoleBase(r) + - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r) +`, r), + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + ) } func testAccAWSEmrClusterConfig(r string) string { - return fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -1825,14 +1830,15 @@ resource "aws_emr_cluster" "tf-test-cluster" { autoscaling_role = "${aws_iam_role.emr-autoscaling-role.arn}" ebs_root_volume_size = 21 } -`, r) + testAccAWSEmrClusterConfigBaseVpc(false) + - testAccAWSEmrClusterConfigIAMServiceRoleBase(r) + - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r) + - testAccAWSEmrClusterConfigIAMAutoscalingRole(r) +`, r), + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + ) } func testAccAWSEmrClusterConfigAdditionalInfo(r string) string { - return fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -1878,14 +1884,15 @@ EOF autoscaling_role = "${aws_iam_role.emr-autoscaling-role.arn}" ebs_root_volume_size = 21 } -`, r) + testAccAWSEmrClusterConfigBaseVpc(false) + - testAccAWSEmrClusterConfigIAMServiceRoleBase(r) + - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r) + - testAccAWSEmrClusterConfigIAMAutoscalingRole(r) +`, r), + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + ) } func testAccAWSEmrClusterConfigConfigurationsJson(r string) string { - return fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -1939,13 +1946,14 @@ EOF service_role = "${aws_iam_role.iam_emr_default_role.arn}" ebs_root_volume_size = 21 } -`, r) + testAccAWSEmrClusterConfigBaseVpc(false) + - testAccAWSEmrClusterConfigIAMServiceRoleBase(r) + - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r) +`, r), + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + ) } func testAccAWSEmrClusterConfig_Kerberos_ClusterDedicatedKdc(r string, password string) string { - return fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` resource "aws_emr_security_configuration" "foo" { configuration = < Date: Wed, 25 Mar 2020 00:46:13 +0200 Subject: [PATCH 089/684] Update resource_aws_route53_health_check_test.go --- aws/resource_aws_route53_health_check_test.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/aws/resource_aws_route53_health_check_test.go b/aws/resource_aws_route53_health_check_test.go index 268143f7549..539b3ad02fd 100644 --- a/aws/resource_aws_route53_health_check_test.go +++ b/aws/resource_aws_route53_health_check_test.go @@ -36,11 +36,7 @@ func TestAccAWSRoute53HealthCheck_basic(t *testing.T) { }, { Config: testAccRoute53HealthCheckConfigUpdate, - Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName, &check), - resource.TestCheckResourceAttr(resourceName, "failure_threshold", "5"), - resource.TestCheckResourceAttr(resourceName, "invert_healthcheck", "false"), - ), + PlanOnly: true, }, }, }) From b76adc1b8a3d0b7c82543f22bc0df31d3bba7855 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 24 Mar 2020 15:52:28 -0700 Subject: [PATCH 090/684] Adds fix to filter out Local Zones from list of Availability Zones --- aws/resource_aws_emr_cluster_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index c62e53fd31f..f26d0dc967f 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -3451,6 +3451,10 @@ data "aws_availability_zones" "available" { # Many instance types are not available in this availability zone blacklisted_zone_ids = ["usw2-az4"] state = "available" + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { From ef4a44db4ca1be348be1928e5c84f420d7be7c49 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Wed, 25 Mar 2020 01:08:56 +0200 Subject: [PATCH 091/684] plan only test for change --- aws/resource_aws_route53_health_check_test.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_route53_health_check_test.go b/aws/resource_aws_route53_health_check_test.go index 539b3ad02fd..3ad8008bdc6 100644 --- a/aws/resource_aws_route53_health_check_test.go +++ b/aws/resource_aws_route53_health_check_test.go @@ -211,11 +211,8 @@ func TestAccAWSRoute53HealthCheck_Ipv6Config(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccRoute53HealthCheckIpv6ExpandedConfig, - Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53HealthCheckExists(resourceName, &check), - resource.TestCheckResourceAttr(resourceName, "ip_address", "1234:5678:9abc:6811:0:0:0:4"), - ), + Config: testAccRoute53HealthCheckIpv6ExpandedConfig, + PlanOnly: true, }, }, }) From c8e14dbdddff4aa4977c2e56fdabc012166e85bb Mon Sep 17 00:00:00 2001 From: ShinYoungMin Date: Wed, 25 Mar 2020 21:42:17 +0900 Subject: [PATCH 092/684] resource/aws_cloudwatch_log_metric_filter: Support resource import (#11992) Output from acceptance testing: ``` --- PASS: TestAccAWSCloudWatchLogMetricFilter_basic (22.93s) ``` --- ...source_aws_cloudwatch_log_metric_filter.go | 23 +++++++- ...e_aws_cloudwatch_log_metric_filter_test.go | 52 +++++++++++++------ ...cloudwatch_log_metric_filter.html.markdown | 8 +++ 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/aws/resource_aws_cloudwatch_log_metric_filter.go b/aws/resource_aws_cloudwatch_log_metric_filter.go index 3db85610fda..e8cd1b08f33 100644 --- a/aws/resource_aws_cloudwatch_log_metric_filter.go +++ b/aws/resource_aws_cloudwatch_log_metric_filter.go @@ -20,6 +20,9 @@ func resourceAwsCloudWatchLogMetricFilter() *schema.Resource { Read: resourceAwsCloudWatchLogMetricFilterRead, Update: resourceAwsCloudWatchLogMetricFilterUpdate, Delete: resourceAwsCloudWatchLogMetricFilterDelete, + Importer: &schema.ResourceImporter{ + State: resourceAwsCloudWatchLogMetricFilterImport, + }, Schema: map[string]*schema.Schema{ "name": { @@ -85,10 +88,13 @@ func resourceAwsCloudWatchLogMetricFilter() *schema.Resource { func resourceAwsCloudWatchLogMetricFilterUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).cloudwatchlogsconn + name := d.Get("name").(string) + logGroupName := d.Get("log_group_name").(string) + input := cloudwatchlogs.PutMetricFilterInput{ - FilterName: aws.String(d.Get("name").(string)), + FilterName: aws.String(name), FilterPattern: aws.String(strings.TrimSpace(d.Get("pattern").(string))), - LogGroupName: aws.String(d.Get("log_group_name").(string)), + LogGroupName: aws.String(logGroupName), } transformations := d.Get("metric_transformation").([]interface{}) @@ -201,3 +207,16 @@ func resourceAwsCloudWatchLogMetricFilterDelete(d *schema.ResourceData, meta int return nil } + +func resourceAwsCloudWatchLogMetricFilterImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + idParts := strings.Split(d.Id(), ":") + if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { + return nil, fmt.Errorf("Unexpected format of ID (%q), expected :", d.Id()) + } + logGroupName := idParts[0] + name := idParts[1] + d.Set("log_group_name", logGroupName) + d.Set("name", name) + d.SetId(name) + return []*schema.ResourceData{d}, nil +} diff --git a/aws/resource_aws_cloudwatch_log_metric_filter_test.go b/aws/resource_aws_cloudwatch_log_metric_filter_test.go index c7073a8efd4..79e54a44703 100644 --- a/aws/resource_aws_cloudwatch_log_metric_filter_test.go +++ b/aws/resource_aws_cloudwatch_log_metric_filter_test.go @@ -14,6 +14,7 @@ import ( func TestAccAWSCloudWatchLogMetricFilter_basic(t *testing.T) { var mf cloudwatchlogs.MetricFilter rInt := acctest.RandInt() + resourceName := "aws_cloudwatch_log_metric_filter.foobar" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -23,15 +24,15 @@ func TestAccAWSCloudWatchLogMetricFilter_basic(t *testing.T) { { Config: testAccAWSCloudWatchLogMetricFilterConfig(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckCloudWatchLogMetricFilterExists("aws_cloudwatch_log_metric_filter.foobar", &mf), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "name", fmt.Sprintf("MyAppAccessCount-%d", rInt)), + testAccCheckCloudWatchLogMetricFilterExists(resourceName, &mf), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("MyAppAccessCount-%d", rInt)), testAccCheckCloudWatchLogMetricFilterName(&mf, fmt.Sprintf("MyAppAccessCount-%d", rInt)), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "pattern", ""), + resource.TestCheckResourceAttr(resourceName, "pattern", ""), testAccCheckCloudWatchLogMetricFilterPattern(&mf, ""), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "log_group_name", fmt.Sprintf("MyApp/access-%d.log", rInt)), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.name", "EventCount"), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.namespace", "YourNamespace"), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.value", "1"), + resource.TestCheckResourceAttr(resourceName, "log_group_name", fmt.Sprintf("MyApp/access-%d.log", rInt)), + resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.name", "EventCount"), + resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.namespace", "YourNamespace"), + resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.value", "1"), testAccCheckCloudWatchLogMetricFilterTransformation(&mf, &cloudwatchlogs.MetricTransformation{ MetricName: aws.String("EventCount"), MetricNamespace: aws.String("YourNamespace"), @@ -39,19 +40,25 @@ func TestAccAWSCloudWatchLogMetricFilter_basic(t *testing.T) { }), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAWSCloudwatchLogMetricFilterImportStateIdFunc(resourceName), + ImportStateVerify: true, + }, { Config: testAccAWSCloudWatchLogMetricFilterConfigModified(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckCloudWatchLogMetricFilterExists("aws_cloudwatch_log_metric_filter.foobar", &mf), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "name", fmt.Sprintf("MyAppAccessCount-%d", rInt)), + testAccCheckCloudWatchLogMetricFilterExists(resourceName, &mf), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("MyAppAccessCount-%d", rInt)), testAccCheckCloudWatchLogMetricFilterName(&mf, fmt.Sprintf("MyAppAccessCount-%d", rInt)), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "pattern", "{ $.errorCode = \"AccessDenied\" }"), + resource.TestCheckResourceAttr(resourceName, "pattern", "{ $.errorCode = \"AccessDenied\" }"), testAccCheckCloudWatchLogMetricFilterPattern(&mf, "{ $.errorCode = \"AccessDenied\" }"), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "log_group_name", fmt.Sprintf("MyApp/access-%d.log", rInt)), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.name", "AccessDeniedCount"), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.namespace", "MyNamespace"), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.value", "2"), - resource.TestCheckResourceAttr("aws_cloudwatch_log_metric_filter.foobar", "metric_transformation.0.default_value", "1"), + 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.default_value", "1"), testAccCheckCloudWatchLogMetricFilterTransformation(&mf, &cloudwatchlogs.MetricTransformation{ MetricName: aws.String("AccessDeniedCount"), MetricNamespace: aws.String("MyNamespace"), @@ -134,7 +141,7 @@ func testAccCheckCloudWatchLogMetricFilterExists(n string, mf *cloudwatchlogs.Me } conn := testAccProvider.Meta().(*AWSClient).cloudwatchlogsconn - metricFilter, err := lookupCloudWatchLogMetricFilter(conn, rs.Primary.ID, rs.Primary.Attributes["log_group_name"], nil) + metricFilter, err := lookupCloudWatchLogMetricFilter(conn, rs.Primary.Attributes["name"], rs.Primary.Attributes["log_group_name"], nil) if err != nil { return err } @@ -153,7 +160,7 @@ func testAccCheckAWSCloudWatchLogMetricFilterDestroy(s *terraform.State) error { continue } - _, err := lookupCloudWatchLogMetricFilter(conn, rs.Primary.ID, rs.Primary.Attributes["log_group_name"], nil) + _, err := lookupCloudWatchLogMetricFilter(conn, rs.Primary.Attributes["name"], rs.Primary.Attributes["log_group_name"], nil) if err == nil { return fmt.Errorf("MetricFilter Still Exists: %s", rs.Primary.ID) } @@ -242,3 +249,14 @@ resource "aws_cloudwatch_log_group" "mama" { } `, rInt, rInt) } + +func testAccAWSCloudwatchLogMetricFilterImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("Not found: %s", resourceName) + } + + return rs.Primary.Attributes["log_group_name"] + ":" + rs.Primary.Attributes["name"], nil + } +} diff --git a/website/docs/r/cloudwatch_log_metric_filter.html.markdown b/website/docs/r/cloudwatch_log_metric_filter.html.markdown index d43ac8e9199..6d77c7e6010 100644 --- a/website/docs/r/cloudwatch_log_metric_filter.html.markdown +++ b/website/docs/r/cloudwatch_log_metric_filter.html.markdown @@ -53,3 +53,11 @@ The `metric_transformation` block supports the following arguments: In addition to all arguments above, the following attributes are exported: * `id` - The name of the metric filter. + +## Import + +CloudWatch Log Metric Filter can be imported using the `log_group_name:name`, e.g. + +``` +$ terraform import aws_cloudwatch_log_metric_filter.test /aws/lambda/function:test +``` From e6b795239a3aa1c956c4280089514a20a6831cf2 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Wed, 25 Mar 2020 08:43:32 -0400 Subject: [PATCH 093/684] Update CHANGELOG for #11992 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e1b9d7dc1a..5cb852f5aaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ENHANCEMENTS: * data-source/aws_availability_zone: Add `group_name`, `network_border_group`, and `opt_in_status` attributes [GH-12400] * data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments [GH-12400] * data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] +* resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] ## 2.54.0 (March 19, 2020) From d55da06ea77bc4b6efaac46366be82662a08f339 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Wed, 25 Mar 2020 14:47:58 +0200 Subject: [PATCH 094/684] resource/aws_mq_configuration: Remove extraneous call to ListTags during refresh and add ValidateFunc to engine_type (#11843) Output from acceptance testing: ``` --- PASS: TestAccAWSMqConfiguration_withData (14.44s) --- PASS: TestAccAWSMqConfiguration_basic (16.08s) --- PASS: TestAccAWSMqConfiguration_updateTags (28.40s) ``` --- aws/resource_aws_mq_configuration.go | 12 ++-- aws/resource_aws_mq_configuration_test.go | 83 ++++++++++++++--------- 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/aws/resource_aws_mq_configuration.go b/aws/resource_aws_mq_configuration.go index 08afb2ec5bb..4b5ddc65dbe 100644 --- a/aws/resource_aws_mq_configuration.go +++ b/aws/resource_aws_mq_configuration.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/mq" "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" ) @@ -53,6 +54,9 @@ func resourceAwsMqConfiguration() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + mq.EngineTypeActivemq, + }, true), }, "engine_version": { Type: schema.TypeString, @@ -106,7 +110,7 @@ func resourceAwsMqConfigurationRead(d *schema.ResourceData, meta interface{}) er ConfigurationId: aws.String(d.Id()), }) if err != nil { - if isAWSErr(err, "NotFoundException", "") { + if isAWSErr(err, mq.ErrCodeNotFoundException, "") { log.Printf("[WARN] MQ Configuration %q not found, removing from state", d.Id()) d.SetId("") return nil @@ -136,11 +140,7 @@ func resourceAwsMqConfigurationRead(d *schema.ResourceData, meta interface{}) er d.Set("data", string(b)) - tags, err := keyvaluetags.MqListTags(conn, aws.StringValue(out.Arn)) - if err != nil { - return fmt.Errorf("error listing tags for MQ Configuration (%s): %s", d.Id(), err) - } - if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + if err := d.Set("tags", keyvaluetags.MqKeyValueTags(out.Tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } diff --git a/aws/resource_aws_mq_configuration_test.go b/aws/resource_aws_mq_configuration_test.go index ff9be2f1642..dff90f465fa 100644 --- a/aws/resource_aws_mq_configuration_test.go +++ b/aws/resource_aws_mq_configuration_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -13,6 +14,7 @@ import ( func TestAccAWSMqConfiguration_basic(t *testing.T) { configurationName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "aws_mq_configuration.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMq(t) }, @@ -22,25 +24,30 @@ func TestAccAWSMqConfiguration_basic(t *testing.T) { { Config: testAccMqConfigurationConfig(configurationName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqConfigurationExists("aws_mq_configuration.test"), - resource.TestCheckResourceAttrSet("aws_mq_configuration.test", "arn"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "description", "TfAccTest MQ Configuration"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "engine_type", "ActiveMQ"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "engine_version", "5.15.0"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "latest_revision", "2"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "name", configurationName), + testAccCheckAwsMqConfigurationExists(resourceName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "mq", regexp.MustCompile(`configuration:+.`)), + resource.TestCheckResourceAttr(resourceName, "description", "TfAccTest MQ Configuration"), + resource.TestCheckResourceAttr(resourceName, "engine_type", "ActiveMQ"), + resource.TestCheckResourceAttr(resourceName, "engine_version", "5.15.0"), + resource.TestCheckResourceAttr(resourceName, "latest_revision", "2"), + resource.TestCheckResourceAttr(resourceName, "name", configurationName), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccMqConfigurationConfig_descriptionUpdated(configurationName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqConfigurationExists("aws_mq_configuration.test"), - resource.TestCheckResourceAttrSet("aws_mq_configuration.test", "arn"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "description", "TfAccTest MQ Configuration Updated"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "engine_type", "ActiveMQ"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "engine_version", "5.15.0"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "latest_revision", "3"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "name", configurationName), + testAccCheckAwsMqConfigurationExists(resourceName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "mq", regexp.MustCompile(`configuration:+.`)), + resource.TestCheckResourceAttr(resourceName, "description", "TfAccTest MQ Configuration Updated"), + resource.TestCheckResourceAttr(resourceName, "engine_type", "ActiveMQ"), + resource.TestCheckResourceAttr(resourceName, "engine_version", "5.15.0"), + resource.TestCheckResourceAttr(resourceName, "latest_revision", "3"), + resource.TestCheckResourceAttr(resourceName, "name", configurationName), ), }, }, @@ -49,6 +56,7 @@ func TestAccAWSMqConfiguration_basic(t *testing.T) { func TestAccAWSMqConfiguration_withData(t *testing.T) { configurationName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "aws_mq_configuration.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMq(t) }, @@ -58,21 +66,27 @@ func TestAccAWSMqConfiguration_withData(t *testing.T) { { Config: testAccMqConfigurationWithDataConfig(configurationName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqConfigurationExists("aws_mq_configuration.test"), - resource.TestCheckResourceAttrSet("aws_mq_configuration.test", "arn"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "description", "TfAccTest MQ Configuration"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "engine_type", "ActiveMQ"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "engine_version", "5.15.0"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "latest_revision", "2"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "name", configurationName), + testAccCheckAwsMqConfigurationExists(resourceName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "mq", regexp.MustCompile(`configuration:+.`)), + resource.TestCheckResourceAttr(resourceName, "description", "TfAccTest MQ Configuration"), + resource.TestCheckResourceAttr(resourceName, "engine_type", "ActiveMQ"), + resource.TestCheckResourceAttr(resourceName, "engine_version", "5.15.0"), + resource.TestCheckResourceAttr(resourceName, "latest_revision", "2"), + resource.TestCheckResourceAttr(resourceName, "name", configurationName), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } func TestAccAWSMqConfiguration_updateTags(t *testing.T) { configurationName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "aws_mq_configuration.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMq(t) }, @@ -82,26 +96,31 @@ func TestAccAWSMqConfiguration_updateTags(t *testing.T) { { Config: testAccMqConfigurationConfig_updateTags1(configurationName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqConfigurationExists("aws_mq_configuration.test"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "tags.%", "1"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "tags.env", "test"), + testAccCheckAwsMqConfigurationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "test"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccMqConfigurationConfig_updateTags2(configurationName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqConfigurationExists("aws_mq_configuration.test"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "tags.%", "2"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "tags.env", "test2"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "tags.role", "test-role"), + testAccCheckAwsMqConfigurationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "test2"), + resource.TestCheckResourceAttr(resourceName, "tags.role", "test-role"), ), }, { Config: testAccMqConfigurationConfig_updateTags3(configurationName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsMqConfigurationExists("aws_mq_configuration.test"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "tags.%", "1"), - resource.TestCheckResourceAttr("aws_mq_configuration.test", "tags.role", "test-role"), + testAccCheckAwsMqConfigurationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.role", "test-role"), ), }, }, @@ -122,7 +141,7 @@ func testAccCheckAwsMqConfigurationDestroy(s *terraform.State) error { _, err := conn.DescribeConfiguration(input) if err != nil { - if isAWSErr(err, "NotFoundException", "") { + if isAWSErr(err, mq.ErrCodeNotFoundException, "") { return nil } return err From 6c0de73154f6479744d6b83be50b7bc567411101 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Wed, 25 Mar 2020 08:48:26 -0400 Subject: [PATCH 095/684] Update CHANGELOG for #11843 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cb852f5aaa..aa07c9befad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ ENHANCEMENTS: * data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments [GH-12400] * data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] * resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] +* resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument [GH-11843] + +BUG FIXES: + +* resource/aws_mq_configuration: Remove extraneous `ListTags` API call during refresh [GH-11843] ## 2.54.0 (March 19, 2020) From 5178a038f901e7b111104e5de335477b64bfc344 Mon Sep 17 00:00:00 2001 From: Petteri Leppikallio Date: Wed, 25 Mar 2020 14:56:58 +0200 Subject: [PATCH 096/684] resource/aws_athena_workgroup: Add force_destroy argument (#12254) Output from acceptance testing: ``` --- PASS: TestAccAWSAthenaWorkGroup_disappears (13.52s) --- PASS: TestAccAWSAthenaWorkGroup_basic (17.71s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_PublishCloudWatchMetricsEnabled (20.62s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_EncryptionConfiguration_SseS3 (21.41s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_EnforceWorkgroupConfiguration (23.30s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_BytesScannedCutoffPerQuery (35.04s) --- PASS: TestAccAWSAthenaWorkGroup_Description (35.46s) --- PASS: TestAccAWSAthenaWorkGroup_ForceDestroy (36.53s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_OutputLocation (37.56s) --- PASS: TestAccAWSAthenaWorkGroup_Tags (39.00s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_EncryptionConfiguration_Kms (41.25s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_OutputLocation_ForceDestroy (50.81s) --- PASS: TestAccAWSAthenaWorkGroup_State (51.30s) ``` --- aws/resource_aws_athena_workgroup.go | 14 ++ aws/resource_aws_athena_workgroup_test.go | 201 +++++++++++++++--- website/docs/r/athena_workgroup.html.markdown | 1 + 3 files changed, 186 insertions(+), 30 deletions(-) diff --git a/aws/resource_aws_athena_workgroup.go b/aws/resource_aws_athena_workgroup.go index 10ed951e383..4b8f75de76e 100644 --- a/aws/resource_aws_athena_workgroup.go +++ b/aws/resource_aws_athena_workgroup.go @@ -115,6 +115,11 @@ func resourceAwsAthenaWorkgroup() *schema.Resource { athena.WorkGroupStateEnabled, }, false), }, + "force_destroy": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, "tags": tagsSchema(), }, } @@ -199,6 +204,12 @@ func resourceAwsAthenaWorkgroupRead(d *schema.ResourceData, meta interface{}) er d.Set("name", resp.WorkGroup.Name) d.Set("state", resp.WorkGroup.State) + if v, ok := d.GetOk("force_destroy"); ok { + d.Set("force_destroy", v.(bool)) + } else { + d.Set("force_destroy", false) + } + tags, err := keyvaluetags.AthenaListTags(conn, arn.String()) if err != nil { @@ -219,6 +230,9 @@ func resourceAwsAthenaWorkgroupDelete(d *schema.ResourceData, meta interface{}) WorkGroup: aws.String(d.Id()), } + if v, ok := d.GetOk("force_destroy"); ok { + input.RecursiveDeleteOption = aws.Bool(v.(bool)) + } _, err := conn.DeleteWorkGroup(input) if err != nil { diff --git a/aws/resource_aws_athena_workgroup_test.go b/aws/resource_aws_athena_workgroup_test.go index 36454a4abbe..872911cb671 100644 --- a/aws/resource_aws_athena_workgroup_test.go +++ b/aws/resource_aws_athena_workgroup_test.go @@ -37,9 +37,10 @@ func TestAccAWSAthenaWorkGroup_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, }, }, }) @@ -86,9 +87,10 @@ func TestAccAWSAthenaWorkGroup_Configuration_BytesScannedCutoffPerQuery(t *testi ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, }, { Config: testAccAthenaWorkGroupConfigConfigurationBytesScannedCutoffPerQuery(rName, 10485760), @@ -121,9 +123,10 @@ func TestAccAWSAthenaWorkGroup_Configuration_EnforceWorkgroupConfiguration(t *te ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, }, { Config: testAccAthenaWorkGroupConfigConfigurationEnforceWorkgroupConfiguration(rName, true), @@ -156,9 +159,10 @@ func TestAccAWSAthenaWorkGroup_Configuration_PublishCloudWatchMetricsEnabled(t * ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, }, { Config: testAccAthenaWorkGroupConfigConfigurationPublishCloudWatchMetricsEnabled(rName, true), @@ -193,9 +197,10 @@ func TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_EncryptionConfi ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, }, }, }) @@ -224,9 +229,10 @@ func TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_EncryptionConfi ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, }, { Config: testAccAthenaWorkGroupConfigConfigurationResultConfigurationEncryptionConfigurationEncryptionOptionWithKms(rName, rEncryption2), @@ -264,9 +270,10 @@ func TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_OutputLocation( ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, }, { Config: testAccAthenaWorkGroupConfigConfigurationResultConfigurationOutputLocation(rName, rOutputLocation2), @@ -281,6 +288,46 @@ func TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_OutputLocation( }) } +func TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_OutputLocation_ForceDestroy(t *testing.T) { + var workgroup1, workgroup2 athena.WorkGroup + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_athena_workgroup.test" + rOutputLocation1 := fmt.Sprintf("%s-1", rName) + rOutputLocation2 := fmt.Sprintf("%s-2", rName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAthenaWorkGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAthenaWorkGroupConfigConfigurationResultConfigurationOutputLocationForceDestroy(rName, rOutputLocation1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAthenaWorkGroupExists(resourceName, &workgroup1), + resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.result_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.result_configuration.0.output_location", "s3://"+rOutputLocation1+"/test/output"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + { + Config: testAccAthenaWorkGroupConfigConfigurationResultConfigurationOutputLocationForceDestroy(rName, rOutputLocation2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAthenaWorkGroupExists(resourceName, &workgroup2), + resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.result_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.result_configuration.0.output_location", "s3://"+rOutputLocation2+"/test/output"), + ), + }, + }, + }) +} + func TestAccAWSAthenaWorkGroup_Description(t *testing.T) { var workgroup1, workgroup2 athena.WorkGroup rName := acctest.RandomWithPrefix("tf-acc-test") @@ -301,9 +348,10 @@ func TestAccAWSAthenaWorkGroup_Description(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, }, { Config: testAccAthenaWorkGroupConfigDescription(rName, rDescriptionUpdate), @@ -334,9 +382,10 @@ func TestAccAWSAthenaWorkGroup_State(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, }, { Config: testAccAthenaWorkGroupConfigState(rName, athena.WorkGroupStateEnabled), @@ -356,6 +405,37 @@ func TestAccAWSAthenaWorkGroup_State(t *testing.T) { }) } +func TestAccAWSAthenaWorkGroup_ForceDestroy(t *testing.T) { + var workgroup athena.WorkGroup + rName := acctest.RandomWithPrefix("tf-acc-test") + dbName := acctest.RandString(5) + queryName1 := acctest.RandomWithPrefix("tf-athena-named-query-") + queryName2 := acctest.RandomWithPrefix("tf-athena-named-query-") + resourceName := "aws_athena_workgroup.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAthenaWorkGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAthenaWorkGroupConfigForceDestroy(rName, dbName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAthenaWorkGroupExists(resourceName, &workgroup), + testAccCheckAWSAthenaCreateNamedQuery(&workgroup, dbName, queryName1, fmt.Sprintf("SELECT * FROM %s limit 10;", rName)), + testAccCheckAWSAthenaCreateNamedQuery(&workgroup, dbName, queryName2, fmt.Sprintf("SELECT * FROM %s limit 100;", rName)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + }, + }) +} + func TestAccAWSAthenaWorkGroup_Tags(t *testing.T) { var workgroup1, workgroup2, workgroup3 athena.WorkGroup rName := acctest.RandomWithPrefix("tf-acc-test") @@ -375,9 +455,10 @@ func TestAccAWSAthenaWorkGroup_Tags(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, }, { Config: testAccAthenaWorkGroupConfigTags2(rName, "key1", "value1updated", "key2", "value2"), @@ -400,6 +481,26 @@ func TestAccAWSAthenaWorkGroup_Tags(t *testing.T) { }) } +func testAccCheckAWSAthenaCreateNamedQuery(workGroup *athena.WorkGroup, databaseName, queryName, query string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).athenaconn + + input := &athena.CreateNamedQueryInput{ + Name: aws.String(queryName), + WorkGroup: workGroup.Name, + Database: aws.String(databaseName), + QueryString: aws.String(query), + Description: aws.String("tf test"), + } + + if _, err := conn.CreateNamedQuery(input); err != nil { + return fmt.Errorf("error creating Named Query (%s) on Workgroup (%s): %s", queryName, aws.StringValue(workGroup.Name), err) + } + + return nil + } +} + func testAccCheckAWSAthenaWorkGroupDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).athenaconn for _, rs := range s.RootModule().Resources { @@ -539,6 +640,27 @@ resource "aws_athena_workgroup" "test" { `, rName, bucketName) } +func testAccAthenaWorkGroupConfigConfigurationResultConfigurationOutputLocationForceDestroy(rName string, bucketName string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "test"{ + bucket = %[2]q + force_destroy = true +} + +resource "aws_athena_workgroup" "test" { + name = %[1]q + + force_destroy = true + + configuration { + result_configuration { + output_location = "s3://${aws_s3_bucket.test.bucket}/test/output" + } + } +} +`, rName, bucketName) +} + func testAccAthenaWorkGroupConfigConfigurationResultConfigurationEncryptionConfigurationEncryptionOptionSseS3(rName string) string { return fmt.Sprintf(` resource "aws_athena_workgroup" "test" { @@ -610,3 +732,22 @@ resource "aws_athena_workgroup" "test" { } `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } + +func testAccAthenaWorkGroupConfigForceDestroy(rName, dbName string) string { + return fmt.Sprintf(` +resource "aws_athena_workgroup" "test" { + name = %[1]q + force_destroy = true +} +resource "aws_s3_bucket" "test" { + bucket = %[1]q + force_destroy = true +} + +resource "aws_athena_database" "test" { + name = %[2]q + bucket = "${aws_s3_bucket.test.bucket}" + force_destroy = true +} +`, rName, dbName) +} diff --git a/website/docs/r/athena_workgroup.html.markdown b/website/docs/r/athena_workgroup.html.markdown index 2ca348db1c1..3b76c1932eb 100644 --- a/website/docs/r/athena_workgroup.html.markdown +++ b/website/docs/r/athena_workgroup.html.markdown @@ -41,6 +41,7 @@ The following arguments are supported: * `description` - (Optional) Description of the workgroup. * `state` - (Optional) State of the workgroup. Valid values are `DISABLED` or `ENABLED`. Defaults to `ENABLED`. * `tags` - (Optional) Key-value mapping of resource tags for the workgroup. +* `force_destroy` - (Optional) The option to delete the workgroup and its contents even if the workgroup contains any named queries. ### configuration Argument Reference From 4deb3c16416f725aae13209efdf0ecfb5f96c12e Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Wed, 25 Mar 2020 08:58:44 -0400 Subject: [PATCH 097/684] Update CHANGELOG for #12254 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa07c9befad..f082387dfa5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ENHANCEMENTS: * data-source/aws_availability_zone: Add `group_name`, `network_border_group`, and `opt_in_status` attributes [GH-12400] * data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments [GH-12400] * data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] +* resource/aws_athena_workgroup: Add `force_destroy` argument [GH-12254] * resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] * resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument [GH-11843] From 8740302c441583e0956b99ca132b0bf54e3501d6 Mon Sep 17 00:00:00 2001 From: James Crowley Date: Thu, 26 Mar 2020 00:05:00 +1100 Subject: [PATCH 098/684] Correcting possible values for encryption_option (#12510) These were listed with -'s but the correct values are one of CSE_KMS, SSE_KMS or SSE_S3. --- website/docs/r/athena_workgroup.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/athena_workgroup.html.markdown b/website/docs/r/athena_workgroup.html.markdown index 3b76c1932eb..ef1c7a579e1 100644 --- a/website/docs/r/athena_workgroup.html.markdown +++ b/website/docs/r/athena_workgroup.html.markdown @@ -63,8 +63,8 @@ The `result_configuration` configuration block within the `configuration` suppor The `encryption_configuration` configuration block within the `result_configuration` of the `configuration` supports the following arguments: -* `encryption_option` - (Required) Indicates whether Amazon S3 server-side encryption with Amazon S3-managed keys (SSE-S3), server-side encryption with KMS-managed keys (SSE-KMS), or client-side encryption with KMS-managed keys (CSE-KMS) is used. If a query runs in a workgroup and the workgroup overrides client-side settings, then the workgroup's setting for encryption is used. It specifies whether query results must be encrypted, for all queries that run in this workgroup. -* `kms_key_arn` - (Optional) For SSE-KMS and CSE-KMS, this is the KMS key Amazon Resource Name (ARN). +* `encryption_option` - (Required) Indicates whether Amazon S3 server-side encryption with Amazon S3-managed keys (`SSE_S3`), server-side encryption with KMS-managed keys (`SSE_KMS`), or client-side encryption with KMS-managed keys (`CSE_KMS`) is used. If a query runs in a workgroup and the workgroup overrides client-side settings, then the workgroup's setting for encryption is used. It specifies whether query results must be encrypted, for all queries that run in this workgroup. +* `kms_key_arn` - (Optional) For `SSE_KMS` and `CSE_KMS`, this is the KMS key Amazon Resource Name (ARN). ## Attributes Reference From f06d424f55ab5961a7c91515eef0bb1a6e5d7efc Mon Sep 17 00:00:00 2001 From: cory Date: Wed, 25 Mar 2020 13:48:49 +0000 Subject: [PATCH 099/684] Removes extra attributes. --- aws/resource_aws_dynamodb_table.go | 40 ------------------------------ 1 file changed, 40 deletions(-) diff --git a/aws/resource_aws_dynamodb_table.go b/aws/resource_aws_dynamodb_table.go index 14c8d1cf8f7..72ce9bb2122 100644 --- a/aws/resource_aws_dynamodb_table.go +++ b/aws/resource_aws_dynamodb_table.go @@ -288,46 +288,6 @@ func resourceAwsDynamoDbTable() *schema.Resource { Type: schema.TypeString, Required: true, }, - "kms_master_key_id": { - Type: schema.TypeString, - Optional: true, - }, - "provision_capacity_override": { - Type: schema.TypeMap, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "read_capacity": { - Type: schema.TypeInt, - Required: true, - }, - }, - }, - }, - "global_secondary_index": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - "provisioned_capacity_override": { - Type: schema.TypeMap, - Required: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "read_capacity": { - Type: schema.TypeInt, - Required: true, - }, - }, - }, - }, - }, - }, - }, }, }, }, From d5257211bc0c7a2098a52fc320d1ca3fef0e2135 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Wed, 25 Mar 2020 17:18:46 -0400 Subject: [PATCH 100/684] resource/aws_db_instance: Use expandStringSet and add testing for snapshot_identifier with db_subnet_group_name Output from acceptance testing: ``` --- PASS: TestAccAWSDBInstance_AllowMajorVersionUpgrade (468.71s) --- PASS: TestAccAWSDBInstance_basic (542.30s) --- PASS: TestAccAWSDBInstance_cloudwatchLogsExportConfiguration (531.07s) --- PASS: TestAccAWSDBInstance_cloudwatchLogsExportConfigurationUpdate (908.96s) --- PASS: TestAccAWSDBInstance_DeletionProtection (518.69s) --- PASS: TestAccAWSDBInstance_EnabledCloudwatchLogsExports_MSSQL (834.56s) --- PASS: TestAccAWSDBInstance_EnabledCloudwatchLogsExports_Oracle (984.80s) --- PASS: TestAccAWSDBInstance_EnabledCloudwatchLogsExports_Postgresql (562.72s) --- PASS: TestAccAWSDBInstance_FinalSnapshotIdentifier_SkipFinalSnapshot (697.57s) --- PASS: TestAccAWSDBInstance_generatedName (454.93s) --- PASS: TestAccAWSDBInstance_generatedName (454.93s) --- PASS: TestAccAWSDBInstance_iamAuth (443.68s) --- PASS: TestAccAWSDBInstance_IsAlreadyBeingDeleted (497.68s) --- PASS: TestAccAWSDBInstance_kmsKey (496.42s) --- PASS: TestAccAWSDBInstance_MaxAllocatedStorage (612.65s) --- PASS: TestAccAWSDBInstance_MinorVersion (499.38s) --- PASS: TestAccAWSDBInstance_MonitoringInterval (1197.86s) --- PASS: TestAccAWSDBInstance_MonitoringRoleArn_EnabledToDisabled (777.72s) --- PASS: TestAccAWSDBInstance_MonitoringRoleArn_EnabledToRemoved (759.80s) --- PASS: TestAccAWSDBInstance_MonitoringRoleArn_RemovedToEnabled (665.14s) --- PASS: TestAccAWSDBInstance_MSSQL_Domain (3414.21s) --- PASS: TestAccAWSDBInstance_MSSQL_DomainSnapshotRestore (2970.09s) --- PASS: TestAccAWSDBInstance_MSSQL_DomainSnapshotRestore (2990.04s) --- PASS: TestAccAWSDBInstance_MSSQL_DomainSnapshotRestore (2990.04s) --- PASS: TestAccAWSDBInstance_MSSQL_TZ (1976.16s) --- PASS: TestAccAWSDBInstance_MySQL_SnapshotRestoreWithEngineVersion (1841.14s) --- PASS: TestAccAWSDBInstance_namePrefix (549.17s) --- PASS: TestAccAWSDBInstance_NoDeleteAutomatedBackups (718.39s) --- PASS: TestAccAWSDBInstance_optionGroup (521.01s) --- PASS: TestAccAWSDBInstance_Password (484.36s) --- PASS: TestAccAWSDBInstance_portUpdate (634.53s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb (1639.18s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb (1639.18s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_AllocatedStorage (1830.41s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_AllocatedStorage (1830.41s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_AllowMajorVersionUpgrade (1411.65s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_AutoMinorVersionUpgrade (1360.36s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_AvailabilityZone (1600.67s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_BackupRetentionPeriod (1830.56s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_BackupWindow (1536.32s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_CACertificateIdentifier (1586.12s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_IamDatabaseAuthenticationEnabled (1505.73s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_MaintenanceWindow (1632.49s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_MaxAllocatedStorage (1433.69s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_Monitoring (1578.14s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_MultiAZ (1997.82s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_ParameterGroupName (1706.42s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_PerformanceInsightsEnabled (2000.60s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_Port (1568.18s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_VpcSecurityGroupIds (1398.68s) --- PASS: TestAccAWSDBInstance_separate_iops_update (719.12s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier (1139.35s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_AllocatedStorage (1474.21s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_AllowMajorVersionUpgrade (2093.45s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_AutoMinorVersionUpgrade (1389.23s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_AvailabilityZone (1144.65s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_BackupRetentionPeriod (1559.87s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_BackupRetentionPeriod_Unset (1767.66s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_BackupWindow (1330.61s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_DbSubnetGroupName (1363.94s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_DbSubnetGroupName_RamShared (1262.21s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_DbSubnetGroupName_VpcSecurityGroupIds (1265.81s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_DeletionProtection (1386.48s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_IamDatabaseAuthenticationEnabled (1423.82s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_Io1Storage (1736.06s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_MaintenanceWindow (1173.36s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_MaxAllocatedStorage (1294.73s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_Monitoring (1373.89s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_MultiAZ (1745.06s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_MultiAZ_SQLServer (4135.67s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_ParameterGroupName (1301.29s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_PerformanceInsightsEnabled (1475.73s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_Port (1379.89s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_Tags (1120.65s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_VpcSecurityGroupIds (1243.26s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_VpcSecurityGroupIds_Tags (1169.39s) ``` --- aws/provider_test.go | 12 + aws/resource_aws_db_instance.go | 30 +-- aws/resource_aws_db_instance_test.go | 323 +++++++++++++++++++++++++++ 3 files changed, 340 insertions(+), 25 deletions(-) diff --git a/aws/provider_test.go b/aws/provider_test.go index 63b57f08061..7f227081ac4 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -402,6 +402,18 @@ func testAccOrganizationsAccountPreCheck(t *testing.T) { t.Skip("skipping tests; this AWS account must not be an existing member of an AWS Organization") } +func testAccOrganizationsEnabledPreCheck(t *testing.T) { + conn := testAccProvider.Meta().(*AWSClient).organizationsconn + input := &organizations.DescribeOrganizationInput{} + _, err := conn.DescribeOrganization(input) + if isAWSErr(err, organizations.ErrCodeAWSOrganizationsNotInUseException, "") { + t.Skip("this AWS account must be an existing member of an AWS Organization") + } + if err != nil { + t.Fatalf("error describing AWS Organization: %s", err) + } +} + func testAccAlternateAccountProviderConfig() string { //lintignore:AT004 return fmt.Sprintf(` diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index 98dc765ba29..09cb730ae95 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -736,19 +736,11 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error } if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { - var s []*string - for _, v := range attr.List() { - s = append(s, aws.String(v.(string))) - } - opts.VpcSecurityGroupIds = s + opts.VpcSecurityGroupIds = expandStringSet(attr) } if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { - var s []*string - for _, v := range attr.List() { - s = append(s, aws.String(v.(string))) - } - opts.DBSecurityGroups = s + opts.DBSecurityGroups = expandStringSet(attr) } if attr, ok := d.GetOk("storage_type"); ok { opts.StorageType = aws.String(attr.(string)) @@ -1008,11 +1000,7 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error } if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { - var s []*string - for _, v := range attr.List() { - s = append(s, aws.String(v.(string))) - } - opts.VpcSecurityGroupIds = s + opts.VpcSecurityGroupIds = expandStringSet(attr) } if attr, ok := d.GetOk("performance_insights_enabled"); ok { @@ -1116,19 +1104,11 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error } if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { - var s []*string - for _, v := range attr.List() { - s = append(s, aws.String(v.(string))) - } - opts.VpcSecurityGroupIds = s + opts.VpcSecurityGroupIds = expandStringSet(attr) } if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { - var s []*string - for _, v := range attr.List() { - s = append(s, aws.String(v.(string))) - } - opts.DBSecurityGroups = s + opts.DBSecurityGroups = expandStringSet(attr) } if attr, ok := d.GetOk("storage_type"); ok { opts.StorageType = aws.String(attr.(string)) diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index 22819b8be8e..3eab5cd6ef6 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/aws/aws-sdk-go/aws" @@ -1213,6 +1214,101 @@ func TestAccAWSDBInstance_SnapshotIdentifier_BackupWindow(t *testing.T) { }) } +func TestAccAWSDBInstance_SnapshotIdentifier_DbSubnetGroupName(t *testing.T) { + var dbInstance, sourceDbInstance rds.DBInstance + var dbSnapshot rds.DBSnapshot + var dbSubnetGroup rds.DBSubnetGroup + + rName := acctest.RandomWithPrefix("tf-acc-test") + dbSubnetGroupResourceName := "aws_db_subnet_group.test" + sourceDbResourceName := "aws_db_instance.source" + snapshotResourceName := "aws_db_snapshot.test" + resourceName := "aws_db_instance.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDBInstanceConfig_SnapshotIdentifier_DbSubnetGroupName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists(sourceDbResourceName, &sourceDbInstance), + testAccCheckDbSnapshotExists(snapshotResourceName, &dbSnapshot), + testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), + testAccCheckDBSubnetGroupExists(resourceName, &dbSubnetGroup), + resource.TestCheckResourceAttrPair(resourceName, "db_subnet_group_name", dbSubnetGroupResourceName, "name"), + ), + }, + }, + }) +} + +func TestAccAWSDBInstance_SnapshotIdentifier_DbSubnetGroupName_RamShared(t *testing.T) { + var dbInstance, sourceDbInstance rds.DBInstance + var dbSnapshot rds.DBSnapshot + var dbSubnetGroup rds.DBSubnetGroup + var providers []*schema.Provider + + rName := acctest.RandomWithPrefix("tf-acc-test") + dbSubnetGroupResourceName := "aws_db_subnet_group.test" + sourceDbResourceName := "aws_db_instance.source" + snapshotResourceName := "aws_db_snapshot.test" + resourceName := "aws_db_instance.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + testAccOrganizationsEnabledPreCheck(t) + }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckAWSDBInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDBInstanceConfig_SnapshotIdentifier_DbSubnetGroupName_RamShared(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists(sourceDbResourceName, &sourceDbInstance), + testAccCheckDbSnapshotExists(snapshotResourceName, &dbSnapshot), + testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), + testAccCheckDBSubnetGroupExists(dbSubnetGroupResourceName, &dbSubnetGroup), + resource.TestCheckResourceAttrPair(resourceName, "db_subnet_group_name", dbSubnetGroupResourceName, "name"), + ), + }, + }, + }) +} + +func TestAccAWSDBInstance_SnapshotIdentifier_DbSubnetGroupName_VpcSecurityGroupIds(t *testing.T) { + var dbInstance, sourceDbInstance rds.DBInstance + var dbSnapshot rds.DBSnapshot + var dbSubnetGroup rds.DBSubnetGroup + + rName := acctest.RandomWithPrefix("tf-acc-test") + dbSubnetGroupResourceName := "aws_db_subnet_group.test" + sourceDbResourceName := "aws_db_instance.source" + snapshotResourceName := "aws_db_snapshot.test" + resourceName := "aws_db_instance.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDBInstanceConfig_SnapshotIdentifier_DbSubnetGroupName_VpcSecurityGroupIds(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists(sourceDbResourceName, &sourceDbInstance), + testAccCheckDbSnapshotExists(snapshotResourceName, &dbSnapshot), + testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), + testAccCheckDBSubnetGroupExists(resourceName, &dbSubnetGroup), + resource.TestCheckResourceAttrPair(resourceName, "db_subnet_group_name", dbSubnetGroupResourceName, "name"), + ), + }, + }, + }) +} + func TestAccAWSDBInstance_SnapshotIdentifier_DeletionProtection(t *testing.T) { var dbInstance, sourceDbInstance rds.DBInstance var dbSnapshot rds.DBSnapshot @@ -5129,6 +5225,233 @@ resource "aws_db_instance" "test" { `, rName, rName, backupWindow, rName, maintenanceWindow) } +func testAccAWSDBInstanceConfig_SnapshotIdentifier_DbSubnetGroupName(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 = %[1]q + } +} + +resource "aws_subnet" "test" { + count = 2 + + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = "10.0.${count.index}.0/24" + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_db_subnet_group" "test" { + name = %[1]q + subnet_ids = aws_subnet.test[*].id +} + +resource "aws_db_instance" "source" { + allocated_storage = 5 + engine = "mariadb" + identifier = "%[1]s-source" + instance_class = "db.t2.micro" + password = "avoid-plaintext-passwords" + username = "tfacctest" + skip_final_snapshot = true +} + +resource "aws_db_snapshot" "test" { + db_instance_identifier = aws_db_instance.source.id + db_snapshot_identifier = %[1]q +} + +resource "aws_db_instance" "test" { + db_subnet_group_name = aws_db_subnet_group.test.name + identifier = %[1]q + instance_class = aws_db_instance.source.instance_class + snapshot_identifier = aws_db_snapshot.test.id + skip_final_snapshot = true +} +`, rName) +} + +func testAccAWSDBInstanceConfig_SnapshotIdentifier_DbSubnetGroupName_RamShared(rName string) string { + return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` +data "aws_availability_zones" "available" { + provider = "aws.alternate" + + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +data "aws_organizations_organization" "test" {} + +resource "aws_vpc" "test" { + provider = "aws.alternate" + + cidr_block = "10.0.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "test" { + count = 2 + provider = "aws.alternate" + + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = "10.0.${count.index}.0/24" + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_ram_resource_share" "test" { + provider = "aws.alternate" + + name = %[1]q +} + +resource "aws_ram_principal_association" "test" { + provider = "aws.alternate" + + principal = data.aws_organizations_organization.test.arn + resource_share_arn = aws_ram_resource_share.test.arn +} + +resource "aws_ram_resource_association" "test" { + count = 2 + provider = "aws.alternate" + + resource_arn = aws_subnet.test[count.index].arn + resource_share_arn = aws_ram_resource_share.test.id +} + +resource "aws_db_subnet_group" "test" { + depends_on = [aws_ram_principal_association.test, aws_ram_resource_association.test] + + name = %[1]q + subnet_ids = aws_subnet.test[*].id +} + +resource "aws_security_group" "test" { + depends_on = [aws_ram_principal_association.test, aws_ram_resource_association.test] + + name = %[1]q + vpc_id = aws_vpc.test.id +} + +resource "aws_db_instance" "source" { + allocated_storage = 5 + engine = "mariadb" + identifier = "%[1]s-source" + instance_class = "db.t2.micro" + password = "avoid-plaintext-passwords" + username = "tfacctest" + skip_final_snapshot = true +} + +resource "aws_db_snapshot" "test" { + db_instance_identifier = aws_db_instance.source.id + db_snapshot_identifier = %[1]q +} + +resource "aws_db_instance" "test" { + db_subnet_group_name = aws_db_subnet_group.test.name + identifier = %[1]q + instance_class = aws_db_instance.source.instance_class + snapshot_identifier = aws_db_snapshot.test.id + skip_final_snapshot = true + vpc_security_group_ids = [aws_security_group.test.id] +} +`, rName) +} + +func testAccAWSDBInstanceConfig_SnapshotIdentifier_DbSubnetGroupName_VpcSecurityGroupIds(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 = %[1]q + } +} + +resource "aws_security_group" "test" { + name = %[1]q + vpc_id = aws_vpc.test.id +} + +resource "aws_subnet" "test" { + count = 2 + + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = "10.0.${count.index}.0/24" + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_db_subnet_group" "test" { + name = %[1]q + subnet_ids = aws_subnet.test[*].id +} + +resource "aws_db_instance" "source" { + allocated_storage = 5 + engine = "mariadb" + identifier = "%[1]s-source" + instance_class = "db.t2.micro" + password = "avoid-plaintext-passwords" + username = "tfacctest" + skip_final_snapshot = true +} + +resource "aws_db_snapshot" "test" { + db_instance_identifier = aws_db_instance.source.id + db_snapshot_identifier = %[1]q +} + +resource "aws_db_instance" "test" { + db_subnet_group_name = aws_db_subnet_group.test.name + identifier = %[1]q + instance_class = aws_db_instance.source.instance_class + snapshot_identifier = aws_db_snapshot.test.id + skip_final_snapshot = true + vpc_security_group_ids = [aws_security_group.test.id] +} +`, rName) +} + func testAccAWSDBInstanceConfig_SnapshotIdentifier_DeletionProtection(rName string, deletionProtection bool) string { return fmt.Sprintf(` resource "aws_db_instance" "source" { From 5eeb864d0a0497bbbc320a401878cb6ddbb03285 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Wed, 25 Mar 2020 23:19:34 +0200 Subject: [PATCH 101/684] plan only test for change revert --- aws/resource_aws_route53_health_check_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_health_check_test.go b/aws/resource_aws_route53_health_check_test.go index 3ad8008bdc6..58a6c0b8e4d 100644 --- a/aws/resource_aws_route53_health_check_test.go +++ b/aws/resource_aws_route53_health_check_test.go @@ -36,7 +36,11 @@ func TestAccAWSRoute53HealthCheck_basic(t *testing.T) { }, { Config: testAccRoute53HealthCheckConfigUpdate, - PlanOnly: true, + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53HealthCheckExists(resourceName, &check), + resource.TestCheckResourceAttr(resourceName, "failure_threshold", "5"), + resource.TestCheckResourceAttr(resourceName, "invert_healthcheck", "false"), + ), }, }, }) From aa3bbd6bb7ecf49c41cfc147dec0ea5a79e4c75f Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Wed, 25 Mar 2020 17:20:51 -0400 Subject: [PATCH 102/684] Update CHANGELOG for #12447 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f082387dfa5..d6c6fdf81b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ ENHANCEMENTS: BUG FIXES: +* resource/aws_db_instance: Allow restoring from snapshot into RAM shared Subnet with VPC Security Group [GH-12447] * resource/aws_mq_configuration: Remove extraneous `ListTags` API call during refresh [GH-11843] ## 2.54.0 (March 19, 2020) From f3eb8159f9ec5e7fa14f8587dbfc4123b832f579 Mon Sep 17 00:00:00 2001 From: Marko Antolovic Date: Thu, 26 Mar 2020 00:21:16 +0100 Subject: [PATCH 103/684] docs/resource/aws_cognito_user_pool: Update the resource definition (#12529) --- website/docs/r/cognito_user_pool.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cognito_user_pool.markdown b/website/docs/r/cognito_user_pool.markdown index ea197f4873d..1ad9ad02945 100644 --- a/website/docs/r/cognito_user_pool.markdown +++ b/website/docs/r/cognito_user_pool.markdown @@ -23,7 +23,7 @@ resource "aws_cognito_user_pool" "pool" { ### Enabling SMS and Software Token Multi-Factor Authentication ```hcl -resource "aws_cognito_user_pool_mfa_config" "example" { +resource "aws_cognito_user_pool" "example" { # ... other configuration ... mfa_configuration = "ON" From f004cdec2392f00f45f36cf15717bf4423772a2f Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Wed, 25 Mar 2020 19:44:21 -0400 Subject: [PATCH 104/684] tests/provider: Bulk update aws_availability_zones data sources in test configurations to exclude Local Zones (#12517) * tests/provider: Bulk update aws_availability_zones data sources in test configurations to exclude Local Zones Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12412 This is the least risky update for all testing to exclude Local Zones from the data source, since us-west-2-lax-1 generally is missing functionality and also to prevent Availability Zone and Local Zone mixing when multiple Availability Zones are required, which is not allowed in many services. In the future, this type of configuration churn can be reduced with one of the following solutions: - Removing aws_availability_zones data source usage where it has now been superceded by the creation of the aws_ec2_instance_type_offering data source - Standardizing base configurations per data source/resource - Standardizing shared configurations into helper test configurations and composing them Output from acceptance testing (as a smoke test): ``` --- PASS: TestAccAWSLB_ALB_basic (197.43s) ``` * docs/provider: Include Local Zones filtering in Contributing Guide Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/12517#issuecomment-603784217 * data-source/aws_vpc_endpoint_service: Keep non-filtered aws_availability_zones data source configuration Since the expected return value of availability_zones applies to all Availability Zones and Local Zones: ``` --- FAIL: TestAccDataSourceAwsVpcEndpointService_gateway (6.13s) testing.go:654: Step 0 error: Check failed: Check 3/10 error: data.aws_vpc_endpoint_service.test: Attribute 'availability_zones.#' expected "4", got "5" ``` Output from acceptance testing: ``` --- PASS: TestAccDataSourceAwsVpcEndpointService_gateway (15.03s) ``` * tests/data-source/aws_availability_zone: Exclude Local Zones from aws_availability_zones results in test configurations Previously: ``` --- FAIL: TestAccDataSourceAwsAvailabilityZone_Filter (9.96s) testing.go:654: Step 0 error: Check failed: Check 1/7 error: data.aws_availability_zone.test: Attribute 'group_name' expected "us-west-2", got "us-west-2-lax-1" ``` Output from acceptance testing: ``` --- PASS: TestAccDataSourceAwsAvailabilityZone_Filter (16.70s) --- PASS: TestAccDataSourceAwsAvailabilityZone_AllAvailabilityZones (16.97s) --- PASS: TestAccDataSourceAwsAvailabilityZone_Name (17.17s) --- PASS: TestAccDataSourceAwsAvailabilityZone_ZoneId (17.28s) ``` --- .github/CONTRIBUTING.md | 14 +- aws/data_source_aws_autoscaling_group_test.go | 5 + ...data_source_aws_autoscaling_groups_test.go | 18 ++- aws/data_source_aws_availability_zone_test.go | 36 ++++- aws/data_source_aws_cloudhsm2_cluster_test.go | 9 +- ...ata_source_aws_db_cluster_snapshot_test.go | 27 +++- ...ce_aws_directory_service_directory_test.go | 8 +- aws/data_source_aws_ebs_snapshot_test.go | 27 +++- aws/data_source_aws_ebs_volume_test.go | 18 ++- ...rce_aws_ec2_instance_type_offering_test.go | 5 + ...ce_aws_ec2_instance_type_offerings_test.go | 5 + ...ec2_transit_gateway_vpc_attachment_test.go | 10 ++ aws/data_source_aws_eip_test.go | 5 + ..._aws_elasticache_replication_group_test.go | 9 +- ...ta_source_aws_elasticsearch_domain_test.go | 5 + aws/data_source_aws_elb_test.go | 9 +- aws/data_source_aws_lb_listener_test.go | 27 +++- aws/data_source_aws_lb_target_group_test.go | 18 ++- aws/data_source_aws_lb_test.go | 18 ++- aws/data_source_aws_mq_broker_test.go | 9 +- aws/data_source_aws_network_interface_test.go | 18 ++- aws/data_source_aws_route_test.go | 5 + aws/data_source_aws_subnet_test.go | 36 ++++- ...ta_source_aws_vpc_endpoint_service_test.go | 9 +- aws/data_source_aws_vpc_endpoint_test.go | 9 +- aws/resource_aws_ami_copy_test.go | 9 +- aws/resource_aws_ami_test.go | 9 +- ...source_aws_api_gateway_integration_test.go | 9 +- aws/resource_aws_api_gateway_rest_api_test.go | 18 ++- aws/resource_aws_api_gateway_vpc_link_test.go | 9 +- ...ws_appautoscaling_scheduled_action_test.go | 5 + ...resource_aws_appautoscaling_target_test.go | 5 + aws/resource_aws_autoscaling_group_test.go | 79 +++++++++- aws/resource_aws_autoscaling_policy_test.go | 9 +- aws/resource_aws_backup_selection_test.go | 5 + ...esource_aws_cloud9_environment_ec2_test.go | 5 + aws/resource_aws_cloudhsm2_cluster_test.go | 9 +- aws/resource_aws_cloudhsm2_hsm_test.go | 9 +- aws/resource_aws_codebuild_project_test.go | 10 ++ ...ce_aws_codedeploy_deployment_group_test.go | 18 +++ aws/resource_aws_db_cluster_snapshot_test.go | 27 +++- aws/resource_aws_db_instance_test.go | 18 ++- aws/resource_aws_db_subnet_group_test.go | 25 ++++ ...tory_service_conditional_forwarder_test.go | 5 + ...ce_aws_directory_service_directory_test.go | 50 +++++++ ...directory_service_log_subscription_test.go | 5 + ...ource_aws_dms_replication_instance_test.go | 27 +++- ...esource_aws_docdb_cluster_instance_test.go | 9 +- ...esource_aws_docdb_cluster_snapshot_test.go | 9 +- aws/resource_aws_docdb_cluster_test.go | 9 +- aws/resource_aws_ebs_snapshot_copy_test.go | 30 ++++ aws/resource_aws_ebs_volume_test.go | 81 ++++++++-- ...ource_aws_ec2_capacity_reservation_test.go | 99 +++++++++++-- ...source_aws_ec2_client_vpn_endpoint_test.go | 9 +- ...ec2_client_vpn_network_association_test.go | 5 + aws/resource_aws_ec2_fleet_test.go | 9 +- ...rce_aws_ec2_traffic_mirror_session_test.go | 5 + ...urce_aws_ec2_traffic_mirror_target_test.go | 5 + ...urce_aws_ec2_transit_gateway_route_test.go | 5 + ...it_gateway_vpc_attachment_accepter_test.go | 5 + ...ec2_transit_gateway_vpc_attachment_test.go | 55 +++++++ ...resource_aws_ecs_capacity_provider_test.go | 9 +- aws/resource_aws_ecs_service_test.go | 108 ++++++++++++-- aws/resource_aws_eip_association_test.go | 21 ++- aws/resource_aws_eip_test.go | 12 +- aws/resource_aws_eks_cluster_test.go | 9 +- aws/resource_aws_eks_fargate_profile_test.go | 5 + aws/resource_aws_eks_node_group_test.go | 5 + ..._aws_elastic_beanstalk_environment_test.go | 5 + aws/resource_aws_elasticache_cluster_test.go | 32 +++- ..._aws_elasticache_replication_group_test.go | 56 ++++++- aws/resource_aws_elasticsearch_domain_test.go | 15 ++ aws/resource_aws_elb_test.go | 138 +++++++++++++++++- aws/resource_aws_emr_instance_group_test.go | 5 + ...esource_aws_fsx_lustre_file_system_test.go | 5 + ...source_aws_fsx_windows_file_system_test.go | 5 + aws/resource_aws_glue_connection_test.go | 9 +- aws/resource_aws_instance_test.go | 24 +++ aws/resource_aws_launch_template_test.go | 63 +++++++- ...source_aws_lb_listener_certificate_test.go | 9 +- aws/resource_aws_lb_listener_rule_test.go | 108 ++++++++++++-- aws/resource_aws_lb_listener_test.go | 90 ++++++++++-- ...urce_aws_lb_ssl_negotiation_policy_test.go | 5 + ...rce_aws_lb_target_group_attachment_test.go | 5 + aws/resource_aws_lb_test.go | 135 +++++++++++++++-- aws/resource_aws_lightsail_instance_test.go | 15 ++ ...aws_lightsail_static_ip_attachment_test.go | 5 + ...oad_balancer_backend_server_policy_test.go | 15 ++ aws/resource_aws_mq_broker_test.go | 9 +- aws/resource_aws_msk_cluster_test.go | 5 + ...ource_aws_neptune_cluster_instance_test.go | 9 +- aws/resource_aws_neptune_cluster_test.go | 5 + ...ws_network_interface_sg_attachment_test.go | 9 +- aws/resource_aws_rds_cluster_instance_test.go | 9 +- aws/resource_aws_rds_cluster_test.go | 27 ++++ ...urce_aws_route53_resolver_endpoint_test.go | 9 +- ...resource_aws_route53_resolver_rule_test.go | 9 +- aws/resource_aws_route_table_test.go | 5 + aws/resource_aws_route_test.go | 23 ++- aws/resource_aws_shield_protection_test.go | 27 +++- ..._snapshot_create_volume_permission_test.go | 9 +- ...resource_aws_spot_instance_request_test.go | 18 ++- aws/resource_aws_ssm_association_test.go | 9 +- ...esource_aws_storagegateway_gateway_test.go | 5 + aws/resource_aws_vpc_endpoint_service_test.go | 9 +- ...ws_vpc_endpoint_subnet_association_test.go | 18 ++- aws/resource_aws_vpc_endpoint_test.go | 27 +++- ...ws_wafregional_web_acl_association_test.go | 9 +- aws/resource_aws_worklink_fleet_test.go | 9 +- aws/resource_aws_workspaces_directory_test.go | 5 + 110 files changed, 2055 insertions(+), 181 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b618ba29a75..a8081b09c3b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -824,7 +824,19 @@ The below are location-based items that _may_ be noted during review and are rec } ``` -- [ ] __Uses aws_availability_zones Data Source__: Any hardcoded AWS Availability Zone configuration, e.g. `us-west-2a`, should be replaced with the [`aws_availability_zones` data source](https://www.terraform.io/docs/providers/aws/d/availability_zones.html). A common pattern is declaring `data "aws_availability_zones" "current" {}` and referencing it via `data.aws_availability_zones.current.names[0]` or `data.aws_availability_zones.current.names[count.index]` in resources utilizing `count`. +- [ ] __Uses aws_availability_zones Data Source__: Any hardcoded AWS Availability Zone configuration, e.g. `us-west-2a`, should be replaced with the [`aws_availability_zones` data source](https://www.terraform.io/docs/providers/aws/d/availability_zones.html). A common pattern is declaring `data "aws_availability_zones" "available" {...}` and referencing it via `data.aws_availability_zones.available.names[0]` or `data.aws_availability_zones.available.names[count.index]` in resources utilizing `count`. + + ```hcl + data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } + } + ``` + - [ ] __Uses aws_region Data Source__: Any hardcoded AWS Region configuration, e.g. `us-west-2`, should be replaced with the [`aws_region` data source](https://www.terraform.io/docs/providers/aws/d/region.html). A common pattern is declaring `data "aws_region" "current" {}` and referencing it via `data.aws_region.current.name` - [ ] __Uses aws_partition Data Source__: Any hardcoded AWS Partition configuration, e.g. the `aws` in a `arn:aws:SERVICE:REGION:ACCOUNT:RESOURCE` ARN, should be replaced with the [`aws_partition` data source](https://www.terraform.io/docs/providers/aws/d/partition.html). A common pattern is declaring `data "aws_partition" "current" {}` and referencing it via `data.aws_partition.current.partition` - [ ] __Uses Builtin ARN Check Functions__: Tests should utilize available ARN check functions, e.g. `testAccMatchResourceAttrRegionalARN()`, to validate ARN attribute values in the Terraform state over `resource.TestCheckResourceAttrSet()` and `resource.TestMatchResourceAttr()` diff --git a/aws/data_source_aws_autoscaling_group_test.go b/aws/data_source_aws_autoscaling_group_test.go index 85a5cbd0381..fdb44b0278e 100644 --- a/aws/data_source_aws_autoscaling_group_test.go +++ b/aws/data_source_aws_autoscaling_group_test.go @@ -60,6 +60,11 @@ data "aws_ami" "ubuntu" { data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_launch_configuration" "data_source_aws_autoscaling_group_test" { diff --git a/aws/data_source_aws_autoscaling_groups_test.go b/aws/data_source_aws_autoscaling_groups_test.go index b51e9ff755c..dfad46e0eab 100644 --- a/aws/data_source_aws_autoscaling_groups_test.go +++ b/aws/data_source_aws_autoscaling_groups_test.go @@ -92,7 +92,14 @@ data "aws_ami" "test_ami" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_launch_configuration" "foobar" { image_id = "${data.aws_ami.test_ami.id}" @@ -167,7 +174,14 @@ data "aws_ami" "test_ami" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_launch_configuration" "foobar" { image_id = "${data.aws_ami.test_ami.id}" diff --git a/aws/data_source_aws_availability_zone_test.go b/aws/data_source_aws_availability_zone_test.go index 327e72e566a..0b897c762f5 100644 --- a/aws/data_source_aws_availability_zone_test.go +++ b/aws/data_source_aws_availability_zone_test.go @@ -106,7 +106,14 @@ func TestAccDataSourceAwsAvailabilityZone_ZoneId(t *testing.T) { func testAccDataSourceAwsAvailabilityZoneConfigAllAvailabilityZones() string { return fmt.Sprintf(` -data "aws_availability_zones" "test" {} +data "aws_availability_zones" "test" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_availability_zone" "test" { all_availability_zones = true @@ -117,7 +124,14 @@ data "aws_availability_zone" "test" { func testAccDataSourceAwsAvailabilityZoneConfigFilter() string { return fmt.Sprintf(` -data "aws_availability_zones" "test" {} +data "aws_availability_zones" "test" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_availability_zone" "test" { filter { @@ -130,7 +144,14 @@ data "aws_availability_zone" "test" { func testAccDataSourceAwsAvailabilityZoneConfigName() string { return fmt.Sprintf(` -data "aws_availability_zones" "test" {} +data "aws_availability_zones" "test" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_availability_zone" "test" { name = data.aws_availability_zones.test.names[0] @@ -140,7 +161,14 @@ data "aws_availability_zone" "test" { func testAccDataSourceAwsAvailabilityZoneConfigZoneId() string { return fmt.Sprintf(` -data "aws_availability_zones" "test" {} +data "aws_availability_zones" "test" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_availability_zone" "test" { zone_id = data.aws_availability_zones.test.zone_ids[0] diff --git a/aws/data_source_aws_cloudhsm2_cluster_test.go b/aws/data_source_aws_cloudhsm2_cluster_test.go index 0de8c6eea19..438bc9f7512 100644 --- a/aws/data_source_aws_cloudhsm2_cluster_test.go +++ b/aws/data_source_aws_cloudhsm2_cluster_test.go @@ -37,7 +37,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "cloudhsm_v2_test_vpc" { cidr_block = "10.0.0.0/16" diff --git a/aws/data_source_aws_db_cluster_snapshot_test.go b/aws/data_source_aws_db_cluster_snapshot_test.go index b34ae28184f..7401069cb9f 100644 --- a/aws/data_source_aws_db_cluster_snapshot_test.go +++ b/aws/data_source_aws_db_cluster_snapshot_test.go @@ -118,7 +118,14 @@ func testAccCheckAwsDbClusterSnapshotDataSourceExists(dataSourceName string) res func testAccCheckAwsDbClusterSnapshotDataSourceConfig_DbClusterSnapshotIdentifier(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "192.168.0.0/16" @@ -169,7 +176,14 @@ data "aws_db_cluster_snapshot" "test" { func testAccCheckAwsDbClusterSnapshotDataSourceConfig_DbClusterIdentifier(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "192.168.0.0/16" @@ -220,7 +234,14 @@ data "aws_db_cluster_snapshot" "test" { func testAccCheckAwsDbClusterSnapshotDataSourceConfig_MostRecent(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "192.168.0.0/16" diff --git a/aws/data_source_aws_directory_service_directory_test.go b/aws/data_source_aws_directory_service_directory_test.go index 05ba19318e3..ea441cf319d 100644 --- a/aws/data_source_aws_directory_service_directory_test.go +++ b/aws/data_source_aws_directory_service_directory_test.go @@ -2,9 +2,10 @@ package aws import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "testing" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" ) @@ -74,6 +75,11 @@ func testAccDataSourceAwsDirectoryServiceDirectoryConfig_Prerequisites(adType st return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "main" { diff --git a/aws/data_source_aws_ebs_snapshot_test.go b/aws/data_source_aws_ebs_snapshot_test.go index 8a02456f7fb..b1bd08121b3 100644 --- a/aws/data_source_aws_ebs_snapshot_test.go +++ b/aws/data_source_aws_ebs_snapshot_test.go @@ -88,7 +88,14 @@ func testAccCheckAwsEbsSnapshotDataSourceID(n string) resource.TestCheckFunc { } const testAccCheckAwsEbsSnapshotDataSourceConfig = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -106,7 +113,14 @@ data "aws_ebs_snapshot" "test" { ` const testAccCheckAwsEbsSnapshotDataSourceConfigFilter = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -127,7 +141,14 @@ data "aws_ebs_snapshot" "test" { ` const testAccCheckAwsEbsSnapshotDataSourceConfigMostRecent = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" diff --git a/aws/data_source_aws_ebs_volume_test.go b/aws/data_source_aws_ebs_volume_test.go index 3539896872a..111630214b0 100644 --- a/aws/data_source_aws_ebs_volume_test.go +++ b/aws/data_source_aws_ebs_volume_test.go @@ -61,7 +61,14 @@ func testAccCheckAwsEbsVolumeDataSourceID(n string) resource.TestCheckFunc { } const testAccCheckAwsEbsVolumeDataSourceConfig = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "example" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -86,7 +93,14 @@ data "aws_ebs_volume" "ebs_volume" { ` const testAccCheckAwsEbsVolumeDataSourceConfigWithMultipleFilters = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "external1" { availability_zone = "${data.aws_availability_zones.available.names[0]}" diff --git a/aws/data_source_aws_ec2_instance_type_offering_test.go b/aws/data_source_aws_ec2_instance_type_offering_test.go index 5da0f721ed4..e19de44bd1b 100644 --- a/aws/data_source_aws_ec2_instance_type_offering_test.go +++ b/aws/data_source_aws_ec2_instance_type_offering_test.go @@ -100,6 +100,11 @@ func testAccAWSEc2InstanceTypeOfferingDataSourceConfigLocationType() string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } # Rather than hardcode an instance type in the testing, diff --git a/aws/data_source_aws_ec2_instance_type_offerings_test.go b/aws/data_source_aws_ec2_instance_type_offerings_test.go index f81bcd5872f..2f42bfb32fd 100644 --- a/aws/data_source_aws_ec2_instance_type_offerings_test.go +++ b/aws/data_source_aws_ec2_instance_type_offerings_test.go @@ -94,6 +94,11 @@ func testAccAWSEc2InstanceTypeOfferingsDataSourceConfigLocationType() string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_ec2_instance_type_offerings" "test" { diff --git a/aws/data_source_aws_ec2_transit_gateway_vpc_attachment_test.go b/aws/data_source_aws_ec2_transit_gateway_vpc_attachment_test.go index 2a1651fdd65..1acb93589bb 100644 --- a/aws/data_source_aws_ec2_transit_gateway_vpc_attachment_test.go +++ b/aws/data_source_aws_ec2_transit_gateway_vpc_attachment_test.go @@ -63,6 +63,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -106,6 +111,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/data_source_aws_eip_test.go b/aws/data_source_aws_eip_test.go index 78c61c4d2de..4f8177ab47e 100644 --- a/aws/data_source_aws_eip_test.go +++ b/aws/data_source_aws_eip_test.go @@ -260,6 +260,11 @@ data "aws_availability_zones" "available" { # Error launching source instance: Unsupported: Your requested instance type (t2.micro) is not supported in your requested Availability Zone (us-west-2d). blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/data_source_aws_elasticache_replication_group_test.go b/aws/data_source_aws_elasticache_replication_group_test.go index c95fa027fa1..0472fd626c4 100644 --- a/aws/data_source_aws_elasticache_replication_group_test.go +++ b/aws/data_source_aws_elasticache_replication_group_test.go @@ -63,7 +63,14 @@ func TestAccDataSourceAwsElasticacheReplicationGroup_ClusterMode(t *testing.T) { func testAccDataSourceAwsElasticacheReplicationGroupConfig_basic(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_elasticache_replication_group" "test" { replication_group_id = %[1]q diff --git a/aws/data_source_aws_elasticsearch_domain_test.go b/aws/data_source_aws_elasticsearch_domain_test.go index 32b76b7c3fe..ed9448e7a49 100644 --- a/aws/data_source_aws_elasticsearch_domain_test.go +++ b/aws/data_source_aws_elasticsearch_domain_test.go @@ -130,6 +130,11 @@ func testAccAWSElasticsearchDomainConfigAdvancedWithDataSource(rInt int) string return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_partition" "current" {} diff --git a/aws/data_source_aws_elb_test.go b/aws/data_source_aws_elb_test.go index 5adcf47bec7..f39d1cbf96d 100644 --- a/aws/data_source_aws_elb_test.go +++ b/aws/data_source_aws_elb_test.go @@ -63,7 +63,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "elb_test" { cidr_block = "10.0.0.0/16" diff --git a/aws/data_source_aws_lb_listener_test.go b/aws/data_source_aws_lb_listener_test.go index 57723cd07ee..4f56e6b4e89 100644 --- a/aws/data_source_aws_lb_listener_test.go +++ b/aws/data_source_aws_lb_listener_test.go @@ -157,7 +157,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -276,7 +283,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -387,7 +401,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" diff --git a/aws/data_source_aws_lb_target_group_test.go b/aws/data_source_aws_lb_target_group_test.go index 9e0cab28d3f..6d2bf779ae7 100644 --- a/aws/data_source_aws_lb_target_group_test.go +++ b/aws/data_source_aws_lb_target_group_test.go @@ -180,7 +180,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -290,7 +297,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" diff --git a/aws/data_source_aws_lb_test.go b/aws/data_source_aws_lb_test.go index 425d73add2f..b1cd11e1184 100644 --- a/aws/data_source_aws_lb_test.go +++ b/aws/data_source_aws_lb_test.go @@ -112,7 +112,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -189,7 +196,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" diff --git a/aws/data_source_aws_mq_broker_test.go b/aws/data_source_aws_mq_broker_test.go index 4199f6aa6bd..88ceaedd433 100644 --- a/aws/data_source_aws_mq_broker_test.go +++ b/aws/data_source_aws_mq_broker_test.go @@ -97,7 +97,14 @@ variable "prefix" { default = "%s" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "acctest" { cidr_block = "10.0.0.0/16" diff --git a/aws/data_source_aws_network_interface_test.go b/aws/data_source_aws_network_interface_test.go index 48783114bf7..407fbdfe69a 100644 --- a/aws/data_source_aws_network_interface_test.go +++ b/aws/data_source_aws_network_interface_test.go @@ -34,7 +34,14 @@ func TestAccDataSourceAwsNetworkInterface_basic(t *testing.T) { func testAccDataSourceAwsNetworkInterface_basic(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +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" @@ -90,7 +97,14 @@ func TestAccDataSourceAwsNetworkInterface_filters(t *testing.T) { func testAccDataSourceAwsNetworkInterface_filters(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +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" diff --git a/aws/data_source_aws_route_test.go b/aws/data_source_aws_route_test.go index b7c3eab5c3a..82cba87ac67 100644 --- a/aws/data_source_aws_route_test.go +++ b/aws/data_source_aws_route_test.go @@ -199,6 +199,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/data_source_aws_subnet_test.go b/aws/data_source_aws_subnet_test.go index 0c8a81d48ba..f656b5a01f8 100644 --- a/aws/data_source_aws_subnet_test.go +++ b/aws/data_source_aws_subnet_test.go @@ -183,7 +183,14 @@ func TestAccDataSourceAwsSubnet_ipv6ByIpv6CidrBlock(t *testing.T) { func testAccDataSourceAwsSubnetConfig(rInt int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "172.%d.0.0/16" @@ -240,7 +247,14 @@ data "aws_subnet" "by_az_id" { func testAccDataSourceAwsSubnetConfigIpv6(rInt int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "172.%d.0.0/16" @@ -266,7 +280,14 @@ resource "aws_subnet" "test" { func testAccDataSourceAwsSubnetConfigIpv6WithDataSourceFilter(rInt int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "172.%d.0.0/16" @@ -299,7 +320,14 @@ data "aws_subnet" "by_ipv6_cidr" { func testAccDataSourceAwsSubnetConfigIpv6WithDataSourceIpv6CidrBlock(rInt int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "172.%d.0.0/16" diff --git a/aws/data_source_aws_vpc_endpoint_service_test.go b/aws/data_source_aws_vpc_endpoint_service_test.go index 8c4552d626c..6c2f9553bf4 100644 --- a/aws/data_source_aws_vpc_endpoint_service_test.go +++ b/aws/data_source_aws_vpc_endpoint_service_test.go @@ -128,7 +128,14 @@ resource "aws_lb" "test" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "test1" { vpc_id = "${aws_vpc.test.id}" diff --git a/aws/data_source_aws_vpc_endpoint_test.go b/aws/data_source_aws_vpc_endpoint_test.go index 0f19a277545..f89d9249c32 100644 --- a/aws/data_source_aws_vpc_endpoint_test.go +++ b/aws/data_source_aws_vpc_endpoint_test.go @@ -338,7 +338,14 @@ resource "aws_vpc" "test" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "test" { vpc_id = "${aws_vpc.test.id}" diff --git a/aws/resource_aws_ami_copy_test.go b/aws/resource_aws_ami_copy_test.go index e15a31f9449..e51707437ab 100644 --- a/aws/resource_aws_ami_copy_test.go +++ b/aws/resource_aws_ami_copy_test.go @@ -211,7 +211,14 @@ func testAccCheckAWSAMICopyAttributes(image *ec2.Image, expectedName string) res func testAccAWSAMICopyConfigBase() string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_region" "current" {} resource "aws_ebs_volume" "test" { diff --git a/aws/resource_aws_ami_test.go b/aws/resource_aws_ami_test.go index 3427dd4db3f..f40ed30281c 100644 --- a/aws/resource_aws_ami_test.go +++ b/aws/resource_aws_ami_test.go @@ -303,7 +303,14 @@ func testAccCheckAmiEbsBlockDevice(bd *ec2.BlockDeviceMapping, ed *ec2.EbsBlockD func testAccAmiConfig_base(rName string, size int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "foo" { availability_zone = "${data.aws_availability_zones.available.names[0]}" diff --git a/aws/resource_aws_api_gateway_integration_test.go b/aws/resource_aws_api_gateway_integration_test.go index 738cc9e7db2..4e1a7fc6f66 100644 --- a/aws/resource_aws_api_gateway_integration_test.go +++ b/aws/resource_aws_api_gateway_integration_test.go @@ -695,7 +695,14 @@ variable "name" { default = "%s" } -data "aws_availability_zones" "test" {} +data "aws_availability_zones" "test" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "10.10.0.0/16" diff --git a/aws/resource_aws_api_gateway_rest_api_test.go b/aws/resource_aws_api_gateway_rest_api_test.go index 04bbd35e428..f34a8a944fe 100644 --- a/aws/resource_aws_api_gateway_rest_api_test.go +++ b/aws/resource_aws_api_gateway_rest_api_test.go @@ -707,7 +707,14 @@ data "aws_security_group" "test" { name = "default" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "test" { vpc_id = "${aws_vpc.test.id}" @@ -764,7 +771,14 @@ data "aws_security_group" "test" { name = "default" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "test" { vpc_id = "${aws_vpc.test.id}" diff --git a/aws/resource_aws_api_gateway_vpc_link_test.go b/aws/resource_aws_api_gateway_vpc_link_test.go index 0094888a297..038db4e50da 100644 --- a/aws/resource_aws_api_gateway_vpc_link_test.go +++ b/aws/resource_aws_api_gateway_vpc_link_test.go @@ -213,7 +213,14 @@ resource "aws_vpc" "test" { } } -data "aws_availability_zones" "test" {} +data "aws_availability_zones" "test" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "test" { vpc_id = "${aws_vpc.test.id}" diff --git a/aws/resource_aws_appautoscaling_scheduled_action_test.go b/aws/resource_aws_appautoscaling_scheduled_action_test.go index 39ccc6966a5..3f0d7c14289 100644 --- a/aws/resource_aws_appautoscaling_scheduled_action_test.go +++ b/aws/resource_aws_appautoscaling_scheduled_action_test.go @@ -213,6 +213,11 @@ data "aws_availability_zones" "available" { # The requested instance type c4.large is not supported in the requested availability zone. blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_partition" "current" {} diff --git a/aws/resource_aws_appautoscaling_target_test.go b/aws/resource_aws_appautoscaling_target_test.go index c6aece57a51..cf0190e08e5 100644 --- a/aws/resource_aws_appautoscaling_target_test.go +++ b/aws/resource_aws_appautoscaling_target_test.go @@ -326,6 +326,11 @@ data "aws_availability_zones" "available" { # The requested instance type m3.xlarge is not supported in the requested availability zone. blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_partition" "current" {} diff --git a/aws/resource_aws_autoscaling_group_test.go b/aws/resource_aws_autoscaling_group_test.go index 1b94795abb4..d77e0cf43f7 100644 --- a/aws/resource_aws_autoscaling_group_test.go +++ b/aws/resource_aws_autoscaling_group_test.go @@ -934,6 +934,11 @@ data "aws_availability_zones" "available" { # t2.micro is not supported in us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_launch_template" "test" { @@ -2320,6 +2325,11 @@ data "aws_availability_zones" "available" { # t2.micro is not supported in us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } @@ -2420,6 +2430,11 @@ data "aws_availability_zones" "available" { # t2.micro is not supported in us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_subnet" "foo" { @@ -3383,6 +3398,11 @@ data "aws_availability_zones" "available" { # t2.micro is not supported in us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_subnet" "test" { @@ -3436,7 +3456,14 @@ resource "aws_launch_template" "foobar" { instance_type = "t2.micro" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_autoscaling_group" "bar" { availability_zones = ["${data.aws_availability_zones.available.names[0]}"] @@ -3472,7 +3499,14 @@ resource "aws_launch_configuration" "test" { instance_type = "t2.micro" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_autoscaling_group" "bar" { availability_zones = ["${data.aws_availability_zones.available.names[0]}"] @@ -3511,7 +3545,14 @@ resource "aws_launch_template" "foobar2" { instance_type = "t2.micro" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_autoscaling_group" "bar" { availability_zones = ["${data.aws_availability_zones.available.names[0]}"] @@ -3552,7 +3593,14 @@ resource "aws_launch_template" "foobar2" { instance_type = "t2.micro" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_autoscaling_group" "bar" { availability_zones = ["${data.aws_availability_zones.available.names[0]}"] @@ -3578,7 +3626,14 @@ data "aws_ami" "test" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_iam_role" "test" { assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}" @@ -3630,6 +3685,11 @@ data "aws_availability_zones" "available" { # t2.micro is not supported in us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_launch_template" "test" { @@ -3700,7 +3760,14 @@ data "aws_ami" "test" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_launch_template" "test" { image_id = "${data.aws_ami.test.id}" diff --git a/aws/resource_aws_autoscaling_policy_test.go b/aws/resource_aws_autoscaling_policy_test.go index f46dcf16cbe..eb56a137559 100644 --- a/aws/resource_aws_autoscaling_policy_test.go +++ b/aws/resource_aws_autoscaling_policy_test.go @@ -343,7 +343,14 @@ data "aws_ami" "amzn" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_launch_configuration" "test" { name = "%s" diff --git a/aws/resource_aws_backup_selection_test.go b/aws/resource_aws_backup_selection_test.go index 59c8bb24392..3963decd041 100644 --- a/aws/resource_aws_backup_selection_test.go +++ b/aws/resource_aws_backup_selection_test.go @@ -306,6 +306,11 @@ func testAccBackupSelectionConfigWithResources(rInt int) string { return testAccBackupSelectionConfigBase(rInt) + fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_ebs_volume" "test" { diff --git a/aws/resource_aws_cloud9_environment_ec2_test.go b/aws/resource_aws_cloud9_environment_ec2_test.go index 8c2ddbdd886..c4f61d15ca7 100644 --- a/aws/resource_aws_cloud9_environment_ec2_test.go +++ b/aws/resource_aws_cloud9_environment_ec2_test.go @@ -294,6 +294,11 @@ data "aws_availability_zones" "available" { # t2.micro instance type is not available in these Availability Zones blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/resource_aws_cloudhsm2_cluster_test.go b/aws/resource_aws_cloudhsm2_cluster_test.go index f2ace54485f..83ca0d101c2 100644 --- a/aws/resource_aws_cloudhsm2_cluster_test.go +++ b/aws/resource_aws_cloudhsm2_cluster_test.go @@ -161,7 +161,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "cloudhsm_v2_test_vpc" { cidr_block = "10.0.0.0/16" diff --git a/aws/resource_aws_cloudhsm2_hsm_test.go b/aws/resource_aws_cloudhsm2_hsm_test.go index 82ae0970c87..6f30a4105cc 100644 --- a/aws/resource_aws_cloudhsm2_hsm_test.go +++ b/aws/resource_aws_cloudhsm2_hsm_test.go @@ -42,7 +42,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "cloudhsm_v2_test_vpc" { cidr_block = "10.0.0.0/16" diff --git a/aws/resource_aws_codebuild_project_test.go b/aws/resource_aws_codebuild_project_test.go index 7e9b5a95713..9e4724114f6 100644 --- a/aws/resource_aws_codebuild_project_test.go +++ b/aws/resource_aws_codebuild_project_test.go @@ -3046,6 +3046,11 @@ data "aws_availability_zones" "available" { # InvalidInputException: CodeBuild currently doesn't support VPC in us-west-2d, please select subnets in other availability zones. blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -3102,6 +3107,11 @@ data "aws_availability_zones" "available" { # InvalidInputException: CodeBuild currently doesn't support VPC in us-west-2d, please select subnets in other availability zones. blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/resource_aws_codedeploy_deployment_group_test.go b/aws/resource_aws_codedeploy_deployment_group_test.go index 251b1cf1b53..c2a7762ff31 100644 --- a/aws/resource_aws_codedeploy_deployment_group_test.go +++ b/aws/resource_aws_codedeploy_deployment_group_test.go @@ -3006,6 +3006,12 @@ data "aws_ami" "amzn-ami-minimal-hvm-ebs" { } data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_subnet" "test" { @@ -3091,6 +3097,12 @@ data "aws_ami" "amzn-ami-minimal-hvm-ebs" { } data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_subnet" "test" { @@ -3271,6 +3283,12 @@ resource "aws_codedeploy_deployment_group" "test" { func testAccAWSCodeDeployDeploymentGroupConfigEcsBase(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" { diff --git a/aws/resource_aws_db_cluster_snapshot_test.go b/aws/resource_aws_db_cluster_snapshot_test.go index fbb6f4cefda..9477d4c6145 100644 --- a/aws/resource_aws_db_cluster_snapshot_test.go +++ b/aws/resource_aws_db_cluster_snapshot_test.go @@ -164,7 +164,14 @@ func testAccCheckDbClusterSnapshotExists(resourceName string, dbClusterSnapshot func testAccAwsDbClusterSnapshotConfig(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "192.168.0.0/16" @@ -208,7 +215,14 @@ resource "aws_db_cluster_snapshot" "test" { func testAccAwsDbClusterSnapshotConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "192.168.0.0/16" @@ -255,7 +269,14 @@ resource "aws_db_cluster_snapshot" "test" { func testAccAwsDbClusterSnapshotConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "192.168.0.0/16" diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index 3eab5cd6ef6..b495bb3c12a 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -4617,7 +4617,14 @@ resource "aws_db_instance" "test" { func testAccAWSDBInstanceConfig_ReplicateSourceDb_AvailabilityZone(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_db_instance" "source" { allocated_storage = 5 @@ -5113,7 +5120,14 @@ resource "aws_db_instance" "test" { func testAccAWSDBInstanceConfig_SnapshotIdentifier_AvailabilityZone(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_db_instance" "source" { allocated_storage = 5 diff --git a/aws/resource_aws_db_subnet_group_test.go b/aws/resource_aws_db_subnet_group_test.go index df10aa76dc6..a5949f466a4 100644 --- a/aws/resource_aws_db_subnet_group_test.go +++ b/aws/resource_aws_db_subnet_group_test.go @@ -286,6 +286,11 @@ func testAccDBSubnetGroupConfig(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" { @@ -331,6 +336,11 @@ func testAccDBSubnetGroupConfig_updatedDescription(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" { @@ -376,6 +386,11 @@ resource "aws_db_subnet_group" "test" { const testAccDBSubnetGroupConfig_namePrefix = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -411,6 +426,11 @@ resource "aws_db_subnet_group" "test" { const testAccDBSubnetGroupConfig_generatedName = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -445,6 +465,11 @@ resource "aws_db_subnet_group" "test" { const testAccDBSubnetGroupConfig_withUnderscoresAndPeriodsAndSpaces = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "main" { diff --git a/aws/resource_aws_directory_service_conditional_forwarder_test.go b/aws/resource_aws_directory_service_conditional_forwarder_test.go index 8ecc90621d8..f0d0c3e4148 100644 --- a/aws/resource_aws_directory_service_conditional_forwarder_test.go +++ b/aws/resource_aws_directory_service_conditional_forwarder_test.go @@ -138,6 +138,11 @@ func testAccDirectoryServiceConditionalForwarderConfig(ip1, ip2 string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "bar" { diff --git a/aws/resource_aws_directory_service_directory_test.go b/aws/resource_aws_directory_service_directory_test.go index c1796200c19..546265ea1b9 100644 --- a/aws/resource_aws_directory_service_directory_test.go +++ b/aws/resource_aws_directory_service_directory_test.go @@ -449,6 +449,11 @@ func testAccPreCheckAWSDirectoryServiceSimpleDirectory(t *testing.T) { const testAccDirectoryServiceDirectoryConfig = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "test" { @@ -490,6 +495,11 @@ resource "aws_subnet" "test" { const testAccDirectoryServiceDirectoryTagsConfig = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "test" { @@ -536,6 +546,11 @@ resource "aws_subnet" "test" { const testAccDirectoryServiceDirectoryUpdateTagsConfig = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "test" { @@ -583,6 +598,11 @@ resource "aws_subnet" "test" { const testAccDirectoryServiceDirectoryRemoveTagsConfig = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "test" { @@ -628,6 +648,11 @@ resource "aws_subnet" "test" { const testAccDirectoryServiceDirectoryConfig_connector = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "test" { @@ -683,6 +708,11 @@ resource "aws_subnet" "test" { const testAccDirectoryServiceDirectoryConfig_microsoft = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "test" { @@ -724,6 +754,11 @@ resource "aws_subnet" "test" { const testAccDirectoryServiceDirectoryConfig_microsoftStandard = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "test" { @@ -767,6 +802,11 @@ func testAccDirectoryServiceDirectoryConfig_withAlias(alias string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "test2" { @@ -811,6 +851,11 @@ func testAccDirectoryServiceDirectoryConfig_withSso(alias string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "test2" { @@ -856,6 +901,11 @@ func testAccDirectoryServiceDirectoryConfig_withSso_modified(alias string) strin return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "test2" { diff --git a/aws/resource_aws_directory_service_log_subscription_test.go b/aws/resource_aws_directory_service_log_subscription_test.go index 4f628e573a5..0b455330f94 100644 --- a/aws/resource_aws_directory_service_log_subscription_test.go +++ b/aws/resource_aws_directory_service_log_subscription_test.go @@ -105,6 +105,11 @@ func testAccDirectoryServiceLogSubscriptionConfig(logGroupName string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_directory_service_directory" "bar" { diff --git a/aws/resource_aws_dms_replication_instance_test.go b/aws/resource_aws_dms_replication_instance_test.go index e83893b08ef..4ed59901e0d 100644 --- a/aws/resource_aws_dms_replication_instance_test.go +++ b/aws/resource_aws_dms_replication_instance_test.go @@ -684,7 +684,14 @@ resource "aws_dms_replication_instance" "test" { func testAccAWSDmsReplicationInstanceConfig_AvailabilityZone(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_partition" "current" {} @@ -778,7 +785,14 @@ resource "aws_dms_replication_instance" "test" { func testAccAWSDmsReplicationInstanceConfig_ReplicationSubnetGroupId(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_partition" "current" {} @@ -852,7 +866,14 @@ resource "aws_dms_replication_instance" "test" { func testAccAWSDmsReplicationInstanceConfig_VpcSecurityGroupIds(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_partition" "current" {} diff --git a/aws/resource_aws_docdb_cluster_instance_test.go b/aws/resource_aws_docdb_cluster_instance_test.go index e3552389ca3..7cdbc29fef5 100644 --- a/aws/resource_aws_docdb_cluster_instance_test.go +++ b/aws/resource_aws_docdb_cluster_instance_test.go @@ -327,7 +327,14 @@ resource "aws_docdb_cluster_instance" "cluster_instances" { func testAccAWSDocDBClusterInstanceConfig_az(n int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_docdb_cluster" "default" { cluster_identifier = "tf-docdb-cluster-test-%d" diff --git a/aws/resource_aws_docdb_cluster_snapshot_test.go b/aws/resource_aws_docdb_cluster_snapshot_test.go index c85fe8f90a2..6afa257748a 100644 --- a/aws/resource_aws_docdb_cluster_snapshot_test.go +++ b/aws/resource_aws_docdb_cluster_snapshot_test.go @@ -110,7 +110,14 @@ func testAccCheckDocDBClusterSnapshotExists(resourceName string, dbClusterSnapsh func testAccAwsDocDBClusterSnapshotConfig(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "192.168.0.0/16" diff --git a/aws/resource_aws_docdb_cluster_test.go b/aws/resource_aws_docdb_cluster_test.go index 18087a3c920..f7199ee8319 100644 --- a/aws/resource_aws_docdb_cluster_test.go +++ b/aws/resource_aws_docdb_cluster_test.go @@ -729,7 +729,14 @@ resource "aws_docdb_cluster" "default" { func testAccDocDBClusterConfig_Port(rInt, port int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_docdb_cluster" "test" { availability_zones = ["${data.aws_availability_zones.available.names[0]}", "${data.aws_availability_zones.available.names[1]}", "${data.aws_availability_zones.available.names[2]}"] diff --git a/aws/resource_aws_ebs_snapshot_copy_test.go b/aws/resource_aws_ebs_snapshot_copy_test.go index d2c0fe4da26..031271fc3c5 100644 --- a/aws/resource_aws_ebs_snapshot_copy_test.go +++ b/aws/resource_aws_ebs_snapshot_copy_test.go @@ -235,6 +235,11 @@ func testAccCheckEbsSnapshotCopyExists(n string, v *ec2.Snapshot) resource.TestC const testAccAwsEbsSnapshotCopyConfig = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_region" "current" {} @@ -266,6 +271,11 @@ func testAccAwsEbsSnapshotCopyConfigTags1(tagKey1, tagValue1 string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_region" "current" {} @@ -299,6 +309,11 @@ func testAccAwsEbsSnapshotCopyConfigTags2(tagKey1, tagValue1, tagKey2, tagValue2 return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_region" "current" {} @@ -332,6 +347,11 @@ resource "aws_ebs_snapshot_copy" "test" { const testAccAwsEbsSnapshotCopyConfigWithDescription = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_region" "current" {} @@ -369,6 +389,11 @@ var testAccAwsEbsSnapshotCopyConfigWithRegions = testAccAlternateRegionProviderC data "aws_availability_zones" "alternate_available" { provider = "aws.alternate" state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_region" "alternate" { @@ -407,6 +432,11 @@ resource "aws_ebs_snapshot_copy" "test" { const testAccAwsEbsSnapshotCopyConfigWithKms = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_region" "current" {} diff --git a/aws/resource_aws_ebs_volume_test.go b/aws/resource_aws_ebs_volume_test.go index be65651d090..c7845e03d88 100644 --- a/aws/resource_aws_ebs_volume_test.go +++ b/aws/resource_aws_ebs_volume_test.go @@ -372,7 +372,14 @@ func testAccCheckVolumeExists(n string, v *ec2.Volume) resource.TestCheckFunc { } const testAccAwsEbsVolumeConfig = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -423,7 +430,14 @@ resource "aws_instance" "test" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { depends_on = ["aws_instance.test"] @@ -498,7 +512,14 @@ resource "aws_volume_attachment" "test" { ` const testAccAwsEbsVolumeConfigUpdateSize = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -511,7 +532,14 @@ resource "aws_ebs_volume" "test" { ` const testAccAwsEbsVolumeConfigUpdateType = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -524,7 +552,14 @@ resource "aws_ebs_volume" "test" { ` const testAccAwsEbsVolumeConfigWithIops = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -538,7 +573,14 @@ resource "aws_ebs_volume" "test" { ` const testAccAwsEbsVolumeConfigWithIopsUpdated = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -573,7 +615,14 @@ resource "aws_kms_key" "test" { POLICY } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -584,7 +633,14 @@ resource "aws_ebs_volume" "test" { ` const testAccAwsEbsVolumeConfigWithTags = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -596,7 +652,14 @@ resource "aws_ebs_volume" "test" { ` const testAccAwsEbsVolumeConfigWithNoIops = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" diff --git a/aws/resource_aws_ec2_capacity_reservation_test.go b/aws/resource_aws_ec2_capacity_reservation_test.go index 09e3c7f5a53..7473731107c 100644 --- a/aws/resource_aws_ec2_capacity_reservation_test.go +++ b/aws/resource_aws_ec2_capacity_reservation_test.go @@ -466,7 +466,14 @@ func testAccPreCheckAWSEc2CapacityReservation(t *testing.T) { } const testAccEc2CapacityReservationConfig = ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -478,7 +485,14 @@ resource "aws_ec2_capacity_reservation" "test" { func testAccEc2CapacityReservationConfig_ebsOptimized(ebsOptimized bool) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -492,7 +506,14 @@ resource "aws_ec2_capacity_reservation" "test" { func testAccEc2CapacityReservationConfig_endDate(endDate string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -507,7 +528,14 @@ resource "aws_ec2_capacity_reservation" "test" { func testAccEc2CapacityReservationConfig_endDateType(endDateType string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -521,7 +549,14 @@ resource "aws_ec2_capacity_reservation" "test" { func testAccEc2CapacityReservationConfig_ephemeralStorage(ephemeralStorage bool) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -535,7 +570,14 @@ resource "aws_ec2_capacity_reservation" "test" { func testAccEc2CapacityReservationConfig_instanceCount(instanceCount int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -548,7 +590,14 @@ resource "aws_ec2_capacity_reservation" "test" { func testAccEc2CapacityReservationConfig_instanceMatchCriteria(instanceMatchCriteria string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -562,7 +611,14 @@ resource "aws_ec2_capacity_reservation" "test" { func testAccEc2CapacityReservationConfig_instanceType(instanceType string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -575,7 +631,14 @@ resource "aws_ec2_capacity_reservation" "test" { func testAccEc2CapacityReservationConfig_tags_single(tag1Key, tag1Value string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -592,7 +655,14 @@ resource "aws_ec2_capacity_reservation" "test" { func testAccEc2CapacityReservationConfig_tags_multiple(tag1Key, tag1Value, tag2Key, tag2Value string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -610,7 +680,14 @@ resource "aws_ec2_capacity_reservation" "test" { func testAccEc2CapacityReservationConfig_tenancy(tenancy string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" diff --git a/aws/resource_aws_ec2_client_vpn_endpoint_test.go b/aws/resource_aws_ec2_client_vpn_endpoint_test.go index c2ce2d7076f..bd450f5eaf5 100644 --- a/aws/resource_aws_ec2_client_vpn_endpoint_test.go +++ b/aws/resource_aws_ec2_client_vpn_endpoint_test.go @@ -411,7 +411,14 @@ resource "aws_ec2_client_vpn_endpoint" "test" { func testAccEc2ClientVpnEndpointConfigWithMicrosoftAD(rName string) string { return testAccEc2ClientVpnEndpointConfigAcmCertificateBase() + fmt.Sprintf(` -data "aws_availability_zones" "available" {} +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" diff --git a/aws/resource_aws_ec2_client_vpn_network_association_test.go b/aws/resource_aws_ec2_client_vpn_network_association_test.go index ee7f733ab9e..7d69dc7619d 100644 --- a/aws/resource_aws_ec2_client_vpn_network_association_test.go +++ b/aws/resource_aws_ec2_client_vpn_network_association_test.go @@ -152,6 +152,11 @@ data "aws_availability_zones" "available" { # InvalidParameterValue: AZ us-west-2d is not currently supported. Please choose another az in this region blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/resource_aws_ec2_fleet_test.go b/aws/resource_aws_ec2_fleet_test.go index 2ee8f058d69..20ce10cbae9 100644 --- a/aws/resource_aws_ec2_fleet_test.go +++ b/aws/resource_aws_ec2_fleet_test.go @@ -1474,7 +1474,14 @@ resource "aws_ec2_fleet" "test" { func testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_AvailabilityZone(rName string, availabilityZoneIndex int) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_fleet" "test" { launch_template_config { diff --git a/aws/resource_aws_ec2_traffic_mirror_session_test.go b/aws/resource_aws_ec2_traffic_mirror_session_test.go index 434c48ff192..dfa43b39db6 100644 --- a/aws/resource_aws_ec2_traffic_mirror_session_test.go +++ b/aws/resource_aws_ec2_traffic_mirror_session_test.go @@ -196,6 +196,11 @@ func testAccTrafficMirrorSessionConfigBase(rName string) string { return fmt.Sprintf(` data "aws_availability_zones" "azs" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_ami" "amzn-linux" { diff --git a/aws/resource_aws_ec2_traffic_mirror_target_test.go b/aws/resource_aws_ec2_traffic_mirror_target_test.go index 3ddd2921f83..8453fdea456 100644 --- a/aws/resource_aws_ec2_traffic_mirror_target_test.go +++ b/aws/resource_aws_ec2_traffic_mirror_target_test.go @@ -200,6 +200,11 @@ func testAccTrafficMirrorTargetConfigBase(rName string) string { return fmt.Sprintf(` data "aws_availability_zones" "azs" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "vpc" { diff --git a/aws/resource_aws_ec2_transit_gateway_route_test.go b/aws/resource_aws_ec2_transit_gateway_route_test.go index bf5c2de6518..e51161a9a3c 100644 --- a/aws/resource_aws_ec2_transit_gateway_route_test.go +++ b/aws/resource_aws_ec2_transit_gateway_route_test.go @@ -209,6 +209,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/resource_aws_ec2_transit_gateway_vpc_attachment_accepter_test.go b/aws/resource_aws_ec2_transit_gateway_vpc_attachment_accepter_test.go index 77858422334..ca9c284ead8 100644 --- a/aws/resource_aws_ec2_transit_gateway_vpc_attachment_accepter_test.go +++ b/aws/resource_aws_ec2_transit_gateway_vpc_attachment_accepter_test.go @@ -195,6 +195,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_ec2_transit_gateway" "test" { diff --git a/aws/resource_aws_ec2_transit_gateway_vpc_attachment_test.go b/aws/resource_aws_ec2_transit_gateway_vpc_attachment_test.go index fcce2d89056..b7bea1599a8 100644 --- a/aws/resource_aws_ec2_transit_gateway_vpc_attachment_test.go +++ b/aws/resource_aws_ec2_transit_gateway_vpc_attachment_test.go @@ -547,6 +547,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -583,6 +588,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -620,6 +630,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -659,6 +674,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_organizations_organization" "test" {} @@ -721,6 +741,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -759,6 +784,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -797,6 +827,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -837,6 +872,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -878,6 +918,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -919,6 +964,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -956,6 +1006,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/resource_aws_ecs_capacity_provider_test.go b/aws/resource_aws_ecs_capacity_provider_test.go index 0c8aaa1f6a2..f31b9a331f3 100644 --- a/aws/resource_aws_ecs_capacity_provider_test.go +++ b/aws/resource_aws_ecs_capacity_provider_test.go @@ -210,7 +210,14 @@ data "aws_ami" "test" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_launch_template" "test" { image_id = data.aws_ami.test.id diff --git a/aws/resource_aws_ecs_service_test.go b/aws/resource_aws_ecs_service_test.go index 53f43dc934a..6e2c2222ffe 100644 --- a/aws/resource_aws_ecs_service_test.go +++ b/aws/resource_aws_ecs_service_test.go @@ -1519,7 +1519,14 @@ resource "aws_ecs_service" "mongo" { func testAccAWSEcsServiceWithPlacementConstraint(clusterName, tdName, svcName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ecs_cluster" "default" { name = "%s" @@ -1592,7 +1599,14 @@ resource "aws_ecs_service" "mongo" { func testAccAWSEcsServiceWithLaunchTypeFargate(sg1Name, sg2Name, clusterName, tdName, svcName, assignPublicIP string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "main" { cidr_block = "10.10.0.0/16" @@ -1682,7 +1696,14 @@ resource "aws_ecs_service" "main" { func testAccAWSEcsServiceWithLaunchTypeFargateAndPlatformVersion(sg1Name, sg2Name, clusterName, tdName, svcName, platformVersion string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "main" { cidr_block = "10.10.0.0/16" @@ -1774,7 +1795,14 @@ resource "aws_ecs_service" "main" { func testAccAWSEcsService_healthCheckGracePeriodSeconds(vpcNameTag, clusterName, tdName, roleName, policyName, lbName, svcName string, healthCheckGracePeriodSeconds int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "main" { cidr_block = "10.10.0.0/16" @@ -1914,7 +1942,14 @@ resource "aws_ecs_service" "with_alb" { func testAccAWSEcsService_withIamRole(clusterName, tdName, roleName, policyName, svcName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +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" @@ -2069,7 +2104,14 @@ func tpl_testAccAWSEcsService_withLbChanges(clusterName, tdName, image, containerName string, containerPort, hostPort int, roleName, policyName string, instancePort int, svcName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +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" @@ -2325,7 +2367,14 @@ resource "aws_ecs_service" "jenkins" { func testAccAWSEcsServiceWithAlb(clusterName, tdName, roleName, policyName, lbName, svcName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "main" { cidr_block = "10.10.0.0/16" @@ -2463,7 +2512,14 @@ resource "aws_ecs_service" "with_alb" { func testAccAWSEcsServiceWithMultipleTargetGroups(clusterName, tdName, lbName, svcName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "main" { cidr_block = "10.10.0.0/16" @@ -2596,7 +2652,14 @@ func testAccAWSEcsServiceWithNetworkConfiguration_modified(sg1Name, sg2Name, clu func tpl_testAccAWSEcsServiceWithNetworkConfiguration(sg1Name, sg2Name, clusterName, tdName, svcName string, securityGroups string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "main" { cidr_block = "10.10.0.0/16" @@ -2676,7 +2739,14 @@ resource "aws_ecs_service" "main" { func testAccAWSEcsService_withServiceRegistries(rName, clusterName, tdName, svcName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "test" {} +data "aws_availability_zones" "test" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" @@ -2770,7 +2840,14 @@ resource "aws_ecs_service" "test" { func testAccAWSEcsService_withServiceRegistries_container(rName, clusterName, tdName, svcName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "test" {} +data "aws_availability_zones" "test" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" @@ -2930,7 +3007,14 @@ resource "aws_ecs_service" "ghost" { func testAccAWSEcsServiceConfigDeploymentControllerTypeCodeDeploy(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +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" diff --git a/aws/resource_aws_eip_association_test.go b/aws/resource_aws_eip_association_test.go index ae6a795d6aa..38a12ac0686 100644 --- a/aws/resource_aws_eip_association_test.go +++ b/aws/resource_aws_eip_association_test.go @@ -283,7 +283,12 @@ func testAccCheckAWSEIPAssociationDestroy(s *terraform.State) error { const testAccAWSEIPAssociationConfig = ` data "aws_availability_zones" "available" { - state = "available" + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -353,7 +358,12 @@ resource "aws_network_interface" "test" { const testAccAWSEIPAssociationConfigDisappears = ` data "aws_availability_zones" "available" { - state = "available" + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_ami" "amzn-ami-minimal-pv" { @@ -405,7 +415,12 @@ provider "aws" { resource "aws_eip" "test" {} data "aws_availability_zones" "available" { - state = "available" + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_ami" "ubuntu" { diff --git a/aws/resource_aws_eip_test.go b/aws/resource_aws_eip_test.go index 3cd06a1090c..7080eceafe5 100644 --- a/aws/resource_aws_eip_test.go +++ b/aws/resource_aws_eip_test.go @@ -903,7 +903,12 @@ resource "aws_eip" "test" { const testAccAWSEIPNetworkInterfaceConfig = ` data "aws_availability_zones" "available" { - state = "available" + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -942,6 +947,11 @@ resource "aws_eip" "test" { const testAccAWSEIPMultiNetworkInterfaceConfig = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/resource_aws_eks_cluster_test.go b/aws/resource_aws_eks_cluster_test.go index 80c1e8d8e40..521a1857fde 100644 --- a/aws/resource_aws_eks_cluster_test.go +++ b/aws/resource_aws_eks_cluster_test.go @@ -518,7 +518,14 @@ func testAccPreCheckAWSEks(t *testing.T) { func testAccAWSEksClusterConfig_Base(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_iam_role" "test" { name = "%s" diff --git a/aws/resource_aws_eks_fargate_profile_test.go b/aws/resource_aws_eks_fargate_profile_test.go index 50617362970..342cf3acb7d 100644 --- a/aws/resource_aws_eks_fargate_profile_test.go +++ b/aws/resource_aws_eks_fargate_profile_test.go @@ -348,6 +348,11 @@ func testAccAWSEksFargateProfileConfigBase(rName string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_partition" "current" {} diff --git a/aws/resource_aws_eks_node_group_test.go b/aws/resource_aws_eks_node_group_test.go index 4c77c3d1805..28bfdf51a2b 100644 --- a/aws/resource_aws_eks_node_group_test.go +++ b/aws/resource_aws_eks_node_group_test.go @@ -641,6 +641,11 @@ func testAccAWSEksNodeGroupConfigBase(rName string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_partition" "current" {} diff --git a/aws/resource_aws_elastic_beanstalk_environment_test.go b/aws/resource_aws_elastic_beanstalk_environment_test.go index 8c30d5acbe6..01fa5d8fa1e 100644 --- a/aws/resource_aws_elastic_beanstalk_environment_test.go +++ b/aws/resource_aws_elastic_beanstalk_environment_test.go @@ -762,6 +762,11 @@ data "aws_availability_zones" "available" { # after waiting upwards of one hour to initialize the Auto Scaling Group. blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_elastic_beanstalk_solution_stack" "test" { diff --git a/aws/resource_aws_elasticache_cluster_test.go b/aws/resource_aws_elasticache_cluster_test.go index 20fa0ca9afc..f72b0b5c6ee 100644 --- a/aws/resource_aws_elasticache_cluster_test.go +++ b/aws/resource_aws_elasticache_cluster_test.go @@ -993,7 +993,14 @@ func testAccAWSElasticacheClusterConfig_NumCacheNodesWithPreferredAvailabilityZo } return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_elasticache_cluster" "test" { apply_immediately = true @@ -1008,7 +1015,12 @@ resource "aws_elasticache_cluster" "test" { var testAccAWSElasticacheClusterInVPCConfig = fmt.Sprintf(` data "aws_availability_zones" "available" { - state = "available" + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -1069,7 +1081,12 @@ resource "aws_sns_topic" "test" { var testAccAWSElasticacheClusterMultiAZInVPCConfig = fmt.Sprintf(` data "aws_availability_zones" "available" { - state = "available" + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -1266,7 +1283,14 @@ resource "aws_elasticache_cluster" "test" { func testAccAWSElasticacheClusterConfig_ReplicationGroupID_AvailabilityZone(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_elasticache_replication_group" "test" { replication_group_description = "Terraform Acceptance Testing" diff --git a/aws/resource_aws_elasticache_replication_group_test.go b/aws/resource_aws_elasticache_replication_group_test.go index 4e6f978991b..c434043cac6 100644 --- a/aws/resource_aws_elasticache_replication_group_test.go +++ b/aws/resource_aws_elasticache_replication_group_test.go @@ -851,6 +851,11 @@ func testAccAWSElasticacheReplicationGroupConfig_Uppercase(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" { @@ -980,6 +985,11 @@ resource "aws_elasticache_replication_group" "test" { var testAccAWSElasticacheReplicationGroupInVPCConfig = fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -1032,6 +1042,11 @@ resource "aws_elasticache_replication_group" "test" { var testAccAWSElasticacheReplicationGroupMultiAZInVPCConfig = 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 = "192.168.0.0/16" @@ -1091,10 +1106,15 @@ resource "aws_elasticache_replication_group" "test" { var testAccAWSElasticacheReplicationGroupRedisClusterInVPCConfig = fmt.Sprintf(` data "aws_availability_zones" "available" { - # InvalidParameterValue: Specified node type cache.m3.medium is not available in AZ us-east-1b. - blacklisted_zone_ids = ["use1-az1"] - state = "available" + # InvalidParameterValue: Specified node type cache.m3.medium is not available in AZ us-east-1b. + blacklisted_zone_ids = ["use1-az1"] + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] } +} resource "aws_vpc" "test" { cidr_block = "192.168.0.0/16" tags = { @@ -1157,6 +1177,11 @@ func testAccAWSElasticacheReplicationGroupNativeRedisClusterErrorConfig(rInt int return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -1233,6 +1258,11 @@ func testAccAWSElasticacheReplicationGroupNativeRedisClusterConfig(rName 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" { @@ -1307,6 +1337,11 @@ func testAccAWSElasticacheReplicationGroup_UseCmkKmsKeyId(rInt int, rString stri return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "foo" { @@ -1374,6 +1409,11 @@ func testAccAWSElasticacheReplicationGroup_EnableAtRestEncryptionConfig(rInt int return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -1436,6 +1476,11 @@ func testAccAWSElasticacheReplicationGroup_EnableAuthTokenTransitEncryptionConfi return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -1501,6 +1546,11 @@ data "aws_availability_zones" "available" { # InvalidParameterValue: Specified node type cache.m3.medium is not available in AZ us-east-1b. blacklisted_zone_ids = ["use1-az1"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/resource_aws_elasticsearch_domain_test.go b/aws/resource_aws_elasticsearch_domain_test.go index d884734879e..20e61c413c6 100644 --- a/aws/resource_aws_elasticsearch_domain_test.go +++ b/aws/resource_aws_elasticsearch_domain_test.go @@ -1375,6 +1375,11 @@ func testAccESDomainConfig_vpc(randInt int) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "elasticsearch_in_vpc" { @@ -1448,6 +1453,11 @@ func testAccESDomainConfig_vpc_update(randInt int, update bool) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "elasticsearch_in_vpc" { @@ -1532,6 +1542,11 @@ func testAccESDomainConfig_internetToVpcEndpoint(randInt int) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "elasticsearch_in_vpc" { diff --git a/aws/resource_aws_elb_test.go b/aws/resource_aws_elb_test.go index 23798e1e516..d8aa1bcdb85 100644 --- a/aws/resource_aws_elb_test.go +++ b/aws/resource_aws_elb_test.go @@ -1107,6 +1107,11 @@ func testAccCheckAWSELBExists(n string, res *elb.LoadBalancerDescription) resour const testAccAWSELBConfig = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1127,6 +1132,11 @@ func testAccAWSELBConfigTags1(tagKey1, tagValue1 string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1152,6 +1162,11 @@ func testAccAWSELBConfigTags2(tagKey1, tagValue1, tagKey2, tagValue2 string) str return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1177,6 +1192,11 @@ resource "aws_elb" "test" { const testAccAWSELBFullRangeOfCharacters = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1195,6 +1215,11 @@ resource "aws_elb" "test" { const testAccAWSELBAccessLogs = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1229,6 +1254,11 @@ resource "aws_elb" "test" { data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } ` + testAccAWSELBAccessLogsCommon(r) } @@ -1254,6 +1284,11 @@ resource "aws_elb" "test" { data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } ` + testAccAWSELBAccessLogsCommon(r) } @@ -1293,6 +1328,11 @@ EOF const testAccAWSELB_namePrefix = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1311,6 +1351,11 @@ resource "aws_elb" "test" { const testAccAWSELBGeneratedName = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1328,6 +1373,11 @@ resource "aws_elb" "test" { const testAccAWSELB_zeroValueName = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1351,6 +1401,11 @@ output "lb_name" { const testAccAWSELBConfig_AvailabilityZonesUpdate = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1383,6 +1438,11 @@ data "aws_ami" "amzn-ami-minimal-hvm-ebs" { data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1407,6 +1467,11 @@ resource "aws_instance" "test" { const testAccAWSELBConfigHealthCheck = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1432,6 +1497,11 @@ resource "aws_elb" "test" { const testAccAWSELBConfigHealthCheck_update = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1457,6 +1527,11 @@ resource "aws_elb" "test" { const testAccAWSELBConfigListener_update = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1474,6 +1549,11 @@ resource "aws_elb" "test" { const testAccAWSELBConfigListener_multipleListeners = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1498,6 +1578,11 @@ resource "aws_elb" "test" { const testAccAWSELBConfigIdleTimeout = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1517,6 +1602,11 @@ resource "aws_elb" "test" { const testAccAWSELBConfigIdleTimeout_update = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1536,6 +1626,11 @@ resource "aws_elb" "test" { const testAccAWSELBConfigConnectionDraining = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1556,6 +1651,11 @@ resource "aws_elb" "test" { const testAccAWSELBConfigConnectionDraining_update_timeout = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1576,6 +1676,11 @@ resource "aws_elb" "test" { const testAccAWSELBConfigConnectionDraining_update_disable = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1595,6 +1700,11 @@ resource "aws_elb" "test" { const testAccAWSELBConfigSecurityGroups = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_elb" "test" { @@ -1626,7 +1736,14 @@ resource "aws_security_group" "test" { func testAccELBConfig_Listener_IAMServerCertificate(certName, certificate, key, lbProtocol string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_iam_server_certificate" "test_cert" { name = "%[1]s" @@ -1650,7 +1767,14 @@ resource "aws_elb" "test" { func testAccELBConfig_Listener_IAMServerCertificate_AddInvalidListener(certName, certificate, key string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_iam_server_certificate" "test_cert" { name = "%[1]s" @@ -1684,6 +1808,11 @@ resource "aws_elb" "test" { const testAccAWSELBConfig_subnets = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "azelb" { @@ -1755,6 +1884,11 @@ resource "aws_internet_gateway" "gw" { const testAccAWSELBConfig_subnet_swap = ` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "azelb" { diff --git a/aws/resource_aws_emr_instance_group_test.go b/aws/resource_aws_emr_instance_group_test.go index 7de2a8a3371..a8a71e8a8cb 100644 --- a/aws/resource_aws_emr_instance_group_test.go +++ b/aws/resource_aws_emr_instance_group_test.go @@ -346,6 +346,11 @@ data "aws_availability_zones" "available" { # Many instance types are not available in this availability zone blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_partition" "current" {} diff --git a/aws/resource_aws_fsx_lustre_file_system_test.go b/aws/resource_aws_fsx_lustre_file_system_test.go index 335e9432095..6cdbc5ecd65 100644 --- a/aws/resource_aws_fsx_lustre_file_system_test.go +++ b/aws/resource_aws_fsx_lustre_file_system_test.go @@ -474,6 +474,11 @@ func testAccAwsFsxLustreFileSystemConfigBase() 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" { diff --git a/aws/resource_aws_fsx_windows_file_system_test.go b/aws/resource_aws_fsx_windows_file_system_test.go index 3562f2881d4..f055f83f8d7 100644 --- a/aws/resource_aws_fsx_windows_file_system_test.go +++ b/aws/resource_aws_fsx_windows_file_system_test.go @@ -614,6 +614,11 @@ func testAccAwsFsxWindowsFileSystemConfigBase() 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" { diff --git a/aws/resource_aws_glue_connection_test.go b/aws/resource_aws_glue_connection_test.go index 3746498c0a5..8e31285c107 100644 --- a/aws/resource_aws_glue_connection_test.go +++ b/aws/resource_aws_glue_connection_test.go @@ -343,7 +343,14 @@ resource "aws_glue_connection" "test" { func testAccAWSGlueConnectionConfig_PhysicalConnectionRequirements(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +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" diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index 952ae4c8e96..52132794240 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -2736,6 +2736,12 @@ func testAccInstanceConfigInDefaultVpcBySgName(rName string) string { data "aws_availability_zones" "current" { # Exclude usw2-az4 (us-west-2d) as it has limited instance types. blacklisted_zone_ids = ["usw2-az4"] + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_vpc" "default" { @@ -2762,6 +2768,12 @@ func testAccInstanceConfigInDefaultVpcBySgId(rName string) string { data "aws_availability_zones" "current" { # Exclude usw2-az4 (us-west-2d) as it has limited instance types. blacklisted_zone_ids = ["usw2-az4"] + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_vpc" "default" { @@ -4123,6 +4135,12 @@ func testAccAwsInstanceVpcConfig(rName string, mapPublicIpOnLaunch bool) string data "aws_availability_zones" "current" { # Exclude usw2-az4 (us-west-2d) as it has limited instance types. blacklisted_zone_ids = ["usw2-az4"] + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { @@ -4188,6 +4206,12 @@ func testAccAwsInstanceVpcIpv6Config(rName string) string { data "aws_availability_zones" "current" { # Exclude usw2-az4 (us-west-2d) as it has limited instance types. blacklisted_zone_ids = ["usw2-az4"] + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/resource_aws_launch_template_test.go b/aws/resource_aws_launch_template_test.go index 109fc6813a8..ebd3b765f56 100644 --- a/aws/resource_aws_launch_template_test.go +++ b/aws/resource_aws_launch_template_test.go @@ -949,7 +949,14 @@ data "aws_ami" "test" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_launch_template" "test" { image_id = "${data.aws_ami.test.id}" @@ -999,7 +1006,14 @@ data "aws_ami" "test" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_launch_template" "test" { image_id = "${data.aws_ami.test.id}" @@ -1143,7 +1157,14 @@ resource "aws_launch_template" "test" { func testAccAWSLaunchTemplateConfig_capacityReservation_target(rInt int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ec2_capacity_reservation" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" @@ -1335,7 +1356,14 @@ resource "aws_launch_template" "test" { instance_type = "t2.micro" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_autoscaling_group" "bar" { availability_zones = ["${data.aws_availability_zones.available.names[0]}"] @@ -1366,7 +1394,14 @@ resource "aws_launch_template" "test" { instance_type = "t2.nano" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_autoscaling_group" "bar" { availability_zones = ["${data.aws_availability_zones.available.names[0]}"] @@ -1404,7 +1439,14 @@ resource "aws_launch_template" "test" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_autoscaling_group" "test" { availability_zones = ["${data.aws_availability_zones.available.names[0]}"] @@ -1444,7 +1486,14 @@ resource "aws_launch_template" "test" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_autoscaling_group" "test" { availability_zones = ["${data.aws_availability_zones.available.names[0]}"] diff --git a/aws/resource_aws_lb_listener_certificate_test.go b/aws/resource_aws_lb_listener_certificate_test.go index 89848cc0114..90473f16098 100644 --- a/aws/resource_aws_lb_listener_certificate_test.go +++ b/aws/resource_aws_lb_listener_certificate_test.go @@ -162,7 +162,14 @@ func testAccCheckAwsLbListenerCertificateNotExists(name string) resource.TestChe func testAccLbListenerCertificateConfigLbListenerBase(rName, key, certificate string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +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" diff --git a/aws/resource_aws_lb_listener_rule_test.go b/aws/resource_aws_lb_listener_rule_test.go index f0d5dc0e52b..cc5fc7dde20 100644 --- a/aws/resource_aws_lb_listener_rule_test.go +++ b/aws/resource_aws_lb_listener_rule_test.go @@ -1326,7 +1326,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1439,7 +1446,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1552,7 +1566,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1657,7 +1678,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1762,7 +1790,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1875,7 +1910,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1999,7 +2041,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -2097,7 +2146,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -2381,7 +2437,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -2540,7 +2603,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -2594,7 +2664,14 @@ variable "rName" { default = %[1]q } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_lb_listener_rule" "test" { listener_arn = "${aws_lb_listener.test.arn}" @@ -2879,7 +2956,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" diff --git a/aws/resource_aws_lb_listener_test.go b/aws/resource_aws_lb_listener_test.go index 2bc2ca19c4d..d711bcd586a 100644 --- a/aws/resource_aws_lb_listener_test.go +++ b/aws/resource_aws_lb_listener_test.go @@ -500,7 +500,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -592,7 +599,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -674,7 +688,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -776,7 +797,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -840,7 +868,14 @@ resource "aws_iam_server_certificate" "test_cert" { func testAccAWSLBListenerConfig_Protocol_Tls(rName, key, certificate string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_acm_certificate" "test" { certificate_body = "%[2]s" @@ -949,7 +984,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1034,7 +1076,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1115,7 +1164,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +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" @@ -1242,7 +1298,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +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" @@ -1324,7 +1387,14 @@ variable "rName" { default = %[1]q } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_lb_listener" "test" { load_balancer_arn = "${aws_lb.test.id}" diff --git a/aws/resource_aws_lb_ssl_negotiation_policy_test.go b/aws/resource_aws_lb_ssl_negotiation_policy_test.go index ca8079aa07f..31f4b658e22 100644 --- a/aws/resource_aws_lb_ssl_negotiation_policy_test.go +++ b/aws/resource_aws_lb_ssl_negotiation_policy_test.go @@ -186,6 +186,11 @@ func testAccSslNegotiationPolicyConfig(rName, key, certificate string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_iam_server_certificate" "test" { diff --git a/aws/resource_aws_lb_target_group_attachment_test.go b/aws/resource_aws_lb_target_group_attachment_test.go index 9d0bb230591..4a6ffa861e7 100644 --- a/aws/resource_aws_lb_target_group_attachment_test.go +++ b/aws/resource_aws_lb_target_group_attachment_test.go @@ -243,6 +243,11 @@ data "aws_availability_zones" "available" { # t2.micro instance type is not available in these Availability Zones blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_ami" "amzn-ami-minimal-hvm-ebs" { diff --git a/aws/resource_aws_lb_test.go b/aws/resource_aws_lb_test.go index 82e82eabfb4..f1facebb960 100644 --- a/aws/resource_aws_lb_test.go +++ b/aws/resource_aws_lb_test.go @@ -1309,7 +1309,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1380,7 +1387,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1451,7 +1465,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1520,7 +1541,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1672,7 +1700,14 @@ resource "aws_subnet" "alb_test" { func testAccAWSLBConfig_networkLoadBalancerEIP(lbName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "main" { cidr_block = "10.10.0.0/16" @@ -1756,7 +1791,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1825,7 +1867,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1893,7 +1942,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -1974,7 +2030,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -2050,7 +2113,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -2118,7 +2188,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -2168,7 +2245,14 @@ resource "aws_security_group" "alb_test" { func testAccAWSLBConfigALBAccessLogsBase(bucketName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_elb_service_account" "current" {} @@ -2245,7 +2329,14 @@ resource "aws_lb" "test" { func testAccAWSLBConfigNLBAccessLogsBase(bucketName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_elb_service_account" "current" {} @@ -2353,7 +2444,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" @@ -2398,7 +2496,14 @@ variable "subnets" { type = "list" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" diff --git a/aws/resource_aws_lightsail_instance_test.go b/aws/resource_aws_lightsail_instance_test.go index 5c4b9b687eb..50d137dd9c9 100644 --- a/aws/resource_aws_lightsail_instance_test.go +++ b/aws/resource_aws_lightsail_instance_test.go @@ -296,6 +296,11 @@ func testAccAWSLightsailInstanceConfig_basic(lightsailName string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_lightsail_instance" "lightsail_instance_test" { @@ -311,6 +316,11 @@ func testAccAWSLightsailInstanceConfig_tags1(lightsailName string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_lightsail_instance" "lightsail_instance_test" { @@ -329,6 +339,11 @@ func testAccAWSLightsailInstanceConfig_tags2(lightsailName string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_lightsail_instance" "lightsail_instance_test" { diff --git a/aws/resource_aws_lightsail_static_ip_attachment_test.go b/aws/resource_aws_lightsail_static_ip_attachment_test.go index 748cd540e41..731c310ca5f 100644 --- a/aws/resource_aws_lightsail_static_ip_attachment_test.go +++ b/aws/resource_aws_lightsail_static_ip_attachment_test.go @@ -138,6 +138,11 @@ func testAccAWSLightsailStaticIpAttachmentConfig_basic(staticIpName, instanceNam return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_lightsail_static_ip_attachment" "test" { diff --git a/aws/resource_aws_load_balancer_backend_server_policy_test.go b/aws/resource_aws_load_balancer_backend_server_policy_test.go index 4bca3f03432..51e9f40c3ea 100644 --- a/aws/resource_aws_load_balancer_backend_server_policy_test.go +++ b/aws/resource_aws_load_balancer_backend_server_policy_test.go @@ -144,6 +144,11 @@ func testAccAWSLoadBalancerBackendServerPolicyConfig_basic0(rName, privateKey, p return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_iam_server_certificate" "test-iam-cert0" { @@ -206,6 +211,11 @@ func testAccAWSLoadBalancerBackendServerPolicyConfig_basic1(rName, privateKey1, return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_iam_server_certificate" "test-iam-cert0" { @@ -279,6 +289,11 @@ func testAccAWSLoadBalancerBackendServerPolicyConfig_basic2(rName, privateKey, c return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_iam_server_certificate" "test-iam-cert0" { diff --git a/aws/resource_aws_mq_broker_test.go b/aws/resource_aws_mq_broker_test.go index f904e01995e..0554e7e025e 100644 --- a/aws/resource_aws_mq_broker_test.go +++ b/aws/resource_aws_mq_broker_test.go @@ -845,7 +845,14 @@ resource "aws_mq_broker" "test" { func testAccMqBrokerConfig_allFieldsCustomVpc(sgName, cfgName, cfgBody, brokerName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "main" { cidr_block = "10.11.0.0/16" diff --git a/aws/resource_aws_msk_cluster_test.go b/aws/resource_aws_msk_cluster_test.go index 5cfacf4a664..b837e6bb404 100644 --- a/aws/resource_aws_msk_cluster_test.go +++ b/aws/resource_aws_msk_cluster_test.go @@ -625,6 +625,11 @@ resource "aws_vpc" "example_vpc" { data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_subnet" "example_subnet_az1" { diff --git a/aws/resource_aws_neptune_cluster_instance_test.go b/aws/resource_aws_neptune_cluster_instance_test.go index b54c2bd5e55..0e913a1ce31 100644 --- a/aws/resource_aws_neptune_cluster_instance_test.go +++ b/aws/resource_aws_neptune_cluster_instance_test.go @@ -281,7 +281,14 @@ resource "aws_neptune_parameter_group" "bar" { func testAccAWSNeptuneClusterInstanceConfig_az(n int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_neptune_cluster" "default" { cluster_identifier = "tf-neptune-cluster-test-%d" diff --git a/aws/resource_aws_neptune_cluster_test.go b/aws/resource_aws_neptune_cluster_test.go index ef19fd7aca3..157afb991a1 100644 --- a/aws/resource_aws_neptune_cluster_test.go +++ b/aws/resource_aws_neptune_cluster_test.go @@ -572,6 +572,11 @@ func testAccCheckAWSNeptuneClusterSnapshot(rName string) resource.TestCheckFunc var testAccAWSNeptuneClusterConfigBase = ` data "aws_availability_zones" "test" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } ` diff --git a/aws/resource_aws_network_interface_sg_attachment_test.go b/aws/resource_aws_network_interface_sg_attachment_test.go index 93fbc71981e..33f050da593 100644 --- a/aws/resource_aws_network_interface_sg_attachment_test.go +++ b/aws/resource_aws_network_interface_sg_attachment_test.go @@ -335,7 +335,14 @@ resource "aws_network_interface_sg_attachment" "test" { func testAccAwsNetworkInterfaceSGAttachmentConfigMultiple(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_subnet" "test" { availability_zone = "${data.aws_availability_zones.available.names[0]}" diff --git a/aws/resource_aws_rds_cluster_instance_test.go b/aws/resource_aws_rds_cluster_instance_test.go index ea4e527ba27..8b12fa9826a 100644 --- a/aws/resource_aws_rds_cluster_instance_test.go +++ b/aws/resource_aws_rds_cluster_instance_test.go @@ -955,7 +955,14 @@ resource "aws_db_parameter_group" "bar" { func testAccAWSClusterInstanceConfig_az(n int) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_rds_cluster" "default" { cluster_identifier = "tf-aurora-cluster-test-%d" diff --git a/aws/resource_aws_rds_cluster_test.go b/aws/resource_aws_rds_cluster_test.go index 8b24ddd5f3f..719c06969d5 100644 --- a/aws/resource_aws_rds_cluster_test.go +++ b/aws/resource_aws_rds_cluster_test.go @@ -2123,6 +2123,11 @@ func testAccAWSClusterConfig_AvailabilityZones(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_rds_cluster" "test" { @@ -2164,6 +2169,11 @@ func testAccAWSClusterConfig_DbSubnetGroupName(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_rds_cluster" "test" { @@ -2213,6 +2223,11 @@ func testAccAWSClusterConfig_s3Restore(bucketName string, bucketPrefix string, u return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_region" "current" {} @@ -2799,6 +2814,13 @@ func testAccAWSClusterConfigEncryptedCrossRegionReplica(n int) string { return testAccAlternateRegionProviderConfig() + fmt.Sprintf(` data "aws_availability_zones" "alternate" { provider = "aws.alternate" + + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } data "aws_caller_identity" "current" {} @@ -2935,6 +2957,11 @@ func testAccAWSRDSClusterConfig_EngineMode_Multimaster(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" { diff --git a/aws/resource_aws_route53_resolver_endpoint_test.go b/aws/resource_aws_route53_resolver_endpoint_test.go index 865c6161f9c..71506f58a92 100644 --- a/aws/resource_aws_route53_resolver_endpoint_test.go +++ b/aws/resource_aws_route53_resolver_endpoint_test.go @@ -221,7 +221,14 @@ resource "aws_vpc" "foo" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "sn1" { vpc_id = "${aws_vpc.foo.id}" diff --git a/aws/resource_aws_route53_resolver_rule_test.go b/aws/resource_aws_route53_resolver_rule_test.go index c1e37b17501..e6cb3e69d94 100644 --- a/aws/resource_aws_route53_resolver_rule_test.go +++ b/aws/resource_aws_route53_resolver_rule_test.go @@ -507,7 +507,14 @@ resource "aws_vpc" "foo" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "sn1" { vpc_id = "${aws_vpc.foo.id}" diff --git a/aws/resource_aws_route_table_test.go b/aws/resource_aws_route_table_test.go index 327774f58bc..8dccbc81c18 100644 --- a/aws/resource_aws_route_table_test.go +++ b/aws/resource_aws_route_table_test.go @@ -854,6 +854,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/resource_aws_route_test.go b/aws/resource_aws_route_test.go index 294fc4a72c5..8edd0395213 100644 --- a/aws/resource_aws_route_test.go +++ b/aws/resource_aws_route_test.go @@ -548,7 +548,14 @@ resource "aws_vpc" "examplevpc" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_internet_gateway" "internet" { vpc_id = "${aws_vpc.examplevpc.id}" @@ -657,7 +664,14 @@ resource "aws_vpc" "examplevpc" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_internet_gateway" "internet" { vpc_id = "${aws_vpc.examplevpc.id}" @@ -959,6 +973,11 @@ data "aws_availability_zones" "available" { # IncorrectState: Transit Gateway is not available in availability zone us-west-2d blacklisted_zone_ids = ["usw2-az4"] state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/resource_aws_shield_protection_test.go b/aws/resource_aws_shield_protection_test.go index 1519d599827..0d1b4245596 100644 --- a/aws/resource_aws_shield_protection_test.go +++ b/aws/resource_aws_shield_protection_test.go @@ -261,7 +261,14 @@ resource "aws_shield_protection" "acctest" { func testAccShieldProtectionElbConfig(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} variable "subnets" { default = ["10.0.1.0/24", "10.0.2.0/24"] @@ -325,7 +332,14 @@ resource "aws_shield_protection" "acctest" { func testAccShieldProtectionAlbConfig(rName string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} variable "subnets" { default = ["10.0.1.0/24", "10.0.2.0/24"] @@ -485,7 +499,14 @@ variable "name" { default = "%s" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_region" "current" {} data "aws_caller_identity" "current" {} diff --git a/aws/resource_aws_snapshot_create_volume_permission_test.go b/aws/resource_aws_snapshot_create_volume_permission_test.go index 126baad8ad1..dda97f48d53 100644 --- a/aws/resource_aws_snapshot_create_volume_permission_test.go +++ b/aws/resource_aws_snapshot_create_volume_permission_test.go @@ -84,7 +84,14 @@ func testAccAWSSnapshotCreateVolumePermissionDestroyed(accountId, snapshotId *st func testAccAWSSnapshotCreateVolumePermissionConfig(includeCreateVolumePermission bool, accountID string) string { base := ` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_ebs_volume" "example" { availability_zone = "${data.aws_availability_zones.available.names[0]}" diff --git a/aws/resource_aws_spot_instance_request_test.go b/aws/resource_aws_spot_instance_request_test.go index 37696a29edf..87bb7a90eac 100644 --- a/aws/resource_aws_spot_instance_request_test.go +++ b/aws/resource_aws_spot_instance_request_test.go @@ -673,8 +673,13 @@ func testAccAWSSpotInstanceRequestConfig_withBlockDuration(rInt int) string { func testAccAWSSpotInstanceRequestConfigVPC(rInt int) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { - blacklisted_zone_ids = ["usw2-az4"] - state = "available" + blacklisted_zone_ids = ["usw2-az4"] + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "foo_VPC" { @@ -724,8 +729,13 @@ tags = { func testAccAWSSpotInstanceRequestConfig_SubnetAndSGAndPublicIpAddress(rInt int) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { - blacklisted_zone_ids = ["usw2-az4"] - state = "available" + blacklisted_zone_ids = ["usw2-az4"] + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_spot_instance_request" "foo" { diff --git a/aws/resource_aws_ssm_association_test.go b/aws/resource_aws_ssm_association_test.go index a9de36d9e94..b4a610e1a58 100644 --- a/aws/resource_aws_ssm_association_test.go +++ b/aws/resource_aws_ssm_association_test.go @@ -779,7 +779,14 @@ variable "name" { default = "%s" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} data "aws_ami" "amzn" { most_recent = true diff --git a/aws/resource_aws_storagegateway_gateway_test.go b/aws/resource_aws_storagegateway_gateway_test.go index df61efc101f..0db6caf5bba 100644 --- a/aws/resource_aws_storagegateway_gateway_test.go +++ b/aws/resource_aws_storagegateway_gateway_test.go @@ -687,6 +687,11 @@ func testAccAWSStorageGatewayGatewayConfig_SmbActiveDirectorySettings(rName stri # Directory Service Directories must be deployed across multiple EC2 Availability Zones data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } resource "aws_vpc" "test" { diff --git a/aws/resource_aws_vpc_endpoint_service_test.go b/aws/resource_aws_vpc_endpoint_service_test.go index 9f122e379e2..a81c265c5aa 100644 --- a/aws/resource_aws_vpc_endpoint_service_test.go +++ b/aws/resource_aws_vpc_endpoint_service_test.go @@ -292,7 +292,14 @@ resource "aws_lb" "test2" { } } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "test1" { vpc_id = "${aws_vpc.test.id}" diff --git a/aws/resource_aws_vpc_endpoint_subnet_association_test.go b/aws/resource_aws_vpc_endpoint_subnet_association_test.go index a68982d0cd6..0e94dee4e39 100644 --- a/aws/resource_aws_vpc_endpoint_subnet_association_test.go +++ b/aws/resource_aws_vpc_endpoint_subnet_association_test.go @@ -140,7 +140,14 @@ data "aws_security_group" "default" { data "aws_region" "current" {} -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc_endpoint" "ec2" { vpc_id = "${aws_vpc.foo.id}" @@ -180,7 +187,14 @@ data "aws_security_group" "default" { data "aws_region" "current" {} -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc_endpoint" "ec2" { vpc_id = "${aws_vpc.foo.id}" diff --git a/aws/resource_aws_vpc_endpoint_test.go b/aws/resource_aws_vpc_endpoint_test.go index de586af56fb..f7e1c9c54ed 100644 --- a/aws/resource_aws_vpc_endpoint_test.go +++ b/aws/resource_aws_vpc_endpoint_test.go @@ -703,7 +703,14 @@ resource "aws_vpc" "test" { data "aws_region" "current" {} -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "test1" { vpc_id = "${aws_vpc.test.id}" @@ -787,7 +794,14 @@ resource "aws_vpc" "test" { data "aws_region" "current" {} -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "test1" { vpc_id = "${aws_vpc.test.id}" @@ -884,7 +898,14 @@ resource "aws_lb" "test" { data "aws_region" "current" {} -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "test1" { vpc_id = "${aws_vpc.test.id}" diff --git a/aws/resource_aws_wafregional_web_acl_association_test.go b/aws/resource_aws_wafregional_web_acl_association_test.go index dbadd952f7f..c2836645abe 100644 --- a/aws/resource_aws_wafregional_web_acl_association_test.go +++ b/aws/resource_aws_wafregional_web_acl_association_test.go @@ -208,7 +208,14 @@ resource "aws_vpc" "foo" { cidr_block = "10.1.0.0/16" } -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_subnet" "foo" { vpc_id = "${aws_vpc.foo.id}" diff --git a/aws/resource_aws_worklink_fleet_test.go b/aws/resource_aws_worklink_fleet_test.go index f293c9548d1..7158dee4997 100644 --- a/aws/resource_aws_worklink_fleet_test.go +++ b/aws/resource_aws_worklink_fleet_test.go @@ -386,7 +386,14 @@ resource "aws_worklink_fleet" "test" { func testAccAWSWorkLinkFleetConfigNetwork_Base(rName, cidrBlock string) string { return fmt.Sprintf(` -data "aws_availability_zones" "available" {} +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_vpc" "test" { cidr_block = "%s" diff --git a/aws/resource_aws_workspaces_directory_test.go b/aws/resource_aws_workspaces_directory_test.go index 162b43141d8..f00fc179691 100644 --- a/aws/resource_aws_workspaces_directory_test.go +++ b/aws/resource_aws_workspaces_directory_test.go @@ -325,6 +325,11 @@ data "aws_region" "current" {} data "aws_availability_zones" "available" { state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } } locals { From 6b755c022d32d19403a13a6faaa4db91363a6edc Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 26 Mar 2020 10:19:08 -0400 Subject: [PATCH 105/684] docs/data-source/aws_launch_template: Add missing tags argument --- website/docs/d/launch_template.html.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/d/launch_template.html.markdown b/website/docs/d/launch_template.html.markdown index c8ce035bea7..b9db24e4111 100644 --- a/website/docs/d/launch_template.html.markdown +++ b/website/docs/d/launch_template.html.markdown @@ -33,8 +33,9 @@ data "aws_launch_template" "test" { The following arguments are supported: -* `name` - (Optional) The name of the launch template. * `filter` - (Optional) Configuration block(s) for filtering. Detailed below. +* `name` - (Optional) The name of the launch template. +* `tags` - (Optional) A mapping of tags, each pair of which must exactly match a pair on the desired Launch Template. ### filter Configuration Block From 4769a9c37b45af837c04142137d31cf110562057 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Thu, 26 Mar 2020 16:37:58 +0200 Subject: [PATCH 106/684] data-source/aws_prefix_list: Add filter argument (#12416) Output from acceptance testing: ``` --- PASS: TestAccDataSourceAwsPrefixList_filter (7.92s) --- PASS: TestAccDataSourceAwsPrefixList_basic (8.05s) ``` --- aws/data_source_aws_prefix_list.go | 7 ++++- aws/data_source_aws_prefix_list_test.go | 34 +++++++++++++++++++++++- website/docs/d/prefix_list.html.markdown | 25 +++++++++++++---- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/aws/data_source_aws_prefix_list.go b/aws/data_source_aws_prefix_list.go index faf1eeee18c..82c8a2ae37f 100644 --- a/aws/data_source_aws_prefix_list.go +++ b/aws/data_source_aws_prefix_list.go @@ -28,6 +28,7 @@ func dataSourceAwsPrefixList() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "filter": dataSourceFiltersSchema(), }, } } @@ -35,8 +36,12 @@ func dataSourceAwsPrefixList() *schema.Resource { func dataSourceAwsPrefixListRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - req := &ec2.DescribePrefixListsInput{} + filters, filtersOk := d.GetOk("filter") + req := &ec2.DescribePrefixListsInput{} + if filtersOk { + req.Filters = buildAwsDataSourceFilters(filters.(*schema.Set)) + } if prefixListID := d.Get("prefix_list_id"); prefixListID != "" { req.PrefixListIds = aws.StringSlice([]string{prefixListID.(string)}) } diff --git a/aws/data_source_aws_prefix_list_test.go b/aws/data_source_aws_prefix_list_test.go index 919fd364add..e74778a01b3 100644 --- a/aws/data_source_aws_prefix_list_test.go +++ b/aws/data_source_aws_prefix_list_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/terraform" ) -func TestAccDataSourceAwsPrefixList(t *testing.T) { +func TestAccDataSourceAwsPrefixList_basic(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -25,6 +25,22 @@ func TestAccDataSourceAwsPrefixList(t *testing.T) { }) } +func TestAccDataSourceAwsPrefixList_filter(t *testing.T) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsPrefixListConfigFilter, + Check: resource.ComposeTestCheckFunc( + testAccDataSourceAwsPrefixListCheck("data.aws_prefix_list.s3_by_id"), + testAccDataSourceAwsPrefixListCheck("data.aws_prefix_list.s3_by_name"), + ), + }, + }, + }) +} + func testAccDataSourceAwsPrefixListCheck(name string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] @@ -66,3 +82,19 @@ data "aws_prefix_list" "s3_by_name" { name = "com.amazonaws.us-west-2.s3" } ` + +const testAccDataSourceAwsPrefixListConfigFilter = ` +data "aws_prefix_list" "s3_by_name" { + filter { + name = "prefix-list-name" + values = ["com.amazonaws.us-west-2.s3"] + } +} + +data "aws_prefix_list" "s3_by_id" { + filter { + name = "prefix-list-id" + values = ["pl-68a54001"] + } +} +` diff --git a/website/docs/d/prefix_list.html.markdown b/website/docs/d/prefix_list.html.markdown index 46631fa3948..0caeb0809e8 100644 --- a/website/docs/d/prefix_list.html.markdown +++ b/website/docs/d/prefix_list.html.markdown @@ -44,6 +44,17 @@ resource "aws_network_acl_rule" "private_s3" { } ``` +### Filter + +```hcl +data "aws_prefix_list" "test" { + filter { + name = "prefix-list-id" + values = ["pl-68a54001"] + } +} +``` + ## Argument Reference The arguments of this data source act as filters for querying the available @@ -51,16 +62,20 @@ prefix lists. The given filters must match exactly one prefix list whose data will be exported as attributes. * `prefix_list_id` - (Optional) The ID of the prefix list to select. - * `name` - (Optional) The name of the prefix list to select. +* `filter` - (Optional) Configuration block(s) for filtering. Detailed below. + +### filter Configuration Block + +The following arguments are supported by the `filter` configuration block: + +* `name` - (Required) The name of the filter field. Valid values can be found in the [EC2 DescribePrefixLists API Reference](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribePrefixLists.html). +* `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. ## Attributes Reference In addition to all arguments above, the following attributes are exported: * `id` - The ID of the selected prefix list. - * `name` - The name of the selected prefix list. - -* `cidr_blocks` - The list of CIDR blocks for the AWS service associated -with the prefix list. +* `cidr_blocks` - The list of CIDR blocks for the AWS service associated with the prefix list. From 24acb01986c2e93467c24050b3077e601d37a75c Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 26 Mar 2020 10:39:47 -0400 Subject: [PATCH 107/684] Update CHANGELOG for #12416 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6c6fdf81b9..47bbfb2fd7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ENHANCEMENTS: * data-source/aws_availability_zone: Add `group_name`, `network_border_group`, and `opt_in_status` attributes [GH-12400] * data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments [GH-12400] * data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] +* data-source/aws_prefix_list: Add `filter` argument [GH-12416] * resource/aws_athena_workgroup: Add `force_destroy` argument [GH-12254] * resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] * resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument [GH-11843] From ad1cf189a3bdc629af742b89b2db8c3d6de7d725 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 26 Mar 2020 10:42:02 -0400 Subject: [PATCH 108/684] Update CHANGELOG for #12403 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47bbfb2fd7c..e82a0905732 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ENHANCEMENTS: * data-source/aws_availability_zone: Add `group_name`, `network_border_group`, and `opt_in_status` attributes [GH-12400] * data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments [GH-12400] * data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] +* data-source/aws_launch_template: Add `filter` and `tags` arguments [GH-12403] * data-source/aws_prefix_list: Add `filter` argument [GH-12416] * resource/aws_athena_workgroup: Add `force_destroy` argument [GH-12254] * resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] From a04a10394bd12f1467d4d0aee4a0a60e40861fc3 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Thu, 26 Mar 2020 16:43:24 +0200 Subject: [PATCH 109/684] data-source/aws_vpc_endpoint_service: Add filter argument (#12404) Output from acceptance testing (test failure is related to an API change that will be fixed separately): ``` --- FAIL: TestAccDataSourceAwsVpcEndpointService_interface (6.32s) --- PASS: TestAccDataSourceAwsVpcEndpointService_gateway (8.68s) --- PASS: TestAccDataSourceAwsVpcEndpointService_custom_filter (200.00s) --- PASS: TestAccDataSourceAwsVpcEndpointService_custom_filter_tags (200.99s) --- PASS: TestAccDataSourceAwsVpcEndpointService_custom (209.48s) ``` --- aws/data_source_aws_vpc_endpoint_service.go | 21 +++-- ...ta_source_aws_vpc_endpoint_service_test.go | 79 ++++++++++++++++++- .../docs/d/vpc_endpoint_service.html.markdown | 22 +++++- 3 files changed, 114 insertions(+), 8 deletions(-) diff --git a/aws/data_source_aws_vpc_endpoint_service.go b/aws/data_source_aws_vpc_endpoint_service.go index 53af9811123..3c749e07ea3 100644 --- a/aws/data_source_aws_vpc_endpoint_service.go +++ b/aws/data_source_aws_vpc_endpoint_service.go @@ -69,6 +69,7 @@ func dataSourceAwsVpcEndpointService() *schema.Resource { Type: schema.TypeBool, Computed: true, }, + "filter": dataSourceFiltersSchema(), }, } } @@ -76,18 +77,28 @@ func dataSourceAwsVpcEndpointService() *schema.Resource { func dataSourceAwsVpcEndpointServiceRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn + filters, filtersOk := d.GetOk("filter") + tags, tagsOk := d.GetOk("tags") + var serviceName string + serviceNameOk := false if v, ok := d.GetOk("service_name"); ok { serviceName = v.(string) + serviceNameOk = true } else if v, ok := d.GetOk("service"); ok { serviceName = fmt.Sprintf("com.amazonaws.%s.%s", meta.(*AWSClient).region, v.(string)) - } else { - return fmt.Errorf( - "One of ['service', 'service_name'] must be set to query VPC Endpoint Services") + serviceNameOk = true } - req := &ec2.DescribeVpcEndpointServicesInput{ - ServiceNames: aws.StringSlice([]string{serviceName}), + req := &ec2.DescribeVpcEndpointServicesInput{} + if filtersOk { + req.Filters = buildAwsDataSourceFilters(filters.(*schema.Set)) + } + if serviceNameOk { + req.ServiceNames = aws.StringSlice([]string{serviceName}) + } + if tagsOk { + req.Filters = append(req.Filters, ec2TagFiltersFromMap(tags.(map[string]interface{}))...) } log.Printf("[DEBUG] Reading VPC Endpoint Service: %s", req) diff --git a/aws/data_source_aws_vpc_endpoint_service_test.go b/aws/data_source_aws_vpc_endpoint_service_test.go index 6c2f9553bf4..140e6adcc44 100644 --- a/aws/data_source_aws_vpc_endpoint_service_test.go +++ b/aws/data_source_aws_vpc_endpoint_service_test.go @@ -86,6 +86,56 @@ func TestAccDataSourceAwsVpcEndpointService_custom(t *testing.T) { }) } +func TestAccDataSourceAwsVpcEndpointService_custom_filter(t *testing.T) { + datasourceName := "data.aws_vpc_endpoint_service.test" + rName := fmt.Sprintf("tf-testacc-vpcesvc-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsVpcEndpointServiceCustomConfigFilter(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(datasourceName, "acceptance_required", "true"), + resource.TestCheckResourceAttr(datasourceName, "availability_zones.#", "2"), + resource.TestCheckResourceAttr(datasourceName, "manages_vpc_endpoints", "false"), + testAccCheckResourceAttrAccountID(datasourceName, "owner"), + resource.TestCheckResourceAttr(datasourceName, "service_type", "Interface"), + resource.TestCheckResourceAttr(datasourceName, "vpc_endpoint_policy_supported", "false"), + resource.TestCheckResourceAttr(datasourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(datasourceName, "tags.Name", rName), + ), + }, + }, + }) +} + +func TestAccDataSourceAwsVpcEndpointService_custom_filter_tags(t *testing.T) { + datasourceName := "data.aws_vpc_endpoint_service.test" + rName := fmt.Sprintf("tf-testacc-vpcesvc-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsVpcEndpointServiceCustomConfigFilterTags(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(datasourceName, "acceptance_required", "true"), + resource.TestCheckResourceAttr(datasourceName, "availability_zones.#", "2"), + resource.TestCheckResourceAttr(datasourceName, "manages_vpc_endpoints", "false"), + testAccCheckResourceAttrAccountID(datasourceName, "owner"), + resource.TestCheckResourceAttr(datasourceName, "service_type", "Interface"), + resource.TestCheckResourceAttr(datasourceName, "vpc_endpoint_policy_supported", "false"), + resource.TestCheckResourceAttr(datasourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(datasourceName, "tags.Name", rName), + ), + }, + }, + }) +} + const testAccDataSourceAwsVpcEndpointServiceGatewayConfig = ` data "aws_availability_zones" "available" {} @@ -100,7 +150,7 @@ data "aws_vpc_endpoint_service" "test" { } ` -func testAccDataSourceAwsVpcEndpointServiceCustomConfig(rName string) string { +func testAccDataSourceAwsVpcEndpointServiceCustomConfigBase(rName string) string { return fmt.Sprintf(` resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" @@ -168,9 +218,34 @@ resource "aws_vpc_endpoint_service" "test" { Name = %[1]q } } +`, rName) +} +func testAccDataSourceAwsVpcEndpointServiceCustomConfig(rName string) string { + return testAccDataSourceAwsVpcEndpointServiceCustomConfigBase(rName) + fmt.Sprintf(` data "aws_vpc_endpoint_service" "test" { service_name = "${aws_vpc_endpoint_service.test.service_name}" } -`, rName) +`) +} + +func testAccDataSourceAwsVpcEndpointServiceCustomConfigFilter(rName string) string { + return testAccDataSourceAwsVpcEndpointServiceCustomConfigBase(rName) + fmt.Sprintf(` +data "aws_vpc_endpoint_service" "test" { + filter { + name = "service-name" + values = ["${aws_vpc_endpoint_service.test.service_name}"] + } +} +`) +} + +func testAccDataSourceAwsVpcEndpointServiceCustomConfigFilterTags(rName string) string { + return testAccDataSourceAwsVpcEndpointServiceCustomConfigBase(rName) + fmt.Sprintf(` +data "aws_vpc_endpoint_service" "test" { + tags = { + Name = "${aws_vpc_endpoint_service.test.tags["Name"]}" + } +} +`) } diff --git a/website/docs/d/vpc_endpoint_service.html.markdown b/website/docs/d/vpc_endpoint_service.html.markdown index 165a00a2389..ad68e8ed6a9 100644 --- a/website/docs/d/vpc_endpoint_service.html.markdown +++ b/website/docs/d/vpc_endpoint_service.html.markdown @@ -41,6 +41,17 @@ data "aws_vpc_endpoint_service" "custome" { } ``` +### Filter + +```hcl +data "aws_vpc_endpoint_service" "test" { + filter { + name = "service-name" + values = ["some-service"] + } +} +``` + ## Argument Reference The arguments of this data source act as filters for querying the available VPC endpoint services. @@ -48,8 +59,17 @@ The given filters must match exactly one VPC endpoint service whose data will be * `service` - (Optional) The common name of an AWS service (e.g. `s3`). * `service_name` - (Optional) The service name that is specified when creating a VPC endpoint. For AWS services the service name is usually in the form `com.amazonaws..` (the SageMaker Notebook service is an exception to this rule, the service name is in the form `aws.sagemaker..notebook`). +* `filter` - (Optional) Configuration block(s) for filtering. Detailed below. +* `tags` - (Optional) A mapping of tags, each pair of which must exactly match a pair on the desired VPC Endpoint Service. + +~> **NOTE:** Specifying `service` will not work for non-AWS services or AWS services that don't follow the standard `service_name` pattern of `com.amazonaws..`. + +### filter Configuration Block + +The following arguments are supported by the `filter` configuration block: -~> **NOTE:** One of `service` or `service_name` must be specified. Specifying `service` will not work for non-AWS services or AWS services that don't follow the standard `service_name` pattern of `com.amazonaws..`. +* `name` - (Required) The name of the filter field. Valid values can be found in the [EC2 DescribeVpcEndpointServices API Reference](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcEndpointServices.html). +* `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. ## Attributes Reference From 3795f994903baff2a4f7886ffc9c49f4fb3b65c8 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 26 Mar 2020 10:45:35 -0400 Subject: [PATCH 110/684] Update CHANGELOG for #12404 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e82a0905732..e6488b2c773 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ ENHANCEMENTS: * data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] * data-source/aws_launch_template: Add `filter` and `tags` arguments [GH-12403] * data-source/aws_prefix_list: Add `filter` argument [GH-12416] +* data-source/aws_vpc_endpoint_service: Add `filter` argument [GH-12404] * resource/aws_athena_workgroup: Add `force_destroy` argument [GH-12254] * resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] * resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument [GH-11843] From 72c1e706f43ebe7bc83076c7e056a33207a401cb Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 26 Mar 2020 10:46:10 -0400 Subject: [PATCH 111/684] Update CHANGELOG for #12404 to account for tags argument --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6488b2c773..dbc08e61261 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ ENHANCEMENTS: * data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] * data-source/aws_launch_template: Add `filter` and `tags` arguments [GH-12403] * data-source/aws_prefix_list: Add `filter` argument [GH-12416] -* data-source/aws_vpc_endpoint_service: Add `filter` argument [GH-12404] +* data-source/aws_vpc_endpoint_service: Add `filter` and `tags` arguments [GH-12404] * resource/aws_athena_workgroup: Add `force_destroy` argument [GH-12254] * resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] * resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument [GH-11843] From fa932b0a0fb19105173a265af5cda9b36f3682a7 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Thu, 26 Mar 2020 17:44:58 +0200 Subject: [PATCH 112/684] data-source/aws_ec2_transit_gateway_vpn_attachment: Add filter and tags arguments (#12415) Output from acceptance testing: ``` --- PASS: TestAccAWSEc2TransitGatewayVpnAttachmentDataSource_filter (470.70s) --- PASS: TestAccAWSEc2TransitGatewayVpnAttachmentDataSource_TransitGatewayIdAndVpnConnectionId (529.23s) ``` --- ..._aws_ec2_transit_gateway_vpn_attachment.go | 38 +++++++++---- ...ec2_transit_gateway_vpn_attachment_test.go | 55 ++++++++++++++++++- ...ansit_gateway_vpn_attachment.html.markdown | 24 +++++++- 3 files changed, 102 insertions(+), 15 deletions(-) diff --git a/aws/data_source_aws_ec2_transit_gateway_vpn_attachment.go b/aws/data_source_aws_ec2_transit_gateway_vpn_attachment.go index 02bc3da6459..408f47de399 100644 --- a/aws/data_source_aws_ec2_transit_gateway_vpn_attachment.go +++ b/aws/data_source_aws_ec2_transit_gateway_vpn_attachment.go @@ -19,12 +19,13 @@ func dataSourceAwsEc2TransitGatewayVpnAttachment() *schema.Resource { "tags": tagsSchemaComputed(), "transit_gateway_id": { Type: schema.TypeString, - Required: true, + Optional: true, }, "vpn_connection_id": { Type: schema.TypeString, - Required: true, + Optional: true, }, + "filter": dataSourceFiltersSchema(), }, } } @@ -32,23 +33,40 @@ func dataSourceAwsEc2TransitGatewayVpnAttachment() *schema.Resource { func dataSourceAwsEc2TransitGatewayVpnAttachmentRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn + filters, filtersOk := d.GetOk("filter") + tags, tagsOk := d.GetOk("tags") + connectionId, connectionIdOk := d.GetOk("vpn_connection_id") + transitGatewayId, transitGatewayIdOk := d.GetOk("transit_gateway_id") + input := &ec2.DescribeTransitGatewayAttachmentsInput{ Filters: []*ec2.Filter{ - { - Name: aws.String("resource-id"), - Values: []*string{aws.String(d.Get("vpn_connection_id").(string))}, - }, { Name: aws.String("resource-type"), Values: []*string{aws.String(ec2.TransitGatewayAttachmentResourceTypeVpn)}, }, - { - Name: aws.String("transit-gateway-id"), - Values: []*string{aws.String(d.Get("transit_gateway_id").(string))}, - }, }, } + if filtersOk { + input.Filters = append(input.Filters, buildAwsDataSourceFilters(filters.(*schema.Set))...) + } + if tagsOk { + input.Filters = append(input.Filters, ec2TagFiltersFromMap(tags.(map[string]interface{}))...) + } + if connectionIdOk { + input.Filters = append(input.Filters, &ec2.Filter{ + Name: aws.String("resource-id"), + Values: []*string{aws.String(connectionId.(string))}, + }) + } + + if transitGatewayIdOk { + input.Filters = append(input.Filters, &ec2.Filter{ + Name: aws.String("transit-gateway-id"), + Values: []*string{aws.String(transitGatewayId.(string))}, + }) + } + log.Printf("[DEBUG] Reading EC2 Transit Gateway VPN Attachments: %s", input) output, err := conn.DescribeTransitGatewayAttachments(input) diff --git a/aws/data_source_aws_ec2_transit_gateway_vpn_attachment_test.go b/aws/data_source_aws_ec2_transit_gateway_vpn_attachment_test.go index c8cfd12d7f4..95bbfe600cb 100644 --- a/aws/data_source_aws_ec2_transit_gateway_vpn_attachment_test.go +++ b/aws/data_source_aws_ec2_transit_gateway_vpn_attachment_test.go @@ -34,9 +34,39 @@ func TestAccAWSEc2TransitGatewayVpnAttachmentDataSource_TransitGatewayIdAndVpnCo }) } -func testAccAWSEc2TransitGatewayVpnAttachmentDataSourceConfigTransitGatewayIdAndVpnConnectionId(rBgpAsn int) string { +func TestAccAWSEc2TransitGatewayVpnAttachmentDataSource_filter(t *testing.T) { + rBgpAsn := acctest.RandIntRange(64512, 65534) + dataSourceName := "data.aws_ec2_transit_gateway_vpn_attachment.test" + transitGatewayResourceName := "aws_ec2_transit_gateway.test" + vpnConnectionResourceName := "aws_vpn_connection.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckAWSEc2TransitGateway(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2TransitGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2TransitGatewayVpnAttachmentDataSourceConfigFilter(rBgpAsn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "0"), + resource.TestCheckResourceAttrPair(dataSourceName, "transit_gateway_id", transitGatewayResourceName, "id"), + resource.TestCheckResourceAttrPair(dataSourceName, "vpn_connection_id", vpnConnectionResourceName, "id"), + ), + }, + }, + }) +} + +func testAccAWSEc2TransitGatewayVpnAttachmentDataSourceConfigBase(rBgpAsn int) string { return fmt.Sprintf(` -resource "aws_ec2_transit_gateway" "test" {} +resource "aws_ec2_transit_gateway" "test" { + tags = { + Name = "tf-acc-test-ec2-vpn-connection-transit-gateway-id" + } +} resource "aws_customer_gateway" "test" { bgp_asn = %[1]d @@ -52,11 +82,30 @@ resource "aws_vpn_connection" "test" { customer_gateway_id = "${aws_customer_gateway.test.id}" transit_gateway_id = "${aws_ec2_transit_gateway.test.id}" type = "${aws_customer_gateway.test.type}" + + tags = { + Name = "tf-acc-test-ec2-vpn-connection-transit-gateway-id" + } +} +`, rBgpAsn) } +func testAccAWSEc2TransitGatewayVpnAttachmentDataSourceConfigTransitGatewayIdAndVpnConnectionId(rBgpAsn int) string { + return testAccAWSEc2TransitGatewayVpnAttachmentDataSourceConfigBase(rBgpAsn) + fmt.Sprintf(` data "aws_ec2_transit_gateway_vpn_attachment" "test" { transit_gateway_id = "${aws_ec2_transit_gateway.test.id}" vpn_connection_id = "${aws_vpn_connection.test.id}" } -`, rBgpAsn) +`) +} + +func testAccAWSEc2TransitGatewayVpnAttachmentDataSourceConfigFilter(rBgpAsn int) string { + return testAccAWSEc2TransitGatewayVpnAttachmentDataSourceConfigBase(rBgpAsn) + fmt.Sprintf(` +data "aws_ec2_transit_gateway_vpn_attachment" "test" { + filter { + name = "resource-id" + values = ["${aws_vpn_connection.test.id}"] + } +} +`) } diff --git a/website/docs/d/ec2_transit_gateway_vpn_attachment.html.markdown b/website/docs/d/ec2_transit_gateway_vpn_attachment.html.markdown index 1daf93be9a0..78673f71a8a 100644 --- a/website/docs/d/ec2_transit_gateway_vpn_attachment.html.markdown +++ b/website/docs/d/ec2_transit_gateway_vpn_attachment.html.markdown @@ -21,12 +21,32 @@ data "aws_ec2_transit_gateway_vpn_attachment" "example" { } ``` +### Filter + +```hcl +data "aws_ec2_transit_gateway_vpn_attachment" "test" { + filter { + name = "resource-id" + values = ["some-resource"] + } +} +``` + ## Argument Reference The following arguments are supported: -* `transit_gateway_id` - (Required) Identifier of the EC2 Transit Gateway. -* `vpn_connection_id` - (Required) Identifier of the EC2 VPN Connection. +* `transit_gateway_id` - (Optional) Identifier of the EC2 Transit Gateway. +* `vpn_connection_id` - (Optional) Identifier of the EC2 VPN Connection. +* `filter` - (Optional) Configuration block(s) for filtering. Detailed below. +* `tags` - (Optional) A mapping of tags, each pair of which must exactly match a pair on the desired Transit Gateway VPN Attachment. + +### filter Configuration Block + +The following arguments are supported by the `filter` configuration block: + +* `name` - (Required) The name of the filter field. Valid values can be found in the [EC2 DescribeTransitGatewayAttachments API Reference](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeTransitGatewayAttachments.html). +* `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. ## Attribute Reference From c215f6310c6a55ad0fdfb8b6a7312c0285643b33 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 26 Mar 2020 11:45:28 -0400 Subject: [PATCH 113/684] Update CHANGELOG for #12415 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbc08e61261..34ec3df977f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ENHANCEMENTS: * data-source/aws_availability_zone: Add `group_name`, `network_border_group`, and `opt_in_status` attributes [GH-12400] * data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments [GH-12400] * data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] +* data-source/aws_ec2_transit_gateway_vpn_attachment: Add filter and tags arguments [GH-12415] * data-source/aws_launch_template: Add `filter` and `tags` arguments [GH-12403] * data-source/aws_prefix_list: Add `filter` argument [GH-12416] * data-source/aws_vpc_endpoint_service: Add `filter` and `tags` arguments [GH-12404] From df92ab624118b12d2f9f581ef81d0e7f6b462599 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 26 Mar 2020 13:07:48 -0400 Subject: [PATCH 114/684] provider: Switch stale handling from hashibot to official GitHub Action (#12542) This implements very conservative stale issue and pull request handling for now to potentially clear out some very old backlog items that may no longer be relevant on more recent versions of Terraform CLI and the Terraform AWS Provider. We will potentially reduce the staleness time as we get through more of the actionable backlog. --- .github/workflows/stale.yml | 26 ++++++++++++++++++++++++++ .hashibot.hcl | 15 --------------- 2 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000000..02f7eae85fa --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,26 @@ +name: "Stale issues and pull requests" +on: + schedule: + - cron: "0 0 * * *" + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + days-before-stale: 720 + days-before-close: 30 + exempt-issue-label: 'needs-triage' + exempt-pr-label: 'needs-triage' + stale-issue-label: 'stale' + stale-issue-message: | + Marking this issue as stale due to inactivity. This helps our maintainers find and focus on the active issues. If this issue receives no comments in the next 30 days it will automatically be closed. Maintainers can also remove the stale label. + + If this issue was automatically closed and you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thank you! + stale-pr-label: 'stale' + stale-pr-message: | + Marking this pull request as stale due to inactivity. This helps our maintainers find and focus on the active pull requests. If this pull request receives no comments in the next 30 days it will automatically be closed. Maintainers can also remove the stale label. + + If this pull request was automatically closed and you feel this pull request should be reopened, we encourage creating a new pull request linking back to this one for added context. Thank you! diff --git a/.hashibot.hcl b/.hashibot.hcl index 997c3f348e9..b716ec27504 100644 --- a/.hashibot.hcl +++ b/.hashibot.hcl @@ -11,21 +11,6 @@ poll "closed_issue_locker" "locker" { EOF } -poll "stale_issue_closer" "closer" { - schedule = "0 22 23 * * *" - no_reply_in_last = "2160h" # 90 days - max_issues = 500 - sleep_between_issues = "5s" - created_after = "2019-06-01" - exclude_labels = ["needs-triage", "technical-debt"] - extra_search_params = "reactions:<20 no:milestone no:assignee" - message = <<-EOF - I'm going to close this issue due to inactivity (_90 days_ without response ⏳ ). 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 -} - behavior "deprecated_import_commenter" "hashicorp_terraform" { import_regexp = "github.com/hashicorp/terraform/" marker_label = "terraform-plugin-sdk-migration" From 79a5e6330bdf9f28e5cf16598fc9ddc18317c4f8 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Thu, 26 Mar 2020 14:36:03 -0400 Subject: [PATCH 115/684] resource/aws_storagegateway_nfs_file_share: Implement path attribute (#12530) Output from acceptance testing: ``` --- PASS: TestAccAWSStorageGatewayNfsFileShare_basic (198.28s) --- PASS: TestAccAWSStorageGatewayNfsFileShare_ClientList (265.22s) --- PASS: TestAccAWSStorageGatewayNfsFileShare_DefaultStorageClass (270.50s) --- PASS: TestAccAWSStorageGatewayNfsFileShare_GuessMIMETypeEnabled (287.48s) --- PASS: TestAccAWSStorageGatewayNfsFileShare_KMSEncrypted (157.73s) --- PASS: TestAccAWSStorageGatewayNfsFileShare_KMSKeyArn (303.82s) --- PASS: TestAccAWSStorageGatewayNfsFileShare_NFSFileShareDefaults (249.59s) --- PASS: TestAccAWSStorageGatewayNfsFileShare_ObjectACL (270.81s) --- PASS: TestAccAWSStorageGatewayNfsFileShare_ReadOnly (270.54s) --- PASS: TestAccAWSStorageGatewayNfsFileShare_RequesterPays (247.61s) --- PASS: TestAccAWSStorageGatewayNfsFileShare_Squash (317.48s) --- PASS: TestAccAWSStorageGatewayNfsFileShare_tags (315.32s) ``` --- aws/resource_aws_storagegateway_nfs_file_share.go | 4 ++++ aws/resource_aws_storagegateway_nfs_file_share_test.go | 1 + 2 files changed, 5 insertions(+) diff --git a/aws/resource_aws_storagegateway_nfs_file_share.go b/aws/resource_aws_storagegateway_nfs_file_share.go index 289b1c2bd1d..c467b0e9519 100644 --- a/aws/resource_aws_storagegateway_nfs_file_share.go +++ b/aws/resource_aws_storagegateway_nfs_file_share.go @@ -126,6 +126,10 @@ func resourceAwsStorageGatewayNfsFileShare() *schema.Resource { storagegateway.ObjectACLPublicReadWrite, }, false), }, + "path": { + Type: schema.TypeString, + Computed: true, + }, "read_only": { Type: schema.TypeBool, Optional: true, diff --git a/aws/resource_aws_storagegateway_nfs_file_share_test.go b/aws/resource_aws_storagegateway_nfs_file_share_test.go index aefa6abc64f..b5de023aacd 100644 --- a/aws/resource_aws_storagegateway_nfs_file_share_test.go +++ b/aws/resource_aws_storagegateway_nfs_file_share_test.go @@ -38,6 +38,7 @@ func TestAccAWSStorageGatewayNfsFileShare_basic(t *testing.T) { resource.TestMatchResourceAttr(resourceName, "location_arn", regexp.MustCompile(`^arn:`)), resource.TestCheckResourceAttr(resourceName, "nfs_file_share_defaults.#", "0"), resource.TestCheckResourceAttr(resourceName, "object_acl", storagegateway.ObjectACLPrivate), + resource.TestMatchResourceAttr(resourceName, "path", regexp.MustCompile(`^/.+`)), resource.TestCheckResourceAttr(resourceName, "read_only", "false"), resource.TestCheckResourceAttr(resourceName, "requester_pays", "false"), resource.TestMatchResourceAttr(resourceName, "role_arn", regexp.MustCompile(`^arn:`)), From 9b8ec1dc8f0ccc9be7417d10f81c2349b0ab584a Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 26 Mar 2020 14:37:24 -0400 Subject: [PATCH 116/684] Update CHANGELOG for #12530 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34ec3df977f..730d5853ea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ ENHANCEMENTS: * resource/aws_athena_workgroup: Add `force_destroy` argument [GH-12254] * resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] * resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument [GH-11843] +* resource/aws_storagegateway_nfs_file_share: Add `path` attribute [GH-12530] BUG FIXES: From 21f49a7cd27de4e912ce5f8a1484c186e7176ad7 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Thu, 26 Mar 2020 20:51:00 +0200 Subject: [PATCH 117/684] data-source/aws_ec2_transit_gateway_dx_gateway_attachement: Add filter and tags arguments (#12516) Output from acceptance testing: ``` --- PASS: TestAccAWSEc2TransitGatewayDxGatewayAttachmentDataSource_filter (1163.07s) --- PASS: TestAccAWSEc2TransitGatewayDxGatewayAttachmentDataSource_TransitGatewayIdAndDxGatewayId (1171.51s) ``` --- ...2_transit_gateway_dx_gateway_attachment.go | 40 ++++++++---- ...nsit_gateway_dx_gateway_attachment_test.go | 65 ++++++++++++++++++- ...ateway_dx_gateway_attachment.html.markdown | 13 +++- 3 files changed, 102 insertions(+), 16 deletions(-) diff --git a/aws/data_source_aws_ec2_transit_gateway_dx_gateway_attachment.go b/aws/data_source_aws_ec2_transit_gateway_dx_gateway_attachment.go index 37f83b28a9a..6de780ec45d 100644 --- a/aws/data_source_aws_ec2_transit_gateway_dx_gateway_attachment.go +++ b/aws/data_source_aws_ec2_transit_gateway_dx_gateway_attachment.go @@ -18,13 +18,14 @@ func dataSourceAwsEc2TransitGatewayDxGatewayAttachment() *schema.Resource { Schema: map[string]*schema.Schema{ "dx_gateway_id": { Type: schema.TypeString, - Required: true, + Optional: true, }, "tags": tagsSchemaComputed(), "transit_gateway_id": { Type: schema.TypeString, - Required: true, + Optional: true, }, + "filter": dataSourceFiltersSchema(), }, } } @@ -32,22 +33,39 @@ func dataSourceAwsEc2TransitGatewayDxGatewayAttachment() *schema.Resource { func dataSourceAwsEc2TransitGatewayDxGatewayAttachmentRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn + filters, filtersOk := d.GetOk("filter") + tags, tagsOk := d.GetOk("tags") + dxGatewayId, dxGatewayIdOk := d.GetOk("dx_gateway_id") + transitGatewayId, transitGatewayIdOk := d.GetOk("transit_gateway_id") + input := &ec2.DescribeTransitGatewayAttachmentsInput{ Filters: []*ec2.Filter{ - { - Name: aws.String("resource-id"), - Values: []*string{aws.String(d.Get("dx_gateway_id").(string))}, - }, { Name: aws.String("resource-type"), - Values: []*string{aws.String("direct-connect-gateway")}, // Not yet defined in ec2/api.go. - }, - { - Name: aws.String("transit-gateway-id"), - Values: []*string{aws.String(d.Get("transit_gateway_id").(string))}, + Values: []*string{aws.String(ec2.TransitGatewayAttachmentResourceTypeDirectConnectGateway)}, }, }, } + if filtersOk { + input.Filters = append(input.Filters, buildAwsDataSourceFilters(filters.(*schema.Set))...) + } + if tagsOk { + input.Filters = append(input.Filters, ec2TagFiltersFromMap(tags.(map[string]interface{}))...) + } + // to preserve original functionality + if dxGatewayIdOk { + input.Filters = append(input.Filters, &ec2.Filter{ + Name: aws.String("resource-id"), + Values: []*string{aws.String(dxGatewayId.(string))}, + }) + } + + if transitGatewayIdOk { + input.Filters = append(input.Filters, &ec2.Filter{ + Name: aws.String("transit-gateway-id"), + Values: []*string{aws.String(transitGatewayId.(string))}, + }) + } log.Printf("[DEBUG] Reading EC2 Transit Gateway Direct Connect Gateway Attachments: %s", input) output, err := conn.DescribeTransitGatewayAttachments(input) diff --git a/aws/data_source_aws_ec2_transit_gateway_dx_gateway_attachment_test.go b/aws/data_source_aws_ec2_transit_gateway_dx_gateway_attachment_test.go index 323142186f0..adf5af3a8eb 100644 --- a/aws/data_source_aws_ec2_transit_gateway_dx_gateway_attachment_test.go +++ b/aws/data_source_aws_ec2_transit_gateway_dx_gateway_attachment_test.go @@ -9,7 +9,7 @@ import ( ) func TestAccAWSEc2TransitGatewayDxGatewayAttachmentDataSource_TransitGatewayIdAndDxGatewayId(t *testing.T) { - rName := fmt.Sprintf("terraform-testacc-tgwdxgwattach-%d", acctest.RandInt()) + rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := randIntRange(64512, 65534) dataSourceName := "data.aws_ec2_transit_gateway_dx_gateway_attachment.test" transitGatewayResourceName := "aws_ec2_transit_gateway.test" @@ -24,7 +24,7 @@ func TestAccAWSEc2TransitGatewayDxGatewayAttachmentDataSource_TransitGatewayIdAn CheckDestroy: testAccCheckAWSEc2TransitGatewayDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2TransitGatewayVpnAttachmentDataSourceConfigTransitGatewayIdAndDxGatewayId(rName, rBgpAsn), + Config: testAccAWSEc2TransitGatewayDxAttachmentDataSourceConfig(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(dataSourceName, "tags.%", "0"), resource.TestCheckResourceAttrPair(dataSourceName, "transit_gateway_id", transitGatewayResourceName, "id"), @@ -35,7 +35,34 @@ func TestAccAWSEc2TransitGatewayDxGatewayAttachmentDataSource_TransitGatewayIdAn }) } -func testAccAWSEc2TransitGatewayVpnAttachmentDataSourceConfigTransitGatewayIdAndDxGatewayId(rName string, rBgpAsn int) string { +func TestAccAWSEc2TransitGatewayDxGatewayAttachmentDataSource_filter(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + rBgpAsn := randIntRange(64512, 65534) + dataSourceName := "data.aws_ec2_transit_gateway_dx_gateway_attachment.test" + transitGatewayResourceName := "aws_ec2_transit_gateway.test" + dxGatewayResourceName := "aws_dx_gateway.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckAWSEc2TransitGateway(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2TransitGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2TransitGatewayDxAttachmentDataSourceConfigFilter(rName, rBgpAsn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "0"), + resource.TestCheckResourceAttrPair(dataSourceName, "transit_gateway_id", transitGatewayResourceName, "id"), + resource.TestCheckResourceAttrPair(dataSourceName, "dx_gateway_id", dxGatewayResourceName, "id"), + ), + }, + }, + }) +} + +func testAccAWSEc2TransitGatewayDxAttachmentDataSourceConfig(rName string, rBgpAsn int) string { return fmt.Sprintf(` resource "aws_dx_gateway" "test" { name = %[1]q @@ -64,3 +91,35 @@ data "aws_ec2_transit_gateway_dx_gateway_attachment" "test" { } `, rName, rBgpAsn) } + +func testAccAWSEc2TransitGatewayDxAttachmentDataSourceConfigFilter(rName string, rBgpAsn int) string { + return fmt.Sprintf(` +resource "aws_dx_gateway" "test" { + name = %[1]q + amazon_side_asn = "%[2]d" +} + +resource "aws_ec2_transit_gateway" "test" { + tags = { + Name = %[1]q + } +} + +resource "aws_dx_gateway_association" "test" { + dx_gateway_id = "${aws_dx_gateway.test.id}" + associated_gateway_id = "${aws_ec2_transit_gateway.test.id}" + + allowed_prefixes = [ + "10.255.255.0/30", + "10.255.255.8/30", + ] +} + +data "aws_ec2_transit_gateway_dx_gateway_attachment" "test" { + filter { + name = "resource-id" + values = ["${aws_dx_gateway_association.test.dx_gateway_id}"] + } +} +`, rName, rBgpAsn) +} diff --git a/website/docs/d/ec2_transit_gateway_dx_gateway_attachment.html.markdown b/website/docs/d/ec2_transit_gateway_dx_gateway_attachment.html.markdown index e2df224b1ca..ab2cba30afa 100644 --- a/website/docs/d/ec2_transit_gateway_dx_gateway_attachment.html.markdown +++ b/website/docs/d/ec2_transit_gateway_dx_gateway_attachment.html.markdown @@ -25,8 +25,17 @@ data "aws_ec2_transit_gateway_dx_gateway_attachment" "example" { The following arguments are supported: -* `transit_gateway_id` - (Required) Identifier of the EC2 Transit Gateway. -* `dx_gateway_id` - (Required) Identifier of the Direct Connect Gateway. +* `transit_gateway_id` - (Optional) Identifier of the EC2 Transit Gateway. +* `dx_gateway_id` - (Optional) Identifier of the Direct Connect Gateway. +* `filter` - (Optional) Configuration block(s) for filtering. Detailed below. +* `tags` - (Optional) A mapping of tags, each pair of which must exactly match a pair on the desired Transit Gateway Direct Connect Gateway Attachment. + +### filter Configuration Block + +The following arguments are supported by the `filter` configuration block: + +* `name` - (Required) The name of the filter field. Valid values can be found in the [EC2 DescribeTransitGatewayAttachments API Reference](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeTransitGatewayAttachments.html). +* `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. ## Attribute Reference From 6583fbc2615e3e51426c6060e43e2ec48db844c7 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 26 Mar 2020 14:52:27 -0400 Subject: [PATCH 118/684] Update CHANGELOG for #12516 --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 730d5853ea1..dd01fe4eba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ ENHANCEMENTS: * data-source/aws_availability_zone: Add `group_name`, `network_border_group`, and `opt_in_status` attributes [GH-12400] * data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments [GH-12400] * data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] -* data-source/aws_ec2_transit_gateway_vpn_attachment: Add filter and tags arguments [GH-12415] +* data-source/aws_ec2_transit_gateway_dx_gateway_attachement: Add `filter` and `tags` arguments [GH-12516] +* data-source/aws_ec2_transit_gateway_vpn_attachment: Add `filter` and `tags` arguments [GH-12415] * data-source/aws_launch_template: Add `filter` and `tags` arguments [GH-12403] * data-source/aws_prefix_list: Add `filter` argument [GH-12416] * data-source/aws_vpc_endpoint_service: Add `filter` and `tags` arguments [GH-12404] From d6fce80e319d4c2b0b79744905abb323d73b6def Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 26 Mar 2020 11:59:36 -0700 Subject: [PATCH 119/684] Reorders parameters for composed configurations for cleaner formatting --- aws/resource_aws_emr_cluster_test.go | 143 +++++++++++++++------------ 1 file changed, 79 insertions(+), 64 deletions(-) diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index f26d0dc967f..cc95a86ea3f 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -1729,7 +1729,10 @@ func testAccAWSEmrComposeConfig(mapPublicIPOnLaunch bool, config ...string) stri } func testAccAWSEmrClusterConfig_bootstrap(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + fmt.Sprintf(` resource "aws_emr_cluster" "test" { name = "%[1]s" release_label = "emr-5.0.0" @@ -1787,13 +1790,15 @@ EOF acl = "public-read" } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), ) } func testAccAWSEmrClusterConfig(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -1831,14 +1836,15 @@ resource "aws_emr_cluster" "tf-test-cluster" { ebs_root_volume_size = 21 } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } func testAccAWSEmrClusterConfigAdditionalInfo(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -1885,14 +1891,14 @@ EOF ebs_root_volume_size = 21 } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } func testAccAWSEmrClusterConfigConfigurationsJson(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -1947,8 +1953,6 @@ EOF ebs_root_volume_size = 21 } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), ) } @@ -1999,7 +2003,11 @@ resource "aws_emr_cluster" "tf-test-cluster" { } func testAccAWSEmrClusterConfig_SecurityConfiguration(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-5.5.0" @@ -2078,11 +2086,7 @@ resource "aws_kms_key" "foo" { } POLICY } -`, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), - ) +`, r)) } const testAccAWSEmrClusterConfig_Step_DebugLoggingStep = ` @@ -2494,7 +2498,11 @@ resource "aws_emr_cluster" "test" { } func testAccAWSEmrClusterConfigInstanceGroups(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -2579,14 +2587,15 @@ EOT autoscaling_role = "${aws_iam_role.emr-autoscaling-role.arn}" } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } func testAccAWSEmrClusterConfigInstanceGroupsName(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -2652,14 +2661,15 @@ resource "aws_emr_cluster" "tf-test-cluster" { autoscaling_role = "${aws_iam_role.emr-autoscaling-role.arn}" } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } func testAccAWSEmrClusterConfigInstanceGroupsUpdate(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -2744,14 +2754,15 @@ EOT autoscaling_role = "${aws_iam_role.emr-autoscaling-role.arn}" } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } func testAccAWSEmrClusterConfigInstanceGroups_st1(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -2834,14 +2845,15 @@ EOT autoscaling_role = "${aws_iam_role.emr-autoscaling-role.arn}" } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } func testAccAWSEmrClusterConfigInstanceGroups_updateAutoScalingPolicy(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -2924,9 +2936,6 @@ EOT autoscaling_role = "${aws_iam_role.emr-autoscaling-role.arn}" } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } @@ -3093,7 +3102,11 @@ resource "aws_emr_cluster" "test" { } func testAccAWSEmrClusterConfigTerminationPolicy(r string, term string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -3128,14 +3141,15 @@ resource "aws_emr_cluster" "tf-test-cluster" { autoscaling_role = "${aws_iam_role.emr-autoscaling-role.arn}" } `, r, term), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } func testAccAWSEmrClusterConfig_keepJob(r string, keepJob string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -3180,14 +3194,15 @@ resource "aws_emr_cluster" "tf-test-cluster" { autoscaling_role = "${aws_iam_role.emr-autoscaling-role.arn}" } `, r, keepJob), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } func testAccAWSEmrClusterConfigVisibleToAllUsersUpdated(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -3222,14 +3237,15 @@ resource "aws_emr_cluster" "tf-test-cluster" { autoscaling_role = "${aws_iam_role.emr-autoscaling-role.arn}" } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } func testAccAWSEmrClusterConfigUpdatedTags(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -3263,14 +3279,15 @@ resource "aws_emr_cluster" "tf-test-cluster" { autoscaling_role = "${aws_iam_role.emr-autoscaling-role.arn}" } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } func testAccAWSEmrClusterConfigUpdatedRootVolumeSize(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleBase(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-4.6.0" @@ -3306,9 +3323,6 @@ resource "aws_emr_cluster" "tf-test-cluster" { ebs_root_volume_size = 48 } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleBase(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } @@ -3349,7 +3363,11 @@ data "aws_caller_identity" "current" {} } func testAccAWSEmrClusterConfigCustomAmiID(r string) string { - return testAccAWSEmrComposeConfig(false, fmt.Sprintf(` + return testAccAWSEmrComposeConfig(false, + testAccAWSEmrClusterConfigIAMServiceRoleCustomAmiID(r), + testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigIAMAutoscalingRole(r), + fmt.Sprintf(` resource "aws_emr_cluster" "tf-test-cluster" { name = "%[1]s" release_label = "emr-5.7.0" @@ -3411,9 +3429,6 @@ data "aws_ami" "emr-custom-ami" { } } `, r), - testAccAWSEmrClusterConfigIAMServiceRoleCustomAmiID(r), - testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), - testAccAWSEmrClusterConfigIAMAutoscalingRole(r), ) } From 4a2073d289b1bf6c313e9486b0c3c52d73b20da7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 26 Mar 2020 15:15:36 -0400 Subject: [PATCH 120/684] resource/aws_flow_log: Add max_aggregation_interval argument (#12483) Output from acceptance testing in AWS Commercial: ``` --- PASS: TestAccAWSFlowLog_LogDestinationType_S3_Invalid (8.93s) --- PASS: TestAccAWSFlowLog_disappears (13.03s) --- PASS: TestAccAWSFlowLog_LogDestinationType_CloudWatchLogs (15.27s) --- PASS: TestAccAWSFlowLog_SubnetID (16.29s) --- PASS: TestAccAWSFlowLog_LogDestinationType_MaxAggregationInterval (16.33s) --- PASS: TestAccAWSFlowLog_LogDestinationType_S3 (18.44s) --- PASS: TestAccAWSFlowLog_VPCID (22.36s) --- PASS: TestAccAWSFlowLog_LogFormat (24.01s) --- PASS: TestAccAWSFlowLog_tags (28.29s) ``` Output from acceptance testing in AWS GovCloud (US) (test failures unrelated): ``` --- FAIL: TestAccAWSFlowLog_SubnetID (2.89s) --- FAIL: TestAccAWSFlowLog_LogDestinationType_S3_Invalid (6.77s) --- PASS: TestAccAWSFlowLog_disappears (8.80s) --- PASS: TestAccAWSFlowLog_LogDestinationType_CloudWatchLogs (12.10s) --- PASS: TestAccAWSFlowLog_LogDestinationType_MaxAggregationInterval (13.01s) --- PASS: TestAccAWSFlowLog_VPCID (13.42s) --- PASS: TestAccAWSFlowLog_LogDestinationType_S3 (15.63s) --- PASS: TestAccAWSFlowLog_LogFormat (17.73s) --- PASS: TestAccAWSFlowLog_tags (21.54s) ``` --- aws/resource_aws_flow_log.go | 15 ++++++ aws/resource_aws_flow_log_test.go | 72 ++++++++++++++++++++++++++- website/docs/r/flow_log.html.markdown | 4 ++ 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_flow_log.go b/aws/resource_aws_flow_log.go index 082e90db453..5ed03640695 100644 --- a/aws/resource_aws_flow_log.go +++ b/aws/resource_aws_flow_log.go @@ -101,6 +101,15 @@ func resourceAwsFlowLog() *schema.Resource { ForceNew: true, Computed: true, }, + + "max_aggregation_interval": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Default: 600, + ValidateFunc: validation.IntInSlice([]int{60, 600}), + }, + "tags": tagsSchema(), }, } @@ -150,10 +159,15 @@ func resourceAwsLogFlowCreate(d *schema.ResourceData, meta interface{}) error { if v, ok := d.GetOk("log_group_name"); ok && v != "" { opts.LogGroupName = aws.String(v.(string)) } + if v, ok := d.GetOk("log_format"); ok && v != "" { opts.LogFormat = aws.String(v.(string)) } + if v, ok := d.GetOk("max_aggregation_interval"); ok { + opts.MaxAggregationInterval = aws.Int64(int64(v.(int))) + } + if v, ok := d.GetOk("tags"); ok && len(v.(map[string]interface{})) > 0 { opts.TagSpecifications = ec2TagSpecificationsFromMap(d.Get("tags").(map[string]interface{}), ec2.ResourceTypeVpcFlowLog) } @@ -205,6 +219,7 @@ func resourceAwsLogFlowRead(d *schema.ResourceData, meta interface{}) error { d.Set("log_group_name", fl.LogGroupName) d.Set("iam_role_arn", fl.DeliverLogsPermissionArn) d.Set("log_format", fl.LogFormat) + d.Set("max_aggregation_interval", fl.MaxAggregationInterval) var resourceKey string if strings.HasPrefix(*fl.ResourceId, "vpc-") { resourceKey = "vpc_id" diff --git a/aws/resource_aws_flow_log_test.go b/aws/resource_aws_flow_log_test.go index 67207403aee..44c09455775 100644 --- a/aws/resource_aws_flow_log_test.go +++ b/aws/resource_aws_flow_log_test.go @@ -34,6 +34,7 @@ func TestAccAWSFlowLog_VPCID(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "log_destination", ""), resource.TestCheckResourceAttr(resourceName, "log_destination_type", "cloud-watch-logs"), resource.TestCheckResourceAttrPair(resourceName, "log_group_name", cloudwatchLogGroupResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "max_aggregation_interval", "600"), resource.TestCheckResourceAttr(resourceName, "traffic_type", "ALL"), resource.TestCheckResourceAttrPair(resourceName, "vpc_id", vpcResourceName, "id"), ), @@ -105,6 +106,7 @@ func TestAccAWSFlowLog_SubnetID(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "log_destination", ""), resource.TestCheckResourceAttr(resourceName, "log_destination_type", "cloud-watch-logs"), resource.TestCheckResourceAttrPair(resourceName, "log_group_name", cloudwatchLogGroupResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "max_aggregation_interval", "600"), resource.TestCheckResourceAttrPair(resourceName, "subnet_id", subnetResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "traffic_type", "ALL"), ), @@ -195,6 +197,33 @@ func TestAccAWSFlowLog_LogDestinationType_S3_Invalid(t *testing.T) { }) } +func TestAccAWSFlowLog_LogDestinationType_MaxAggregationInterval(t *testing.T) { + var flowLog ec2.FlowLog + resourceName := "aws_flow_log.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckFlowLogDestroy, + Steps: []resource.TestStep{ + { + Config: testAccFlowLogConfig_MaxAggregationInterval(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckFlowLogExists(resourceName, &flowLog), + testAccCheckAWSFlowLogAttributes(&flowLog), + resource.TestCheckResourceAttr(resourceName, "max_aggregation_interval", "60"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSFlowLog_tags(t *testing.T) { var flowLog ec2.FlowLog resourceName := "aws_flow_log.test" @@ -491,6 +520,7 @@ resource "aws_flow_log" "test" { } `, rName) } + func testAccFlowLogConfig_LogFormat(rName string) string { return testAccFlowLogConfigBase(rName) + fmt.Sprintf(` resource "aws_iam_role" "test" { @@ -523,7 +553,7 @@ resource "aws_s3_bucket" "test" { bucket = %[1]q force_destroy = true } - + resource "aws_flow_log" "test" { log_destination = "${aws_s3_bucket.test.arn}" @@ -621,3 +651,43 @@ resource "aws_flow_log" "test" { } `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } + +func testAccFlowLogConfig_MaxAggregationInterval(rName string) string { + return testAccFlowLogConfigBase(rName) + fmt.Sprintf(` +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = < Date: Thu, 26 Mar 2020 15:17:15 -0400 Subject: [PATCH 121/684] Update CHANGELOG for #12483 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd01fe4eba7..2c69af5caa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ ENHANCEMENTS: * data-source/aws_vpc_endpoint_service: Add `filter` and `tags` arguments [GH-12404] * resource/aws_athena_workgroup: Add `force_destroy` argument [GH-12254] * resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] +* resource/aws_flow_log: Add `max_aggregation_interval` argument [GH-12483] * resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument [GH-11843] * resource/aws_storagegateway_nfs_file_share: Add `path` attribute [GH-12530] From 303a43d8daddcad0af6d42e0c1bda1df3317f15a Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 8 Mar 2019 10:22:05 +0000 Subject: [PATCH 122/684] Add Codepipeline action region support Adds support for the region parameter of Codepipeline actions. This was added in November: https://aws.amazon.com/about-aws/whats-new/2018/11/aws-codepipeline-now-supports-cross-region-actions/ --- aws/resource_aws_codepipeline.go | 13 +++++++++++++ website/docs/r/codepipeline.markdown | 1 + 2 files changed, 14 insertions(+) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 0234732184e..4e90ca5a0a6 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -155,6 +155,11 @@ func resourceAwsCodePipeline() *schema.Resource { Optional: true, Computed: true, }, + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, }, }, }, @@ -319,6 +324,10 @@ func expandAwsCodePipelineActions(s []interface{}) []*codepipeline.ActionDeclara if ro > 0 { action.RunOrder = aws.Int64(int64(ro)) } + r := data["region"].(string) + if r != "" { + action.Region = aws.String(r) + } actions = append(actions, &action) } return actions @@ -360,6 +369,10 @@ func flattenAwsCodePipelineStageActions(actions []*codepipeline.ActionDeclaratio values["run_order"] = int(*action.RunOrder) } + if action.Region != nil { + values["region"] = *action.Region + } + actionsList = append(actionsList, values) } return actionsList diff --git a/website/docs/r/codepipeline.markdown b/website/docs/r/codepipeline.markdown index 386913ca07c..3bd08d7909b 100644 --- a/website/docs/r/codepipeline.markdown +++ b/website/docs/r/codepipeline.markdown @@ -190,6 +190,7 @@ A `action` block supports the following arguments: * `output_artifacts` - (Optional) A list of artifact names to output. Output artifact names must be unique within a pipeline. * `role_arn` - (Optional) The ARN of the IAM service role that will perform the declared action. This is assumed through the roleArn for the pipeline. * `run_order` - (Optional) The order in which actions are run. +* `region` - (Optional) The region in which to run the action. ~> **Note:** The input artifact of an action must exactly match the output artifact declared in a preceding action, but the input artifact does not have to be the next action in strict sequence from the action that provided the output artifact. Actions in parallel can declare different output artifacts, which are in turn consumed by different following actions. From 3cb893ee6471bfc0f32af86c08cb963b8a3a15e4 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 8 Mar 2019 17:28:05 +0000 Subject: [PATCH 123/684] Add support for Codepipeline artifact_stores Adds support for specifying Artifact Stores to enable multi region pipelines. --- aws/resource_aws_codepipeline.go | 106 +++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 4e90ca5a0a6..52166518d5b 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -40,10 +40,9 @@ func resourceAwsCodePipeline() *schema.Resource { Type: schema.TypeString, Required: true, }, - "artifact_store": { Type: schema.TypeList, - Required: true, + Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -84,6 +83,59 @@ func resourceAwsCodePipeline() *schema.Resource { }, }, }, + "artifact_stores": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "artifact_store": { + Type: schema.TypeList, + Required: false, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + codepipeline.ArtifactStoreTypeS3, + }, false), + }, + "encryption_key": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + codepipeline.EncryptionKeyTypeKms, + }, false), + }, + }, + }, + }, + }, + }, + }, + "region": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, "stage": { Type: schema.TypeList, MinItems: 2, @@ -206,19 +258,28 @@ func resourceAwsCodePipelineCreate(d *schema.ResourceData, meta interface{}) err } func expandAwsCodePipeline(d *schema.ResourceData) *codepipeline.PipelineDeclaration { - pipelineArtifactStore := expandAwsCodePipelineArtifactStore(d) pipelineStages := expandAwsCodePipelineStages(d) + pipelineArtifactStore := expandAwsCodePipelineArtifactStore(d) + pipelineArtifactStores := expandAwsCodePipelineArtifactStores(d) pipeline := codepipeline.PipelineDeclaration{ - Name: aws.String(d.Get("name").(string)), - RoleArn: aws.String(d.Get("role_arn").(string)), - ArtifactStore: pipelineArtifactStore, - Stages: pipelineStages, + Name: aws.String(d.Get("name").(string)), + RoleArn: aws.String(d.Get("role_arn").(string)), + ArtifactStore: pipelineArtifactStore, + ArtifactStores: pipelineArtifactStores, + Stages: pipelineStages, } + return &pipeline } + func expandAwsCodePipelineArtifactStore(d *schema.ResourceData) *codepipeline.ArtifactStore { configs := d.Get("artifact_store").([]interface{}) + + if configs == nil { + return nil + } + data := configs[0].(map[string]interface{}) pipelineArtifactStore := codepipeline.ArtifactStore{ Location: aws.String(data["location"].(string)), @@ -236,6 +297,37 @@ func expandAwsCodePipelineArtifactStore(d *schema.ResourceData) *codepipeline.Ar return &pipelineArtifactStore } +func expandAwsCodePipelineArtifactStores(d *schema.ResourceData) map[string]*codepipeline.ArtifactStore { + configs := d.Get("artifact_stores").([]interface{}) + + if configs == nil { + return nil + } + + pipelineArtifactStores := make(map[string]*codepipeline.ArtifactStore) + + for _, config := range configs { + data := config.(map[string]interface{}) + pipelineArtifactStores[data["region"].(string)] = &codepipeline.ArtifactStore{ + Location: aws.String(data["location"].(string)), + Type: aws.String(data["type"].(string)), + } + + tek := data["encryption_key"].([]interface{}) + + if len(tek) > 0 { + vk := tek[0].(map[string]interface{}) + ek := codepipeline.EncryptionKey{ + Type: aws.String(vk["type"].(string)), + Id: aws.String(vk["id"].(string)), + } + pipelineArtifactStores[data["region"].(string)].EncryptionKey = &ek + } + } + + return pipelineArtifactStores +} + func flattenAwsCodePipelineArtifactStore(artifactStore *codepipeline.ArtifactStore) []interface{} { values := map[string]interface{}{} values["type"] = *artifactStore.Type From 629a5aa22c4d62d9dc79eddcbe8c653c5f853e13 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Wed, 19 Feb 2020 23:50:00 +0000 Subject: [PATCH 124/684] One definition of the artifactStoreSchema --- aws/resource_aws_codepipeline.go | 124 ++++++++++--------------------- 1 file changed, 39 insertions(+), 85 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 52166518d5b..f9aba663be0 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -15,6 +15,43 @@ import ( ) func resourceAwsCodePipeline() *schema.Resource { + var artifactStoreSchema = map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + }, + + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + codepipeline.ArtifactStoreTypeS3, + }, false), + }, + + "encryption_key": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + codepipeline.EncryptionKeyTypeKms, + }, false), + }, + }, + }, + }, + } + return &schema.Resource{ Create: resourceAwsCodePipelineCreate, Read: resourceAwsCodePipelineRead, @@ -44,96 +81,13 @@ func resourceAwsCodePipeline() *schema.Resource { Type: schema.TypeList, Optional: true, MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "location": { - Type: schema.TypeString, - Required: true, - }, - - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - codepipeline.ArtifactStoreTypeS3, - }, false), - }, - - "encryption_key": { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Required: true, - }, - - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - codepipeline.EncryptionKeyTypeKms, - }, false), - }, - }, - }, - }, - }, - }, + Elem: artifactStoreSchema, }, "artifact_stores": { Type: schema.TypeMap, Optional: true, Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "artifact_store": { - Type: schema.TypeList, - Required: false, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "location": { - Type: schema.TypeString, - Required: true, - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - codepipeline.ArtifactStoreTypeS3, - }, false), - }, - "encryption_key": { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Required: true, - }, - - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - codepipeline.EncryptionKeyTypeKms, - }, false), - }, - }, - }, - }, - }, - }, - }, - "region": { - Type: schema.TypeString, - Required: true, - }, - }, + Schema: artifactStoreSchema, }, }, "stage": { From 9df6d5a90b51a7f436daadff8ca88c972b4e939d Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Thu, 20 Feb 2020 00:05:49 +0000 Subject: [PATCH 125/684] Use expandAwsCodePipelineArtifactStore to expand artifactStores --- aws/resource_aws_codepipeline.go | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index f9aba663be0..5877336b8bf 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -252,7 +252,7 @@ func expandAwsCodePipelineArtifactStore(d *schema.ResourceData) *codepipeline.Ar } func expandAwsCodePipelineArtifactStores(d *schema.ResourceData) map[string]*codepipeline.ArtifactStore { - configs := d.Get("artifact_stores").([]interface{}) + configs := d.Get("artifact_stores").(map[string]*schema.ResourceData) if configs == nil { return nil @@ -260,23 +260,8 @@ func expandAwsCodePipelineArtifactStores(d *schema.ResourceData) map[string]*cod pipelineArtifactStores := make(map[string]*codepipeline.ArtifactStore) - for _, config := range configs { - data := config.(map[string]interface{}) - pipelineArtifactStores[data["region"].(string)] = &codepipeline.ArtifactStore{ - Location: aws.String(data["location"].(string)), - Type: aws.String(data["type"].(string)), - } - - tek := data["encryption_key"].([]interface{}) - - if len(tek) > 0 { - vk := tek[0].(map[string]interface{}) - ek := codepipeline.EncryptionKey{ - Type: aws.String(vk["type"].(string)), - Id: aws.String(vk["id"].(string)), - } - pipelineArtifactStores[data["region"].(string)].EncryptionKey = &ek - } + for region, config := range configs { + pipelineArtifactStores[region] = expandAwsCodePipelineArtifactStore(config) } return pipelineArtifactStores From 0d78dfa46fd77538c16da68fe4d2ed4fa9c83838 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Thu, 20 Feb 2020 17:51:16 +0000 Subject: [PATCH 126/684] [WIP] Test for multi region codepipeline. --- aws/resource_aws_codepipeline_test.go | 172 ++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 22bb36b486a..7496a07a3e5 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -182,6 +182,34 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { }) } +func TestAccAWSCodePipeline_basic_multiregion(t *testing.T) { + if os.Getenv("GITHUB_TOKEN") == "" { + t.Skip("Environment variable GITHUB_TOKEN is not set") + } + + name := acctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCodePipelineDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCodePipelineConfig_multiregion(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCodePipelineExists("aws_codepipeline.bar"), + resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.name", "Build"), + resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.action.0.region", "eu-west-1"), + resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.action.1.region", "eu-central-1"), + resource.TestMatchResourceAttr( + "aws_codepipeline.bar", "stage.2.action.0.role_arn", + regexp.MustCompile("^arn:aws:iam::[0-9]{12}:role/codepipeline-action-role.*")), + ), + }, + }, + }) +} + func testAccCheckAWSCodePipelineExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -876,3 +904,147 @@ resource "aws_codepipeline" "test" { } `, rName, tag1, tag2) } + +func testAccAWSCodePipelineConfig_multiregion(rName string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "eu-west-1" { + bucket = "tf-test-pipeline-eu-west-1-%s" + acl = "private" +} + +resource "aws_s3_bucket" "eu-central-1" { + bucket = "tf-test-pipeline-eu-central-1-%s" + acl = "private" +} + +resource "aws_iam_role" "codepipeline_role" { + name = "codepipeline-role-%s" + + assume_role_policy = < Date: Thu, 26 Mar 2020 14:23:06 -0700 Subject: [PATCH 127/684] Fixes and test updates --- aws/resource_aws_codepipeline.go | 30 +- aws/resource_aws_codepipeline_test.go | 788 ++++++++---------- aws/resource_aws_codepipeline_webhook_test.go | 21 - 3 files changed, 364 insertions(+), 475 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 5877336b8bf..0ce759c7619 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -81,10 +81,12 @@ func resourceAwsCodePipeline() *schema.Resource { Type: schema.TypeList, Optional: true, MaxItems: 1, - Elem: artifactStoreSchema, + Elem: &schema.Resource{ + Schema: artifactStoreSchema, + }, }, "artifact_stores": { - Type: schema.TypeMap, + Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: artifactStoreSchema, @@ -108,6 +110,7 @@ func resourceAwsCodePipeline() *schema.Resource { "configuration": { Type: schema.TypeMap, Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, }, "category": { Type: schema.TypeString, @@ -230,7 +233,7 @@ func expandAwsCodePipeline(d *schema.ResourceData) *codepipeline.PipelineDeclara func expandAwsCodePipelineArtifactStore(d *schema.ResourceData) *codepipeline.ArtifactStore { configs := d.Get("artifact_store").([]interface{}) - if configs == nil { + if len(configs) == 0 { return nil } @@ -252,17 +255,17 @@ func expandAwsCodePipelineArtifactStore(d *schema.ResourceData) *codepipeline.Ar } func expandAwsCodePipelineArtifactStores(d *schema.ResourceData) map[string]*codepipeline.ArtifactStore { - configs := d.Get("artifact_stores").(map[string]*schema.ResourceData) + configs := d.Get("artifact_stores").([]interface{}) - if configs == nil { + if len(configs) == 0 { return nil } pipelineArtifactStores := make(map[string]*codepipeline.ArtifactStore) - for region, config := range configs { - pipelineArtifactStores[region] = expandAwsCodePipelineArtifactStore(config) - } + // for region, config := range configs { + // pipelineArtifactStores[region] = expandAwsCodePipelineArtifactStore(config.(*schema.ResourceData)) + // } return pipelineArtifactStores } @@ -281,6 +284,14 @@ func flattenAwsCodePipelineArtifactStore(artifactStore *codepipeline.ArtifactSto return []interface{}{values} } +func flattenAwsCodePipelineArtifactStores(artifactStores map[string]*codepipeline.ArtifactStore) []interface{} { + values := []interface{}{} + for _, artifactStore := range artifactStores { + values = append(values, artifactStore) + } + return values +} + func expandAwsCodePipelineStages(d *schema.ResourceData) []*codepipeline.StageDeclaration { configs := d.Get("stage").([]interface{}) pipelineStages := []*codepipeline.StageDeclaration{} @@ -490,6 +501,9 @@ func resourceAwsCodePipelineRead(d *schema.ResourceData, meta interface{}) error if err := d.Set("artifact_store", flattenAwsCodePipelineArtifactStore(pipeline.ArtifactStore)); err != nil { return err } + if err := d.Set("artifact_stores", flattenAwsCodePipelineArtifactStores(pipeline.ArtifactStores)); err != nil { + return err + } if err := d.Set("stage", flattenAwsCodePipelineStages(pipeline.Stages)); err != nil { return err diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 7496a07a3e5..8c35e5d035b 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -14,10 +14,6 @@ import ( ) func TestAccAWSCodePipeline_basic(t *testing.T) { - if os.Getenv("GITHUB_TOKEN") == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } - name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -30,11 +26,49 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { Config: testAccAWSCodePipelineConfig_basic(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName), - resource.TestMatchResourceAttr(resourceName, "arn", - regexp.MustCompile(fmt.Sprintf("^arn:aws:codepipeline:[^:]+:[0-9]{12}:test-pipeline-%s", name))), + resource.TestCheckResourceAttrPair(resourceName, "role_arn", "aws_iam_role.codepipeline_role", "arn"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s", name))), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.type", "S3"), + resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.#", "1"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.id", "1234"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.type", "KMS"), + resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "0"), + resource.TestCheckResourceAttr(resourceName, "stage.#", "2"), + + resource.TestCheckResourceAttr(resourceName, "stage.0.name", "Source"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.name", "Source"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.category", "Source"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.owner", "ThirdParty"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.provider", "GitHub"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.version", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.input_artifacts.#", "0"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.output_artifacts.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.output_artifacts.0", "test"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "3"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Owner", "lifesum-terraform"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Repo", "test"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Branch", "master"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.role_arn", ""), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.run_order", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.region", ""), + + resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.category", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.owner", "AWS"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.provider", "CodeBuild"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.version", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.input_artifacts.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.input_artifacts.0", "test"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.output_artifacts.#", "0"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.configuration.%", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.configuration.ProjectName", "test"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.role_arn", ""), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.run_order", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", ""), ), }, { @@ -47,8 +81,30 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.type", "S3"), + resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.#", "1"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.id", "4567"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.type", "KMS"), + resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "0"), + resource.TestCheckResourceAttr(resourceName, "stage.#", "2"), + + resource.TestCheckResourceAttr(resourceName, "stage.0.name", "Source"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.name", "Source"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.input_artifacts.#", "0"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.output_artifacts.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.output_artifacts.0", "bar"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "3"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Owner", "foo-terraform"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Repo", "bar"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Branch", "stable"), + + resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.input_artifacts.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.input_artifacts.0", "bar"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.configuration.%", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.configuration.ProjectName", "foo"), ), }, }, @@ -56,10 +112,6 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { } func TestAccAWSCodePipeline_emptyArtifacts(t *testing.T) { - if os.Getenv("GITHUB_TOKEN") == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } - name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -72,17 +124,10 @@ func TestAccAWSCodePipeline_emptyArtifacts(t *testing.T) { Config: testAccAWSCodePipelineConfig_emptyArtifacts(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName), - resource.TestMatchResourceAttr(resourceName, "arn", - regexp.MustCompile(fmt.Sprintf("^arn:aws:codepipeline:[^:]+:[0-9]{12}:test-pipeline-%s", name))), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s", name))), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.type", "S3"), - resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.category", "Build"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.owner", "AWS"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.provider", "CodeBuild"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.input_artifacts.#", "1"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.output_artifacts.#", "0"), + resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.#", "0"), ), ExpectNonEmptyPlan: true, }, @@ -96,10 +141,6 @@ func TestAccAWSCodePipeline_emptyArtifacts(t *testing.T) { } func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { - if os.Getenv("GITHUB_TOKEN") == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } - name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -114,9 +155,7 @@ func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { testAccCheckAWSCodePipelineExists(resourceName), resource.TestCheckResourceAttr(resourceName, "stage.2.name", "Deploy"), resource.TestCheckResourceAttr(resourceName, "stage.2.action.0.category", "Deploy"), - resource.TestMatchResourceAttr( - resourceName, "stage.2.action.0.role_arn", - regexp.MustCompile("^arn:aws:iam::[0-9]{12}:role/codepipeline-action-role.*")), + resource.TestCheckResourceAttrPair(resourceName, "stage.2.action.0.role_arn", "aws_iam_role.codepipeline_action_role", "arn"), ), }, { @@ -129,10 +168,6 @@ func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { } func TestAccAWSCodePipeline_tags(t *testing.T) { - if os.Getenv("GITHUB_TOKEN") == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } - name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -182,33 +217,32 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { }) } -func TestAccAWSCodePipeline_basic_multiregion(t *testing.T) { - if os.Getenv("GITHUB_TOKEN") == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } - - name := acctest.RandString(10) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSCodePipelineDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSCodePipelineConfig_multiregion(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists("aws_codepipeline.bar"), - resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.name", "Build"), - resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.action.0.region", "eu-west-1"), - resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.action.1.region", "eu-central-1"), - resource.TestMatchResourceAttr( - "aws_codepipeline.bar", "stage.2.action.0.role_arn", - regexp.MustCompile("^arn:aws:iam::[0-9]{12}:role/codepipeline-action-role.*")), - ), - }, - }, - }) -} +// func TestAccAWSCodePipeline_basic_multiregion(t *testing.T) { +// name := acctest.RandString(10) + +// resource.ParallelTest(t, resource.TestCase{ +// PreCheck: func() { testAccPreCheck(t) }, +// Providers: testAccProviders, +// CheckDestroy: testAccCheckAWSCodePipelineDestroy, +// Steps: []resource.TestStep{ +// { +// Config: testAccAWSCodePipelineConfig_multiregion(name), +// Check: resource.ComposeTestCheckFunc( +// testAccCheckAWSCodePipelineExists("aws_codepipeline.bar"), +// resource.TestCheckResourceAttr("aws_codepipeline.bar", "artifact_stores.%", "2"), +// resource.TestCheckNoResourceAttr("aws_codepipeline.bar", "artifact_store.#"), +// resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.name", "Build"), +// resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.action.0.region", "eu-west-1"), +// resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.action.1.region", "eu-central-1"), +// resource.TestMatchResourceAttr( +// "aws_codepipeline.bar", "stage.2.action.0.role_arn", +// regexp.MustCompile("^arn:aws:iam::[0-9]{12}:role/codepipeline-action-role.*"), +// ), +// ), +// }, +// }, +// }) +// } func testAccCheckAWSCodePipelineExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -253,6 +287,10 @@ func testAccCheckAWSCodePipelineDestroy(s *terraform.State) error { } func testAccPreCheckAWSCodePipeline(t *testing.T) { + if os.Getenv("GITHUB_TOKEN") == "" { + t.Skip("Environment variable GITHUB_TOKEN is not set") + } + conn := testAccProvider.Meta().(*AWSClient).codepipelineconn input := &codepipeline.ListPipelinesInput{} @@ -268,13 +306,17 @@ func testAccPreCheckAWSCodePipeline(t *testing.T) { } } -func testAccAWSCodePipelineConfig_basic(rName string) string { +func testAccAWSCodePipelineS3Bucket(rName string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "foo" { bucket = "tf-test-pipeline-%s" acl = "private" } +`, rName) +} +func testAccAWSCodePipelineServiceIAMRole(rName string) string { + return fmt.Sprintf(` resource "aws_iam_role" "codepipeline_role" { name = "codepipeline-role-%s" @@ -326,67 +368,11 @@ resource "aws_iam_role_policy" "codepipeline_policy" { } EOF } - -resource "aws_codepipeline" "test" { - name = "test-pipeline-%s" - role_arn = "${aws_iam_role.codepipeline_role.arn}" - - artifact_store { - location = "${aws_s3_bucket.foo.bucket}" - type = "S3" - - encryption_key { - id = "1234" - type = "KMS" - } - } - - stage { - name = "Source" - - action { - name = "Source" - category = "Source" - owner = "ThirdParty" - provider = "GitHub" - version = "1" - output_artifacts = ["test"] - - configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "master" - } - } - } - - stage { - name = "Build" - - action { - name = "Build" - category = "Build" - owner = "AWS" - provider = "CodeBuild" - input_artifacts = ["test"] - version = "1" - - configuration = { - ProjectName = "test" - } - } - } -} -`, rName, rName, rName) +`, rName) } -func testAccAWSCodePipelineConfig_basicUpdated(rName string) string { +func testAccAWSCodePipelineServiceIAMRoleWithAssumeRole(rName string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "foo" { - bucket = "tf-test-pipeline-%s" - acl = "private" -} - resource "aws_iam_role" "codepipeline_role" { name = "codepipeline-role-%s" @@ -433,12 +419,26 @@ resource "aws_iam_role_policy" "codepipeline_policy" { "codebuild:StartBuild" ], "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "sts:AssumeRole" + ], + "Resource": "${aws_iam_role.codepipeline_action_role.arn}" } ] } EOF } +`, rName) +} +func testAccAWSCodePipelineConfig_basic(rName string) string { + return composeConfig( + testAccAWSCodePipelineS3Bucket(rName), + testAccAWSCodePipelineServiceIAMRole(rName), + fmt.Sprintf(` resource "aws_codepipeline" "test" { name = "test-pipeline-%s" role_arn = "${aws_iam_role.codepipeline_role.arn}" @@ -448,7 +448,7 @@ resource "aws_codepipeline" "test" { type = "S3" encryption_key { - id = "4567" + id = "1234" type = "KMS" } } @@ -462,12 +462,12 @@ resource "aws_codepipeline" "test" { owner = "ThirdParty" provider = "GitHub" version = "1" - output_artifacts = ["bar"] + output_artifacts = ["test"] configuration = { - Owner = "foo-terraform" - Repo = "bar" - Branch = "stable" + Owner = "lifesum-terraform" + Repo = "test" + Branch = "master" } } } @@ -480,77 +480,81 @@ resource "aws_codepipeline" "test" { category = "Build" owner = "AWS" provider = "CodeBuild" - input_artifacts = ["bar"] + input_artifacts = ["test"] version = "1" configuration = { - ProjectName = "foo" + ProjectName = "test" } } } } -`, rName, rName, rName) +`, rName)) } -func testAccAWSCodePipelineConfig_emptyArtifacts(rName string) string { - return fmt.Sprintf(` -resource "aws_s3_bucket" "foo" { - bucket = "tf-test-pipeline-%s" - acl = "private" -} +func testAccAWSCodePipelineConfig_basicUpdated(rName string) string { + return composeConfig( + testAccAWSCodePipelineS3Bucket(rName), + testAccAWSCodePipelineServiceIAMRole(rName), + fmt.Sprintf(` +resource "aws_codepipeline" "test" { + name = "test-pipeline-%s" + role_arn = "${aws_iam_role.codepipeline_role.arn}" -resource "aws_iam_role" "codepipeline_role" { - name = "codepipeline-role-%s" + artifact_store { + location = "${aws_s3_bucket.foo.bucket}" + type = "S3" - assume_role_policy = < Date: Thu, 26 Mar 2020 16:21:07 -0700 Subject: [PATCH 128/684] Corrects error in destroy check --- aws/resource_aws_codepipeline_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 8c35e5d035b..5c48ca499d2 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -280,10 +280,13 @@ func testAccCheckAWSCodePipelineDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Expected AWS CodePipeline to be gone, but was still found") } - return nil + if isAWSErr(err, "PipelineNotFoundException", "") { + return nil + } + return err } - return fmt.Errorf("Default error in CodePipeline Test") + return nil } func testAccPreCheckAWSCodePipeline(t *testing.T) { From 7d3bcf9fe7cfb5e232d3b1dddd20987e77a29659 Mon Sep 17 00:00:00 2001 From: Arvind Kumar Date: Fri, 27 Mar 2020 19:22:55 +0530 Subject: [PATCH 129/684] docs/resource/aws_api_gateway_deployment: Fixed documentation example (#12486) - Wrapped string variable within interpolation syntax for depends_on argument in examples --- website/docs/r/api_gateway_deployment.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/api_gateway_deployment.html.markdown b/website/docs/r/api_gateway_deployment.html.markdown index dc51982bdc7..b0ee2a3664c 100644 --- a/website/docs/r/api_gateway_deployment.html.markdown +++ b/website/docs/r/api_gateway_deployment.html.markdown @@ -11,7 +11,7 @@ description: |- Provides an API Gateway REST Deployment. -> **Note:** Depends on having `aws_api_gateway_integration` inside your rest api (which in turn depends on `aws_api_gateway_method`). To avoid race conditions -you might need to add an explicit `depends_on = ["aws_api_gateway_integration.name"]`. +you might need to add an explicit `depends_on = ["${aws_api_gateway_integration.name}"]`. ## Example Usage @@ -42,7 +42,7 @@ resource "aws_api_gateway_integration" "MyDemoIntegration" { } resource "aws_api_gateway_deployment" "MyDemoDeployment" { - depends_on = ["aws_api_gateway_integration.MyDemoIntegration"] + depends_on = ["${aws_api_gateway_integration.MyDemoIntegration}"] rest_api_id = "${aws_api_gateway_rest_api.MyDemoAPI.id}" stage_name = "test" From 20c85c19eb3af4a7651136980b338f5f86b5ee43 Mon Sep 17 00:00:00 2001 From: Sheikh Araf Date: Fri, 27 Mar 2020 19:41:25 +0530 Subject: [PATCH 130/684] resource/aws_msk_cluster: Add logging_info configuration block (support CloudWatch, Firehose, and S3 logging) (#12215) Output from acceptance testing: ``` --- PASS: TestAccAWSMskCluster_basic (818.33s) --- PASS: TestAccAWSMskCluster_EncryptionInfo_EncryptionInTransit_InCluster (910.16s) --- PASS: TestAccAWSMskCluster_EncryptionInfo_EncryptionAtRestKmsKeyArn (921.25s) --- PASS: TestAccAWSMskCluster_EnhancedMonitoring (933.26s) --- PASS: TestAccAWSMskCluster_EncryptionInfo_EncryptionInTransit_ClientBroker (986.14s) --- PASS: TestAccAWSMskCluster_BrokerNodeGroupInfo_EbsVolumeSize (998.17s) --- PASS: TestAccAWSMskCluster_Tags (1021.85s) --- PASS: TestAccAWSMskCluster_OpenMonitoring (1118.75s) --- PASS: TestAccAWSMskCluster_LoggingInfo (1217.09s) --- PASS: TestAccAWSMskCluster_NumberOfBrokerNodes (1472.97s) ``` --- aws/resource_aws_msk_cluster.go | 227 ++++++++++++++++++++++- aws/resource_aws_msk_cluster_test.go | 157 ++++++++++++++++ website/docs/r/msk_cluster.html.markdown | 88 +++++++++ 3 files changed, 471 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_msk_cluster.go b/aws/resource_aws_msk_cluster.go index 74ffbf6b31f..a28dbd26535 100644 --- a/aws/resource_aws_msk_cluster.go +++ b/aws/resource_aws_msk_cluster.go @@ -252,6 +252,83 @@ func resourceAwsMskCluster() *schema.Resource { }, }, }, + "logging_info": { + Type: schema.TypeList, + Optional: true, + DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "broker_logs": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cloudwatch_logs": { + Type: schema.TypeList, + Optional: true, + DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Required: true, + }, + "log_group": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "firehose": { + Type: schema.TypeList, + Optional: true, + DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Required: true, + }, + "delivery_stream": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "s3": { + Type: schema.TypeList, + Optional: true, + DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Required: true, + }, + "bucket": { + Type: schema.TypeString, + Optional: true, + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, "tags": tagsSchema(), "zookeeper_connect_string": { Type: schema.TypeString, @@ -274,6 +351,7 @@ func resourceAwsMskClusterCreate(d *schema.ResourceData, meta interface{}) error KafkaVersion: aws.String(d.Get("kafka_version").(string)), NumberOfBrokerNodes: aws.Int64(int64(d.Get("number_of_broker_nodes").(int))), OpenMonitoring: expandMskOpenMonitoring(d.Get("open_monitoring").([]interface{})), + LoggingInfo: expandMskLoggingInfo(d.Get("logging_info").([]interface{})), Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().KafkaTags(), } @@ -393,6 +471,10 @@ func resourceAwsMskClusterRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error setting open_monitoring: %s", err) } + if err := d.Set("logging_info", flattenMskLoggingInfo(cluster.LoggingInfo)); err != nil { + return fmt.Errorf("error setting logging_info: %s", err) + } + d.Set("zookeeper_connect_string", aws.StringValue(cluster.ZookeeperConnectString)) return nil @@ -454,12 +536,13 @@ func resourceAwsMskClusterUpdate(d *schema.ResourceData, meta interface{}) error } } - if d.HasChange("enhanced_monitoring") || d.HasChange("open_monitoring") { + if d.HasChange("enhanced_monitoring") || d.HasChange("open_monitoring") || d.HasChange("logging_info") { input := &kafka.UpdateMonitoringInput{ ClusterArn: aws.String(d.Id()), CurrentVersion: aws.String(d.Get("current_version").(string)), EnhancedMonitoring: aws.String(d.Get("enhanced_monitoring").(string)), OpenMonitoring: expandMskOpenMonitoring(d.Get("open_monitoring").([]interface{})), + LoggingInfo: expandMskLoggingInfo(d.Get("logging_info").([]interface{})), } output, err := conn.UpdateMonitoring(input) @@ -672,6 +755,82 @@ func expandMskOpenMonitoringPrometheusNodeExporter(l []interface{}) *kafka.NodeE return nodeExporter } +func expandMskLoggingInfo(l []interface{}) *kafka.LoggingInfo { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + loggingInfo := &kafka.LoggingInfo{ + BrokerLogs: expandMskLoggingInfoBrokerLogs(m["broker_logs"].([]interface{})), + } + + return loggingInfo +} + +func expandMskLoggingInfoBrokerLogs(l []interface{}) *kafka.BrokerLogs { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + brokerLogs := &kafka.BrokerLogs{ + CloudWatchLogs: expandMskLoggingInfoBrokerLogsCloudWatchLogs(m["cloudwatch_logs"].([]interface{})), + Firehose: expandMskLoggingInfoBrokerLogsFirehose(m["firehose"].([]interface{})), + S3: expandMskLoggingInfoBrokerLogsS3(m["s3"].([]interface{})), + } + + return brokerLogs +} + +func expandMskLoggingInfoBrokerLogsCloudWatchLogs(l []interface{}) *kafka.CloudWatchLogs { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + cloudWatchLogs := &kafka.CloudWatchLogs{ + Enabled: aws.Bool(m["enabled"].(bool)), + LogGroup: aws.String(m["log_group"].(string)), + } + + return cloudWatchLogs +} + +func expandMskLoggingInfoBrokerLogsFirehose(l []interface{}) *kafka.Firehose { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + firehose := &kafka.Firehose{ + Enabled: aws.Bool(m["enabled"].(bool)), + DeliveryStream: aws.String(m["delivery_stream"].(string)), + } + + return firehose +} + +func expandMskLoggingInfoBrokerLogsS3(l []interface{}) *kafka.S3 { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + s3 := &kafka.S3{ + Enabled: aws.Bool(m["enabled"].(bool)), + Bucket: aws.String(m["bucket"].(string)), + Prefix: aws.String(m["prefix"].(string)), + } + + return s3 +} + func flattenMskBrokerNodeGroupInfo(b *kafka.BrokerNodeGroupInfo) []map[string]interface{} { if b == nil { @@ -804,6 +963,72 @@ func flattenMskOpenMonitoringPrometheusNodeExporter(e *kafka.NodeExporter) []map return []map[string]interface{}{m} } +func flattenMskLoggingInfo(e *kafka.LoggingInfo) []map[string]interface{} { + if e == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "broker_logs": flattenMskLoggingInfoBrokerLogs(e.BrokerLogs), + } + + return []map[string]interface{}{m} +} + +func flattenMskLoggingInfoBrokerLogs(e *kafka.BrokerLogs) []map[string]interface{} { + if e == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "cloudwatch_logs": flattenMskLoggingInfoBrokerLogsCloudWatchLogs(e.CloudWatchLogs), + "firehose": flattenMskLoggingInfoBrokerLogsFirehose(e.Firehose), + "s3": flattenMskLoggingInfoBrokerLogsS3(e.S3), + } + + return []map[string]interface{}{m} +} + +func flattenMskLoggingInfoBrokerLogsCloudWatchLogs(e *kafka.CloudWatchLogs) []map[string]interface{} { + if e == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "enabled": aws.BoolValue(e.Enabled), + "log_group": aws.StringValue(e.LogGroup), + } + + return []map[string]interface{}{m} +} + +func flattenMskLoggingInfoBrokerLogsFirehose(e *kafka.Firehose) []map[string]interface{} { + if e == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "enabled": aws.BoolValue(e.Enabled), + "delivery_stream": aws.StringValue(e.DeliveryStream), + } + + return []map[string]interface{}{m} +} + +func flattenMskLoggingInfoBrokerLogsS3(e *kafka.S3) []map[string]interface{} { + if e == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "enabled": aws.BoolValue(e.Enabled), + "bucket": aws.StringValue(e.Bucket), + "prefix": aws.StringValue(e.Prefix), + } + + return []map[string]interface{}{m} +} + func resourceAwsMskClusterDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).kafkaconn diff --git a/aws/resource_aws_msk_cluster_test.go b/aws/resource_aws_msk_cluster_test.go index b837e6bb404..9ba563e2b35 100644 --- a/aws/resource_aws_msk_cluster_test.go +++ b/aws/resource_aws_msk_cluster_test.go @@ -463,6 +463,58 @@ func TestAccAWSMskCluster_OpenMonitoring(t *testing.T) { }) } +func TestAccAWSMskCluster_LoggingInfo(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) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckMskClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccMskClusterConfigLoggingInfo(rName, false, false, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckMskClusterExists(resourceName, &cluster1), + resource.TestCheckResourceAttr(resourceName, "logging_info.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.cloudwatch_logs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.cloudwatch_logs.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.firehose.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.firehose.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.s3.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.s3.0.enabled", "false"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + 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 + }, + }, + { + Config: testAccMskClusterConfigLoggingInfo(rName, true, true, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckMskClusterExists(resourceName, &cluster2), + testAccCheckMskClusterNotRecreated(&cluster1, &cluster2), + resource.TestCheckResourceAttr(resourceName, "logging_info.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.cloudwatch_logs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.cloudwatch_logs.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.firehose.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.firehose.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.s3.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logging_info.0.broker_logs.0.s3.0.enabled", "true"), + ), + }, + }, + }) +} + func TestAccAWSMskCluster_Tags(t *testing.T) { var cluster kafka.ClusterInfo var td kafka.ListTagsForResourceOutput @@ -991,6 +1043,111 @@ resource "aws_msk_cluster" "test" { `, rName, jmxExporterEnabled, nodeExporterEnabled) } +func testAccMskClusterConfigLoggingInfo(rName string, cloudwatchLogsEnabled bool, firehoseEnabled bool, s3Enabled bool) string { + cloudwatchLogsLogGroup := "" + firehoseDeliveryStream := "" + s3Bucket := "" + + if cloudwatchLogsEnabled { + cloudwatchLogsLogGroup = "${aws_cloudwatch_log_group.test.name}" + } + if firehoseEnabled { + firehoseDeliveryStream = "${aws_kinesis_firehose_delivery_stream.test.name}" + } + if s3Enabled { + s3Bucket = "${aws_s3_bucket.bucket.id}" + } + + return testAccMskClusterBaseConfig() + fmt.Sprintf(` +resource "aws_cloudwatch_log_group" "test" { + name = "msk_broker_logs" +} + +resource "aws_s3_bucket" "bucket" { + bucket = "msk-broker-logs-test-bucket" + acl = "private" +} + +resource "aws_iam_role" "firehose_role" { + name = "firehose_test_role" + + assume_role_policy = < Date: Fri, 27 Mar 2020 10:12:05 -0400 Subject: [PATCH 131/684] Update CHANGELOG for #12215 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c69af5caa1..2c89b8a1a0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ ENHANCEMENTS: * resource/aws_athena_workgroup: Add `force_destroy` argument [GH-12254] * resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] * resource/aws_flow_log: Add `max_aggregation_interval` argument [GH-12483] +* resource/aws_msk_cluster: Add `logging_info` configuration block (support CloudWatch, Firehose, and S3 logging) [GH-12215] * resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument [GH-11843] * resource/aws_storagegateway_nfs_file_share: Add `path` attribute [GH-12530] From adab81bb20cbd0644b13d08526f21eb23aa60475 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 27 Mar 2020 17:33:30 +0300 Subject: [PATCH 132/684] resource/aws_ecs_task_definition: Add inference_accelerator configuration block (#11757) Output from acceptance testing: ``` --- PASS: TestAccAWSEcsTaskDefinition_withDockerVolumeMinimalConfig (12.44s) --- PASS: TestAccAWSEcsTaskDefinition_withScratchVolume (12.65s) --- PASS: TestAccAWSEcsTaskDefinition_constraint (12.67s) --- PASS: TestValidateAwsEcsTaskDefinitionContainerDefinitions (0.00s) --- PASS: TestAccAWSEcsTaskDefinition_arrays (13.05s) --- PASS: TestAccAWSEcsTaskDefinition_withTaskScopedDockerVolume (13.33s) --- PASS: TestAccAWSEcsTaskDefinition_Fargate (15.38s) --- PASS: TestAccAWSEcsTaskDefinition_withIPCMode (15.97s) --- PASS: TestAccAWSEcsTaskDefinition_basic (17.90s) --- PASS: TestAccAWSEcsTaskDefinition_withNetworkMode (18.84s) --- PASS: TestAccAWSEcsTaskDefinition_withEFSVolumeMinimal (20.25s) --- PASS: TestAccAWSEcsTaskDefinition_withDockerVolume (22.01s) --- PASS: TestAccAWSEcsTaskDefinition_ProxyConfiguration (22.30s) --- PASS: TestAccAWSEcsTaskDefinition_withPidMode (25.98s) --- PASS: TestAccAWSEcsTaskDefinition_inferenceAccelerator (14.47s) --- PASS: TestAccAWSEcsTaskDefinition_withTaskRoleArn (27.53s) --- PASS: TestAccAWSEcsTaskDefinition_ExecutionRole (27.50s) --- PASS: TestAccAWSEcsTaskDefinition_changeVolumesForcesNewResource (29.71s) --- PASS: TestAccAWSEcsTaskDefinition_Tags (30.14s) --- PASS: TestAccAWSEcsTaskDefinition_Inactive (41.32s) --- PASS: TestAccAWSEcsTaskDefinition_withEFSVolume (42.35s) --- PASS: TestAccAWSEcsTaskDefinition_withEcsService (75.72s) ``` --- aws/resource_aws_ecs_task_definition.go | 58 +++++++++++++++ aws/resource_aws_ecs_task_definition_test.go | 71 +++++++++++++++++++ .../docs/r/ecs_task_definition.html.markdown | 47 ++++++++++++ 3 files changed, 176 insertions(+) diff --git a/aws/resource_aws_ecs_task_definition.go b/aws/resource_aws_ecs_task_definition.go index 884716673ef..043ffbf8cf2 100644 --- a/aws/resource_aws_ecs_task_definition.go +++ b/aws/resource_aws_ecs_task_definition.go @@ -288,6 +288,25 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { }, "tags": tagsSchema(), + "inference_accelerators": { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "device_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "device_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, }, } } @@ -356,6 +375,14 @@ func resourceAwsEcsTaskDefinitionCreate(d *schema.ResourceData, meta interface{} input.Volumes = volumes } + if v, ok := d.GetOk("inference_accelerators"); ok { + iAcc, err := expandEcsInferenceAccelerators(v.(*schema.Set).List()) + if err != nil { + return err + } + input.InferenceAccelerators = iAcc + } + constraints := d.Get("placement_constraints").(*schema.Set).List() if len(constraints) > 0 { var pc []*ecs.TaskDefinitionPlacementConstraint @@ -475,6 +502,10 @@ func resourceAwsEcsTaskDefinitionRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("error setting volume: %s", err) } + if err := d.Set("inference_accelerators", flattenEcsInferenceAccelerators(taskDefinition.InferenceAccelerators)); err != nil { + return fmt.Errorf("error setting inference accelerators: %s", err) + } + if err := d.Set("placement_constraints", flattenPlacementConstraints(taskDefinition.PlacementConstraints)); err != nil { log.Printf("[ERR] Error setting placement_constraints for (%s): %s", d.Id(), err) } @@ -562,3 +593,30 @@ func resourceAwsEcsTaskDefinitionVolumeHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%s-", m["host_path"].(string))) return hashcode.String(buf.String()) } + +func flattenEcsInferenceAccelerators(list []*ecs.InferenceAccelerator) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(list)) + for _, iAcc := range list { + l := map[string]interface{}{ + "device_name": *iAcc.DeviceName, + "device_type": *iAcc.DeviceType, + } + + result = append(result, l) + } + return result +} + +func expandEcsInferenceAccelerators(configured []interface{}) ([]*ecs.InferenceAccelerator, error) { + iAccs := make([]*ecs.InferenceAccelerator, 0, len(configured)) + for _, lRaw := range configured { + data := lRaw.(map[string]interface{}) + l := &ecs.InferenceAccelerator{ + DeviceName: aws.String(data["device_name"].(string)), + DeviceType: aws.String(data["device_type"].(string)), + } + iAccs = append(iAccs, l) + } + + return iAccs, nil +} diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index 867eb51550f..2b02a9ef9ed 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -679,6 +679,34 @@ func TestAccAWSEcsTaskDefinition_ProxyConfiguration(t *testing.T) { }) } +func TestAccAWSEcsTaskDefinition_inferenceAccelerator(t *testing.T) { + var def ecs.TaskDefinition + + tdName := acctest.RandomWithPrefix("tf-acc-td-basic") + resourceName := "aws_ecs_task_definition.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEcsTaskDefinitionConfigInferenceAccelerator(tdName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), + resource.TestCheckResourceAttr(resourceName, "inference_accelerators.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAWSEcsTaskDefinitionImportStateIdFunc(resourceName), + ImportStateVerify: true, + }, + }, + }) +} + func testAccAWSEcsTaskDefinitionConfigProxyConfiguration(rName string, containerName string, proxyType string, ignoredUid string, ignoredGid string, appPorts string, proxyIngressPort string, proxyEgressPort string, egressIgnoredPorts string, egressIgnoredIPs string) string { @@ -1926,6 +1954,49 @@ DEFINITION `, rName, rName, tag1Key, tag1Value, tag2Key, tag2Value) } +func testAccAWSEcsTaskDefinitionConfigInferenceAccelerator(tdName string) string { + return fmt.Sprintf(` +resource "aws_ecs_task_definition" "test" { + family = "%s" + + container_definitions = < Date: Fri, 27 Mar 2020 10:35:42 -0400 Subject: [PATCH 133/684] docs/provider: Run make website-lint-fix --- website/docs/d/iam_role.html.markdown | 2 +- website/docs/r/ecs_task_definition.html.markdown | 4 ++-- website/docs/r/opsworks_ganglia_layer.html.markdown | 2 +- website/docs/r/opsworks_haproxy_layer.html.markdown | 2 +- website/docs/r/opsworks_java_app_layer.html.markdown | 2 +- website/docs/r/opsworks_memcached_layer.html.markdown | 2 +- website/docs/r/opsworks_mysql_layer.html.markdown | 2 +- website/docs/r/opsworks_nodejs_app_layer.html.markdown | 2 +- website/docs/r/opsworks_php_app_layer.html.markdown | 2 +- website/docs/r/opsworks_static_web_layer.html.markdown | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/website/docs/d/iam_role.html.markdown b/website/docs/d/iam_role.html.markdown index a0b4e63eb21..cccb6126893 100644 --- a/website/docs/d/iam_role.html.markdown +++ b/website/docs/d/iam_role.html.markdown @@ -35,4 +35,4 @@ data "aws_iam_role" "example" { * `path` - The path to the role. * `permissions_boundary` - The ARN of the policy that is used to set the permissions boundary for the role. * `unique_id` - The stable and unique string identifying the role. -* `tags` - The tags attached to the role. \ No newline at end of file +* `tags` - The tags attached to the role. diff --git a/website/docs/r/ecs_task_definition.html.markdown b/website/docs/r/ecs_task_definition.html.markdown index cb872bde259..ecc07d7548e 100644 --- a/website/docs/r/ecs_task_definition.html.markdown +++ b/website/docs/r/ecs_task_definition.html.markdown @@ -202,12 +202,12 @@ Guide](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-query- * `device_name` - (Required) The Elastic Inference accelerator device name. The deviceName must also be referenced in a container definition as a ResourceRequirement. * `device_type` - (Required) The Elastic Inference accelerator type to use. -##### Example Usage: +##### Example Usage ```hcl resource "aws_ecs_task_definition" "test" { family = "test" - container_definitions = < Date: Fri, 27 Mar 2020 10:39:28 -0400 Subject: [PATCH 134/684] resource/aws_ecs_task_definition: Remove pluralization from inference_accelerator configuration block argument Output from acceptance testing: ``` --- PASS: TestAccAWSEcsTaskDefinition_inferenceAccelerator (16.11s) ``` --- aws/resource_aws_ecs_task_definition.go | 6 +++--- aws/resource_aws_ecs_task_definition_test.go | 4 ++-- website/docs/r/ecs_task_definition.html.markdown | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_ecs_task_definition.go b/aws/resource_aws_ecs_task_definition.go index 043ffbf8cf2..17ed66768bf 100644 --- a/aws/resource_aws_ecs_task_definition.go +++ b/aws/resource_aws_ecs_task_definition.go @@ -288,7 +288,7 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { }, "tags": tagsSchema(), - "inference_accelerators": { + "inference_accelerator": { Type: schema.TypeSet, Optional: true, ForceNew: true, @@ -375,7 +375,7 @@ func resourceAwsEcsTaskDefinitionCreate(d *schema.ResourceData, meta interface{} input.Volumes = volumes } - if v, ok := d.GetOk("inference_accelerators"); ok { + if v, ok := d.GetOk("inference_accelerator"); ok { iAcc, err := expandEcsInferenceAccelerators(v.(*schema.Set).List()) if err != nil { return err @@ -502,7 +502,7 @@ func resourceAwsEcsTaskDefinitionRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("error setting volume: %s", err) } - if err := d.Set("inference_accelerators", flattenEcsInferenceAccelerators(taskDefinition.InferenceAccelerators)); err != nil { + if err := d.Set("inference_accelerator", flattenEcsInferenceAccelerators(taskDefinition.InferenceAccelerators)); err != nil { return fmt.Errorf("error setting inference accelerators: %s", err) } diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index 2b02a9ef9ed..99e9a5d9dd1 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -694,7 +694,7 @@ func TestAccAWSEcsTaskDefinition_inferenceAccelerator(t *testing.T) { Config: testAccAWSEcsTaskDefinitionConfigInferenceAccelerator(tdName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), - resource.TestCheckResourceAttr(resourceName, "inference_accelerators.#", "1"), + resource.TestCheckResourceAttr(resourceName, "inference_accelerator.#", "1"), ), }, { @@ -1988,7 +1988,7 @@ resource "aws_ecs_task_definition" "test" { ] TASK_DEFINITION - inference_accelerators { + inference_accelerator { device_name = "device_1" device_type = "eia1.medium" } diff --git a/website/docs/r/ecs_task_definition.html.markdown b/website/docs/r/ecs_task_definition.html.markdown index ecc07d7548e..a6db3efbe5c 100644 --- a/website/docs/r/ecs_task_definition.html.markdown +++ b/website/docs/r/ecs_task_definition.html.markdown @@ -111,7 +111,7 @@ official [Developer Guide](https://docs.aws.amazon.com/AmazonECS/latest/develope * `memory` - (Optional) The amount (in MiB) of memory used by the task. If the `requires_compatibilities` is `FARGATE` this field is required. * `requires_compatibilities` - (Optional) A set of launch types required by the task. The valid values are `EC2` and `FARGATE`. * `proxy_configuration` - (Optional) The [proxy configuration](#proxy-configuration-arguments) details for the App Mesh proxy. -* `inference_accelerators` - (Optional) The [inference accelerators](#inference-accelerators-arguments) details for Inference Accelerators. +* `inference_accelerator` - (Optional) Configuration block(s) with Inference Accelerators settings. Detailed below. * `tags` - (Optional) Key-value mapping of resource tags #### Volume Block Arguments @@ -236,7 +236,7 @@ resource "aws_ecs_task_definition" "test" { ] TASK_DEFINITION - inference_accelerators { + inference_accelerator { device_name = "device_1" device_type = "eia1.medium" } From b9c2ba09fdda6ae8f264b7f8b4961631556b7211 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 3 Mar 2020 15:42:14 -0800 Subject: [PATCH 135/684] Corrects type of `bootstrap_action` from TypeSet to TypeList --- aws/resource_aws_emr_cluster.go | 4 ++-- aws/resource_aws_emr_cluster_test.go | 21 ++++++++++++++++++++- website/docs/r/emr_cluster.html.markdown | 2 +- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_emr_cluster.go b/aws/resource_aws_emr_cluster.go index 3e4d689f79d..ef3a799d090 100644 --- a/aws/resource_aws_emr_cluster.go +++ b/aws/resource_aws_emr_cluster.go @@ -492,7 +492,7 @@ func resourceAwsEMRCluster() *schema.Resource { Set: resourceAwsEMRClusterInstanceGroupHash, }, "bootstrap_action": { - Type: schema.TypeSet, + Type: schema.TypeList, Optional: true, ForceNew: true, Elem: &schema.Resource{ @@ -860,7 +860,7 @@ func resourceAwsEMRClusterCreate(d *schema.ResourceData, meta interface{}) error } if v, ok := d.GetOk("bootstrap_action"); ok { - bootstrapActions := v.(*schema.Set).List() + bootstrapActions := v.([]interface{}) params.BootstrapActions = expandBootstrapActions(bootstrapActions) } if v, ok := d.GetOk("step"); ok { diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index cc95a86ea3f..c3a7d506ad0 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -1157,7 +1157,20 @@ func TestAccAWSEMRCluster_bootstrap_ordering(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), testAccCheck_bootstrap_order(&cluster, argsInts, argsStrings), - resource.TestCheckResourceAttr(resourceName, "bootstrap_action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.#", "3"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.name", "runif"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.path", "s3://elasticmapreduce/bootstrap-actions/run-if"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.args.#", "2"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.args.0", "instance.isMaster=true"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.args.1", "echo running on master node"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.1.name", "test"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.1.path", fmt.Sprintf("s3://%s/testscript.sh", rName)), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.1.args.#", "10"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.2.name", "runif-2"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.2.path", "s3://elasticmapreduce/bootstrap-actions/run-if"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.2.args.#", "2"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.2.args.0", "instance.isMaster=true"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.2.args.1", "echo also running on master node"), ), }, { @@ -1773,6 +1786,12 @@ resource "aws_emr_cluster" "test" { "10", ] } + + bootstrap_action { + path = "s3://elasticmapreduce/bootstrap-actions/run-if" + name = "runif-2" + args = ["instance.isMaster=true", "echo also running on master node"] + } } resource "aws_s3_bucket" "tester" { diff --git a/website/docs/r/emr_cluster.html.markdown b/website/docs/r/emr_cluster.html.markdown index 4c024e843a6..5543fa9e700 100644 --- a/website/docs/r/emr_cluster.html.markdown +++ b/website/docs/r/emr_cluster.html.markdown @@ -245,7 +245,7 @@ The following arguments are supported: * `kerberos_attributes` - (Optional) Kerberos configuration for the cluster. Defined below * `ebs_root_volume_size` - (Optional) Size in GiB of the EBS root device volume of the Linux AMI that is used for each EC2 instance. Available in Amazon EMR version 4.x and later. * `custom_ami_id` - (Optional) A custom Amazon Linux AMI for the cluster (instead of an EMR-owned AMI). Available in Amazon EMR version 5.7.0 and later. -* `bootstrap_action` - (Optional) List of bootstrap actions that will be run before Hadoop is started on the cluster nodes. Defined below +* `bootstrap_action` - (Optional) Ordered list of bootstrap actions that will be run before Hadoop is started on the cluster nodes. Defined below. * `configurations` - (Optional) List of configurations supplied for the EMR cluster you are creating * `configurations_json` - (Optional) A JSON string for supplying list of configurations for the EMR cluster. From 8943ae941ec5954e7d6cf2c67703ee5e5e6e44fa Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 4 Mar 2020 13:23:13 -0800 Subject: [PATCH 136/684] Adds tests for adding and reordering `bootstrap_actions` --- aws/resource_aws_emr_cluster_test.go | 183 +++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index c3a7d506ad0..c77fabaf863 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -1154,6 +1154,28 @@ func TestAccAWSEMRCluster_bootstrap_ordering(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSEmrClusterConfig_bootstrap(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + testAccCheck_bootstrap_order(&cluster, argsInts, argsStrings), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.name", "runif"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.path", "s3://elasticmapreduce/bootstrap-actions/run-if"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.args.#", "2"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.args.0", "instance.isMaster=true"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.args.1", "echo running on master node"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.1.name", "test"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.1.path", fmt.Sprintf("s3://%s/testscript.sh", rName)), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.1.args.#", "10"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, + }, + { + Config: testAccAWSEmrClusterConfig_bootstrapAdd(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), testAccCheck_bootstrap_order(&cluster, argsInts, argsStrings), @@ -1179,6 +1201,33 @@ func TestAccAWSEMRCluster_bootstrap_ordering(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, }, + { + Config: testAccAWSEmrClusterConfig_bootstrapReorder(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEmrClusterExists(resourceName, &cluster), + testAccCheck_bootstrap_order(&cluster, argsInts, argsStrings), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.#", "3"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.name", "runif"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.path", "s3://elasticmapreduce/bootstrap-actions/run-if"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.args.#", "2"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.args.0", "instance.isMaster=true"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.args.1", "echo running on master node"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.2.name", "test"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.2.path", fmt.Sprintf("s3://%s/testscript.sh", rName)), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.2.args.#", "10"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.1.name", "runif-2"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.1.path", "s3://elasticmapreduce/bootstrap-actions/run-if"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.1.args.#", "2"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.1.args.0", "instance.isMaster=true"), + resource.TestCheckResourceAttr(resourceName, "bootstrap_action.1.args.1", "echo also running on master node"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"configurations", "keep_job_flow_alive_when_no_steps"}, + }, }, }) } @@ -1786,6 +1835,70 @@ resource "aws_emr_cluster" "test" { "10", ] } +} + +resource "aws_s3_bucket" "tester" { + bucket = "%[1]s" + acl = "public-read" +} + +resource "aws_s3_bucket_object" "testobject" { + bucket = "${aws_s3_bucket.tester.bucket}" + key = "testscript.sh" + content = < Date: Wed, 4 Mar 2020 13:46:57 -0800 Subject: [PATCH 137/684] Applies `terrafmt fmt` --- aws/resource_aws_emr_cluster_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index c77fabaf863..e1b9da7109d 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -1843,8 +1843,8 @@ resource "aws_s3_bucket" "tester" { } resource "aws_s3_bucket_object" "testobject" { - bucket = "${aws_s3_bucket.tester.bucket}" - key = "testscript.sh" + bucket = "${aws_s3_bucket.tester.bucket}" + key = "testscript.sh" content = < Date: Thu, 5 Mar 2020 18:05:03 -0800 Subject: [PATCH 138/684] Removes unneeded test --- aws/resource_aws_emr_cluster_test.go | 62 +--------------------------- 1 file changed, 1 insertion(+), 61 deletions(-) diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index e1b9da7109d..f96c589ef78 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "log" - "reflect" "regexp" "testing" "time" @@ -1127,26 +1126,9 @@ func TestAccAWSEMRCluster_Step_Multiple(t *testing.T) { func TestAccAWSEMRCluster_bootstrap_ordering(t *testing.T) { var cluster emr.Cluster + resourceName := "aws_emr_cluster.test" rName := acctest.RandomWithPrefix("tf-emr-bootstrap") - argsInts := []string{ - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - } - - argsStrings := []string{ - "instance.isMaster=true", - "echo running on master node", - } - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -1156,7 +1138,6 @@ func TestAccAWSEMRCluster_bootstrap_ordering(t *testing.T) { Config: testAccAWSEmrClusterConfig_bootstrap(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), - testAccCheck_bootstrap_order(&cluster, argsInts, argsStrings), resource.TestCheckResourceAttr(resourceName, "bootstrap_action.#", "2"), resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.name", "runif"), resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.path", "s3://elasticmapreduce/bootstrap-actions/run-if"), @@ -1178,7 +1159,6 @@ func TestAccAWSEMRCluster_bootstrap_ordering(t *testing.T) { Config: testAccAWSEmrClusterConfig_bootstrapAdd(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), - testAccCheck_bootstrap_order(&cluster, argsInts, argsStrings), resource.TestCheckResourceAttr(resourceName, "bootstrap_action.#", "3"), resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.name", "runif"), resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.path", "s3://elasticmapreduce/bootstrap-actions/run-if"), @@ -1205,7 +1185,6 @@ func TestAccAWSEMRCluster_bootstrap_ordering(t *testing.T) { Config: testAccAWSEmrClusterConfig_bootstrapReorder(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEmrClusterExists(resourceName, &cluster), - testAccCheck_bootstrap_order(&cluster, argsInts, argsStrings), resource.TestCheckResourceAttr(resourceName, "bootstrap_action.#", "3"), resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.name", "runif"), resource.TestCheckResourceAttr(resourceName, "bootstrap_action.0.path", "s3://elasticmapreduce/bootstrap-actions/run-if"), @@ -1509,45 +1488,6 @@ func TestAccAWSEMRCluster_custom_ami_id(t *testing.T) { }) } -func testAccCheck_bootstrap_order(cluster *emr.Cluster, argsInts, argsStrings []string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - emrconn := testAccProvider.Meta().(*AWSClient).emrconn - req := emr.ListBootstrapActionsInput{ - ClusterId: cluster.Id, - } - - resp, err := emrconn.ListBootstrapActions(&req) - if err != nil { - return fmt.Errorf("Error listing boostrap actions in test: %s", err) - } - - // make sure we actually checked something - var ran bool - for _, ba := range resp.BootstrapActions { - // assume name matches the config - rArgs := aws.StringValueSlice(ba.Args) - if *ba.Name == "test" { - ran = true - if !reflect.DeepEqual(argsInts, rArgs) { - return fmt.Errorf("Error matching Bootstrap args:\n\texpected: %#v\n\tgot: %#v", argsInts, rArgs) - } - } else if *ba.Name == "runif" { - ran = true - if !reflect.DeepEqual(argsStrings, rArgs) { - return fmt.Errorf("Error matching Bootstrap args:\n\texpected: %#v\n\tgot: %#v", argsStrings, rArgs) - } - } - } - - if !ran { - return fmt.Errorf("Expected to compare bootstrap actions, but no checks were ran") - } - - return nil - } -} - func testAccCheckAWSEmrDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).emrconn From ea41c95b38b58d4274a6af3dea08c1612e40e22f Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 27 Mar 2020 13:04:35 -0400 Subject: [PATCH 139/684] provider: Updates to verify hashibot behaviors and increase stale handling per run (#12556) Reference: https://github.com/hashicorp/github-hashibot/pull/105 Reference: https://github.com/hashicorp/github-hashibot/pull/106 --- .github/workflows/stale.yml | 3 ++- .hashibot.hcl | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 02f7eae85fa..95375328b77 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,7 +1,7 @@ name: "Stale issues and pull requests" on: schedule: - - cron: "0 0 * * *" + - cron: "40 17 * * *" jobs: stale: @@ -14,6 +14,7 @@ jobs: days-before-close: 30 exempt-issue-label: 'needs-triage' exempt-pr-label: 'needs-triage' + operations-per-run: 100 stale-issue-label: 'stale' stale-issue-message: | Marking this issue as stale due to inactivity. This helps our maintainers find and focus on the active issues. If this issue receives no comments in the next 30 days it will automatically be closed. Maintainers can also remove the stale label. diff --git a/.hashibot.hcl b/.hashibot.hcl index b716ec27504..cf3679110c3 100644 --- a/.hashibot.hcl +++ b/.hashibot.hcl @@ -1,5 +1,5 @@ poll "closed_issue_locker" "locker" { - schedule = "0 50 14 * * *" + schedule = "0 10 17 * * *" closed_for = "720h" # 30 days max_issues = 500 sleep_between_issues = "5s" From 9cbf5ef57b7540fc950b856cac9c420cfead33bb Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 27 Mar 2020 13:44:10 -0400 Subject: [PATCH 140/684] tests/data-source/aws_vpc_endpoint_service: Fix EC2 policy check (#12544) Recently, AWS enabled endpoint policy support for EC2 VPC Endpoint services. Previously: ``` --- FAIL: TestAccDataSourceAwsVpcEndpointService_interface (6.11s) testing.go:654: Step 0 error: Check failed: Check 8/9 error: data.aws_vpc_endpoint_service.test: Attribute 'vpc_endpoint_policy_supported' expected "false", got "true" ``` Output from acceptance testing: ``` --- PASS: TestAccDataSourceAwsVpcEndpointService_interface (19.07s) ``` --- aws/data_source_aws_vpc_endpoint_service_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/data_source_aws_vpc_endpoint_service_test.go b/aws/data_source_aws_vpc_endpoint_service_test.go index 140e6adcc44..06d92a4e122 100644 --- a/aws/data_source_aws_vpc_endpoint_service_test.go +++ b/aws/data_source_aws_vpc_endpoint_service_test.go @@ -53,7 +53,7 @@ func TestAccDataSourceAwsVpcEndpointService_interface(t *testing.T) { resource.TestCheckResourceAttr(datasourceName, "owner", "amazon"), resource.TestCheckResourceAttr(datasourceName, "private_dns_name", fmt.Sprintf("ec2.%s.%s", region, testAccGetPartitionDNSSuffix())), resource.TestCheckResourceAttr(datasourceName, "service_type", "Interface"), - resource.TestCheckResourceAttr(datasourceName, "vpc_endpoint_policy_supported", "false"), + resource.TestCheckResourceAttr(datasourceName, "vpc_endpoint_policy_supported", "true"), resource.TestCheckResourceAttr(datasourceName, "tags.%", "0"), ), }, From d6fb651fdd50878303d046d5ea62593f9690b37a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 27 Mar 2020 14:56:37 -0400 Subject: [PATCH 141/684] service/ec2: Support metadata_options in aws_instance and aws_launch_template resources/data sources (#12491) Output from acceptance testing: ``` --- PASS: TestAccAWSInstance_addSecondaryInterface (119.84s) --- PASS: TestAccAWSInstance_addSecurityGroupNetworkInterface (121.22s) --- PASS: TestAccAWSInstance_associatePublic_defaultPrivate (195.96s) --- PASS: TestAccAWSInstance_associatePublic_defaultPublic (116.21s) --- PASS: TestAccAWSInstance_associatePublic_explicitPrivate (74.96s) --- PASS: TestAccAWSInstance_associatePublic_explicitPublic (65.15s) --- PASS: TestAccAWSInstance_associatePublic_overridePrivate (88.82s) --- PASS: TestAccAWSInstance_associatePublic_overridePublic (74.75s) --- PASS: TestAccAWSInstance_associatePublicIPAndPrivateIP (74.45s) --- PASS: TestAccAWSInstance_basic (117.55s) --- PASS: TestAccAWSInstance_blockDevices (81.13s) --- PASS: TestAccAWSInstance_changeInstanceType (250.47s) --- PASS: TestAccAWSInstance_CreditSpecification_Empty_NonBurstable (309.70s) --- PASS: TestAccAWSInstance_creditSpecification_isNotAppliedToNonBurstable (199.97s) --- PASS: TestAccAWSInstance_creditSpecification_standardCpuCredits (83.21s) --- PASS: TestAccAWSInstance_creditSpecification_standardCpuCredits_t2Tot3Taint (371.76s) --- PASS: TestAccAWSInstance_creditSpecification_unknownCpuCredits_t2 (73.69s) --- PASS: TestAccAWSInstance_creditSpecification_unknownCpuCredits_t3 (317.06s) --- PASS: TestAccAWSInstance_creditSpecification_unlimitedCpuCredits (84.87s) --- PASS: TestAccAWSInstance_creditSpecification_unlimitedCpuCredits_t2Tot3Taint (379.62s) --- PASS: TestAccAWSInstance_creditSpecification_unspecifiedDefaultsToStandard (286.49s) --- PASS: TestAccAWSInstance_CreditSpecification_UnspecifiedToEmpty_NonBurstable (80.29s) --- PASS: TestAccAWSInstance_creditSpecification_updateCpuCredits (290.97s) --- PASS: TestAccAWSInstance_creditSpecificationT3_standardCpuCredits (78.24s) --- PASS: TestAccAWSInstance_creditSpecificationT3_unlimitedCpuCredits (88.78s) --- PASS: TestAccAWSInstance_creditSpecificationT3_unspecifiedDefaultsToUnlimited (302.24s) --- PASS: TestAccAWSInstance_creditSpecificationT3_updateCpuCredits (102.13s) --- PASS: TestAccAWSInstance_disableApiTermination (164.50s) --- PASS: TestAccAWSInstance_disappears (261.26s) --- PASS: TestAccAWSInstance_EbsBlockDevice_KmsKeyArn (97.16s) --- PASS: TestAccAWSInstance_forceNewAndTagsDrift (232.47s) --- PASS: TestAccAWSInstance_getPasswordData_falseToTrue (144.52s) --- PASS: TestAccAWSInstance_getPasswordData_trueToFalse (187.83s) --- PASS: TestAccAWSInstance_GP2IopsDevice (180.18s) --- PASS: TestAccAWSInstance_GP2WithIopsValue (74.36s) --- PASS: TestAccAWSInstance_hibernation (154.28s) --- PASS: TestAccAWSInstance_inDefaultVpcBySgId (73.44s) --- PASS: TestAccAWSInstance_inDefaultVpcBySgName (63.63s) --- PASS: TestAccAWSInstance_instanceProfileChange (167.75s) --- PASS: TestAccAWSInstance_ipv6_supportAddressCount (84.39s) --- PASS: TestAccAWSInstance_ipv6_supportAddressCountWithIpv4 (74.64s) --- PASS: TestAccAWSInstance_ipv6AddressCountAndSingleAddressCausesError (10.24s) --- PASS: TestAccAWSInstance_keyPairCheck (64.02s) --- PASS: TestAccAWSInstance_metadataOptions (109.63s) --- PASS: TestAccAWSInstance_multipleRegions (288.93s) --- PASS: TestAccAWSInstance_NetworkInstanceRemovingAllSecurityGroups (80.87s) --- PASS: TestAccAWSInstance_NetworkInstanceSecurityGroups (75.71s) --- PASS: TestAccAWSInstance_NetworkInstanceVPCSecurityGroupIDs (77.31s) --- PASS: TestAccAWSInstance_noAMIEphemeralDevices (53.12s) --- PASS: TestAccAWSInstance_placementGroup (57.48s) --- PASS: TestAccAWSInstance_primaryNetworkInterface (75.66s) --- PASS: TestAccAWSInstance_primaryNetworkInterfaceSourceDestCheck (75.62s) --- PASS: TestAccAWSInstance_privateIP (225.99s) --- PASS: TestAccAWSInstance_RootBlockDevice_KmsKeyArn (332.91s) --- PASS: TestAccAWSInstance_rootBlockDeviceMismatch (184.08s) --- PASS: TestAccAWSInstance_rootInstanceStore (78.80s) --- PASS: TestAccAWSInstance_sourceDestCheck (112.21s) --- PASS: TestAccAWSInstance_tags (122.35s) --- PASS: TestAccAWSInstance_UserData_EmptyStringToUnspecified (93.28s) --- PASS: TestAccAWSInstance_UserData_UnspecifiedToEmptyString (94.48s) --- PASS: TestAccAWSInstance_userDataBase64 (140.77s) --- PASS: TestAccAWSInstance_volumeTags (110.94s) --- PASS: TestAccAWSInstance_volumeTagsComputed (113.26s) --- PASS: TestAccAWSInstance_vpc (195.02s) --- PASS: TestAccAWSInstance_withIamInstanceProfile (104.20s) --- PASS: TestAccAWSInstanceDataSource_AzUserData (126.15s) --- PASS: TestAccAWSInstanceDataSource_basic (243.94s) --- PASS: TestAccAWSInstanceDataSource_blockDevices (132.16s) --- PASS: TestAccAWSInstanceDataSource_creditSpecification (82.57s) --- PASS: TestAccAWSInstanceDataSource_EbsBlockDevice_KmsKeyId (112.70s) --- PASS: TestAccAWSInstanceDataSource_getPasswordData_falseToTrue (136.36s) --- PASS: TestAccAWSInstanceDataSource_getPasswordData_trueToFalse (182.19s) --- PASS: TestAccAWSInstanceDataSource_GetUserData (115.04s) --- PASS: TestAccAWSInstanceDataSource_GetUserData_NoUserData (126.13s) --- PASS: TestAccAWSInstanceDataSource_gp2IopsDevice (95.90s) --- PASS: TestAccAWSInstanceDataSource_keyPair (116.53s) --- PASS: TestAccAWSInstanceDataSource_metadataOptions (269.78s) --- PASS: TestAccAWSInstanceDataSource_PlacementGroup (185.42s) --- PASS: TestAccAWSInstanceDataSource_privateIP (109.88s) --- PASS: TestAccAWSInstanceDataSource_RootBlockDevice_KmsKeyId (125.17s) --- PASS: TestAccAWSInstanceDataSource_rootInstanceStore (103.80s) --- PASS: TestAccAWSInstanceDataSource_SecurityGroups (137.01s) --- PASS: TestAccAWSInstanceDataSource_tags (170.40s) --- PASS: TestAccAWSInstanceDataSource_VPC (86.95s) --- PASS: TestAccAWSInstanceDataSource_VPCSecurityGroups (88.26s) --- PASS: TestAccAWSInstancesDataSource_basic (203.13s) --- PASS: TestAccAWSInstancesDataSource_instance_state_names (181.72s) --- PASS: TestAccAWSInstancesDataSource_tags (191.42s) --- PASS: TestAccAWSLaunchTemplate_associatePublicIPAddress (24.44s) --- PASS: TestAccAWSLaunchTemplate_basic (8.09s) --- PASS: TestAccAWSLaunchTemplate_BlockDeviceMappings_EBS (46.88s) --- PASS: TestAccAWSLaunchTemplate_BlockDeviceMappings_EBS_DeleteOnTermination (41.88s) --- PASS: TestAccAWSLaunchTemplate_capacityReservation_preference (8.13s) --- PASS: TestAccAWSLaunchTemplate_capacityReservation_target (10.02s) --- PASS: TestAccAWSLaunchTemplate_cpuOptions (7.26s) --- PASS: TestAccAWSLaunchTemplate_creditSpecification_nonBurstable (8.32s) --- PASS: TestAccAWSLaunchTemplate_creditSpecification_t2 (8.46s) --- PASS: TestAccAWSLaunchTemplate_creditSpecification_t3 (8.44s) --- PASS: TestAccAWSLaunchTemplate_data (8.06s) --- PASS: TestAccAWSLaunchTemplate_description (13.41s) --- PASS: TestAccAWSLaunchTemplate_disappears (5.99s) --- PASS: TestAccAWSLaunchTemplate_EbsOptimized (29.01s) --- PASS: TestAccAWSLaunchTemplate_ElasticInferenceAccelerator (13.88s) --- PASS: TestAccAWSLaunchTemplate_IamInstanceProfile_EmptyConfigurationBlock (7.29s) --- PASS: TestAccAWSLaunchTemplate_instanceMarketOptions (47.99s) --- PASS: TestAccAWSLaunchTemplate_licenseSpecification (8.17s) --- PASS: TestAccAWSLaunchTemplate_metadataOptions (7.90s) --- PASS: TestAccAWSLaunchTemplate_networkInterface (12.15s) --- PASS: TestAccAWSLaunchTemplate_networkInterface_ipv6AddressCount (8.47s) --- PASS: TestAccAWSLaunchTemplate_networkInterface_ipv6Addresses (8.67s) --- PASS: TestAccAWSLaunchTemplate_networkInterfaceAddresses (12.01s) --- PASS: TestAccAWSLaunchTemplate_tags (14.18s) --- PASS: TestAccAWSLaunchTemplate_update (47.80s) --- PASS: TestAccAWSLaunchTemplateDataSource_basic (8.69s) --- PASS: TestAccAWSLaunchTemplateDataSource_filter_basic (8.92s) --- PASS: TestAccAWSLaunchTemplateDataSource_filter_tags (9.22s) --- PASS: TestAccAWSLaunchTemplateDataSource_metadataOptions (9.91s) ``` --- aws/data_source_aws_instance.go | 24 +++++ aws/data_source_aws_instance_test.go | 51 ++++++++++ aws/data_source_aws_launch_template.go | 24 +++++ aws/data_source_aws_launch_template_test.go | 41 +++++++++ aws/provider_test.go | 49 ++++++++++ aws/resource_aws_instance.go | 97 ++++++++++++++++++++ aws/resource_aws_instance_test.go | 88 +++++++++++++++++- aws/resource_aws_launch_template.go | 77 ++++++++++++++++ aws/resource_aws_launch_template_test.go | 43 +++++++++ website/docs/d/instance.html.markdown | 4 + website/docs/d/launch_template.html.markdown | 4 + website/docs/r/instance.html.markdown | 13 +++ website/docs/r/launch_template.html.markdown | 19 ++++ 13 files changed, 533 insertions(+), 1 deletion(-) diff --git a/aws/data_source_aws_instance.go b/aws/data_source_aws_instance.go index 8f02a7316bd..543e69675a5 100644 --- a/aws/data_source_aws_instance.go +++ b/aws/data_source_aws_instance.go @@ -279,6 +279,26 @@ func dataSourceAwsInstance() *schema.Resource { }, }, }, + "metadata_options": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_endpoint": { + Type: schema.TypeString, + Computed: true, + }, + "http_tokens": { + Type: schema.TypeString, + Computed: true, + }, + "http_put_response_hop_limit": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, "disable_api_termination": { Type: schema.TypeBool, Computed: true, @@ -486,5 +506,9 @@ func instanceDescriptionAttributes(d *schema.ResourceData, instance *ec2.Instanc return fmt.Errorf("error setting credit_specification: %s", err) } + if err := d.Set("metadata_options", flattenEc2InstanceMetadataOptions(instance.MetadataOptions)); err != nil { + return fmt.Errorf("error setting metadata_options: %s", err) + } + return nil } diff --git a/aws/data_source_aws_instance_test.go b/aws/data_source_aws_instance_test.go index 45353709683..fe9a90073e6 100644 --- a/aws/data_source_aws_instance_test.go +++ b/aws/data_source_aws_instance_test.go @@ -444,6 +444,34 @@ func TestAccAWSInstanceDataSource_creditSpecification(t *testing.T) { }) } +func TestAccAWSInstanceDataSource_metadataOptions(t *testing.T) { + resourceName := "aws_instance.test" + datasourceName := "data.aws_instance.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + instanceType := "m1.small" + + resource.ParallelTest(t, resource.TestCase{ + // No subnet_id specified requires default VPC or EC2-Classic. + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckHasDefaultVpcOrEc2Classic(t) + testAccPreCheckOffersEc2InstanceType(t, instanceType) + }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccInstanceDataSourceConfig_metadataOptions(rName, instanceType), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(datasourceName, "metadata_options.#", resourceName, "metadata_options.#"), + resource.TestCheckResourceAttrPair(datasourceName, "metadata_options.0.http_endpoint", resourceName, "metadata_options.0.http_endpoint"), + resource.TestCheckResourceAttrPair(datasourceName, "metadata_options.0.http_tokens", resourceName, "metadata_options.0.http_tokens"), + resource.TestCheckResourceAttrPair(datasourceName, "metadata_options.0.http_put_response_hop_limit", resourceName, "metadata_options.0.http_put_response_hop_limit"), + ), + }, + }, + }) +} + // Lookup based on InstanceID const testAccInstanceDataSourceConfig = ` resource "aws_instance" "test" { @@ -835,3 +863,26 @@ data "aws_instance" "test" { } `) } + +func testAccInstanceDataSourceConfig_metadataOptions(rName, instanceType string) string { + return testAccLatestAmazonLinuxHvmEbsAmiConfig() + fmt.Sprintf(` +resource "aws_instance" "test" { + ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = %[2]q + + tags = { + Name = %[1]q + } + + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 2 + } +} + +data "aws_instance" "test" { + instance_id = aws_instance.test.id +} +`, rName, instanceType) +} diff --git a/aws/data_source_aws_launch_template.go b/aws/data_source_aws_launch_template.go index 66ce2b65dd2..40170b401e0 100644 --- a/aws/data_source_aws_launch_template.go +++ b/aws/data_source_aws_launch_template.go @@ -202,6 +202,26 @@ func dataSourceAwsLaunchTemplate() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "metadata_options": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_endpoint": { + Type: schema.TypeString, + Computed: true, + }, + "http_tokens": { + Type: schema.TypeString, + Computed: true, + }, + "http_put_response_hop_limit": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, "monitoring": { Type: schema.TypeList, Computed: true, @@ -456,6 +476,10 @@ func dataSourceAwsLaunchTemplateRead(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("error setting instance_market_options: %s", err) } + if err := d.Set("metadata_options", flattenLaunchTemplateInstanceMetadataOptions(ltData.MetadataOptions)); err != nil { + return fmt.Errorf("error setting metadata_options: %s", err) + } + if err := d.Set("monitoring", getMonitoring(ltData.Monitoring)); err != nil { return fmt.Errorf("error setting monitoring: %s", err) } diff --git a/aws/data_source_aws_launch_template_test.go b/aws/data_source_aws_launch_template_test.go index dc192cf178e..1d8c90ec7ce 100644 --- a/aws/data_source_aws_launch_template_test.go +++ b/aws/data_source_aws_launch_template_test.go @@ -79,6 +79,29 @@ func TestAccAWSLaunchTemplateDataSource_filter_tags(t *testing.T) { }) } +func TestAccAWSLaunchTemplateDataSource_metadataOptions(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_launch_template.test" + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLaunchTemplateDataSourceConfig_metadataOptions(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "metadata_options.#", resourceName, "metadata_options.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "metadata_options.0.http_endpoint", resourceName, "metadata_options.0.http_endpoint"), + resource.TestCheckResourceAttrPair(dataSourceName, "metadata_options.0.http_tokens", resourceName, "metadata_options.0.http_tokens"), + resource.TestCheckResourceAttrPair(dataSourceName, "metadata_options.0.http_put_response_hop_limit", resourceName, "metadata_options.0.http_put_response_hop_limit"), + ), + }, + }, + }) +} + func testAccAWSLaunchTemplateDataSourceConfig_Basic(rName string) string { return fmt.Sprintf(` resource "aws_launch_template" "test" { @@ -124,3 +147,21 @@ data "aws_launch_template" "test" { } `, rName, rInt) } + +func testAccAWSLaunchTemplateDataSourceConfig_metadataOptions(rName string) string { + return fmt.Sprintf(` +resource "aws_launch_template" "test" { + name = %[1]q + + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 2 + } +} + +data "aws_launch_template" "test" { + name = aws_launch_template.test.name +} +`, rName) +} diff --git a/aws/provider_test.go b/aws/provider_test.go index a5cce24d3eb..b663c5bc040 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -9,8 +9,10 @@ import ( "strings" "testing" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/aws/endpoints" + "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/organizations" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -1137,6 +1139,53 @@ func testAccCheckAWSProviderPartition(providers *[]*schema.Provider, expectedPar } } +// testAccPreCheckHasDefaultVpcOrEc2Classic checks that the test region has a default VPC or has the EC2-Classic platform. +// This check is useful to ensure that an instance can be launched without specifying a subnet. +func testAccPreCheckHasDefaultVpcOrEc2Classic(t *testing.T) { + client := testAccProvider.Meta().(*AWSClient) + + if !testAccHasDefaultVpc(t) && !hasEc2Classic(client.supportedplatforms) { + t.Skipf("skipping tests; %s does not have a default VPC or EC2-Classic", client.region) + } +} + +func testAccHasDefaultVpc(t *testing.T) bool { + conn := testAccProvider.Meta().(*AWSClient).ec2conn + + resp, err := conn.DescribeAccountAttributes(&ec2.DescribeAccountAttributesInput{ + AttributeNames: aws.StringSlice([]string{ec2.AccountAttributeNameDefaultVpc}), + }) + if testAccPreCheckSkipError(err) || + len(resp.AccountAttributes) == 0 || + len(resp.AccountAttributes[0].AttributeValues) == 0 || + aws.StringValue(resp.AccountAttributes[0].AttributeValues[0].AttributeValue) == "none" { + return false + } + if err != nil { + t.Fatalf("error describing EC2 account attributes: %s", err) + } + + return true +} + +// testAccPreCheckOffersEc2InstanceType checks that the test region offers the specified EC2 instance type. +func testAccPreCheckOffersEc2InstanceType(t *testing.T, instanceType string) { + client := testAccProvider.Meta().(*AWSClient) + + resp, err := client.ec2conn.DescribeInstanceTypeOfferings(&ec2.DescribeInstanceTypeOfferingsInput{ + Filters: buildEC2AttributeFilterList(map[string]string{ + "instance-type": instanceType, + }), + LocationType: aws.String(ec2.LocationTypeRegion), + }) + if testAccPreCheckSkipError(err) || len(resp.InstanceTypeOfferings) == 0 { + t.Skipf("skipping tests; %s does not offer EC2 instance type: %s", client.region, instanceType) + } + if err != nil { + t.Fatalf("error describing EC2 instance type offerings: %s", err) + } +} + func testAccAWSProviderConfigEndpoints(endpoints string) string { //lintignore:AT004 return fmt.Sprintf(` diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index 529b6a37f82..d35ac0db122 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -524,6 +524,35 @@ func resourceAwsInstance() *schema.Resource { }, }, }, + + "metadata_options": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_endpoint": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ec2.InstanceMetadataEndpointStateEnabled, ec2.InstanceMetadataEndpointStateDisabled}, false), + }, + "http_tokens": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ec2.HttpTokensStateOptional, ec2.HttpTokensStateRequired}, false), + }, + "http_put_response_hop_limit": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 64), + }, + }, + }, + }, }, } } @@ -572,6 +601,7 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error { CreditSpecification: instanceOpts.CreditSpecification, CpuOptions: instanceOpts.CpuOptions, HibernationOptions: instanceOpts.HibernationOptions, + MetadataOptions: instanceOpts.MetadataOptions, TagSpecifications: tagSpecifications, } @@ -723,6 +753,10 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error { d.Set("hibernation", instance.HibernationOptions.Configured) } + if err := d.Set("metadata_options", flattenEc2InstanceMetadataOptions(instance.MetadataOptions)); err != nil { + return fmt.Errorf("error setting metadata_options: %s", err) + } + d.Set("ami", instance.ImageId) d.Set("instance_type", instance.InstanceType) d.Set("key_name", instance.KeyName) @@ -1211,6 +1245,27 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { } } + if d.HasChange("metadata_options") && !d.IsNewResource() { + if v, ok := d.GetOk("metadata_options"); ok { + if mo, ok := v.([]interface{})[0].(map[string]interface{}); ok { + log.Printf("[DEBUG] Modifying metadata options for Instance (%s)", d.Id()) + input := &ec2.ModifyInstanceMetadataOptionsInput{ + InstanceId: aws.String(d.Id()), + HttpEndpoint: aws.String(mo["http_endpoint"].(string)), + } + if mo["http_endpoint"].(string) == ec2.InstanceMetadataEndpointStateEnabled { + // These parameters are not allowed unless HttpEndpoint is enabled + input.HttpTokens = aws.String(mo["http_tokens"].(string)) + input.HttpPutResponseHopLimit = aws.Int64(int64(mo["http_put_response_hop_limit"].(int))) + } + _, err := conn.ModifyInstanceMetadataOptions(input) + if err != nil { + return fmt.Errorf("Error updating metadata options: %s", err) + } + } + } + } + // TODO(mitchellh): wait for the attributes we modified to // persist the change... @@ -1815,6 +1870,7 @@ type awsInstanceOpts struct { CreditSpecification *ec2.CreditSpecificationRequest CpuOptions *ec2.CpuOptionsRequest HibernationOptions *ec2.HibernationOptionsRequest + MetadataOptions *ec2.InstanceMetadataOptionsRequest } func buildAwsInstanceOpts( @@ -1827,6 +1883,7 @@ func buildAwsInstanceOpts( EBSOptimized: aws.Bool(d.Get("ebs_optimized").(bool)), ImageID: aws.String(d.Get("ami").(string)), InstanceType: aws.String(instanceType), + MetadataOptions: expandEc2InstanceMetadataOptions(d.Get("metadata_options").([]interface{})), } // Set default cpu_credits as Unlimited for T3 instance type @@ -2101,3 +2158,43 @@ func getCreditSpecifications(conn *ec2.EC2, instanceId string) ([]map[string]int return creditSpecifications, nil } + +func expandEc2InstanceMetadataOptions(l []interface{}) *ec2.InstanceMetadataOptionsRequest { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + opts := &ec2.InstanceMetadataOptionsRequest{ + HttpEndpoint: aws.String(m["http_endpoint"].(string)), + } + + if m["http_endpoint"].(string) == ec2.InstanceMetadataEndpointStateEnabled { + // These parameters are not allowed unless HttpEndpoint is enabled + + if v, ok := m["http_tokens"].(string); ok && v != "" { + opts.HttpTokens = aws.String(v) + } + + if v, ok := m["http_put_response_hop_limit"].(int); ok && v != 0 { + opts.HttpPutResponseHopLimit = aws.Int64(int64(v)) + } + } + + return opts +} + +func flattenEc2InstanceMetadataOptions(opts *ec2.InstanceMetadataOptionsResponse) []interface{} { + if opts == nil { + return nil + } + + m := map[string]interface{}{ + "http_endpoint": aws.StringValue(opts.HttpEndpoint), + "http_put_response_hop_limit": aws.Int64Value(opts.HttpPutResponseHopLimit), + "http_tokens": aws.StringValue(opts.HttpTokens), + } + + return []interface{}{m} +} diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index 52132794240..a260b3f93e1 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -2529,6 +2529,52 @@ func TestAccAWSInstance_hibernation(t *testing.T) { }) } +func TestAccAWSInstance_metadataOptions(t *testing.T) { + var v ec2.Instance + resourceName := "aws_instance.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + instanceType := "m1.small" + + resource.ParallelTest(t, resource.TestCase{ + // No subnet_id specified requires default VPC or EC2-Classic. + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckHasDefaultVpcOrEc2Classic(t) + testAccPreCheckOffersEc2InstanceType(t, instanceType) + }, + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccInstanceConfigMetadataOptions(rName, instanceType), + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "metadata_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_endpoint", "disabled"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_tokens", "optional"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_put_response_hop_limit", "1"), + ), + }, + { + Config: testAccInstanceConfigMetadataOptionsUpdated(rName, instanceType), + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "metadata_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_endpoint", "enabled"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_tokens", "required"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_put_response_hop_limit", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckInstanceNotRecreated(t *testing.T, before, after *ec2.Instance) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -4247,7 +4293,7 @@ data "aws_ami" "amzn-ami-minimal-hvm-ebs" { name = "name" values = ["amzn-ami-minimal-hvm-*"] } - + filter { name = "root-device-type" values = ["ebs"] @@ -4285,3 +4331,43 @@ resource "aws_instance" "test" { } `, hibernation) } + +func testAccInstanceConfigMetadataOptions(rName, instanceType string) string { + return testAccLatestAmazonLinuxHvmEbsAmiConfig() + fmt.Sprintf(` +resource "aws_instance" "test" { + ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = %[2]q + + tags = { + Name = %[1]q + } + + metadata_options { + http_endpoint = "disabled" + } +} + +data "aws_instance" "test" { + instance_id = aws_instance.test.id +} +`, rName, instanceType) +} + +func testAccInstanceConfigMetadataOptionsUpdated(rName, instanceType string) string { + return testAccLatestAmazonLinuxHvmEbsAmiConfig() + fmt.Sprintf(` +resource "aws_instance" "test" { + ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = %[2]q + + tags = { + Name = %[1]q + } + + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 2 + } +} +`, rName, instanceType) +} diff --git a/aws/resource_aws_launch_template.go b/aws/resource_aws_launch_template.go index 457d2b4a396..a8e7d8b005c 100644 --- a/aws/resource_aws_launch_template.go +++ b/aws/resource_aws_launch_template.go @@ -355,6 +355,35 @@ func resourceAwsLaunchTemplate() *schema.Resource { }, }, + "metadata_options": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_endpoint": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ec2.LaunchTemplateInstanceMetadataEndpointStateEnabled, ec2.LaunchTemplateInstanceMetadataEndpointStateDisabled}, false), + }, + "http_tokens": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ec2.LaunchTemplateHttpTokensStateOptional, ec2.LaunchTemplateHttpTokensStateRequired}, false), + }, + "http_put_response_hop_limit": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 64), + }, + }, + }, + }, + "monitoring": { Type: schema.TypeList, Optional: true, @@ -697,6 +726,10 @@ func resourceAwsLaunchTemplateRead(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("error setting license_specification: %s", err) } + if err := d.Set("metadata_options", flattenLaunchTemplateInstanceMetadataOptions(ltData.MetadataOptions)); err != nil { + return fmt.Errorf("error setting metadata_options: %s", err) + } + if err := d.Set("monitoring", getMonitoring(ltData.Monitoring)); err != nil { return fmt.Errorf("error setting monitoring: %s", err) } @@ -939,6 +972,46 @@ func getLicenseSpecifications(licenseSpecifications []*ec2.LaunchTemplateLicense return s } +func expandLaunchTemplateInstanceMetadataOptions(l []interface{}) *ec2.LaunchTemplateInstanceMetadataOptionsRequest { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + opts := &ec2.LaunchTemplateInstanceMetadataOptionsRequest{ + HttpEndpoint: aws.String(m["http_endpoint"].(string)), + } + + if m["http_endpoint"].(string) == ec2.LaunchTemplateInstanceMetadataEndpointStateEnabled { + // These parameters are not allowed unless HttpEndpoint is enabled + + if v, ok := m["http_tokens"].(string); ok && v != "" { + opts.HttpTokens = aws.String(v) + } + + if v, ok := m["http_put_response_hop_limit"].(int); ok && v != 0 { + opts.HttpPutResponseHopLimit = aws.Int64(int64(v)) + } + } + + return opts +} + +func flattenLaunchTemplateInstanceMetadataOptions(opts *ec2.LaunchTemplateInstanceMetadataOptions) []interface{} { + if opts == nil { + return nil + } + + m := map[string]interface{}{ + "http_endpoint": aws.StringValue(opts.HttpEndpoint), + "http_put_response_hop_limit": aws.Int64Value(opts.HttpPutResponseHopLimit), + "http_tokens": aws.StringValue(opts.HttpTokens), + } + + return []interface{}{m} +} + func getMonitoring(m *ec2.LaunchTemplatesMonitoring) []interface{} { s := []interface{}{} if m != nil { @@ -1174,6 +1247,10 @@ func buildLaunchTemplateData(d *schema.ResourceData) (*ec2.RequestLaunchTemplate opts.LicenseSpecifications = licenseSpecifications } + if v, ok := d.GetOk("metadata_options"); ok { + opts.MetadataOptions = expandLaunchTemplateInstanceMetadataOptions(v.([]interface{})) + } + if v, ok := d.GetOk("monitoring"); ok { m := v.([]interface{}) if len(m) > 0 && m[0] != nil { diff --git a/aws/resource_aws_launch_template_test.go b/aws/resource_aws_launch_template_test.go index ebd3b765f56..367eabf32d4 100644 --- a/aws/resource_aws_launch_template_test.go +++ b/aws/resource_aws_launch_template_test.go @@ -836,6 +836,35 @@ func TestAccAWSLaunchTemplate_licenseSpecification(t *testing.T) { }) } +func TestAccAWSLaunchTemplate_metadataOptions(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLaunchTemplateConfig_metadataOptions(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "metadata_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_endpoint", "enabled"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_tokens", "required"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_put_response_hop_limit", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckAWSLaunchTemplateExists(n string, t *ec2.LaunchTemplate) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -1507,3 +1536,17 @@ resource "aws_autoscaling_group" "test" { } } ` + +func testAccAWSLaunchTemplateConfig_metadataOptions(rName string) string { + return fmt.Sprintf(` +resource "aws_launch_template" "test" { + name = %[1]q + + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 2 + } +} +`, rName) +} diff --git a/website/docs/d/instance.html.markdown b/website/docs/d/instance.html.markdown index 25fa4879653..6a013104cbe 100644 --- a/website/docs/d/instance.html.markdown +++ b/website/docs/d/instance.html.markdown @@ -112,5 +112,9 @@ interpolation. * `host_id` - The Id of the dedicated host the instance will be assigned to. * `vpc_security_group_ids` - The associated security groups in a non-default VPC. * `credit_specification` - The credit specification of the Instance. +* `metadata_options` - The metadata options of the Instance. + * `http_endpoint` - The state of the metadata service: `enabled`, `disabled`. + * `http_tokens` - If session tokens are required: `optional`, `required`. + * `http_put_response_hop_limit` - The desired HTTP PUT response hop limit for instance metadata requests. [1]: http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html diff --git a/website/docs/d/launch_template.html.markdown b/website/docs/d/launch_template.html.markdown index b9db24e4111..9b8941f31a0 100644 --- a/website/docs/d/launch_template.html.markdown +++ b/website/docs/d/launch_template.html.markdown @@ -71,6 +71,10 @@ In addition to all arguments above, the following attributes are exported: * `instance_type` - The type of the instance. * `kernel_id` - The kernel ID. * `key_name` - The key name to use for the instance. +* `metadata_options` - The metadata options for the instance. + * `http_endpoint` - The state of the metadata service: `enabled`, `disabled`. + * `http_tokens` - If session tokens are required: `optional`, `required`. + * `http_put_response_hop_limit` - The desired HTTP PUT response hop limit for instance metadata requests. * `monitoring` - The monitoring option for the instance. * `network_interfaces` - Customize network interfaces to be attached at instance boot time. See [Network Interfaces](#network-interfaces) below for more details. diff --git a/website/docs/r/instance.html.markdown b/website/docs/r/instance.html.markdown index 94435d4a01f..1b56547543d 100644 --- a/website/docs/r/instance.html.markdown +++ b/website/docs/r/instance.html.markdown @@ -106,6 +106,7 @@ instances. See [Shutdown Behavior](https://docs.aws.amazon.com/AWSEC2/latest/Use * `network_interface` - (Optional) Customize network interfaces to be attached at instance boot time. See [Network Interfaces](#network-interfaces) below for more details. * `credit_specification` - (Optional) Customize the credit specification of the instance. See [Credit Specification](#credit-specification) below for more details. * `hibernation` - (Optional) If true, the launched EC2 instance will support hibernation. +* `metadata_options` - (Optional) Customize the metadata options of the instance. See [Metadata Options](#metadata-options) below for more details. ### Timeouts @@ -197,6 +198,18 @@ The `credit_specification` block supports the following: * `cpu_credits` - (Optional) The credit option for CPU usage. Can be `"standard"` or `"unlimited"`. T3 instances are launched as unlimited by default. T2 instances are launched as standard by default. +### Metadata Options + +Metadata options can be applied/modified to the EC2 Instance at any time. + +The `metadata_options` block supports the following: + +* `http_endpoint` - (Optional) Whether the metadata service is available. Can be `"enabled"` or `"disabled"`. (Default: `"enabled"`). +* `http_tokens` - (Optional) Whether or not the metadata service requires session tokens, also referred to as _Instance Metadata Service Version 2_. Can be `"optional"` or `"required"`. (Default: `"optional"`). +* `http_put_response_hop_limit` - (Optional) The desired HTTP PUT response hop limit for instance metadata requests. The larger the number, the further instance metadata requests can travel. Can be an integer from `1` to `64`. (Default: `1`). + +For more information, see the documentation on the [Instance Metadata Service](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html). + ### Example ```hcl diff --git a/website/docs/r/launch_template.html.markdown b/website/docs/r/launch_template.html.markdown index e5c3d9eb877..d699bc9d1ff 100644 --- a/website/docs/r/launch_template.html.markdown +++ b/website/docs/r/launch_template.html.markdown @@ -71,6 +71,12 @@ resource "aws_launch_template" "foo" { license_configuration_arn = "arn:aws:license-manager:eu-west-1:123456789012:license-configuration:lic-0123456789abcdef0123456789abcdef" } + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 1 + } + monitoring { enabled = true } @@ -129,6 +135,7 @@ The following arguments are supported: * `kernel_id` - The kernel ID. * `key_name` - The key name to use for the instance. * `license_specification` - A list of license specifications to associate with. See [License Specification](#license-specification) below for more details. +* `metadata_options` - (Optional) Customize the metadata options for the instance. See [Metadata Options](#metadata-options) below for more details. * `monitoring` - The monitoring option for the instance. See [Monitoring](#monitoring) below for more details. * `network_interfaces` - Customize network interfaces to be attached at instance boot time. See [Network Interfaces](#network-interfaces) below for more details. @@ -253,6 +260,18 @@ The `spot_options` block supports the following: * `spot_instance_type` - The Spot Instance request type. Can be `one-time`, or `persistent`. * `valid_until` - The end date of the request. +### Metadata Options + +The metadata options for the instances. + +The `metadata_options` block supports the following: + +* `http_endpoint` - (Optional) Whether the metadata service is available. Can be `"enabled"` or `"disabled"`. (Default: `"enabled"`). +* `http_tokens` - (Optional) Whether or not the metadata service requires session tokens, also referred to as _Instance Metadata Service Version 2_. Can be `"optional"` or `"required"`. (Default: `"optional"`). +* `http_put_response_hop_limit` - (Optional) The desired HTTP PUT response hop limit for instance metadata requests. The larger the number, the further instance metadata requests can travel. Can be an integer from `1` to `64`. (Default: `1`). + +For more information, see the documentation on the [Instance Metadata Service](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html). + ### Monitoring The `monitoring` block supports the following: From e612559a5971de725e7ec5d09179b54f110a9252 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 27 Mar 2020 14:59:21 -0400 Subject: [PATCH 142/684] Update CHANGELOG for #12491 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c89b8a1a0a..136a42796f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,12 +12,16 @@ ENHANCEMENTS: * data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] * data-source/aws_ec2_transit_gateway_dx_gateway_attachement: Add `filter` and `tags` arguments [GH-12516] * data-source/aws_ec2_transit_gateway_vpn_attachment: Add `filter` and `tags` arguments [GH-12415] +* data-source/aws_instance: Add `metadata_options` attribute [GH-12491] * data-source/aws_launch_template: Add `filter` and `tags` arguments [GH-12403] +* data-source/aws_launch_template: Add `metadata_options` attribute [GH-12491] * data-source/aws_prefix_list: Add `filter` argument [GH-12416] * data-source/aws_vpc_endpoint_service: Add `filter` and `tags` arguments [GH-12404] * resource/aws_athena_workgroup: Add `force_destroy` argument [GH-12254] * resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] * resource/aws_flow_log: Add `max_aggregation_interval` argument [GH-12483] +* resource/aws_instance: Add `metadata_options` configuration block (support IMDSv2) [GH-12491] +* resource/aws_launch_template: Add `metadata_options` configuration block (support IMDSv2) [GH-12491] * resource/aws_msk_cluster: Add `logging_info` configuration block (support CloudWatch, Firehose, and S3 logging) [GH-12215] * resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument [GH-11843] * resource/aws_storagegateway_nfs_file_share: Add `path` attribute [GH-12530] From 76df6f6fbfe22e3ed9cfad16bf331700e76f953a Mon Sep 17 00:00:00 2001 From: Shray Kumar Date: Fri, 27 Mar 2020 15:07:23 -0400 Subject: [PATCH 143/684] resource/aws_neptune_cluster_instance: Add missing configuring-log-exports as allowed pending state (#12079) Output from acceptance testing: ``` --- PASS: TestAccAWSNeptuneClusterInstance_generatedName (729.54s) --- PASS: TestAccAWSNeptuneClusterInstance_namePrefix (739.61s) --- PASS: TestAccAWSNeptuneClusterInstance_withSubnetGroup (769.73s) --- PASS: TestAccAWSNeptuneClusterInstance_kmsKey (826.88s) --- PASS: TestAccAWSNeptuneClusterInstance_withaz (870.06s) --- PASS: TestAccAWSNeptuneClusterInstance_basic (1654.49s) ``` --- aws/resource_aws_neptune_cluster_instance.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_neptune_cluster_instance.go b/aws/resource_aws_neptune_cluster_instance.go index 0db3d20cc49..ffe605627b4 100644 --- a/aws/resource_aws_neptune_cluster_instance.go +++ b/aws/resource_aws_neptune_cluster_instance.go @@ -493,6 +493,7 @@ var resourceAwsNeptuneClusterInstanceCreateUpdatePendingStates = []string{ "renaming", "starting", "upgrading", + "configuring-log-exports", } var resourceAwsNeptuneClusterInstanceDeletePendingStates = []string{ From 1d719e7407378a193769f2179198b85524444def Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 27 Mar 2020 15:08:38 -0400 Subject: [PATCH 144/684] Update CHANGELOG for #12079 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 136a42796f1..caa5548e277 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ BUG FIXES: * resource/aws_db_instance: Allow restoring from snapshot into RAM shared Subnet with VPC Security Group [GH-12447] * resource/aws_mq_configuration: Remove extraneous `ListTags` API call during refresh [GH-11843] +* resource/aws_neptune_cluster_instance: Add missing `configuring-log-exports` as allowed pending state [GH-12079] ## 2.54.0 (March 19, 2020) From 343e32ed5605b0815bf501bf0f4ba72740603567 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 27 Mar 2020 14:05:46 -0700 Subject: [PATCH 145/684] Update CHANGELOG for #12305 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index caa5548e277..206b8f3f294 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ ENHANCEMENTS: * resource/aws_launch_template: Add `metadata_options` configuration block (support IMDSv2) [GH-12491] * resource/aws_msk_cluster: Add `logging_info` configuration block (support CloudWatch, Firehose, and S3 logging) [GH-12215] * resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument [GH-11843] +* resource/aws_route53_health_check: A dd plan-time validation to `insufficient_data_health_status` [GH-12305] * resource/aws_storagegateway_nfs_file_share: Add `path` attribute [GH-12530] BUG FIXES: @@ -31,6 +32,7 @@ BUG FIXES: * resource/aws_db_instance: Allow restoring from snapshot into RAM shared Subnet with VPC Security Group [GH-12447] * resource/aws_mq_configuration: Remove extraneous `ListTags` API call during refresh [GH-11843] * resource/aws_neptune_cluster_instance: Add missing `configuring-log-exports` as allowed pending state [GH-12079] +* resource/aws_route53_health_check: Do not recreate health check when using compressed ipv6 address [GH-12305] ## 2.54.0 (March 19, 2020) From 3bef4e2479d311b32828051e7b63f51d4c7cccc1 Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Fri, 27 Mar 2020 21:16:46 +0000 Subject: [PATCH 146/684] v2.55.0 --- CHANGELOG.md | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index caa5548e277..c9bcad1bddd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,36 +1,36 @@ -## 2.55.0 (Unreleased) +## 2.55.0 (March 27, 2020) FEATURES: -* **New Resource:** `aws_ec2_availability_zone_group` [GH-12400] +* **New Resource:** `aws_ec2_availability_zone_group` ([#12400](https://github.com/terraform-providers/terraform-provider-aws/issues/12400)) ENHANCEMENTS: -* data-source/aws_availability_zone: Add `all_availability_zones` and `filter` arguments [GH-12400] -* data-source/aws_availability_zone: Add `group_name`, `network_border_group`, and `opt_in_status` attributes [GH-12400] -* data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments [GH-12400] -* data-source/aws_availability_zones: Add `group_names` attribute [GH-12400] -* data-source/aws_ec2_transit_gateway_dx_gateway_attachement: Add `filter` and `tags` arguments [GH-12516] -* data-source/aws_ec2_transit_gateway_vpn_attachment: Add `filter` and `tags` arguments [GH-12415] -* data-source/aws_instance: Add `metadata_options` attribute [GH-12491] -* data-source/aws_launch_template: Add `filter` and `tags` arguments [GH-12403] -* data-source/aws_launch_template: Add `metadata_options` attribute [GH-12491] -* data-source/aws_prefix_list: Add `filter` argument [GH-12416] -* data-source/aws_vpc_endpoint_service: Add `filter` and `tags` arguments [GH-12404] -* resource/aws_athena_workgroup: Add `force_destroy` argument [GH-12254] -* resource/aws_cloudwatch_log_metric_filter: Support resource import [GH-11992] -* resource/aws_flow_log: Add `max_aggregation_interval` argument [GH-12483] -* resource/aws_instance: Add `metadata_options` configuration block (support IMDSv2) [GH-12491] -* resource/aws_launch_template: Add `metadata_options` configuration block (support IMDSv2) [GH-12491] -* resource/aws_msk_cluster: Add `logging_info` configuration block (support CloudWatch, Firehose, and S3 logging) [GH-12215] -* resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument [GH-11843] -* resource/aws_storagegateway_nfs_file_share: Add `path` attribute [GH-12530] +* data-source/aws_availability_zone: Add `all_availability_zones` and `filter` arguments ([#12400](https://github.com/terraform-providers/terraform-provider-aws/issues/12400)) +* data-source/aws_availability_zone: Add `group_name`, `network_border_group`, and `opt_in_status` attributes ([#12400](https://github.com/terraform-providers/terraform-provider-aws/issues/12400)) +* data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments ([#12400](https://github.com/terraform-providers/terraform-provider-aws/issues/12400)) +* data-source/aws_availability_zones: Add `group_names` attribute ([#12400](https://github.com/terraform-providers/terraform-provider-aws/issues/12400)) +* data-source/aws_ec2_transit_gateway_dx_gateway_attachement: Add `filter` and `tags` arguments ([#12516](https://github.com/terraform-providers/terraform-provider-aws/issues/12516)) +* data-source/aws_ec2_transit_gateway_vpn_attachment: Add `filter` and `tags` arguments ([#12415](https://github.com/terraform-providers/terraform-provider-aws/issues/12415)) +* data-source/aws_instance: Add `metadata_options` attribute ([#12491](https://github.com/terraform-providers/terraform-provider-aws/issues/12491)) +* data-source/aws_launch_template: Add `filter` and `tags` arguments ([#12403](https://github.com/terraform-providers/terraform-provider-aws/issues/12403)) +* data-source/aws_launch_template: Add `metadata_options` attribute ([#12491](https://github.com/terraform-providers/terraform-provider-aws/issues/12491)) +* data-source/aws_prefix_list: Add `filter` argument ([#12416](https://github.com/terraform-providers/terraform-provider-aws/issues/12416)) +* data-source/aws_vpc_endpoint_service: Add `filter` and `tags` arguments ([#12404](https://github.com/terraform-providers/terraform-provider-aws/issues/12404)) +* resource/aws_athena_workgroup: Add `force_destroy` argument ([#12254](https://github.com/terraform-providers/terraform-provider-aws/issues/12254)) +* resource/aws_cloudwatch_log_metric_filter: Support resource import ([#11992](https://github.com/terraform-providers/terraform-provider-aws/issues/11992)) +* resource/aws_flow_log: Add `max_aggregation_interval` argument ([#12483](https://github.com/terraform-providers/terraform-provider-aws/issues/12483)) +* resource/aws_instance: Add `metadata_options` configuration block (support IMDSv2) ([#12491](https://github.com/terraform-providers/terraform-provider-aws/issues/12491)) +* resource/aws_launch_template: Add `metadata_options` configuration block (support IMDSv2) ([#12491](https://github.com/terraform-providers/terraform-provider-aws/issues/12491)) +* resource/aws_msk_cluster: Add `logging_info` configuration block (support CloudWatch, Firehose, and S3 logging) ([#12215](https://github.com/terraform-providers/terraform-provider-aws/issues/12215)) +* resource/aws_mq_configuration: Support plan-time validation for `engine_type` argument ([#11843](https://github.com/terraform-providers/terraform-provider-aws/issues/11843)) +* resource/aws_storagegateway_nfs_file_share: Add `path` attribute ([#12530](https://github.com/terraform-providers/terraform-provider-aws/issues/12530)) BUG FIXES: -* resource/aws_db_instance: Allow restoring from snapshot into RAM shared Subnet with VPC Security Group [GH-12447] -* resource/aws_mq_configuration: Remove extraneous `ListTags` API call during refresh [GH-11843] -* resource/aws_neptune_cluster_instance: Add missing `configuring-log-exports` as allowed pending state [GH-12079] +* resource/aws_db_instance: Allow restoring from snapshot into RAM shared Subnet with VPC Security Group ([#12447](https://github.com/terraform-providers/terraform-provider-aws/issues/12447)) +* resource/aws_mq_configuration: Remove extraneous `ListTags` API call during refresh ([#11843](https://github.com/terraform-providers/terraform-provider-aws/issues/11843)) +* resource/aws_neptune_cluster_instance: Add missing `configuring-log-exports` as allowed pending state ([#12079](https://github.com/terraform-providers/terraform-provider-aws/issues/12079)) ## 2.54.0 (March 19, 2020) From 1c5dfb20f8a3371d76edb09fb2fc15c93c838159 Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Fri, 27 Mar 2020 21:33:15 +0000 Subject: [PATCH 147/684] Cleanup after v2.55.0 release --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9bcad1bddd..ca43256546c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +## 2.56.0 (Unreleased) ## 2.55.0 (March 27, 2020) FEATURES: From 7db36f3dd45c8711017ee843f2683952f1ea9b48 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 27 Mar 2020 14:50:57 -0700 Subject: [PATCH 148/684] Fixes rebase errors and adds `depends_on` for IAM policy attachments --- aws/resource_aws_emr_cluster_test.go | 364 ++++++++++++++++----------- 1 file changed, 217 insertions(+), 147 deletions(-) diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index f96c589ef78..65ea77d7b80 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -1734,6 +1734,7 @@ func testAccAWSEmrClusterConfig_bootstrap(r string) string { return testAccAWSEmrComposeConfig(false, testAccAWSEmrClusterConfigIAMServiceRoleBase(r), testAccAWSEmrClusterConfigIAMInstanceProfileBase(r), + testAccAWSEmrClusterConfigBootstrapActionBucket(r), fmt.Sprintf(` resource "aws_emr_cluster" "test" { name = "%[1]s" @@ -1743,14 +1744,19 @@ resource "aws_emr_cluster" "test" { master_instance_type = "c4.large" core_instance_type = "c4.large" core_instance_count = 1 - service_role = "${aws_iam_role.iam_emr_default_role.arn}" - depends_on = ["aws_route_table_association.test"] + + service_role = "${aws_iam_role.emr_service.arn}" + depends_on = [ + "aws_route_table_association.test", + "aws_iam_role_policy_attachment.emr_service", + "aws_iam_role_policy_attachment.emr_instance_profile", + ] ec2_attributes { subnet_id = "${aws_subnet.test.id}" emr_managed_master_security_group = "${aws_security_group.test.id}" emr_managed_slave_security_group = "${aws_security_group.test.id}" - instance_profile = "${aws_iam_instance_profile.emr_profile.arn}" + instance_profile = "${aws_iam_instance_profile.emr_instance_profile.arn}" } bootstrap_action { @@ -1776,29 +1782,16 @@ resource "aws_emr_cluster" "test" { ] } } - -resource "aws_s3_bucket" "tester" { - bucket = "%[1]s" - acl = "public-read" -} - -resource "aws_s3_bucket_object" "testobject" { - bucket = "${aws_s3_bucket.tester.bucket}" - key = "testscript.sh" - content = < Date: Fri, 27 Mar 2020 17:24:08 -0700 Subject: [PATCH 149/684] Removes redundant CodePipelineExists test from CodePipleline webhook tests --- aws/resource_aws_codepipeline_webhook_test.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/aws/resource_aws_codepipeline_webhook_test.go b/aws/resource_aws_codepipeline_webhook_test.go index a1cb4dce10f..bda745d7ccd 100644 --- a/aws/resource_aws_codepipeline_webhook_test.go +++ b/aws/resource_aws_codepipeline_webhook_test.go @@ -15,7 +15,6 @@ func TestAccAWSCodePipelineWebhook_basic(t *testing.T) { var v codepipeline.ListWebhookItem rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_codepipeline_webhook.test" - pipelineResourceName := "aws_codepipeline.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, @@ -25,7 +24,6 @@ func TestAccAWSCodePipelineWebhook_basic(t *testing.T) { { Config: testAccAWSCodePipelineWebhookConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(pipelineResourceName), testAccCheckAWSCodePipelineWebhookExists(resourceName, &v), resource.TestCheckResourceAttrSet(resourceName, "id"), resource.TestCheckResourceAttrSet(resourceName, "url"), @@ -46,7 +44,6 @@ func TestAccAWSCodePipelineWebhook_ipAuth(t *testing.T) { var v codepipeline.ListWebhookItem rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_codepipeline_webhook.test" - pipelineResourceName := "aws_codepipeline.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, @@ -56,7 +53,6 @@ func TestAccAWSCodePipelineWebhook_ipAuth(t *testing.T) { { Config: testAccAWSCodePipelineWebhookConfig_ipAuth(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(pipelineResourceName), testAccCheckAWSCodePipelineWebhookExists(resourceName, &v), resource.TestCheckResourceAttrSet(resourceName, "id"), resource.TestCheckResourceAttrSet(resourceName, "url"), @@ -77,7 +73,6 @@ func TestAccAWSCodePipelineWebhook_unauthenticated(t *testing.T) { var v codepipeline.ListWebhookItem rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_codepipeline_webhook.test" - pipelineResourceName := "aws_codepipeline.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, @@ -87,7 +82,6 @@ func TestAccAWSCodePipelineWebhook_unauthenticated(t *testing.T) { { Config: testAccAWSCodePipelineWebhookConfig_unauthenticated(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(pipelineResourceName), testAccCheckAWSCodePipelineWebhookExists(resourceName, &v), resource.TestCheckResourceAttrSet(resourceName, "id"), resource.TestCheckResourceAttrSet(resourceName, "url"), @@ -106,7 +100,6 @@ func TestAccAWSCodePipelineWebhook_tags(t *testing.T) { var v1, v2, v3 codepipeline.ListWebhookItem rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_codepipeline_webhook.test" - pipelineResourceName := "aws_codepipeline.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, @@ -116,7 +109,6 @@ func TestAccAWSCodePipelineWebhook_tags(t *testing.T) { { Config: testAccAWSCodePipelineWebhookConfigWithTags(rName, "tag1value", "tag2value"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(pipelineResourceName), testAccCheckAWSCodePipelineWebhookExists(resourceName, &v1), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), @@ -127,7 +119,6 @@ func TestAccAWSCodePipelineWebhook_tags(t *testing.T) { { Config: testAccAWSCodePipelineWebhookConfigWithTags(rName, "tag1valueUpdate", "tag2valueUpdate"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(pipelineResourceName), testAccCheckAWSCodePipelineWebhookExists(resourceName, &v2), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), @@ -149,7 +140,6 @@ func TestAccAWSCodePipelineWebhook_tags(t *testing.T) { { Config: testAccAWSCodePipelineWebhookConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(pipelineResourceName), testAccCheckAWSCodePipelineWebhookExists(resourceName, &v3), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), func(s *terraform.State) error { @@ -168,7 +158,6 @@ func TestAccAWSCodePipelineWebhook_UpdateAuthenticationConfiguration_SecretToken var v1, v2 codepipeline.ListWebhookItem rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_codepipeline_webhook.test" - pipelineResourceName := "aws_codepipeline.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, @@ -178,7 +167,6 @@ func TestAccAWSCodePipelineWebhook_UpdateAuthenticationConfiguration_SecretToken { Config: testAccAWSCodePipelineWebhookConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(pipelineResourceName), testAccCheckAWSCodePipelineWebhookExists(resourceName, &v1), resource.TestCheckResourceAttrSet(resourceName, "id"), resource.TestCheckResourceAttrSet(resourceName, "url"), @@ -189,7 +177,6 @@ func TestAccAWSCodePipelineWebhook_UpdateAuthenticationConfiguration_SecretToken { Config: testAccAWSCodePipelineWebhookConfig_secretTokenUpdated(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(pipelineResourceName), testAccCheckAWSCodePipelineWebhookExists(resourceName, &v2), resource.TestCheckResourceAttrSet(resourceName, "id"), resource.TestCheckResourceAttrSet(resourceName, "url"), From e8f9097fbcb7e4ad6d99231b81407bb27ef1aa66 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 27 Mar 2020 17:39:46 -0700 Subject: [PATCH 150/684] Handles creation and import of cross-region CodePipeline actions --- aws/resource_aws_codepipeline.go | 65 +++-- aws/resource_aws_codepipeline_test.go | 398 ++++++++++++++------------ 2 files changed, 261 insertions(+), 202 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 0ce759c7619..5b6e46c80d1 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/codepipeline" + "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" @@ -50,6 +51,10 @@ func resourceAwsCodePipeline() *schema.Resource { }, }, }, + "region": { + Type: schema.TypeString, + Optional: true, + }, } return &schema.Resource{ @@ -86,11 +91,12 @@ func resourceAwsCodePipeline() *schema.Resource { }, }, "artifact_stores": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, Elem: &schema.Resource{ Schema: artifactStoreSchema, }, + Set: resourceAwsCodePipelineArtifactStoreHash, }, "stage": { Type: schema.TypeList, @@ -237,7 +243,29 @@ func expandAwsCodePipelineArtifactStore(d *schema.ResourceData) *codepipeline.Ar return nil } - data := configs[0].(map[string]interface{}) + _, pipelineArtifactStore := expandAwsCodePipelineArtifactStoreData(configs[0].(map[string]interface{})) + + return pipelineArtifactStore +} + +func expandAwsCodePipelineArtifactStores(d *schema.ResourceData) map[string]*codepipeline.ArtifactStore { + configs := d.Get("artifact_stores").(*schema.Set).List() + + if len(configs) == 0 { + return nil + } + + pipelineArtifactStores := make(map[string]*codepipeline.ArtifactStore) + + for _, config := range configs { + region, store := expandAwsCodePipelineArtifactStoreData(config.(map[string]interface{})) + pipelineArtifactStores[region] = store + } + + return pipelineArtifactStores +} + +func expandAwsCodePipelineArtifactStoreData(data map[string]interface{}) (string, *codepipeline.ArtifactStore) { pipelineArtifactStore := codepipeline.ArtifactStore{ Location: aws.String(data["location"].(string)), Type: aws.String(data["type"].(string)), @@ -251,26 +279,15 @@ func expandAwsCodePipelineArtifactStore(d *schema.ResourceData) *codepipeline.Ar } pipelineArtifactStore.EncryptionKey = &ek } - return &pipelineArtifactStore -} - -func expandAwsCodePipelineArtifactStores(d *schema.ResourceData) map[string]*codepipeline.ArtifactStore { - configs := d.Get("artifact_stores").([]interface{}) - - if len(configs) == 0 { - return nil - } - pipelineArtifactStores := make(map[string]*codepipeline.ArtifactStore) - - // for region, config := range configs { - // pipelineArtifactStores[region] = expandAwsCodePipelineArtifactStore(config.(*schema.ResourceData)) - // } - - return pipelineArtifactStores + return data["region"].(string), &pipelineArtifactStore } func flattenAwsCodePipelineArtifactStore(artifactStore *codepipeline.ArtifactStore) []interface{} { + if artifactStore == nil { + return []interface{}{} + } + values := map[string]interface{}{} values["type"] = *artifactStore.Type values["location"] = *artifactStore.Location @@ -286,8 +303,10 @@ func flattenAwsCodePipelineArtifactStore(artifactStore *codepipeline.ArtifactSto func flattenAwsCodePipelineArtifactStores(artifactStores map[string]*codepipeline.ArtifactStore) []interface{} { values := []interface{}{} - for _, artifactStore := range artifactStores { - values = append(values, artifactStore) + for region, artifactStore := range artifactStores { + store := flattenAwsCodePipelineArtifactStore(artifactStore)[0].(map[string]interface{}) + store["region"] = region + values = append(values, store) } return values } @@ -571,3 +590,9 @@ func resourceAwsCodePipelineDelete(d *schema.ResourceData, meta interface{}) err return err } + +func resourceAwsCodePipelineArtifactStoreHash(v interface{}) int { + m := v.(map[string]interface{}) + + return hashcode.String(m["region"].(string)) +} diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 5c48ca499d2..8fa139b22f8 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -9,11 +9,14 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/codepipeline" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/terraform" ) func TestAccAWSCodePipeline_basic(t *testing.T) { + var p1, p2 codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -25,11 +28,12 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { { Config: testAccAWSCodePipelineConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(resourceName), + testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttrPair(resourceName, "role_arn", "aws_iam_role.codepipeline_role", "arn"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s", name))), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.type", "S3"), + resource.TestCheckResourceAttrPair(resourceName, "artifact_store.0.location", "aws_s3_bucket.foo", "bucket"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.#", "1"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.id", "1234"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.type", "KMS"), @@ -79,7 +83,7 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { { Config: testAccAWSCodePipelineConfig_basicUpdated(name), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(resourceName), + testAccCheckAWSCodePipelineExists(resourceName, &p2), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.type", "S3"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.#", "1"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.id", "4567"), @@ -112,6 +116,7 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { } func TestAccAWSCodePipeline_emptyArtifacts(t *testing.T) { + var p codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -123,7 +128,7 @@ func TestAccAWSCodePipeline_emptyArtifacts(t *testing.T) { { Config: testAccAWSCodePipelineConfig_emptyArtifacts(name), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(resourceName), + testAccCheckAWSCodePipelineExists(resourceName, &p), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s", name))), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.type", "S3"), @@ -141,6 +146,7 @@ func TestAccAWSCodePipeline_emptyArtifacts(t *testing.T) { } func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { + var p codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -152,7 +158,7 @@ func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { { Config: testAccAWSCodePipelineConfig_deployWithServiceRole(name), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(resourceName), + testAccCheckAWSCodePipelineExists(resourceName, &p), resource.TestCheckResourceAttr(resourceName, "stage.2.name", "Deploy"), resource.TestCheckResourceAttr(resourceName, "stage.2.action.0.category", "Deploy"), resource.TestCheckResourceAttrPair(resourceName, "stage.2.action.0.role_arn", "aws_iam_role.codepipeline_action_role", "arn"), @@ -168,6 +174,7 @@ func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { } func TestAccAWSCodePipeline_tags(t *testing.T) { + var p1, p2, p3 codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -179,7 +186,7 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { { Config: testAccAWSCodePipelineConfigWithTags(name, "tag1value", "tag2value"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(resourceName), + testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), resource.TestCheckResourceAttr(resourceName, "tags.Name", fmt.Sprintf("test-pipeline-%s", name)), resource.TestCheckResourceAttr(resourceName, "tags.tag1", "tag1value"), @@ -194,7 +201,7 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { { Config: testAccAWSCodePipelineConfigWithTags(name, "tag1valueUpdate", "tag2valueUpdate"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(resourceName), + testAccCheckAWSCodePipelineExists(resourceName, &p2), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), resource.TestCheckResourceAttr(resourceName, "tags.Name", fmt.Sprintf("test-pipeline-%s", name)), resource.TestCheckResourceAttr(resourceName, "tags.tag1", "tag1valueUpdate"), @@ -209,7 +216,7 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { { Config: testAccAWSCodePipelineConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCodePipelineExists(resourceName), + testAccCheckAWSCodePipelineExists(resourceName, &p3), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, @@ -217,34 +224,64 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { }) } -// func TestAccAWSCodePipeline_basic_multiregion(t *testing.T) { -// name := acctest.RandString(10) - -// resource.ParallelTest(t, resource.TestCase{ -// PreCheck: func() { testAccPreCheck(t) }, -// Providers: testAccProviders, -// CheckDestroy: testAccCheckAWSCodePipelineDestroy, -// Steps: []resource.TestStep{ -// { -// Config: testAccAWSCodePipelineConfig_multiregion(name), -// Check: resource.ComposeTestCheckFunc( -// testAccCheckAWSCodePipelineExists("aws_codepipeline.bar"), -// resource.TestCheckResourceAttr("aws_codepipeline.bar", "artifact_stores.%", "2"), -// resource.TestCheckNoResourceAttr("aws_codepipeline.bar", "artifact_store.#"), -// resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.name", "Build"), -// resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.action.0.region", "eu-west-1"), -// resource.TestCheckResourceAttr("aws_codepipeline.bar", "stage.2.action.1.region", "eu-central-1"), -// resource.TestMatchResourceAttr( -// "aws_codepipeline.bar", "stage.2.action.0.role_arn", -// regexp.MustCompile("^arn:aws:iam::[0-9]{12}:role/codepipeline-action-role.*"), -// ), -// ), -// }, -// }, -// }) -// } - -func testAccCheckAWSCodePipelineExists(n string) resource.TestCheckFunc { +func testAccCheckAWSCodePipelineHashArtifactStore(region string) int { + return hashcode.String(region) +} + +func testAccCheckAWSCodePipelineHashArtifactStoreKey(region, key string) string { + return fmt.Sprintf("artifact_stores.%d.%s", testAccCheckAWSCodePipelineHashArtifactStore(region), key) +} + +func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { + var p codepipeline.PipelineDeclaration + resourceName := "aws_codepipeline.test" + var providers []*schema.Provider + + name := acctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccMultipleRegionsPreCheck(t) + testAccAlternateRegionPreCheck(t) + }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckAWSCodePipelineDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCodePipelineConfig_multiregion(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCodePipelineExists(resourceName, &p), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "0"), + resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "2"), + + resource.TestCheckResourceAttr(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetRegion(), "type"), "S3"), + resource.TestCheckResourceAttrPair(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetRegion(), "location"), "aws_s3_bucket.local", "bucket"), + resource.TestCheckResourceAttr(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetRegion(), "region"), testAccGetRegion()), + + resource.TestCheckResourceAttr(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetAlternateRegion(), "type"), "S3"), + resource.TestCheckResourceAttrPair(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetAlternateRegion(), "location"), "aws_s3_bucket.alternate", "bucket"), + resource.TestCheckResourceAttr(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetAlternateRegion(), "region"), testAccGetAlternateRegion()), + + resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", fmt.Sprintf("%s-Build", testAccGetRegion())), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", testAccGetRegion()), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.name", fmt.Sprintf("%s-Build", testAccGetAlternateRegion())), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.region", testAccGetAlternateRegion()), + ), + }, + { + Config: testAccAWSCodePipelineConfig_multiregion(name), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckAWSCodePipelineExists(n string, pipeline *codepipeline.PipelineDeclaration) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -257,11 +294,16 @@ func testAccCheckAWSCodePipelineExists(n string) resource.TestCheckFunc { conn := testAccProvider.Meta().(*AWSClient).codepipelineconn - _, err := conn.GetPipeline(&codepipeline.GetPipelineInput{ + out, err := conn.GetPipeline(&codepipeline.GetPipelineInput{ Name: aws.String(rs.Primary.ID), }) + if err != nil { + return err + } - return err + *pipeline = *out.Pipeline + + return nil } } @@ -802,148 +844,140 @@ resource "aws_codepipeline" "test" { `, rName, tag1, tag2)) } -// func testAccAWSCodePipelineConfig_multiregion(rName string) string { -// return fmt.Sprintf(` -// resource "aws_s3_bucket" "eu-west-1" { -// bucket = "tf-test-pipeline-eu-west-1-%s" -// acl = "private" -// } - -// resource "aws_s3_bucket" "eu-central-1" { -// bucket = "tf-test-pipeline-eu-central-1-%s" -// acl = "private" -// } - -// resource "aws_iam_role" "codepipeline_role" { -// name = "codepipeline-role-%s" - -// assume_role_policy = < Date: Mon, 30 Mar 2020 09:16:37 -0400 Subject: [PATCH 151/684] resource/aws_licensemanager_license_configuration: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12470) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_licensemanager_license_configuration.go:141:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_licensemanager_license_configuration.go:150:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_licensemanager_license_configuration.go:153:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSLicenseManagerLicenseConfiguration_basic (16.06s) --- PASS: TestAccAWSLicenseManagerLicenseConfiguration_update (25.54s) ``` --- aws/resource_aws_licensemanager_license_configuration.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/aws/resource_aws_licensemanager_license_configuration.go b/aws/resource_aws_licensemanager_license_configuration.go index 6e94dda4d9f..fbd56b370a0 100644 --- a/aws/resource_aws_licensemanager_license_configuration.go +++ b/aws/resource_aws_licensemanager_license_configuration.go @@ -138,20 +138,14 @@ func resourceAwsLicenseManagerLicenseConfigurationRead(d *schema.ResourceData, m func resourceAwsLicenseManagerLicenseConfigurationUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).licensemanagerconn - d.Partial(true) - if d.HasChange("tags") { o, n := d.GetChange("tags") if err := keyvaluetags.LicensemanagerUpdateTags(conn, d.Id(), o, n); err != nil { return fmt.Errorf("error updating License Manager License Configuration (%s) tags: %s", d.Id(), err) } - - d.SetPartial("tags") } - d.Partial(false) - opts := &licensemanager.UpdateLicenseConfigurationInput{ LicenseConfigurationArn: aws.String(d.Id()), Name: aws.String(d.Get("name").(string)), From 063fde1a059343e002df3dfdb073d1dc6e1d1e44 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Mar 2020 09:39:10 -0400 Subject: [PATCH 152/684] resource/aws_elasticache_parameter_group: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12471) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_elasticache_parameter_group.go:136:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_elasticache_parameter_group.go:310:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elasticache_parameter_group.go:313:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_elasticache_parameter_group.go:84:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_elasticache_parameter_group.go:85:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elasticache_parameter_group.go:86:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elasticache_parameter_group.go:87:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elasticache_parameter_group.go:88:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSElasticacheParameterGroup_Description (23.39s) --- PASS: TestAccAWSElasticacheParameterGroup_basic (25.25s) --- PASS: TestAccAWSElasticacheParameterGroup_UppercaseName (25.32s) --- PASS: TestAccAWSElasticacheParameterGroup_removeReservedMemoryParameter (42.06s) --- PASS: TestAccAWSElasticacheParameterGroup_removeAllParameters (44.50s) --- PASS: TestAccAWSElasticacheParameterGroup_addParameter (44.70s) --- PASS: TestAccAWSElasticacheParameterGroup_updateReservedMemoryParameter (90.73s) --- PASS: TestAccAWSElasticacheParameterGroup_switchReservedMemoryParameter (91.11s) ``` --- aws/resource_aws_elasticache_parameter_group.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/aws/resource_aws_elasticache_parameter_group.go b/aws/resource_aws_elasticache_parameter_group.go index 5da7b75a078..eb288ef498f 100644 --- a/aws/resource_aws_elasticache_parameter_group.go +++ b/aws/resource_aws_elasticache_parameter_group.go @@ -81,12 +81,6 @@ func resourceAwsElasticacheParameterGroupCreate(d *schema.ResourceData, meta int return fmt.Errorf("Error creating Cache Parameter Group: %s", err) } - d.Partial(true) - d.SetPartial("name") - d.SetPartial("family") - d.SetPartial("description") - d.Partial(false) - d.SetId(*resp.CacheParameterGroup.CacheParameterGroupName) log.Printf("[INFO] Cache Parameter Group ID: %s", d.Id()) @@ -133,8 +127,6 @@ func resourceAwsElasticacheParameterGroupRead(d *schema.ResourceData, meta inter func resourceAwsElasticacheParameterGroupUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).elasticacheconn - d.Partial(true) - if d.HasChange("parameter") { o, n := d.GetChange("parameter") if o == nil { @@ -306,12 +298,8 @@ func resourceAwsElasticacheParameterGroupUpdate(d *schema.ResourceData, meta int return fmt.Errorf("Error modifying Cache Parameter Group: %s", err) } } - - d.SetPartial("parameter") } - d.Partial(false) - return resourceAwsElasticacheParameterGroupRead(d, meta) } From 7d1cdbf059e3533f860d7440c98dbb72317ebcd4 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Mar 2020 09:39:42 -0400 Subject: [PATCH 153/684] resource/aws_globalaccelerator_accelerator: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12472) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_globalaccelerator_accelerator.go:265:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_globalaccelerator_accelerator.go:285:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_globalaccelerator_accelerator.go:286:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_globalaccelerator_accelerator.go:287:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_globalaccelerator_accelerator.go:304:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_globalaccelerator_accelerator.go:314:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_globalaccelerator_accelerator.go:317:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAwsGlobalAcceleratorAccelerator_basic (55.91s) --- PASS: TestAccAwsGlobalAcceleratorAccelerator_update (84.82s) --- PASS: TestAccAwsGlobalAcceleratorAccelerator_tags (92.89s) --- PASS: TestAccAwsGlobalAcceleratorAccelerator_attributes (97.79s) ``` --- aws/resource_aws_globalaccelerator_accelerator.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/aws/resource_aws_globalaccelerator_accelerator.go b/aws/resource_aws_globalaccelerator_accelerator.go index 80907506078..8a0a96621ea 100644 --- a/aws/resource_aws_globalaccelerator_accelerator.go +++ b/aws/resource_aws_globalaccelerator_accelerator.go @@ -262,8 +262,6 @@ func resourceAwsGlobalAcceleratorAcceleratorRetrieve(conn *globalaccelerator.Glo func resourceAwsGlobalAcceleratorAcceleratorUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).globalacceleratorconn - d.Partial(true) - if d.HasChange("name") || d.HasChange("ip_address_type") || d.HasChange("enabled") { opts := &globalaccelerator.UpdateAcceleratorInput{ AcceleratorArn: aws.String(d.Id()), @@ -282,10 +280,6 @@ func resourceAwsGlobalAcceleratorAcceleratorUpdate(d *schema.ResourceData, meta return fmt.Errorf("Error updating Global Accelerator accelerator: %s", err) } - d.SetPartial("name") - d.SetPartial("ip_address_type") - d.SetPartial("enabled") - err = resourceAwsGlobalAcceleratorAcceleratorWaitForDeployedState(conn, d.Id()) if err != nil { return err @@ -298,10 +292,7 @@ func resourceAwsGlobalAcceleratorAcceleratorUpdate(d *schema.ResourceData, meta if err != nil { return err } - } - - d.SetPartial("attributes") } if d.HasChange("tags") { @@ -310,12 +301,8 @@ func resourceAwsGlobalAcceleratorAcceleratorUpdate(d *schema.ResourceData, meta if err := keyvaluetags.GlobalacceleratorUpdateTags(conn, d.Id(), o, n); err != nil { return fmt.Errorf("error updating Global Accelerator accelerator (%s) tags: %s", d.Id(), err) } - - d.SetPartial("tags") } - d.Partial(false) - return resourceAwsGlobalAcceleratorAcceleratorRead(d, meta) } From 0969535e8dbcb6c95e53897c8869b8accd984129 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Mar 2020 09:40:08 -0400 Subject: [PATCH 154/684] resource/aws_qldb_ledger: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12474) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_qldb_ledger.go:159:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_qldb_ledger.go:175:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_qldb_ledger.go:185:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSQLDBLedger_basic (47.45s) --- PASS: TestAccAWSQLDBLedger_Tags (69.25s) ``` --- aws/resource_aws_qldb_ledger.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/aws/resource_aws_qldb_ledger.go b/aws/resource_aws_qldb_ledger.go index 0ae4325454e..685c50d0ee9 100644 --- a/aws/resource_aws_qldb_ledger.go +++ b/aws/resource_aws_qldb_ledger.go @@ -155,9 +155,6 @@ func resourceAwsQLDBLedgerRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsQLDBLedgerUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).qldbconn - // Turn on partial mode - d.Partial(true) - if d.HasChange("deletion_protection") { val := d.Get("deletion_protection").(bool) modifyOpts := &qldb.UpdateLedgerInput{ @@ -171,8 +168,6 @@ func resourceAwsQLDBLedgerUpdate(d *schema.ResourceData, meta interface{}) error return err } - - d.SetPartial("deletion_protection") } if d.HasChange("tags") { @@ -182,7 +177,6 @@ func resourceAwsQLDBLedgerUpdate(d *schema.ResourceData, meta interface{}) error } } - d.Partial(false) return resourceAwsQLDBLedgerRead(d, meta) } From 43225ab341a0a7aa623824d22d989140cfd0571a Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Mar 2020 09:40:33 -0400 Subject: [PATCH 155/684] resource/aws_route53_zone: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12475) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_route53_zone.go:245:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_route53_zone.go:259:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_route53_zone.go:302:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_route53_zone.go:305:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSRoute53Zone_disappears (46.86s) --- PASS: TestAccAWSRoute53Zone_basic (51.82s) --- PASS: TestAccAWSRoute53Zone_DelegationSetID (54.36s) --- PASS: TestAccAWSRoute53Zone_multiple (55.84s) --- PASS: TestAccAWSRoute53Zone_Comment (63.72s) --- PASS: TestAccAWSRoute53Zone_Tags (76.39s) --- PASS: TestAccAWSRoute53Zone_VPC_Single (100.74s) --- PASS: TestAccAWSRoute53Zone_VPC_Multiple (162.98s) --- PASS: TestAccAWSRoute53Zone_ForceDestroy (183.10s) --- PASS: TestAccAWSRoute53Zone_ForceDestroy_TrailingPeriod (184.32s) --- PASS: TestAccAWSRoute53Zone_VPC_Updates (238.08s) ``` --- aws/resource_aws_route53_zone.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/aws/resource_aws_route53_zone.go b/aws/resource_aws_route53_zone.go index 83ab57f67eb..c9116e010d3 100644 --- a/aws/resource_aws_route53_zone.go +++ b/aws/resource_aws_route53_zone.go @@ -242,8 +242,6 @@ func resourceAwsRoute53ZoneUpdate(d *schema.ResourceData, meta interface{}) erro conn := meta.(*AWSClient).r53conn region := meta.(*AWSClient).region - d.Partial(true) - if d.HasChange("comment") { input := route53.UpdateHostedZoneCommentInput{ Id: aws.String(d.Id()), @@ -255,8 +253,6 @@ func resourceAwsRoute53ZoneUpdate(d *schema.ResourceData, meta interface{}) erro if err != nil { return fmt.Errorf("error updating Route53 Hosted Zone (%s) comment: %s", d.Id(), err) } - - d.SetPartial("comment") } if d.HasChange("tags") { @@ -298,12 +294,8 @@ func resourceAwsRoute53ZoneUpdate(d *schema.ResourceData, meta interface{}) erro return err } } - - d.SetPartial("vpc") } - d.Partial(false) - return resourceAwsRoute53ZoneRead(d, meta) } From 671177ac81c9ca9e4489b40616dd17a2c40b2794 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Mar 2020 09:46:31 -0400 Subject: [PATCH 156/684] resource/aws_opsworks_rds_db_instance: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12476) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_opsworks_rds_db_instance.go:46:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_opsworks_rds_db_instance.go:48:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_opsworks_rds_db_instance.go:55:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_opsworks_rds_db_instance.go:60:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_opsworks_rds_db_instance.go:74:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSOpsworksRdsDbInstance (971.17s) ``` --- aws/resource_aws_opsworks_rds_db_instance.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/aws/resource_aws_opsworks_rds_db_instance.go b/aws/resource_aws_opsworks_rds_db_instance.go index 14ca6aebd3a..028f0c45bee 100644 --- a/aws/resource_aws_opsworks_rds_db_instance.go +++ b/aws/resource_aws_opsworks_rds_db_instance.go @@ -43,21 +43,16 @@ func resourceAwsOpsworksRdsDbInstance() *schema.Resource { func resourceAwsOpsworksRdsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*AWSClient).opsworksconn - d.Partial(true) - - d.SetPartial("rds_db_instance_arn") req := &opsworks.UpdateRdsDbInstanceInput{ RdsDbInstanceArn: aws.String(d.Get("rds_db_instance_arn").(string)), } requestUpdate := false if d.HasChange("db_user") { - d.SetPartial("db_user") req.DbUser = aws.String(d.Get("db_user").(string)) requestUpdate = true } if d.HasChange("db_password") { - d.SetPartial("db_password") req.DbPassword = aws.String(d.Get("db_password").(string)) requestUpdate = true } @@ -71,8 +66,6 @@ func resourceAwsOpsworksRdsDbInstanceUpdate(d *schema.ResourceData, meta interfa } } - d.Partial(false) - return resourceAwsOpsworksRdsDbInstanceRead(d, meta) } From 62e099632a7a463a393094b594016b7817c56bf7 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Mar 2020 10:27:48 -0400 Subject: [PATCH 157/684] tests/service/rds: Sweeper and randomization of Database Snapshots (#12546) * tests/resource/aws_db_snapshot: Add sweeper Output from sweeper: ```console $ aws rds describe-db-snapshots | jq '.DBSnapshots | length' 22 $ go test ./aws -v -timeout=10h -sweep=us-west-2,us-east-1 -sweep-run=aws_db_snapshot -sweep-allow-failures 2020/03/26 15:25:52 [DEBUG] Running Sweepers for region (us-west-2): 2020/03/26 15:25:52 [DEBUG] Running Sweeper (aws_db_snapshot) in region (us-west-2) ... 2020/03/26 15:25:55 [INFO] Deleting RDS DB Snapshot: foobarbaz-test-terraform-final-snapshot-1415575510871393062 2020/03/26 15:25:55 [INFO] Deleting RDS DB Snapshot: foobarbaz-test-terraform-final-snapshot-2096347587666036804 2020/03/26 15:25:56 [INFO] Deleting RDS DB Snapshot: foobarbaz-test-terraform-final-snapshot-3189509102282540998 2020/03/26 15:25:56 [INFO] Deleting RDS DB Snapshot: foobarbaz-test-terraform-final-snapshot-3849215471775692750 2020/03/26 15:25:57 [INFO] Deleting RDS DB Snapshot: foobarbaz-test-terraform-final-snapshot-5261498202928368392 2020/03/26 15:25:57 [INFO] Deleting RDS DB Snapshot: foobarbaz-test-terraform-final-snapshot-8318819147033948297 2020/03/26 15:25:58 [INFO] Deleting RDS DB Snapshot: foobarbaz-test-terraform-final-snapshot-8446996715316725494 2020/03/26 15:25:58 [INFO] Deleting RDS DB Snapshot: foobarbaz-test-terraform-final-snapshot-8723502547972545787 2020/03/26 15:25:59 [INFO] Deleting RDS DB Snapshot: foobarbaz-test-terraform-final-snapshot-883321889024723365 2020/03/26 15:25:59 [INFO] Deleting RDS DB Snapshot: foobarbaz-test-terraform-final-snapshot-8895498494739457632 2020/03/26 15:26:00 [INFO] Deleting RDS DB Snapshot: foobarbaz-test-terraform-final-snapshot-908861353114466659 2020/03/26 15:26:00 [INFO] Deleting RDS DB Snapshot: testsnapshot3441505605084517287 2020/03/26 15:26:01 [INFO] Deleting RDS DB Snapshot: testsnapshot5852498985697708882 2020/03/26 15:26:02 [INFO] Deleting RDS DB Snapshot: testsnapshot8445696132681681674 2020/03/26 15:26:02 [INFO] Deleting RDS DB Snapshot: tf-acc-test-2899479871986403180 2020/03/26 15:26:03 [INFO] Deleting RDS DB Snapshot: tf-acc-test-6560511401502549741 2020/03/26 15:26:04 [INFO] Deleting RDS DB Snapshot: tf-acc-test-7361823869622620945 2020/03/26 15:26:04 Sweeper Tests ran successfully: - aws_db_snapshot 2020/03/26 15:26:04 [DEBUG] Running Sweepers for region (us-east-1): 2020/03/26 15:26:04 [DEBUG] Running Sweeper (aws_db_snapshot) in region (us-east-1) ... 2020/03/26 15:26:07 Sweeper Tests ran successfully: - aws_db_snapshot ok github.com/terraform-providers/terraform-provider-aws/aws 16.829s $ aws rds describe-db-snapshots | jq '.DBSnapshots | length' 0 ``` * tests/resource/aws_db_instance: Randomize snapshot naming Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12526 Output from acceptance testing: ``` --- PASS: TestAccAWSDBInstance_FinalSnapshotIdentifier_SkipFinalSnapshot (656.68s) --- PASS: TestAccAWSDBInstance_MySQL_SnapshotRestoreWithEngineVersion (1966.10s) --- PASS: TestAccAWSDBInstance_MSSQL_DomainSnapshotRestore (3005.84s) ``` --- aws/resource_aws_db_instance_test.go | 20 ++++----- aws/resource_aws_db_snapshot_test.go | 63 ++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index b495bb3c12a..7cfbfc41d20 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -2997,7 +2997,7 @@ resource "aws_db_instance" "bar" { func testAccAWSDBInstanceConfig_FinalSnapshotIdentifier_SkipFinalSnapshot() string { return fmt.Sprintf(` resource "aws_db_instance" "snapshot" { - identifier = "tf-test-%d" + identifier = "tf-acc-test-%[1]d" allocated_storage = 5 engine = "mysql" @@ -3013,7 +3013,7 @@ resource "aws_db_instance" "snapshot" { parameter_group_name = "default.mysql5.6" skip_final_snapshot = true - final_snapshot_identifier = "foobarbaz-test-terraform-final-snapshot-1" + final_snapshot_identifier = "tf-acc-test-%[1]d" } `, acctest.RandInt()) } @@ -3921,7 +3921,7 @@ resource "aws_vpc" "foo" { } resource "aws_db_subnet_group" "rds_one" { - name = "tf_acc_test_%d" + name = "tf_acc_test_%[1]d" description = "db subnets for rds_one" subnet_ids = ["${aws_subnet.main.id}", "${aws_subnet.other.id}"] @@ -3950,7 +3950,7 @@ resource "aws_subnet" "other" { resource "aws_db_instance" "mssql" { allocated_storage = 20 engine = "sqlserver-ex" - identifier = "tf-test-mssql-%d" + identifier = "tf-test-mssql-%[1]d" instance_class = "db.t2.micro" password = "somecrazypassword" skip_final_snapshot = true @@ -3959,11 +3959,11 @@ resource "aws_db_instance" "mssql" { resource "aws_db_snapshot" "mssql-snap" { db_instance_identifier = "${aws_db_instance.mssql.id}" - db_snapshot_identifier = "mssql-snap" + db_snapshot_identifier = "tf-acc-test-%[1]d" } resource "aws_db_instance" "mssql_restore" { - identifier = "tf-test-mssql-%d-restore" + identifier = "tf-test-mssql-%[1]d-restore" db_subnet_group_name = "${aws_db_subnet_group.rds_one.name}" @@ -3984,7 +3984,7 @@ resource "aws_db_instance" "mssql_restore" { } resource "aws_security_group" "rds-mssql" { - name = "tf-rds-mssql-test-%d" + name = "tf-rds-mssql-test-%[1]d" description = "TF Testing" vpc_id = "${aws_vpc.foo.id}" @@ -4013,7 +4013,7 @@ resource "aws_directory_service_directory" "foo" { } resource "aws_iam_role" "role" { - name = "tf-acc-db-instance-mssql-domain-role-%d" + name = "tf-acc-db-instance-mssql-domain-role-%[1]d" assume_role_policy = < Date: Mon, 30 Mar 2020 17:40:56 +0200 Subject: [PATCH 158/684] resource/aws_codedeploy_deployment_group: Fix blue_green_deployment_config updates for ECS (#11885) Verified new testing on master fails: ``` TestAccAWSCodeDeployDeploymentGroup_ECS_BlueGreen: testing.go:654: Step 1 error: errors during apply: Error: Error updating CodeDeploy deployment group: InvalidAutoScalingGroupException: For ECS deployment group, autoScalingGroups can not be specified ``` Then fix works as expected, output from acceptance testing: ``` --- PASS: TestAccAWSCodeDeployDeploymentGroup_alarmConfiguration_create (44.76s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_alarmConfiguration_delete (134.22s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_alarmConfiguration_disable (49.17s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_alarmConfiguration_update (66.24s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_autoRollbackConfiguration_create (33.51s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_autoRollbackConfiguration_delete (46.52s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_autoRollbackConfiguration_disable (38.05s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_autoRollbackConfiguration_update (31.32s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_basic (77.12s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_basic_tagSet (78.35s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_blueGreenDeployment_complete (30.40s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_blueGreenDeploymentConfiguration_create (133.17s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_blueGreenDeploymentConfiguration_delete (43.16s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_blueGreenDeploymentConfiguration_update (28.42s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_blueGreenDeploymentConfiguration_update_with_asg (141.84s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_deploymentStyle_create (24.48s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_deploymentStyle_default (50.04s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_deploymentStyle_delete (69.77s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_deploymentStyle_update (82.09s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_disappears (26.67s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_ECS_BlueGreen (313.78s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_inPlaceDeploymentWithTrafficControl_create (25.49s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_inPlaceDeploymentWithTrafficControl_update (48.17s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_loadBalancerInfo_create (46.85s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_loadBalancerInfo_delete (30.40s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_loadBalancerInfo_targetGroupInfo_create (28.59s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_loadBalancerInfo_targetGroupInfo_delete (32.31s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_loadBalancerInfo_targetGroupInfo_update (32.88s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_loadBalancerInfo_update (38.29s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_onPremiseTag (30.71s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_triggerConfiguration_basic (32.39s) --- PASS: TestAccAWSCodeDeployDeploymentGroup_triggerConfiguration_multiple (45.11s) ``` --- ...esource_aws_codedeploy_deployment_group.go | 4 +- ...ce_aws_codedeploy_deployment_group_test.go | 78 +++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_codedeploy_deployment_group.go b/aws/resource_aws_codedeploy_deployment_group.go index 82a2c0f270b..515ec9ca000 100644 --- a/aws/resource_aws_codedeploy_deployment_group.go +++ b/aws/resource_aws_codedeploy_deployment_group.go @@ -685,8 +685,8 @@ func resourceAwsCodeDeployDeploymentGroupUpdate(d *schema.ResourceData, meta int input.DeploymentConfigName = aws.String(n.(string)) } - // include (original or new) autoscaling groups when blue_green_deployment_config changes - if d.HasChange("autoscaling_groups") || d.HasChange("blue_green_deployment_config") { + // include (original or new) autoscaling groups when blue_green_deployment_config changes except for ECS + if _, isEcs := d.GetOk("ecs_service"); d.HasChange("autoscaling_groups") || (d.HasChange("blue_green_deployment_config") && !isEcs) { _, n := d.GetChange("autoscaling_groups") input.AutoScalingGroups = expandStringList(n.(*schema.Set).List()) } diff --git a/aws/resource_aws_codedeploy_deployment_group_test.go b/aws/resource_aws_codedeploy_deployment_group_test.go index c2a7762ff31..a028de2e5bf 100644 --- a/aws/resource_aws_codedeploy_deployment_group_test.go +++ b/aws/resource_aws_codedeploy_deployment_group_test.go @@ -1627,6 +1627,30 @@ func TestAccAWSCodeDeployDeploymentGroup_ECS_BlueGreen(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "load_balancer_info.0.target_group_pair_info.0.target_group.0.name", lbTargetGroupBlueResourceName, "name"), resource.TestCheckResourceAttrPair(resourceName, "load_balancer_info.0.target_group_pair_info.0.target_group.1.name", lbTargetGroupGreenResourceName, "name"), resource.TestCheckResourceAttr(resourceName, "load_balancer_info.0.target_group_pair_info.0.test_traffic_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "blue_green_deployment_config.0.deployment_ready_option.0.action_on_timeout", "CONTINUE_DEPLOYMENT"), + resource.TestCheckResourceAttr(resourceName, "blue_green_deployment_config.0.terminate_blue_instances_on_deployment_success.0.action", "TERMINATE"), + resource.TestCheckResourceAttr(resourceName, "blue_green_deployment_config.0.terminate_blue_instances_on_deployment_success.0.termination_wait_time_in_minutes", "5"), + ), + }, + { + Config: testAccAWSCodeDeployDeploymentGroupConfigEcsBlueGreenUpdate(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCodeDeployDeploymentGroupExists(resourceName, &group), + resource.TestCheckResourceAttr(resourceName, "ecs_service.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "ecs_service.0.cluster_name", ecsClusterResourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "ecs_service.0.service_name", ecsServiceResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "load_balancer_info.#", "1"), + resource.TestCheckResourceAttr(resourceName, "load_balancer_info.0.target_group_pair_info.#", "1"), + resource.TestCheckResourceAttr(resourceName, "load_balancer_info.0.target_group_pair_info.0.prod_traffic_route.#", "1"), + resource.TestCheckResourceAttr(resourceName, "load_balancer_info.0.target_group_pair_info.0.prod_traffic_route.0.listener_arns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "load_balancer_info.0.target_group_pair_info.0.target_group.#", "2"), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_info.0.target_group_pair_info.0.target_group.0.name", lbTargetGroupBlueResourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_info.0.target_group_pair_info.0.target_group.1.name", lbTargetGroupGreenResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "load_balancer_info.0.target_group_pair_info.0.test_traffic_route.#", "0"), + resource.TestCheckResourceAttr("aws_codedeploy_deployment_group.test", "blue_green_deployment_config.0.deployment_ready_option.0.action_on_timeout", "STOP_DEPLOYMENT"), + resource.TestCheckResourceAttr("aws_codedeploy_deployment_group.test", "blue_green_deployment_config.0.deployment_ready_option.0.wait_time_in_minutes", "30"), + resource.TestCheckResourceAttr("aws_codedeploy_deployment_group.test", "blue_green_deployment_config.0.terminate_blue_instances_on_deployment_success.0.action", "TERMINATE"), + resource.TestCheckResourceAttr("aws_codedeploy_deployment_group.test", "blue_green_deployment_config.0.terminate_blue_instances_on_deployment_success.0.termination_wait_time_in_minutes", "60"), ), }, { @@ -3526,3 +3550,57 @@ resource "aws_codedeploy_deployment_group" "test" { } `, rName) } + +func testAccAWSCodeDeployDeploymentGroupConfigEcsBlueGreenUpdate(rName string) string { + return testAccAWSCodeDeployDeploymentGroupConfigEcsBase(rName) + fmt.Sprintf(` +resource "aws_codedeploy_deployment_group" "test" { + app_name = "${aws_codedeploy_app.test.name}" + deployment_config_name = "CodeDeployDefault.ECSAllAtOnce" + deployment_group_name = %q + service_role_arn = "${aws_iam_role.test.arn}" + + auto_rollback_configuration { + enabled = true + events = ["DEPLOYMENT_FAILURE"] + } + + blue_green_deployment_config { + deployment_ready_option { + action_on_timeout = "STOP_DEPLOYMENT" + wait_time_in_minutes = 30 + } + + terminate_blue_instances_on_deployment_success { + action = "TERMINATE" + termination_wait_time_in_minutes = 60 + } + } + + deployment_style { + deployment_option = "WITH_TRAFFIC_CONTROL" + deployment_type = "BLUE_GREEN" + } + + ecs_service { + cluster_name = "${aws_ecs_cluster.test.name}" + service_name = "${aws_ecs_service.test.name}" + } + + load_balancer_info { + target_group_pair_info { + prod_traffic_route { + listener_arns = ["${aws_lb_listener.test.arn}"] + } + + target_group { + name = "${aws_lb_target_group.blue.name}" + } + + target_group { + name = "${aws_lb_target_group.green.name}" + } + } + } +} +`, rName) +} From caafd99b62e2663b1f5a2a8ec35f8213116e4d09 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Mar 2020 11:42:16 -0400 Subject: [PATCH 159/684] Update CHANGELOG for #11885 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b82bc61ad40..920ce89977e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ ## 2.56.0 (Unreleased) + +BUG FIXES: + +* resource/aws_codedeploy_deployment_group: Fix `blue_green_deployment_config` updates for ECS [GH-11885] + ## 2.55.0 (March 27, 2020) FEATURES: From 95f3e0b02172306e938151c725a49b71d431d64e Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Mon, 30 Mar 2020 18:45:01 +0300 Subject: [PATCH 160/684] service/ec2: Add hibernation_options to aws_launch_template resource and data source (#12492) Output from acceptance testing: ``` --- PASS: TestAccAWSLaunchTemplate_associatePublicIPAddress (36.84s) --- PASS: TestAccAWSLaunchTemplate_basic (15.98s) --- PASS: TestAccAWSLaunchTemplate_BlockDeviceMappings_EBS (46.04s) --- PASS: TestAccAWSLaunchTemplate_BlockDeviceMappings_EBS_DeleteOnTermination (50.78s) --- PASS: TestAccAWSLaunchTemplate_capacityReservation_preference (15.50s) --- PASS: TestAccAWSLaunchTemplate_capacityReservation_target (19.67s) --- PASS: TestAccAWSLaunchTemplate_cpuOptions (13.08s) --- PASS: TestAccAWSLaunchTemplate_creditSpecification_nonBurstable (13.92s) --- PASS: TestAccAWSLaunchTemplate_creditSpecification_t2 (15.54s) --- PASS: TestAccAWSLaunchTemplate_creditSpecification_t3 (15.53s) --- PASS: TestAccAWSLaunchTemplate_data (15.38s) --- PASS: TestAccAWSLaunchTemplate_description (23.28s) --- PASS: TestAccAWSLaunchTemplate_disappears (11.34s) --- PASS: TestAccAWSLaunchTemplate_EbsOptimized (49.74s) --- PASS: TestAccAWSLaunchTemplate_ElasticInferenceAccelerator (27.37s) --- PASS: TestAccAWSLaunchTemplate_hibernation (27.45s) --- PASS: TestAccAWSLaunchTemplate_IamInstanceProfile_EmptyConfigurationBlock (16.01s) --- PASS: TestAccAWSLaunchTemplate_instanceMarketOptions (46.97s) --- PASS: TestAccAWSLaunchTemplate_licenseSpecification (13.77s) --- PASS: TestAccAWSLaunchTemplate_metadataOptions (19.10s) --- PASS: TestAccAWSLaunchTemplate_networkInterface (26.05s) --- PASS: TestAccAWSLaunchTemplate_networkInterface_ipv6AddressCount (13.00s) --- PASS: TestAccAWSLaunchTemplate_networkInterface_ipv6Addresses (10.30s) --- PASS: TestAccAWSLaunchTemplate_networkInterfaceAddresses (23.89s) --- PASS: TestAccAWSLaunchTemplate_tags (28.56s) --- PASS: TestAccAWSLaunchTemplate_update (43.83s) --- PASS: TestAccAWSLaunchTemplateDataSource_basic (17.35s) --- PASS: TestAccAWSLaunchTemplateDataSource_filter_basic (19.83s) --- PASS: TestAccAWSLaunchTemplateDataSource_filter_tags (15.37s) --- PASS: TestAccAWSLaunchTemplateDataSource_metadataOptions (17.23s) ``` --- aws/data_source_aws_launch_template.go | 16 ++++++ aws/data_source_aws_launch_template_test.go | 1 + aws/resource_aws_launch_template.go | 46 +++++++++++++++++ aws/resource_aws_launch_template_test.go | 52 ++++++++++++++++++++ website/docs/d/launch_template.html.markdown | 2 + website/docs/r/launch_template.html.markdown | 7 +++ 6 files changed, 124 insertions(+) diff --git a/aws/data_source_aws_launch_template.go b/aws/data_source_aws_launch_template.go index 40170b401e0..648585382db 100644 --- a/aws/data_source_aws_launch_template.go +++ b/aws/data_source_aws_launch_template.go @@ -356,6 +356,18 @@ func dataSourceAwsLaunchTemplate() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "hibernation_options": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "configured": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, "tags": tagsSchemaComputed(), "filter": dataSourceFiltersSchema(), }, @@ -492,6 +504,10 @@ func dataSourceAwsLaunchTemplateRead(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("error setting placement: %s", err) } + if err := d.Set("hibernation_options", flattenLaunchTemplateHibernationOptions(ltData.HibernationOptions)); err != nil { + return fmt.Errorf("error setting hibernation_options: %s", err) + } + if err := d.Set("tag_specifications", getTagSpecifications(ltData.TagSpecifications)); err != nil { return fmt.Errorf("error setting tag_specifications: %s", err) } diff --git a/aws/data_source_aws_launch_template_test.go b/aws/data_source_aws_launch_template_test.go index 1d8c90ec7ce..c17f1502eb4 100644 --- a/aws/data_source_aws_launch_template_test.go +++ b/aws/data_source_aws_launch_template_test.go @@ -25,6 +25,7 @@ func TestAccAWSLaunchTemplateDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "default_version", dataSourceName, "default_version"), resource.TestCheckResourceAttrPair(resourceName, "latest_version", dataSourceName, "latest_version"), resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "hibernation_options", dataSourceName, "hibernation_options"), ), }, }, diff --git a/aws/resource_aws_launch_template.go b/aws/resource_aws_launch_template.go index a8e7d8b005c..66399ee74f1 100644 --- a/aws/resource_aws_launch_template.go +++ b/aws/resource_aws_launch_template.go @@ -542,6 +542,19 @@ func resourceAwsLaunchTemplate() *schema.Resource { }, "tags": tagsSchema(), + "hibernation_options": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "configured": { + Type: schema.TypeBool, + Required: true, + }, + }, + }, + }, }, CustomizeDiff: customdiff.Sequence( @@ -742,6 +755,10 @@ func resourceAwsLaunchTemplateRead(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("error setting placement: %s", err) } + if err := d.Set("hibernation_options", flattenLaunchTemplateHibernationOptions(ltData.HibernationOptions)); err != nil { + return fmt.Errorf("error setting hibernation_options: %s", err) + } + if err := d.Set("tag_specifications", getTagSpecifications(ltData.TagSpecifications)); err != nil { return fmt.Errorf("error setting tag_specifications: %s", err) } @@ -1098,6 +1115,31 @@ func getPlacement(p *ec2.LaunchTemplatePlacement) []interface{} { return s } +func expandLaunchTemplateHibernationOptions(l []interface{}) *ec2.LaunchTemplateHibernationOptionsRequest { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + opts := &ec2.LaunchTemplateHibernationOptionsRequest{ + Configured: aws.Bool(m["configured"].(bool)), + } + + return opts +} + +func flattenLaunchTemplateHibernationOptions(m *ec2.LaunchTemplateHibernationOptions) []interface{} { + s := []interface{}{} + if m != nil { + mo := map[string]interface{}{ + "configured": aws.BoolValue(m.Configured), + } + s = append(s, mo) + } + return s +} + func getTagSpecifications(t []*ec2.LaunchTemplateTagSpecification) []interface{} { s := []interface{}{} for _, v := range t { @@ -1288,6 +1330,10 @@ func buildLaunchTemplateData(d *schema.ResourceData) (*ec2.RequestLaunchTemplate } } + if v, ok := d.GetOk("hibernation_options"); ok { + opts.HibernationOptions = expandLaunchTemplateHibernationOptions(v.([]interface{})) + } + if v, ok := d.GetOk("tag_specifications"); ok { var tagSpecifications []*ec2.LaunchTemplateTagSpecificationRequest t := v.([]interface{}) diff --git a/aws/resource_aws_launch_template_test.go b/aws/resource_aws_launch_template_test.go index 367eabf32d4..7ffea177114 100644 --- a/aws/resource_aws_launch_template_test.go +++ b/aws/resource_aws_launch_template_test.go @@ -865,6 +865,46 @@ func TestAccAWSLaunchTemplate_metadataOptions(t *testing.T) { }) } +func TestAccAWSLaunchTemplate_hibernation(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLaunchTemplateConfigHibernation(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "hibernation_options.0.configured", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSLaunchTemplateConfigHibernation(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "hibernation_options.0.configured", "false"), + ), + }, + { + Config: testAccAWSLaunchTemplateConfigHibernation(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "hibernation_options.0.configured", "true"), + ), + }, + }, + }) +} + func testAccCheckAWSLaunchTemplateExists(n string, t *ec2.LaunchTemplate) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -1550,3 +1590,15 @@ resource "aws_launch_template" "test" { } `, rName) } + +func testAccAWSLaunchTemplateConfigHibernation(rName string, enabled bool) string { + return fmt.Sprintf(` +resource "aws_launch_template" "test" { + name = %[1]q + + hibernation_options { + configured = %[2]t + } +} +`, rName, enabled) +} diff --git a/website/docs/d/launch_template.html.markdown b/website/docs/d/launch_template.html.markdown index 9b8941f31a0..0acba574404 100644 --- a/website/docs/d/launch_template.html.markdown +++ b/website/docs/d/launch_template.html.markdown @@ -86,3 +86,5 @@ In addition to all arguments above, the following attributes are exported: * `tag_specifications` - The tags to apply to the resources during launch. * `tags` - (Optional) A mapping of tags to assign to the launch template. * `user_data` - The Base64-encoded user data to provide when launching the instance. +* `hibernation_options` - The hibernation options for the instance. + diff --git a/website/docs/r/launch_template.html.markdown b/website/docs/r/launch_template.html.markdown index d699bc9d1ff..2e1645eb836 100644 --- a/website/docs/r/launch_template.html.markdown +++ b/website/docs/r/launch_template.html.markdown @@ -147,6 +147,7 @@ The following arguments are supported: * `tag_specifications` - The tags to apply to the resources during launch. See [Tag Specifications](#tag-specifications) below for more details. * `tags` - (Optional) A mapping of tags to assign to the launch template. * `user_data` - The Base64-encoded user data to provide when launching the instance. +* `hibernation_options` - The hibernation options for the instance. See [Hibernation Options](#hibernation-options) below for more details. ### Block devices @@ -312,6 +313,12 @@ The `placement` block supports the following: * `spread_domain` - Reserved for future use. * `tenancy` - The tenancy of the instance (if the instance is running in a VPC). Can be `default`, `dedicated`, or `host`. +### Hibernation Options + +The `hibernation_options` block supports the following: + +* `configured` - If set to `true`, the launched EC2 instance will hibernation enabled. + ### Tag Specifications The tags to apply to the resources during launch. You can tag instances and volumes. More information can be found in the [EC2 API documentation](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_LaunchTemplateTagSpecificationRequest.html). From c72ff34e7e6a67a81354cb193c222e53870cee16 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Mar 2020 11:47:03 -0400 Subject: [PATCH 161/684] Update CHANGELOG for #12492 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 920ce89977e..c5df5a32898 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## 2.56.0 (Unreleased) +ENHANCEMENTS: + +* data-source/aws_launch_template: Add `hibernation_options` attribute [GH-12492] +* resource/aws_launch_template: Add `hibernation_options` configuration block [GH-12492] + BUG FIXES: * resource/aws_codedeploy_deployment_group: Fix `blue_green_deployment_config` updates for ECS [GH-11885] From 1dad917864df20a39c6a77b58e0e8c5caf9815cf Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Mon, 30 Mar 2020 18:50:09 +0300 Subject: [PATCH 162/684] resource/aws_kms_grant: Support resource import (#11991) Output from acceptance testing: ``` --- PASS: TestAccAWSKmsGrant_ARN (35.93s) --- PASS: TestAccAWSKmsGrant_withRetiringPrincipal (35.99s) --- PASS: TestAccAWSKmsGrant_Basic (44.34s) --- PASS: TestAccAWSKmsGrant_bare (44.42s) --- PASS: TestAccAWSKmsGrant_withConstraints (51.33s) ``` --- aws/resource_aws_kms_grant.go | 23 +- aws/resource_aws_kms_grant_test.go | 286 ++++++++++++------------- website/docs/r/kms_grant.html.markdown | 8 + 3 files changed, 160 insertions(+), 157 deletions(-) diff --git a/aws/resource_aws_kms_grant.go b/aws/resource_aws_kms_grant.go index f66ea30e65b..02287042b10 100644 --- a/aws/resource_aws_kms_grant.go +++ b/aws/resource_aws_kms_grant.go @@ -24,6 +24,19 @@ func resourceAwsKmsGrant() *schema.Resource { Read: resourceAwsKmsGrantRead, Delete: resourceAwsKmsGrantDelete, Exists: resourceAwsKmsGrantExists, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + keyId, grantId, err := decodeKmsGrantId(d.Id()) + if err != nil { + return nil, err + } + d.Set("key_id", keyId) + d.Set("grant_id", grantId) + d.SetId(fmt.Sprintf("%s:%s", keyId, grantId)) + + return []*schema.ResourceData{d}, nil + }, + }, Schema: map[string]*schema.Schema{ "name": { @@ -533,16 +546,16 @@ func flattenKmsGrantConstraints(constraint *kms.GrantConstraints) *schema.Set { func decodeKmsGrantId(id string) (string, string, error) { if strings.HasPrefix(id, "arn:aws") { - arn_parts := strings.Split(id, "/") - if len(arn_parts) != 2 { + arnParts := strings.Split(id, "/") + if len(arnParts) != 2 { return "", "", fmt.Errorf("unexpected format of ARN (%q), expected KeyID:GrantID", id) } - arn_prefix := arn_parts[0] - parts := strings.Split(arn_parts[1], ":") + arnPrefix := arnParts[0] + parts := strings.Split(arnParts[1], ":") if len(parts) != 2 { return "", "", fmt.Errorf("unexpected format of ID (%q), expected KeyID:GrantID", id) } - return fmt.Sprintf("%s/%s", arn_prefix, parts[0]), parts[1], nil + return fmt.Sprintf("%s/%s", arnPrefix, parts[0]), parts[1], nil } else { parts := strings.Split(id, ":") if len(parts) != 2 { diff --git a/aws/resource_aws_kms_grant_test.go b/aws/resource_aws_kms_grant_test.go index b275d962c71..ad6d2760eee 100644 --- a/aws/resource_aws_kms_grant_test.go +++ b/aws/resource_aws_kms_grant_test.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "testing" - "time" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -11,7 +10,8 @@ import ( ) func TestAccAWSKmsGrant_Basic(t *testing.T) { - timestamp := time.Now().Format(time.RFC1123) + resourceName := "aws_kms_grant.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -19,23 +19,30 @@ func TestAccAWSKmsGrant_Basic(t *testing.T) { CheckDestroy: testAccCheckAWSKmsGrantDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSKmsGrant_Basic("basic", timestamp, "\"Encrypt\", \"Decrypt\""), + Config: testAccAWSKmsGrant_Basic(rName, "\"Encrypt\", \"Decrypt\""), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSKmsGrantExists("aws_kms_grant.basic"), - resource.TestCheckResourceAttr("aws_kms_grant.basic", "name", "basic"), - resource.TestCheckResourceAttr("aws_kms_grant.basic", "operations.#", "2"), - resource.TestCheckResourceAttr("aws_kms_grant.basic", "operations.2238845196", "Encrypt"), - resource.TestCheckResourceAttr("aws_kms_grant.basic", "operations.1237510779", "Decrypt"), - resource.TestCheckResourceAttrSet("aws_kms_grant.basic", "grantee_principal"), - resource.TestCheckResourceAttrSet("aws_kms_grant.basic", "key_id"), + testAccCheckAWSKmsGrantExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "operations.#", "2"), + resource.TestCheckResourceAttr(resourceName, "operations.2238845196", "Encrypt"), + resource.TestCheckResourceAttr(resourceName, "operations.1237510779", "Decrypt"), + resource.TestCheckResourceAttrSet(resourceName, "grantee_principal"), + resource.TestCheckResourceAttrSet(resourceName, "key_id"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"grant_token", "retire_on_delete"}, + }, }, }) } func TestAccAWSKmsGrant_withConstraints(t *testing.T) { - timestamp := time.Now().Format(time.RFC1123) + resourceName := "aws_kms_grant.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -43,27 +50,33 @@ func TestAccAWSKmsGrant_withConstraints(t *testing.T) { CheckDestroy: testAccCheckAWSKmsGrantDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSKmsGrant_withConstraints("withConstraintsEq", timestamp, "encryption_context_equals", `foo = "bar" + Config: testAccAWSKmsGrant_withConstraints(rName, "encryption_context_equals", `foo = "bar" baz = "kaz"`), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSKmsGrantExists("aws_kms_grant.withConstraintsEq"), - resource.TestCheckResourceAttr("aws_kms_grant.withConstraintsEq", "name", "withConstraintsEq"), - resource.TestCheckResourceAttr("aws_kms_grant.withConstraintsEq", "constraints.#", "1"), - resource.TestCheckResourceAttr("aws_kms_grant.withConstraintsEq", "constraints.449762259.encryption_context_equals.%", "2"), - resource.TestCheckResourceAttr("aws_kms_grant.withConstraintsEq", "constraints.449762259.encryption_context_equals.baz", "kaz"), - resource.TestCheckResourceAttr("aws_kms_grant.withConstraintsEq", "constraints.449762259.encryption_context_equals.foo", "bar"), + testAccCheckAWSKmsGrantExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "constraints.#", "1"), + resource.TestCheckResourceAttr(resourceName, "constraints.449762259.encryption_context_equals.%", "2"), + resource.TestCheckResourceAttr(resourceName, "constraints.449762259.encryption_context_equals.baz", "kaz"), + resource.TestCheckResourceAttr(resourceName, "constraints.449762259.encryption_context_equals.foo", "bar"), ), }, { - Config: testAccAWSKmsGrant_withConstraints("withConstraintsSub", timestamp, "encryption_context_subset", `foo = "bar" + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"grant_token", "retire_on_delete"}, + }, + { + Config: testAccAWSKmsGrant_withConstraints(rName, "encryption_context_subset", `foo = "bar" baz = "kaz"`), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSKmsGrantExists("aws_kms_grant.withConstraintsSub"), - resource.TestCheckResourceAttr("aws_kms_grant.withConstraintsSub", "name", "withConstraintsSub"), - resource.TestCheckResourceAttr("aws_kms_grant.withConstraintsSub", "constraints.#", "1"), - resource.TestCheckResourceAttr("aws_kms_grant.withConstraintsSub", "constraints.2645649985.encryption_context_subset.%", "2"), - resource.TestCheckResourceAttr("aws_kms_grant.withConstraintsSub", "constraints.2645649985.encryption_context_subset.baz", "kaz"), - resource.TestCheckResourceAttr("aws_kms_grant.withConstraintsSub", "constraints.2645649985.encryption_context_subset.foo", "bar"), + testAccCheckAWSKmsGrantExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "constraints.#", "1"), + resource.TestCheckResourceAttr(resourceName, "constraints.2645649985.encryption_context_subset.%", "2"), + resource.TestCheckResourceAttr(resourceName, "constraints.2645649985.encryption_context_subset.baz", "kaz"), + resource.TestCheckResourceAttr(resourceName, "constraints.2645649985.encryption_context_subset.foo", "bar"), ), }, }, @@ -71,7 +84,8 @@ func TestAccAWSKmsGrant_withConstraints(t *testing.T) { } func TestAccAWSKmsGrant_withRetiringPrincipal(t *testing.T) { - timestamp := time.Now().Format(time.RFC1123) + resourceName := "aws_kms_grant.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -79,18 +93,25 @@ func TestAccAWSKmsGrant_withRetiringPrincipal(t *testing.T) { CheckDestroy: testAccCheckAWSKmsGrantDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSKmsGrant_withRetiringPrincipal("withRetiringPrincipal", timestamp), + Config: testAccAWSKmsGrant_withRetiringPrincipal(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSKmsGrantExists("aws_kms_grant.withRetiringPrincipal"), - resource.TestCheckResourceAttrSet("aws_kms_grant.withRetiringPrincipal", "retiring_principal"), + testAccCheckAWSKmsGrantExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "retiring_principal"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"grant_token", "retire_on_delete"}, + }, }, }) } func TestAccAWSKmsGrant_bare(t *testing.T) { - timestamp := time.Now().Format(time.RFC1123) + resourceName := "aws_kms_grant.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -98,20 +119,27 @@ func TestAccAWSKmsGrant_bare(t *testing.T) { CheckDestroy: testAccCheckAWSKmsGrantDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSKmsGrant_bare("bare", timestamp), + Config: testAccAWSKmsGrant_bare(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSKmsGrantExists("aws_kms_grant.bare"), - resource.TestCheckNoResourceAttr("aws_kms_grant.bare", "name"), - resource.TestCheckNoResourceAttr("aws_kms_grant.bare", "constraints.#"), - resource.TestCheckNoResourceAttr("aws_kms_grant.bare", "retiring_principal"), + testAccCheckAWSKmsGrantExists(resourceName), + resource.TestCheckNoResourceAttr(resourceName, "name"), + resource.TestCheckNoResourceAttr(resourceName, "constraints.#"), + resource.TestCheckNoResourceAttr(resourceName, "retiring_principal"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"grant_token", "retire_on_delete"}, + }, }, }) } func TestAccAWSKmsGrant_ARN(t *testing.T) { - timestamp := time.Now().Format(time.RFC1123) + resourceName := "aws_kms_grant.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -119,17 +147,23 @@ func TestAccAWSKmsGrant_ARN(t *testing.T) { CheckDestroy: testAccCheckAWSKmsGrantDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSKmsGrant_ARN("arn", timestamp, "\"Encrypt\", \"Decrypt\""), + Config: testAccAWSKmsGrant_ARN(rName, "\"Encrypt\", \"Decrypt\""), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSKmsGrantExists("aws_kms_grant.arn"), - resource.TestCheckResourceAttr("aws_kms_grant.arn", "name", "arn"), - resource.TestCheckResourceAttr("aws_kms_grant.arn", "operations.#", "2"), - resource.TestCheckResourceAttr("aws_kms_grant.arn", "operations.2238845196", "Encrypt"), - resource.TestCheckResourceAttr("aws_kms_grant.arn", "operations.1237510779", "Decrypt"), - resource.TestCheckResourceAttrSet("aws_kms_grant.arn", "grantee_principal"), - resource.TestCheckResourceAttrSet("aws_kms_grant.arn", "key_id"), + testAccCheckAWSKmsGrantExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "operations.#", "2"), + resource.TestCheckResourceAttr(resourceName, "operations.2238845196", "Encrypt"), + resource.TestCheckResourceAttr(resourceName, "operations.1237510779", "Decrypt"), + resource.TestCheckResourceAttrSet(resourceName, "grantee_principal"), + resource.TestCheckResourceAttrSet(resourceName, "key_id"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"grant_token", "retire_on_delete"}, + }, }, }) } @@ -160,140 +194,88 @@ func testAccCheckAWSKmsGrantExists(name string) resource.TestCheckFunc { } } -func testAccAWSKmsGrant_Basic(rName string, timestamp string, operations string) string { +func testAccAWSKmsGrantConfigBase(rName string) string { return fmt.Sprintf(` -resource "aws_kms_key" "tf-acc-test-key" { - description = "Terraform acc test key %s" +resource "aws_kms_key" "test" { + description = "Terraform acc test key %[1]s" deletion_window_in_days = 7 } -%s - -resource "aws_iam_role" "tf-acc-test-role" { - name = "%s" - path = "/service-role/" - assume_role_policy = "${data.aws_iam_policy_document.assumerole-policy-template.json}" +data "aws_iam_policy_document" "test" { + statement { + effect = "Allow" + actions = [ "sts:AssumeRole" ] + principals { + type = "Service" + identifiers = [ "ec2.amazonaws.com" ] + } + } } -resource "aws_kms_grant" "%[4]s" { - name = "%[4]s" - key_id = "${aws_kms_key.tf-acc-test-key.key_id}" - grantee_principal = "${aws_iam_role.tf-acc-test-role.arn}" - operations = [ %[5]s ] +resource "aws_iam_role" "test" { + name = %[1]q + path = "/service-role/" + assume_role_policy = "${data.aws_iam_policy_document.test.json}" } -`, timestamp, staticAssumeRolePolicyString, acctest.RandomWithPrefix("tf-acc-test-kms-grant-role"), rName, operations) +`, rName) } -func testAccAWSKmsGrant_withConstraints(rName string, timestamp string, constraintName string, encryptionContext string) string { - return fmt.Sprintf(` -resource "aws_kms_key" "tf-acc-test-key" { - description = "Terraform acc test key %s" - deletion_window_in_days = 7 +func testAccAWSKmsGrant_Basic(rName string, operations string) string { + return testAccAWSKmsGrantConfigBase(rName) + fmt.Sprintf(` +resource "aws_kms_grant" "test" { + name = %[1]q + key_id = "${aws_kms_key.test.key_id}" + grantee_principal = "${aws_iam_role.test.arn}" + operations = [ %[2]s ] } - -%s - -resource "aws_iam_role" "tf-acc-test-role" { - name = "%s" - path = "/service-role/" - assume_role_policy = "${data.aws_iam_policy_document.assumerole-policy-template.json}" +`, rName, operations) } -resource "aws_kms_grant" "%[4]s" { - name = "%[4]s" - key_id = "${aws_kms_key.tf-acc-test-key.key_id}" - grantee_principal = "${aws_iam_role.tf-acc-test-role.arn}" +func testAccAWSKmsGrant_withConstraints(rName string, constraintName string, encryptionContext string) string { + return testAccAWSKmsGrantConfigBase(rName) + fmt.Sprintf(` +resource "aws_kms_grant" "test" { + name = "%[1]s" + key_id = "${aws_kms_key.test.key_id}" + grantee_principal = "${aws_iam_role.test.arn}" operations = [ "RetireGrant", "DescribeKey" ] constraints { - %[5]s = { - %[6]s + %[2]s = { + %[3]s } } } -`, timestamp, staticAssumeRolePolicyString, acctest.RandomWithPrefix("tf-acc-test-kms-grant-role"), rName, constraintName, encryptionContext) -} - -func testAccAWSKmsGrant_withRetiringPrincipal(rName string, timestamp string) string { - return fmt.Sprintf(` -resource "aws_kms_key" "tf-acc-test-key" { - description = "Terraform acc test key %s" - deletion_window_in_days = 7 -} - -%s - -resource "aws_iam_role" "tf-acc-test-role" { - name = "%s" - path = "/service-role/" - assume_role_policy = "${data.aws_iam_policy_document.assumerole-policy-template.json}" +`, rName, constraintName, encryptionContext) } -resource "aws_kms_grant" "%[4]s" { - name = "%[4]s" - key_id = "${aws_kms_key.tf-acc-test-key.key_id}" - grantee_principal = "${aws_iam_role.tf-acc-test-role.arn}" +func testAccAWSKmsGrant_withRetiringPrincipal(rName string) string { + return testAccAWSKmsGrantConfigBase(rName) + fmt.Sprintf(` +resource "aws_kms_grant" "test" { + name = "%[1]s" + key_id = "${aws_kms_key.test.key_id}" + grantee_principal = "${aws_iam_role.test.arn}" operations = ["ReEncryptTo", "CreateGrant"] - retiring_principal = "${aws_iam_role.tf-acc-test-role.arn}" + retiring_principal = "${aws_iam_role.test.arn}" } -`, timestamp, staticAssumeRolePolicyString, acctest.RandomWithPrefix("tf-acc-test-kms-grant-role"), rName) +`, rName) } -func testAccAWSKmsGrant_bare(rName string, timestamp string) string { - return fmt.Sprintf(` -resource "aws_kms_key" "tf-acc-test-key" { - description = "Terraform acc test key %s" - deletion_window_in_days = 7 -} - -%s - -resource "aws_iam_role" "tf-acc-test-role" { - name = "%s" - path = "/service-role/" - assume_role_policy = "${data.aws_iam_policy_document.assumerole-policy-template.json}" -} - -resource "aws_kms_grant" "%s" { - key_id = "${aws_kms_key.tf-acc-test-key.key_id}" - grantee_principal = "${aws_iam_role.tf-acc-test-role.arn}" +func testAccAWSKmsGrant_bare(rName string) string { + return testAccAWSKmsGrantConfigBase(rName) + fmt.Sprintf(` +resource "aws_kms_grant" "test" { + key_id = "${aws_kms_key.test.key_id}" + grantee_principal = "${aws_iam_role.test.arn}" operations = ["ReEncryptTo", "CreateGrant"] } -`, timestamp, staticAssumeRolePolicyString, acctest.RandomWithPrefix("tf-acc-test-kms-grant-role"), rName) -} - -const staticAssumeRolePolicyString = ` -data "aws_iam_policy_document" "assumerole-policy-template" { - statement { - effect = "Allow" - actions = [ "sts:AssumeRole" ] - principals { - type = "Service" - identifiers = [ "ec2.amazonaws.com" ] - } - } -} -` - -func testAccAWSKmsGrant_ARN(rName string, timestamp string, operations string) string { - return fmt.Sprintf(` -resource "aws_kms_key" "tf-acc-test-key" { - description = "Terraform acc test key %s" - deletion_window_in_days = 7 -} - -%s - -resource "aws_iam_role" "tf-acc-test-role" { - name = "%s" - path = "/service-role/" - assume_role_policy = "${data.aws_iam_policy_document.assumerole-policy-template.json}" +`) } -resource "aws_kms_grant" "%[4]s" { - name = "%[4]s" - key_id = "${aws_kms_key.tf-acc-test-key.arn}" - grantee_principal = "${aws_iam_role.tf-acc-test-role.arn}" - operations = [ %[5]s ] +func testAccAWSKmsGrant_ARN(rName string, operations string) string { + return testAccAWSKmsGrantConfigBase(rName) + fmt.Sprintf(` +resource "aws_kms_grant" "test" { + name = "%[1]s" + key_id = "${aws_kms_key.test.arn}" + grantee_principal = "${aws_iam_role.test.arn}" + operations = [ %[2]s ] } -`, timestamp, staticAssumeRolePolicyString, acctest.RandomWithPrefix("tf-acc-test-kms-grant-role"), rName, operations) +`, rName, operations) } diff --git a/website/docs/r/kms_grant.html.markdown b/website/docs/r/kms_grant.html.markdown index dda87ed1cd8..cbea30fb761 100644 --- a/website/docs/r/kms_grant.html.markdown +++ b/website/docs/r/kms_grant.html.markdown @@ -74,3 +74,11 @@ In addition to all arguments above, the following attributes are exported: * `grant_id` - The unique identifier for the grant. * `grant_token` - The grant token for the created grant. For more information, see [Grant Tokens](http://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). + +## Import + +KMS Grants can be imported using the Key ID and Grant ID separated by a colon (`:`), e.g. + +``` +$ terraform import aws_kms_grant.test 1234abcd-12ab-34cd-56ef-1234567890ab: abcde1237f76e4ba7987489ac329fbfba6ad343d6f7075dbd1ef191f0120514 +``` From a0dc4b5336aa408f626a5ce350a83c6fab083557 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Mar 2020 11:51:21 -0400 Subject: [PATCH 163/684] Update CHANGELOG for #11991 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5df5a32898..4d30292acbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ENHANCEMENTS: * data-source/aws_launch_template: Add `hibernation_options` attribute [GH-12492] +* resource/aws_kms_grant: Support resource import [GH-11991] * resource/aws_launch_template: Add `hibernation_options` configuration block [GH-12492] BUG FIXES: From f157566b9303d0817deb1cb55df6453b8937f568 Mon Sep 17 00:00:00 2001 From: Eddie Ramirez Date: Mon, 30 Mar 2020 09:21:29 -0700 Subject: [PATCH 164/684] service/directconnect: Support 2Gbps and 5Gbps values in plan-time validation for bandwidth argument (#12559) * https://docs.aws.amazon.com/directconnect/latest/UserGuide/WorkingWithConnections.html * https://docs.aws.amazon.com/directconnect/latest/APIReference/API_CreateLag.html Signed-off-by: Eddie Ramirez --- aws/validators.go | 2 ++ aws/validators_test.go | 2 ++ website/docs/r/dx_connection.html.markdown | 2 +- website/docs/r/dx_lag.html.markdown | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/aws/validators.go b/aws/validators.go index 890b96b12cf..5b1b685d960 100644 --- a/aws/validators.go +++ b/aws/validators.go @@ -1958,6 +1958,8 @@ func validateCognitoRoles(v map[string]interface{}) (errors []error) { func validateDxConnectionBandWidth() schema.SchemaValidateFunc { return validation.StringInSlice([]string{ "1Gbps", + "2Gbps", + "5Gbps", "10Gbps", "50Mbps", "100Mbps", diff --git a/aws/validators_test.go b/aws/validators_test.go index d912edea383..05a2b73c327 100644 --- a/aws/validators_test.go +++ b/aws/validators_test.go @@ -2841,6 +2841,8 @@ func TestValidateCloudFrontPublicKeyNamePrefix(t *testing.T) { func TestValidateDxConnectionBandWidth(t *testing.T) { validBandwidths := []string{ "1Gbps", + "2Gbps", + "5Gbps", "10Gbps", "50Mbps", "100Mbps", diff --git a/website/docs/r/dx_connection.html.markdown b/website/docs/r/dx_connection.html.markdown index b61edfdf0a6..69620571e64 100644 --- a/website/docs/r/dx_connection.html.markdown +++ b/website/docs/r/dx_connection.html.markdown @@ -25,7 +25,7 @@ resource "aws_dx_connection" "hoge" { The following arguments are supported: * `name` - (Required) The name of the connection. -* `bandwidth` - (Required) The bandwidth of the connection. Available values: 1Gbps, 10Gbps. Case sensitive. +* `bandwidth` - (Required) The bandwidth of the connection. Valid values for dedicated connections: 1Gbps, 10Gbps. Valid values for hosted connections: 50Mbps, 100Mbps, 200Mbps, 300Mbps, 400Mbps, 500Mbps, 1Gbps, 2Gbps, 5Gbps and 10Gbps. Case sensitive. * `location` - (Required) The AWS Direct Connect location where the connection is located. See [DescribeLocations](https://docs.aws.amazon.com/directconnect/latest/APIReference/API_DescribeLocations.html) for the list of AWS Direct Connect locations. Use `locationCode`. * `tags` - (Optional) A mapping of tags to assign to the resource. diff --git a/website/docs/r/dx_lag.html.markdown b/website/docs/r/dx_lag.html.markdown index 5b9546f1e0f..1e7a908facf 100644 --- a/website/docs/r/dx_lag.html.markdown +++ b/website/docs/r/dx_lag.html.markdown @@ -28,7 +28,7 @@ resource "aws_dx_lag" "hoge" { The following arguments are supported: * `name` - (Required) The name of the LAG. -* `connections_bandwidth` - (Required) The bandwidth of the individual physical connections bundled by the LAG. Available values: 1Gbps, 10Gbps. Case sensitive. +* `connections_bandwidth` - (Required) The bandwidth of the individual physical connections bundled by the LAG. Valid values: 50Mbps, 100Mbps, 200Mbps, 300Mbps, 400Mbps, 500Mbps, 1Gbps, 2Gbps, 5Gbps and 10Gbps. Case sensitive. * `location` - (Required) The AWS Direct Connect location in which the LAG should be allocated. See [DescribeLocations](https://docs.aws.amazon.com/directconnect/latest/APIReference/API_DescribeLocations.html) for the list of AWS Direct Connect locations. Use `locationCode`. * `force_destroy` - (Optional, Default:false) A boolean that indicates all connections associated with the LAG should be deleted so that the LAG can be destroyed without error. These objects are *not* recoverable. * `tags` - (Optional) A mapping of tags to assign to the resource. From a448d0c3890cd6039988380412450bd6db4cd5e3 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Mar 2020 12:23:16 -0400 Subject: [PATCH 165/684] Update CHANGELOG for #12559 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d30292acbe..e72ba13b6c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ENHANCEMENTS: * data-source/aws_launch_template: Add `hibernation_options` attribute [GH-12492] +* resource/aws_dx_connection: Support `2Gbps` and `5Gbps` values in plan-time validation for `bandwidth` argument [GH-12559] +* resource/aws_dx_lag: Support `2Gbps` and `5Gbps` values in plan-time validation for `bandwidth` argument [GH-12559] * resource/aws_kms_grant: Support resource import [GH-11991] * resource/aws_launch_template: Add `hibernation_options` configuration block [GH-12492] From ecf1281d8fd48cbc5be19ee621214e058ee8c363 Mon Sep 17 00:00:00 2001 From: Dean Shelton Date: Mon, 30 Mar 2020 09:47:33 -0700 Subject: [PATCH 166/684] (docs) show AWS recommended EFS volume mount options (#12576) Co-authored-by: Dean Shelton --- website/docs/r/ecs_task_definition.html.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/website/docs/r/ecs_task_definition.html.markdown b/website/docs/r/ecs_task_definition.html.markdown index a6db3efbe5c..23506b91608 100644 --- a/website/docs/r/ecs_task_definition.html.markdown +++ b/website/docs/r/ecs_task_definition.html.markdown @@ -15,7 +15,7 @@ Manages a revision of an ECS task definition to be used in `aws_ecs_service`. ```hcl resource "aws_ecs_task_definition" "service" { family = "service" - container_definitions = "${file("task-definitions/service.json")}" + container_definitions = file("task-definitions/service.json") volume { name = "service-storage" @@ -70,7 +70,7 @@ contains only a small subset of the available parameters. ```hcl resource "aws_ecs_task_definition" "service" { family = "service" - container_definitions = "${file("task-definitions/service.json")}" + container_definitions = file("task-definitions/service.json") proxy_configuration { type = "APPMESH" @@ -137,7 +137,7 @@ For more information, see [Specifying a Docker volume in your Task Definition De ```hcl resource "aws_ecs_task_definition" "service" { family = "service" - container_definitions = "${file("task-definitions/service.json")}" + container_definitions = file("task-definitions/service.json") volume { name = "service-storage" @@ -150,7 +150,7 @@ resource "aws_ecs_task_definition" "service" { driver_opts = { "type" = "nfs" "device" = "${aws_efs_file_system.fs.dns_name}:/" - "o" = "addr=${aws_efs_file_system.fs.dns_name},nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,nosuid" + "o" = "addr=${aws_efs_file_system.fs.dns_name},rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport" } } } @@ -175,7 +175,7 @@ resource "aws_ecs_task_definition" "service" { name = "service-storage" efs_volume_configuration { - file_system_id = "${aws_efs_file_system.fs.id}" + file_system_id = aws_efs_file_system.fs.id root_directory = "/opt/data" } } From de966f3e0f94f4f85bb693bc76f30048101c1f66 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 30 Mar 2020 10:59:24 -0700 Subject: [PATCH 167/684] Removes "foo" and "bar" --- aws/resource_aws_codepipeline_test.go | 60 +++++++++++++-------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 8fa139b22f8..976532de3b3 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -33,7 +33,7 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s", name))), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.type", "S3"), - resource.TestCheckResourceAttrPair(resourceName, "artifact_store.0.location", "aws_s3_bucket.foo", "bucket"), + resource.TestCheckResourceAttrPair(resourceName, "artifact_store.0.location", "aws_s3_bucket.test", "bucket"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.#", "1"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.id", "1234"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.type", "KMS"), @@ -96,19 +96,19 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.name", "Source"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.input_artifacts.#", "0"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.output_artifacts.#", "1"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.output_artifacts.0", "bar"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.output_artifacts.0", "artifacts"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "3"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Owner", "foo-terraform"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Repo", "bar"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Owner", "test-terraform"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Repo", "test-repo"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Branch", "stable"), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.input_artifacts.#", "1"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.input_artifacts.0", "bar"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.input_artifacts.0", "artifacts"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.configuration.%", "1"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.configuration.ProjectName", "foo"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.configuration.ProjectName", "test"), ), }, }, @@ -397,8 +397,8 @@ resource "aws_iam_role_policy" "codepipeline_policy" { "s3:GetBucketVersioning" ], "Resource": [ - "${aws_s3_bucket.foo.arn}", - "${aws_s3_bucket.foo.arn}/*" + "${aws_s3_bucket.test.arn}", + "${aws_s3_bucket.test.arn}/*" ] }, { @@ -453,8 +453,8 @@ resource "aws_iam_role_policy" "codepipeline_policy" { "s3:GetBucketVersioning" ], "Resource": [ - "${aws_s3_bucket.foo.arn}", - "${aws_s3_bucket.foo.arn}/*" + "${aws_s3_bucket.test.arn}", + "${aws_s3_bucket.test.arn}/*" ] }, { @@ -489,7 +489,7 @@ resource "aws_codepipeline" "test" { role_arn = "${aws_iam_role.codepipeline_role.arn}" artifact_store { - location = "${aws_s3_bucket.foo.bucket}" + location = "${aws_s3_bucket.test.bucket}" type = "S3" encryption_key { @@ -547,7 +547,7 @@ resource "aws_codepipeline" "test" { role_arn = "${aws_iam_role.codepipeline_role.arn}" artifact_store { - location = "${aws_s3_bucket.foo.bucket}" + location = "${aws_s3_bucket.updated.bucket}" type = "S3" encryption_key { @@ -565,11 +565,11 @@ resource "aws_codepipeline" "test" { owner = "ThirdParty" provider = "GitHub" version = "1" - output_artifacts = ["bar"] + output_artifacts = ["artifacts"] configuration = { - Owner = "foo-terraform" - Repo = "bar" + Owner = "test-terraform" + Repo = "test-repo" Branch = "stable" } } @@ -583,11 +583,11 @@ resource "aws_codepipeline" "test" { category = "Build" owner = "AWS" provider = "CodeBuild" - input_artifacts = ["bar"] + input_artifacts = ["artifacts"] version = "1" configuration = { - ProjectName = "foo" + ProjectName = "test" } } } @@ -605,7 +605,7 @@ resource "aws_codepipeline" "test" { role_arn = "${aws_iam_role.codepipeline_role.arn}" artifact_store { - location = "${aws_s3_bucket.foo.bucket}" + location = "${aws_s3_bucket.test.bucket}" type = "S3" } @@ -688,8 +688,8 @@ resource "aws_iam_role_policy" "codepipeline_action_policy" { "s3:GetBucketVersioning" ], "Resource": [ - "${aws_s3_bucket.foo.arn}", - "${aws_s3_bucket.foo.arn}/*" + "${aws_s3_bucket.test.arn}", + "${aws_s3_bucket.test.arn}/*" ] } ] @@ -710,7 +710,7 @@ resource "aws_codepipeline" "test" { role_arn = "${aws_iam_role.codepipeline_role.arn}" artifact_store { - location = "${aws_s3_bucket.foo.bucket}" + location = "${aws_s3_bucket.test.bucket}" type = "S3" encryption_key { @@ -728,11 +728,11 @@ resource "aws_codepipeline" "test" { owner = "ThirdParty" provider = "GitHub" version = "1" - output_artifacts = ["bar"] + output_artifacts = ["artifacts"] configuration = { - Owner = "foo-terraform" - Repo = "bar" + Owner = "test-terraform" + Repo = "test-repo" Branch = "stable" } } @@ -746,12 +746,12 @@ resource "aws_codepipeline" "test" { category = "Build" owner = "AWS" provider = "CodeBuild" - input_artifacts = ["bar"] - output_artifacts = ["baz"] + input_artifacts = ["artifacts"] + output_artifacts = ["artifacts2"] version = "1" configuration = { - ProjectName = "foo" + ProjectName = "test" } } } @@ -764,7 +764,7 @@ resource "aws_codepipeline" "test" { category = "Deploy" owner = "AWS" provider = "CloudFormation" - input_artifacts = ["baz"] + input_artifacts = ["artifacts2"] role_arn = "${aws_iam_role.codepipeline_action_role.arn}" version = "1" @@ -772,7 +772,7 @@ resource "aws_codepipeline" "test" { ActionMode = "CHANGE_SET_REPLACE" ChangeSetName = "changeset" StackName = "stack" - TemplatePath = "baz::template.yaml" + TemplatePath = "artifacts2::template.yaml" } } } @@ -790,7 +790,7 @@ resource "aws_codepipeline" "test" { role_arn = "${aws_iam_role.codepipeline_role.arn}" artifact_store { - location = "${aws_s3_bucket.foo.bucket}" + location = "${aws_s3_bucket.test.bucket}" type = "S3" encryption_key { From c66ae719ddc7beb80a99582eb4b3087ff4107bee Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 30 Mar 2020 14:04:14 -0400 Subject: [PATCH 168/684] service/rds: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12477) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_db_cluster_snapshot.go:197:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_event_subscription.go:239:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_db_event_subscription.go:296:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_event_subscription.go:297:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_event_subscription.go:298:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_event_subscription.go:299:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_event_subscription.go:309:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_event_subscription.go:351:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_event_subscription.go:354:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_db_instance.go:1473:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_db_instance.go:1480:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1488:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1489:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1495:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1501:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1506:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1511:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1516:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1521:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1526:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1531:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1537:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1542:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1547:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1561:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1566:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1571:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1576:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1585:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1591:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1597:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1617:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1623:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1628:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1634:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1645:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1646:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1653:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1657:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1662:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1732:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_instance.go:1735:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_db_option_group.go:288:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_option_group.go:299:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_parameter_group.go:116:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_db_parameter_group.go:117:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_parameter_group.go:118:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_parameter_group.go:119:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_parameter_group.go:120:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_db_parameter_group.go:249:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_db_parameter_group.go:331:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_parameter_group.go:334:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_db_security_group.go:199:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_db_security_group.go:208:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_security_group.go:246:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_db_snapshot.go:224:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_db_subnet_group.go:199:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster.go:1121:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster.go:1137:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster.go:1143:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster.go:1149:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster.go:1246:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_instance.go:493:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_instance.go:499:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_instance.go:503:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_instance.go:511:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_instance.go:517:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_instance.go:523:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_instance.go:529:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_instance.go:535:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_instance.go:541:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_instance.go:547:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_instance.go:553:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_parameter_group.go:185:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_rds_cluster_parameter_group.go:274:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_rds_cluster_parameter_group.go:277:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing (test failures present on master): ``` --- PASS: TestAccAWSDBClusterSnapshot_basic (161.83s) --- PASS: TestAccAWSDBClusterSnapshot_Tags (208.14s) --- PASS: TestAccAWSDBEventSubscription_basicUpdate (127.65s) --- PASS: TestAccAWSDBEventSubscription_categoryUpdate (125.24s) --- PASS: TestAccAWSDBEventSubscription_disappears (78.82s) --- PASS: TestAccAWSDBEventSubscription_withPrefix (81.72s) --- PASS: TestAccAWSDBEventSubscription_withSourceIds (101.26s) --- FAIL: TestAccAWSDBInstance_S3Import (671.95s) --- PASS: TestAccAWSDBInstance_AllowMajorVersionUpgrade (443.80s) --- PASS: TestAccAWSDBInstance_basic (566.04s) --- PASS: TestAccAWSDBInstance_CACertificateIdentifier (623.72s) --- PASS: TestAccAWSDBInstance_cloudwatchLogsExportConfiguration (530.77s) --- PASS: TestAccAWSDBInstance_cloudwatchLogsExportConfigurationUpdate (956.15s) --- PASS: TestAccAWSDBInstance_DeletionProtection (584.27s) --- PASS: TestAccAWSDBInstance_EnabledCloudwatchLogsExports_MSSQL (698.62s) --- PASS: TestAccAWSDBInstance_EnabledCloudwatchLogsExports_Oracle (760.80s) --- PASS: TestAccAWSDBInstance_EnabledCloudwatchLogsExports_Postgresql (623.55s) --- PASS: TestAccAWSDBInstance_FinalSnapshotIdentifier (813.02s) --- PASS: TestAccAWSDBInstance_FinalSnapshotIdentifier_SkipFinalSnapshot (742.11s) --- PASS: TestAccAWSDBInstance_generatedName (473.76s) --- PASS: TestAccAWSDBInstance_iamAuth (423.49s) --- PASS: TestAccAWSDBInstance_IsAlreadyBeingDeleted (539.38s) --- PASS: TestAccAWSDBInstance_kmsKey (462.25s) --- PASS: TestAccAWSDBInstance_MaxAllocatedStorage (625.94s) --- PASS: TestAccAWSDBInstance_MinorVersion (496.98s) --- PASS: TestAccAWSDBInstance_MonitoringInterval (1038.16s) --- PASS: TestAccAWSDBInstance_MonitoringRoleArn_EnabledToDisabled (795.78s) --- PASS: TestAccAWSDBInstance_MonitoringRoleArn_EnabledToRemoved (804.57s) --- PASS: TestAccAWSDBInstance_MonitoringRoleArn_RemovedToEnabled (822.91s) --- PASS: TestAccAWSDBInstance_MSSQL_Domain (3671.81s) --- PASS: TestAccAWSDBInstance_MSSQL_DomainSnapshotRestore (2811.43s) --- PASS: TestAccAWSDBInstance_MSSQL_TZ (1625.50s) --- PASS: TestAccAWSDBInstance_MySQL_SnapshotRestoreWithEngineVersion (1902.87s) --- PASS: TestAccAWSDBInstance_namePrefix (485.32s) --- PASS: TestAccAWSDBInstance_NoDeleteAutomatedBackups (654.56s) --- PASS: TestAccAWSDBInstance_optionGroup (499.87s) --- PASS: TestAccAWSDBInstance_Password (574.56s) --- PASS: TestAccAWSDBInstance_portUpdate (504.62s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb (1527.99s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_AllowMajorVersionUpgrade (1476.93s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_AutoMinorVersionUpgrade (1370.52s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_AvailabilityZone (1482.23s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_BackupRetentionPeriod (1824.62s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_BackupWindow (1598.16s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_CACertificateIdentifier (1454.94s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_IamDatabaseAuthenticationEnabled (1538.08s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_MaintenanceWindow (1582.77s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_MaxAllocatedStorage (1594.36s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_Monitoring (1753.26s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_MultiAZ (2145.53s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_ParameterGroupName (1695.43s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_PerformanceInsightsEnabled (1860.48s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_Port (1448.57s) --- PASS: TestAccAWSDBInstance_ReplicateSourceDb_VpcSecurityGroupIds (1540.51s) --- PASS: TestAccAWSDBInstance_separate_iops_update (781.70s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier (1327.39s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_AllocatedStorage (1519.07s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_AllowMajorVersionUpgrade (2303.64s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_AutoMinorVersionUpgrade (1187.05s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_AvailabilityZone (1298.15s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_BackupRetentionPeriod (1644.94s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_BackupRetentionPeriod_Unset (1704.80s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_BackupWindow (1307.64s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_DeletionProtection (1235.72s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_IamDatabaseAuthenticationEnabled (1295.56s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_Io1Storage (1804.10s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_MaintenanceWindow (1324.91s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_MaxAllocatedStorage (1118.39s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_Monitoring (1256.49s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_MultiAZ (1893.83s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_MultiAZ_SQLServer (3726.44s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_ParameterGroupName (1341.16s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_PerformanceInsightsEnabled (1369.24s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_Port (1241.65s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_Tags (1180.23s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_VpcSecurityGroupIds (1150.78s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_VpcSecurityGroupIds_Tags (1127.44s) --- PASS: TestAccAWSDBInstance_SnapshotIdentifier_VpcSecurityGroupIds_Tags (1305.53s) --- PASS: TestAccAWSDBInstance_subnetGroup (1056.41s) --- PASS: TestAccAWSDBOptionGroup_basic (20.09s) --- PASS: TestAccAWSDBOptionGroup_basicDestroyWithInstance (505.73s) --- PASS: TestAccAWSDBOptionGroup_generatedName (25.87s) --- PASS: TestAccAWSDBOptionGroup_multipleOptions (36.35s) --- PASS: TestAccAWSDBOptionGroup_namePrefix (40.96s) --- PASS: TestAccAWSDBOptionGroup_Option_OptionSettings (120.52s) --- PASS: TestAccAWSDBOptionGroup_Option_OptionSettings_IAMRole (62.67s) --- PASS: TestAccAWSDBOptionGroup_Option_OptionSettings_MultipleNonDefault (67.17s) --- PASS: TestAccAWSDBOptionGroup_OracleOptionsUpdate (110.44s) --- PASS: TestAccAWSDBOptionGroup_sqlServerOptionsUpdate (82.61s) --- PASS: TestAccAWSDBOptionGroup_Tags (65.48s) --- PASS: TestAccAWSDBOptionGroup_Tags_WithOptions (65.91s) --- PASS: TestAccAWSDBOptionGroup_timeoutBlock (26.29s) --- PASS: TestAccAWSDBParameterGroup_basic (113.24s) --- PASS: TestAccAWSDBParameterGroup_Disappears (17.07s) --- PASS: TestAccAWSDBParameterGroup_generatedName (41.36s) --- PASS: TestAccAWSDBParameterGroup_limit (84.28s) --- PASS: TestAccAWSDBParameterGroup_MatchDefault (61.75s) --- PASS: TestAccAWSDBParameterGroup_namePrefix (48.96s) --- PASS: TestAccAWSDBParameterGroup_Only (39.17s) --- PASS: TestAccAWSDBParameterGroup_withApplyMethod (51.68s) --- PASS: TestAccAWSDBSecurityGroup_basic (13.66s) --- PASS: TestAccAWSDBSnapshot_basic (755.49s) --- PASS: TestAccAWSDBSnapshot_disappears (617.74s) --- PASS: TestAccAWSDBSnapshot_tags (651.91s) --- PASS: TestAccAWSDBSubnetGroup_basic (35.79s) --- PASS: TestAccAWSDBSubnetGroup_generatedName (35.00s) --- PASS: TestAccAWSDBSubnetGroup_namePrefix (35.59s) --- PASS: TestAccAWSDBSubnetGroup_updateDescription (61.68s) --- PASS: TestAccAWSDBSubnetGroup_withUndocumentedCharacters (42.07s) --- FAIL: TestAccAWSRDSCluster_s3Restore (1624.16s) --- PASS: TestAccAWSRDSCluster_AvailabilityZones (240.79s) --- PASS: TestAccAWSRDSCluster_BacktrackWindow (248.08s) --- PASS: TestAccAWSRDSCluster_backupsUpdate (183.26s) --- PASS: TestAccAWSRDSCluster_basic (236.10s) --- PASS: TestAccAWSRDSCluster_ClusterIdentifierPrefix (123.32s) --- PASS: TestAccAWSRDSCluster_copyTagsToSnapshot (224.31s) --- PASS: TestAccAWSRDSCluster_DbSubnetGroupName (214.54s) --- PASS: TestAccAWSRDSCluster_DeletionProtection (164.87s) --- PASS: TestAccAWSRDSCluster_EnabledCloudwatchLogsExports (446.46s) --- PASS: TestAccAWSRDSCluster_EnableHttpEndpoint (311.62s) --- PASS: TestAccAWSRDSCluster_encrypted (122.89s) --- PASS: TestAccAWSRDSCluster_EncryptedCrossRegionReplication (1804.90s) --- PASS: TestAccAWSRDSCluster_EngineMode (414.68s) --- PASS: TestAccAWSRDSCluster_EngineMode_Global (132.28s) --- PASS: TestAccAWSRDSCluster_EngineMode_Multimaster (212.05s) --- PASS: TestAccAWSRDSCluster_EngineMode_ParallelQuery (225.62s) --- PASS: TestAccAWSRDSCluster_EngineVersion (136.38s) --- PASS: TestAccAWSRDSCluster_EngineVersionWithPrimaryInstance (1114.96s) --- PASS: TestAccAWSRDSCluster_generatedName (131.15s) --- PASS: TestAccAWSRDSCluster_GlobalClusterIdentifier (203.57s) --- PASS: TestAccAWSRDSCluster_GlobalClusterIdentifier_Add (231.16s) --- PASS: TestAccAWSRDSCluster_GlobalClusterIdentifier_Remove (215.27s) --- PASS: TestAccAWSRDSCluster_GlobalClusterIdentifier_Update (210.72s) --- PASS: TestAccAWSRDSCluster_iamAuth (131.99s) --- PASS: TestAccAWSRDSCluster_kmsKey (150.06s) --- PASS: TestAccAWSRDSCluster_missingUserNameCausesError (7.08s) --- PASS: TestAccAWSRDSCluster_Port (362.74s) --- PASS: TestAccAWSRDSCluster_ScalingConfiguration (410.44s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier (419.84s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_DeletionProtection (411.50s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_EncryptedRestore (352.20s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_EngineMode_ParallelQuery (455.74s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_EngineMode_Provisioned (393.86s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_EngineVersion_Different (373.62s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_EngineVersion_Equal (373.42s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_MasterPassword (459.57s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_MasterUsername (433.11s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_PreferredBackupWindow (407.91s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_PreferredMaintenanceWindow (371.35s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_Tags (374.56s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_VpcSecurityGroupIds (414.24s) --- PASS: TestAccAWSRDSCluster_SnapshotIdentifier_VpcSecurityGroupIds_Tags (404.15s) --- PASS: TestAccAWSRDSCluster_Tags (152.46s) --- PASS: TestAccAWSRDSCluster_takeFinalSnapshot (152.36s) --- PASS: TestAccAWSRDSCluster_updateIamRoles (173.37s) --- FAIL: TestAccAWSRDSClusterInstance_CACertificateIdentifier (819.09s) --- PASS: TestAccAWSRDSClusterInstance_az (745.73s) --- PASS: TestAccAWSRDSClusterInstance_basic (1460.33s) --- PASS: TestAccAWSRDSClusterInstance_CopyTagsToSnapshot (693.56s) --- PASS: TestAccAWSRDSClusterInstance_disappears (696.91s) --- PASS: TestAccAWSRDSClusterInstance_generatedName (720.86s) --- PASS: TestAccAWSRDSClusterInstance_isAlreadyBeingDeleted (708.46s) --- PASS: TestAccAWSRDSClusterInstance_kmsKey (1376.64s) --- PASS: TestAccAWSRDSClusterInstance_MonitoringInterval (1298.65s) --- PASS: TestAccAWSRDSClusterInstance_MonitoringRoleArn_EnabledToDisabled (941.01s) --- PASS: TestAccAWSRDSClusterInstance_MonitoringRoleArn_EnabledToRemoved (965.68s) --- PASS: TestAccAWSRDSClusterInstance_MonitoringRoleArn_RemovedToEnabled (841.84s) --- PASS: TestAccAWSRDSClusterInstance_namePrefix (1063.96s) --- PASS: TestAccAWSRDSClusterInstance_PerformanceInsightsEnabled_AuroraMysql1 (858.33s) --- PASS: TestAccAWSRDSClusterInstance_PerformanceInsightsEnabled_AuroraMysql2 (804.60s) --- PASS: TestAccAWSRDSClusterInstance_PerformanceInsightsEnabled_AuroraPostgresql (794.16s) --- PASS: TestAccAWSRDSClusterInstance_PerformanceInsightsKmsKeyId_AuroraMysql1 (817.10s) --- PASS: TestAccAWSRDSClusterInstance_PerformanceInsightsKmsKeyId_AuroraMysql1_DefaultKeyToCustomKey (764.17s) --- PASS: TestAccAWSRDSClusterInstance_PerformanceInsightsKmsKeyId_AuroraMysql2 (850.24s) --- PASS: TestAccAWSRDSClusterInstance_PerformanceInsightsKmsKeyId_AuroraMysql2_DefaultKeyToCustomKey (847.01s) --- PASS: TestAccAWSRDSClusterInstance_PerformanceInsightsKmsKeyId_AuroraPostgresql (786.92s) --- PASS: TestAccAWSRDSClusterInstance_PerformanceInsightsKmsKeyId_AuroraPostgresql_DefaultKeyToCustomKey (753.94s) --- PASS: TestAccAWSRDSClusterInstance_PubliclyAccessible (762.33s) ``` --- aws/resource_aws_db_cluster_snapshot.go | 2 -- aws/resource_aws_db_event_subscription.go | 10 ------- aws/resource_aws_db_instance.go | 36 ----------------------- aws/resource_aws_db_option_group.go | 3 -- aws/resource_aws_db_parameter_group.go | 12 -------- aws/resource_aws_db_security_group.go | 5 ---- aws/resource_aws_db_snapshot.go | 2 -- aws/resource_aws_db_subnet_group.go | 2 -- aws/resource_aws_rds_cluster.go | 6 ---- aws/resource_aws_rds_cluster_instance.go | 11 ------- 10 files changed, 89 deletions(-) diff --git a/aws/resource_aws_db_cluster_snapshot.go b/aws/resource_aws_db_cluster_snapshot.go index 8a0d1d82deb..51ed357a71e 100644 --- a/aws/resource_aws_db_cluster_snapshot.go +++ b/aws/resource_aws_db_cluster_snapshot.go @@ -193,8 +193,6 @@ func resourceAwsdbClusterSnapshotUpdate(d *schema.ResourceData, meta interface{} if err := keyvaluetags.RdsUpdateTags(conn, d.Get("db_cluster_snapshot_arn").(string), o, n); err != nil { return fmt.Errorf("error updating RDS DB Cluster Snapshot (%s) tags: %s", d.Get("db_cluster_snapshot_arn").(string), err) } - - d.SetPartial("tags") } return nil diff --git a/aws/resource_aws_db_event_subscription.go b/aws/resource_aws_db_event_subscription.go index bcb8b1840cc..a9799c671de 100644 --- a/aws/resource_aws_db_event_subscription.go +++ b/aws/resource_aws_db_event_subscription.go @@ -236,7 +236,6 @@ func resourceAwsDbEventSubscriptionRetrieve(name string, conn *rds.RDS) (*rds.Ev func resourceAwsDbEventSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn - d.Partial(true) requestUpdate := false req := &rds.ModifyEventSubscriptionInput{ @@ -293,10 +292,6 @@ func resourceAwsDbEventSubscriptionUpdate(d *schema.ResourceData, meta interface if err != nil { return fmt.Errorf("Modifying RDS Event Subscription %s failed: %s", d.Id(), err) } - d.SetPartial("event_categories") - d.SetPartial("enabled") - d.SetPartial("sns_topic") - d.SetPartial("source_type") } if d.HasChange("tags") { @@ -305,8 +300,6 @@ func resourceAwsDbEventSubscriptionUpdate(d *schema.ResourceData, meta interface if err := keyvaluetags.RdsUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating RDS Event Subscription (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } if d.HasChange("source_ids") { @@ -348,11 +341,8 @@ func resourceAwsDbEventSubscriptionUpdate(d *schema.ResourceData, meta interface } } } - d.SetPartial("source_ids") } - d.Partial(false) - return nil } diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index 09cb730ae95..4bbb421f5dd 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -1453,81 +1453,64 @@ func waitUntilAwsDbInstanceIsDeleted(id string, conn *rds.RDS, timeout time.Dura func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn - d.Partial(true) - req := &rds.ModifyDBInstanceInput{ ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), DBInstanceIdentifier: aws.String(d.Id()), } - d.SetPartial("apply_immediately") - if !aws.BoolValue(req.ApplyImmediately) { log.Println("[INFO] Only settings updating, instance changes will be applied in next maintenance window") } requestUpdate := false if d.HasChange("allocated_storage") || d.HasChange("iops") { - d.SetPartial("allocated_storage") - d.SetPartial("iops") req.Iops = aws.Int64(int64(d.Get("iops").(int))) req.AllocatedStorage = aws.Int64(int64(d.Get("allocated_storage").(int))) requestUpdate = true } if d.HasChange("allow_major_version_upgrade") { - d.SetPartial("allow_major_version_upgrade") req.AllowMajorVersionUpgrade = aws.Bool(d.Get("allow_major_version_upgrade").(bool)) // Having allowing_major_version_upgrade by itself should not trigger ModifyDBInstance // as it results in InvalidParameterCombination: No modifications were requested } if d.HasChange("backup_retention_period") { - d.SetPartial("backup_retention_period") req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_period").(int))) requestUpdate = true } if d.HasChange("copy_tags_to_snapshot") { - d.SetPartial("copy_tags_to_snapshot") req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool)) requestUpdate = true } if d.HasChange("ca_cert_identifier") { - d.SetPartial("ca_cert_identifier") req.CACertificateIdentifier = aws.String(d.Get("ca_cert_identifier").(string)) requestUpdate = true } if d.HasChange("deletion_protection") { - d.SetPartial("deletion_protection") req.DeletionProtection = aws.Bool(d.Get("deletion_protection").(bool)) requestUpdate = true } if d.HasChange("instance_class") { - d.SetPartial("instance_class") req.DBInstanceClass = aws.String(d.Get("instance_class").(string)) requestUpdate = true } if d.HasChange("parameter_group_name") { - d.SetPartial("parameter_group_name") req.DBParameterGroupName = aws.String(d.Get("parameter_group_name").(string)) requestUpdate = true } if d.HasChange("engine_version") { - d.SetPartial("engine_version") req.EngineVersion = aws.String(d.Get("engine_version").(string)) req.AllowMajorVersionUpgrade = aws.Bool(d.Get("allow_major_version_upgrade").(bool)) requestUpdate = true } if d.HasChange("backup_window") { - d.SetPartial("backup_window") req.PreferredBackupWindow = aws.String(d.Get("backup_window").(string)) requestUpdate = true } if d.HasChange("maintenance_window") { - d.SetPartial("maintenance_window") req.PreferredMaintenanceWindow = aws.String(d.Get("maintenance_window").(string)) requestUpdate = true } if d.HasChange("max_allocated_storage") { - d.SetPartial("max_allocated_storage") mas := d.Get("max_allocated_storage").(int) // The API expects the max allocated storage value to be set to the allocated storage @@ -1541,22 +1524,18 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error requestUpdate = true } if d.HasChange("password") { - d.SetPartial("password") req.MasterUserPassword = aws.String(d.Get("password").(string)) requestUpdate = true } if d.HasChange("multi_az") { - d.SetPartial("multi_az") req.MultiAZ = aws.Bool(d.Get("multi_az").(bool)) requestUpdate = true } if d.HasChange("publicly_accessible") { - d.SetPartial("publicly_accessible") req.PubliclyAccessible = aws.Bool(d.Get("publicly_accessible").(bool)) requestUpdate = true } if d.HasChange("storage_type") { - d.SetPartial("storage_type") req.StorageType = aws.String(d.Get("storage_type").(string)) requestUpdate = true @@ -1565,19 +1544,16 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error } } if d.HasChange("auto_minor_version_upgrade") { - d.SetPartial("auto_minor_version_upgrade") req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) requestUpdate = true } if d.HasChange("monitoring_role_arn") { - d.SetPartial("monitoring_role_arn") req.MonitoringRoleArn = aws.String(d.Get("monitoring_role_arn").(string)) requestUpdate = true } if d.HasChange("monitoring_interval") { - d.SetPartial("monitoring_interval") req.MonitoringInterval = aws.Int64(int64(d.Get("monitoring_interval").(int))) requestUpdate = true } @@ -1597,24 +1573,20 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error } if d.HasChange("option_group_name") { - d.SetPartial("option_group_name") req.OptionGroupName = aws.String(d.Get("option_group_name").(string)) requestUpdate = true } if d.HasChange("port") { - d.SetPartial("port") req.DBPortNumber = aws.Int64(int64(d.Get("port").(int))) requestUpdate = true } if d.HasChange("db_subnet_group_name") { - d.SetPartial("db_subnet_group_name") req.DBSubnetGroupName = aws.String(d.Get("db_subnet_group_name").(string)) requestUpdate = true } if d.HasChange("enabled_cloudwatch_logs_exports") { - d.SetPartial("enabled_cloudwatch_logs_exports") req.CloudwatchLogsExportConfiguration = buildCloudwatchLogsExportConfiguration(d) requestUpdate = true } @@ -1625,24 +1597,19 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error } if d.HasChange("domain") || d.HasChange("domain_iam_role_name") { - d.SetPartial("domain") - d.SetPartial("domain_iam_role_name") req.Domain = aws.String(d.Get("domain").(string)) req.DomainIAMRoleName = aws.String(d.Get("domain_iam_role_name").(string)) requestUpdate = true } if d.HasChange("performance_insights_enabled") || d.HasChange("performance_insights_kms_key_id") || d.HasChange("performance_insights_retention_period") { - d.SetPartial("performance_insights_enabled") req.EnablePerformanceInsights = aws.Bool(d.Get("performance_insights_enabled").(bool)) if v, ok := d.GetOk("performance_insights_kms_key_id"); ok { - d.SetPartial("performance_insights_kms_key_id") req.PerformanceInsightsKMSKeyId = aws.String(v.(string)) } if v, ok := d.GetOk("performance_insights_retention_period"); ok { - d.SetPartial("performance_insights_retention_period") req.PerformanceInsightsRetentionPeriod = aws.Int64(int64(v.(int))) } @@ -1712,11 +1679,8 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error updating RDS DB Instance (%s) tags: %s", d.Get("arn").(string), err) } - d.SetPartial("tags") } - d.Partial(false) - return resourceAwsDbInstanceRead(d, meta) } diff --git a/aws/resource_aws_db_option_group.go b/aws/resource_aws_db_option_group.go index 53d8376f5a0..fb7880a5566 100644 --- a/aws/resource_aws_db_option_group.go +++ b/aws/resource_aws_db_option_group.go @@ -285,7 +285,6 @@ func resourceAwsDbOptionGroupUpdate(d *schema.ResourceData, meta interface{}) er if err != nil { return fmt.Errorf("Error modifying DB Option Group: %s", err) } - d.SetPartial("option") } } @@ -295,8 +294,6 @@ func resourceAwsDbOptionGroupUpdate(d *schema.ResourceData, meta interface{}) er if err := keyvaluetags.RdsUpdateTags(rdsconn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating RDS Option Group (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } return resourceAwsDbOptionGroupRead(d, meta) diff --git a/aws/resource_aws_db_parameter_group.go b/aws/resource_aws_db_parameter_group.go index d553efd4c78..d88f77fb572 100644 --- a/aws/resource_aws_db_parameter_group.go +++ b/aws/resource_aws_db_parameter_group.go @@ -113,12 +113,6 @@ func resourceAwsDbParameterGroupCreate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Error creating DB Parameter Group: %s", err) } - d.Partial(true) - d.SetPartial("name") - d.SetPartial("family") - d.SetPartial("description") - d.Partial(false) - d.SetId(aws.StringValue(resp.DBParameterGroup.DBParameterGroupName)) d.Set("arn", resp.DBParameterGroup.DBParameterGroupArn) log.Printf("[INFO] DB Parameter Group ID: %s", d.Id()) @@ -246,8 +240,6 @@ func resourceAwsDbParameterGroupRead(d *schema.ResourceData, meta interface{}) e func resourceAwsDbParameterGroupUpdate(d *schema.ResourceData, meta interface{}) error { rdsconn := meta.(*AWSClient).rdsconn - d.Partial(true) - if d.HasChange("parameter") { o, n := d.GetChange("parameter") if o == nil { @@ -327,12 +319,8 @@ func resourceAwsDbParameterGroupUpdate(d *schema.ResourceData, meta interface{}) if err := keyvaluetags.RdsUpdateTags(rdsconn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating RDS DB Parameter Group (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } - d.Partial(false) - return resourceAwsDbParameterGroupRead(d, meta) } diff --git a/aws/resource_aws_db_security_group.go b/aws/resource_aws_db_security_group.go index 9164ec903a9..3212ef47688 100644 --- a/aws/resource_aws_db_security_group.go +++ b/aws/resource_aws_db_security_group.go @@ -196,16 +196,12 @@ func resourceAwsDbSecurityGroupRead(d *schema.ResourceData, meta interface{}) er func resourceAwsDbSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn - d.Partial(true) - if d.HasChange("tags") { o, n := d.GetChange("tags") if err := keyvaluetags.RdsUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating RDS DB Security Group (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } if d.HasChange("ingress") { @@ -243,7 +239,6 @@ func resourceAwsDbSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) } } } - d.Partial(false) return resourceAwsDbSecurityGroupRead(d, meta) } diff --git a/aws/resource_aws_db_snapshot.go b/aws/resource_aws_db_snapshot.go index 62ec2beca68..480b1502c9e 100644 --- a/aws/resource_aws_db_snapshot.go +++ b/aws/resource_aws_db_snapshot.go @@ -220,8 +220,6 @@ func resourceAwsDbSnapshotUpdate(d *schema.ResourceData, meta interface{}) error if err := keyvaluetags.RdsUpdateTags(conn, d.Get("db_snapshot_arn").(string), o, n); err != nil { return fmt.Errorf("error updating RDS DB Snapshot (%s) tags: %s", d.Get("db_snapshot_arn").(string), err) } - - d.SetPartial("tags") } return nil diff --git a/aws/resource_aws_db_subnet_group.go b/aws/resource_aws_db_subnet_group.go index 80a29a1d320..a81240e88f7 100644 --- a/aws/resource_aws_db_subnet_group.go +++ b/aws/resource_aws_db_subnet_group.go @@ -195,8 +195,6 @@ func resourceAwsDbSubnetGroupUpdate(d *schema.ResourceData, meta interface{}) er if err := keyvaluetags.RdsUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating RDS DB Subnet Group (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } return resourceAwsDbSubnetGroupRead(d, meta) diff --git a/aws/resource_aws_rds_cluster.go b/aws/resource_aws_rds_cluster.go index ad12871a893..b380bc705a8 100644 --- a/aws/resource_aws_rds_cluster.go +++ b/aws/resource_aws_rds_cluster.go @@ -1118,7 +1118,6 @@ func resourceAwsRDSClusterUpdate(d *schema.ResourceData, meta interface{}) error } if d.HasChange("db_cluster_parameter_group_name") { - d.SetPartial("db_cluster_parameter_group_name") req.DBClusterParameterGroupName = aws.String(d.Get("db_cluster_parameter_group_name").(string)) requestUpdate = true } @@ -1134,19 +1133,16 @@ func resourceAwsRDSClusterUpdate(d *schema.ResourceData, meta interface{}) error } if d.HasChange("enabled_cloudwatch_logs_exports") { - d.SetPartial("enabled_cloudwatch_logs_exports") req.CloudwatchLogsExportConfiguration = buildCloudwatchLogsExportConfiguration(d) requestUpdate = true } if d.HasChange("scaling_configuration") { - d.SetPartial("scaling_configuration") req.ScalingConfiguration = expandRdsClusterScalingConfiguration(d.Get("scaling_configuration").([]interface{}), d.Get("engine_mode").(string)) requestUpdate = true } if d.HasChange("enable_http_endpoint") { - d.SetPartial("enable_http_endpoint") req.EnableHttpEndpoint = aws.Bool(d.Get("enable_http_endpoint").(bool)) requestUpdate = true } @@ -1242,8 +1238,6 @@ func resourceAwsRDSClusterUpdate(d *schema.ResourceData, meta interface{}) error if err := keyvaluetags.RdsUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating tags: %s", err) - } else { - d.SetPartial("tags") } } diff --git a/aws/resource_aws_rds_cluster_instance.go b/aws/resource_aws_rds_cluster_instance.go index f3b1fb06788..b1a17a42510 100644 --- a/aws/resource_aws_rds_cluster_instance.go +++ b/aws/resource_aws_rds_cluster_instance.go @@ -490,17 +490,14 @@ func resourceAwsRDSClusterInstanceUpdate(d *schema.ResourceData, meta interface{ } if d.HasChange("monitoring_role_arn") { - d.SetPartial("monitoring_role_arn") req.MonitoringRoleArn = aws.String(d.Get("monitoring_role_arn").(string)) requestUpdate = true } if d.HasChange("performance_insights_enabled") || d.HasChange("performance_insights_kms_key_id") { - d.SetPartial("performance_insights_enabled") req.EnablePerformanceInsights = aws.Bool(d.Get("performance_insights_enabled").(bool)) if v, ok := d.GetOk("performance_insights_kms_key_id"); ok { - d.SetPartial("performance_insights_kms_key_id") req.PerformanceInsightsKMSKeyId = aws.String(v.(string)) } @@ -508,49 +505,41 @@ func resourceAwsRDSClusterInstanceUpdate(d *schema.ResourceData, meta interface{ } if d.HasChange("preferred_backup_window") { - d.SetPartial("preferred_backup_window") req.PreferredBackupWindow = aws.String(d.Get("preferred_backup_window").(string)) requestUpdate = true } if d.HasChange("preferred_maintenance_window") { - d.SetPartial("preferred_maintenance_window") req.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintenance_window").(string)) requestUpdate = true } if d.HasChange("monitoring_interval") { - d.SetPartial("monitoring_interval") req.MonitoringInterval = aws.Int64(int64(d.Get("monitoring_interval").(int))) requestUpdate = true } if d.HasChange("auto_minor_version_upgrade") { - d.SetPartial("auto_minor_version_upgrade") req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) requestUpdate = true } if d.HasChange("copy_tags_to_snapshot") { - d.SetPartial("copy_tags_to_snapshot") req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool)) requestUpdate = true } if d.HasChange("promotion_tier") { - d.SetPartial("promotion_tier") req.PromotionTier = aws.Int64(int64(d.Get("promotion_tier").(int))) requestUpdate = true } if d.HasChange("publicly_accessible") { - d.SetPartial("publicly_accessible") req.PubliclyAccessible = aws.Bool(d.Get("publicly_accessible").(bool)) requestUpdate = true } if d.HasChange("ca_cert_identifier") { - d.SetPartial("ca_cert_identifier") req.CACertificateIdentifier = aws.String(d.Get("ca_cert_identifier").(string)) requestUpdate = true } From 79de40385b4db08b5e190627d5b3833d868a2648 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 30 Mar 2020 11:05:42 -0700 Subject: [PATCH 169/684] Adds test for changing artifact store location --- aws/resource_aws_codepipeline_test.go | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 976532de3b3..0a6075c83e7 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -85,6 +85,7 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.type", "S3"), + resource.TestCheckResourceAttrPair(resourceName, "artifact_store.0.location", "aws_s3_bucket.updated", "bucket"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.#", "1"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.id", "4567"), resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.type", "KMS"), @@ -351,13 +352,17 @@ func testAccPreCheckAWSCodePipeline(t *testing.T) { } } -func testAccAWSCodePipelineS3Bucket(rName string) string { +func testAccAWSCodePipelineS3DefaultBucket(rName string) string { + return testAccAWSCodePipelineS3Bucket("test", rName) +} + +func testAccAWSCodePipelineS3Bucket(bucket, rName string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "foo" { - bucket = "tf-test-pipeline-%s" +resource "aws_s3_bucket" "%[1]s" { + bucket = "tf-test-pipeline-%[1]s-%[2]s" acl = "private" } -`, rName) +`, bucket, rName) } func testAccAWSCodePipelineServiceIAMRole(rName string) string { @@ -481,7 +486,7 @@ EOF func testAccAWSCodePipelineConfig_basic(rName string) string { return composeConfig( - testAccAWSCodePipelineS3Bucket(rName), + testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), fmt.Sprintf(` resource "aws_codepipeline" "test" { @@ -539,7 +544,8 @@ resource "aws_codepipeline" "test" { func testAccAWSCodePipelineConfig_basicUpdated(rName string) string { return composeConfig( - testAccAWSCodePipelineS3Bucket(rName), + testAccAWSCodePipelineS3DefaultBucket(rName), + testAccAWSCodePipelineS3Bucket("updated", rName), testAccAWSCodePipelineServiceIAMRole(rName), fmt.Sprintf(` resource "aws_codepipeline" "test" { @@ -597,7 +603,7 @@ resource "aws_codepipeline" "test" { func testAccAWSCodePipelineConfig_emptyArtifacts(rName string) string { return composeConfig( - testAccAWSCodePipelineS3Bucket(rName), + testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), fmt.Sprintf(` resource "aws_codepipeline" "test" { @@ -701,7 +707,7 @@ EOF func testAccAWSCodePipelineConfig_deployWithServiceRole(rName string) string { return composeConfig( - testAccAWSCodePipelineS3Bucket(rName), + testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRoleWithAssumeRole(rName), testAccAWSCodePipelineDeployActionIAMRole(rName), fmt.Sprintf(` @@ -782,7 +788,7 @@ resource "aws_codepipeline" "test" { func testAccAWSCodePipelineConfigWithTags(rName, tag1, tag2 string) string { return composeConfig( - testAccAWSCodePipelineS3Bucket(rName), + testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), fmt.Sprintf(` resource "aws_codepipeline" "test" { From 5cd958cbdccbd71cc27b785300d49c35298b64ee Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 30 Mar 2020 15:00:35 -0700 Subject: [PATCH 170/684] Properly hashes artifact stores --- aws/resource_aws_codepipeline.go | 1 - aws/resource_aws_codepipeline_test.go | 273 ++++++++++++++++++++++---- 2 files changed, 230 insertions(+), 44 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 5b6e46c80d1..4beb1107446 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -96,7 +96,6 @@ func resourceAwsCodePipeline() *schema.Resource { Elem: &schema.Resource{ Schema: artifactStoreSchema, }, - Set: resourceAwsCodePipelineArtifactStoreHash, }, "stage": { Type: schema.TypeList, diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 0a6075c83e7..0a14777654e 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -9,10 +9,10 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/codepipeline" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/flatmap" ) func TestAccAWSCodePipeline_basic(t *testing.T) { @@ -225,14 +225,6 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { }) } -func testAccCheckAWSCodePipelineHashArtifactStore(region string) int { - return hashcode.String(region) -} - -func testAccCheckAWSCodePipelineHashArtifactStoreKey(region, key string) string { - return fmt.Sprintf("artifact_stores.%d.%s", testAccCheckAWSCodePipelineHashArtifactStore(region), key) -} - func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { var p codepipeline.PipelineDeclaration resourceName := "aws_codepipeline.test" @@ -256,13 +248,11 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "0"), resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "2"), - resource.TestCheckResourceAttr(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetRegion(), "type"), "S3"), - resource.TestCheckResourceAttrPair(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetRegion(), "location"), "aws_s3_bucket.local", "bucket"), - resource.TestCheckResourceAttr(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetRegion(), "region"), testAccGetRegion()), + testAccCheckAWSCodePipelineArtifactStoresAttr(&p, testAccGetRegion(), "type", "S3"), + testAccCheckAWSCodePipelineArtifactStoresAttrPair(&p, testAccGetRegion(), "location", "aws_s3_bucket.local", "bucket"), - resource.TestCheckResourceAttr(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetAlternateRegion(), "type"), "S3"), - resource.TestCheckResourceAttrPair(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetAlternateRegion(), "location"), "aws_s3_bucket.alternate", "bucket"), - resource.TestCheckResourceAttr(resourceName, testAccCheckAWSCodePipelineHashArtifactStoreKey(testAccGetAlternateRegion(), "region"), testAccGetAlternateRegion()), + testAccCheckAWSCodePipelineArtifactStoresAttr(&p, testAccGetAlternateRegion(), "type", "S3"), + testAccCheckAWSCodePipelineArtifactStoresAttrPair(&p, testAccGetAlternateRegion(), "location", "aws_s3_bucket.alternate", "bucket"), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), @@ -282,6 +272,61 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { }) } +func testAccCheckAWSCodePipelineArtifactStoresAttr(p *codepipeline.PipelineDeclaration, region string, key, value string) resource.TestCheckFunc { + return func(s *terraform.State) error { + as, ok := p.ArtifactStores[region] + if !ok { + return fmt.Errorf("Artifact Store for region %q not found", region) + } + values := flatmap.Flatten(flattenAwsCodePipelineArtifactStore(as)[0].(map[string]interface{})) + + if v, ok := values[key]; !ok || v != value { + if !ok { + return fmt.Errorf("ArtifactStores[%s]: Attribute %q not found", region, key) + } + + return fmt.Errorf( + "ArtifactStores[%s]: Attribute %q expected %#v, got %#v", region, key, value, v) + } + return nil + } +} + +func testAccCheckAWSCodePipelineArtifactStoresAttrPair(p *codepipeline.PipelineDeclaration, region string, keyFirst, nameSecond, keySecond string) resource.TestCheckFunc { + return func(s *terraform.State) error { + as, ok := p.ArtifactStores[region] + if !ok { + return fmt.Errorf("Artifact Store for region %q not found", region) + } + values := flatmap.Flatten(flattenAwsCodePipelineArtifactStore(as)[0].(map[string]interface{})) + + isSecond, err := primaryInstanceState(s, nameSecond) + if err != nil { + return err + } + + vFirst, okFirst := values[keyFirst] + vSecond, okSecond := isSecond.Attributes[keySecond] + + if okFirst != okSecond { + if !okFirst { + return fmt.Errorf("ArtifactStores[%s]: Attribute %q not set, but %q is set in %s as %q", region, keyFirst, keySecond, nameSecond, vSecond) + } + return fmt.Errorf("ArtifactStores[%s]: Attribute %q is %q, but %q is not set in %s", region, keyFirst, vFirst, keySecond, nameSecond) + } + if !(okFirst || okSecond) { + // If they both don't exist then they are equally unset, so that's okay. + return nil + } + + if vFirst != vSecond { + return fmt.Errorf("ArtifactStores[%s]: Attribute '%s' expected %#v, got %#v", region, keyFirst, vSecond, vFirst) + } + + return nil + } +} + func testAccCheckAWSCodePipelineExists(n string, pipeline *codepipeline.PipelineDeclaration) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -352,19 +397,6 @@ func testAccPreCheckAWSCodePipeline(t *testing.T) { } } -func testAccAWSCodePipelineS3DefaultBucket(rName string) string { - return testAccAWSCodePipelineS3Bucket("test", rName) -} - -func testAccAWSCodePipelineS3Bucket(bucket, rName string) string { - return fmt.Sprintf(` -resource "aws_s3_bucket" "%[1]s" { - bucket = "tf-test-pipeline-%[1]s-%[2]s" - acl = "private" -} -`, bucket, rName) -} - func testAccAWSCodePipelineServiceIAMRole(rName string) string { return fmt.Sprintf(` resource "aws_iam_role" "codepipeline_role" { @@ -853,18 +885,144 @@ resource "aws_codepipeline" "test" { func testAccAWSCodePipelineConfig_multiregion(rName string) string { return composeConfig( testAccAlternateRegionProviderConfig(), + testAccAWSCodePipelineS3Bucket("local", rName), + testAccAWSCodePipelineS3BucketWithProvider("alternate", rName, "aws.alternate"), fmt.Sprintf(` -resource "aws_s3_bucket" "local" { - bucket = "tf-test-pipeline-local-%[1]s" - acl = "private" +resource "aws_iam_role" "codepipeline_role" { + name = "codepipeline-role-%[1]s" + + assume_role_policy = < Date: Mon, 30 Mar 2020 15:13:45 -0700 Subject: [PATCH 171/684] Adds tests for updating cross-region CodePipeline actions --- aws/resource_aws_codepipeline_test.go | 154 ++++++++++++++++++-------- 1 file changed, 105 insertions(+), 49 deletions(-) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 0a14777654e..7183fe99abf 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -272,59 +272,60 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { }) } -func testAccCheckAWSCodePipelineArtifactStoresAttr(p *codepipeline.PipelineDeclaration, region string, key, value string) resource.TestCheckFunc { - return func(s *terraform.State) error { - as, ok := p.ArtifactStores[region] - if !ok { - return fmt.Errorf("Artifact Store for region %q not found", region) - } - values := flatmap.Flatten(flattenAwsCodePipelineArtifactStore(as)[0].(map[string]interface{})) - - if v, ok := values[key]; !ok || v != value { - if !ok { - return fmt.Errorf("ArtifactStores[%s]: Attribute %q not found", region, key) - } - - return fmt.Errorf( - "ArtifactStores[%s]: Attribute %q expected %#v, got %#v", region, key, value, v) - } - return nil - } -} +func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { + var p1, p2 codepipeline.PipelineDeclaration + resourceName := "aws_codepipeline.test" + var providers []*schema.Provider -func testAccCheckAWSCodePipelineArtifactStoresAttrPair(p *codepipeline.PipelineDeclaration, region string, keyFirst, nameSecond, keySecond string) resource.TestCheckFunc { - return func(s *terraform.State) error { - as, ok := p.ArtifactStores[region] - if !ok { - return fmt.Errorf("Artifact Store for region %q not found", region) - } - values := flatmap.Flatten(flattenAwsCodePipelineArtifactStore(as)[0].(map[string]interface{})) + name := acctest.RandString(10) - isSecond, err := primaryInstanceState(s, nameSecond) - if err != nil { - return err - } + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccMultipleRegionsPreCheck(t) + testAccAlternateRegionPreCheck(t) + }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckAWSCodePipelineDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCodePipelineConfig_multiregion(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCodePipelineExists(resourceName, &p1), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "0"), + resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "2"), - vFirst, okFirst := values[keyFirst] - vSecond, okSecond := isSecond.Attributes[keySecond] + testAccCheckAWSCodePipelineArtifactStoresAttr(&p1, testAccGetRegion(), "encryption_key.0.id", "1234"), + testAccCheckAWSCodePipelineArtifactStoresAttr(&p1, testAccGetAlternateRegion(), "encryption_key.0.id", "5678"), - if okFirst != okSecond { - if !okFirst { - return fmt.Errorf("ArtifactStores[%s]: Attribute %q not set, but %q is set in %s as %q", region, keyFirst, keySecond, nameSecond, vSecond) - } - return fmt.Errorf("ArtifactStores[%s]: Attribute %q is %q, but %q is not set in %s", region, keyFirst, vFirst, keySecond, nameSecond) - } - if !(okFirst || okSecond) { - // If they both don't exist then they are equally unset, so that's okay. - return nil - } + resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", fmt.Sprintf("%s-Build", testAccGetRegion())), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", testAccGetRegion()), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.name", fmt.Sprintf("%s-Build", testAccGetAlternateRegion())), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.region", testAccGetAlternateRegion()), + ), + }, + { + Config: testAccAWSCodePipelineConfig_multiregionUpdated(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCodePipelineExists(resourceName, &p2), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "0"), + resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "2"), - if vFirst != vSecond { - return fmt.Errorf("ArtifactStores[%s]: Attribute '%s' expected %#v, got %#v", region, keyFirst, vSecond, vFirst) - } + testAccCheckAWSCodePipelineArtifactStoresAttr(&p2, testAccGetRegion(), "encryption_key.0.id", "4321"), + testAccCheckAWSCodePipelineArtifactStoresAttr(&p2, testAccGetAlternateRegion(), "encryption_key.0.id", "8765"), - return nil - } + resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", fmt.Sprintf("%s-BuildUpdated", testAccGetRegion())), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", testAccGetRegion()), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.name", fmt.Sprintf("%s-BuildUpdated", testAccGetAlternateRegion())), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.region", testAccGetAlternateRegion()), + ), + }, + }, + }) } func testAccCheckAWSCodePipelineExists(n string, pipeline *codepipeline.PipelineDeclaration) resource.TestCheckFunc { @@ -1123,7 +1124,7 @@ resource "aws_codepipeline" "test" { action { region = "%[2]s" - name = "%[2]s-Build" + name = "%[2]s-BuildUpdated" category = "Build" owner = "AWS" provider = "CodeBuild" @@ -1136,7 +1137,7 @@ resource "aws_codepipeline" "test" { } action { region = "%[3]s" - name = "%[3]s-Build" + name = "%[3]s-BuildUpdated" category = "Build" owner = "AWS" provider = "CodeBuild" @@ -1174,3 +1175,58 @@ resource "aws_s3_bucket" "%[1]s" { } `, bucket, rName, provider) } + +func testAccCheckAWSCodePipelineArtifactStoresAttr(p *codepipeline.PipelineDeclaration, region string, key, value string) resource.TestCheckFunc { + return func(s *terraform.State) error { + as, ok := p.ArtifactStores[region] + if !ok { + return fmt.Errorf("Artifact Store for region %q not found", region) + } + values := flatmap.Flatten(flattenAwsCodePipelineArtifactStore(as)[0].(map[string]interface{})) + + if v, ok := values[key]; !ok || v != value { + if !ok { + return fmt.Errorf("ArtifactStores[%s]: Attribute %q not found", region, key) + } + + return fmt.Errorf( + "ArtifactStores[%s]: Attribute %q expected %#v, got %#v", region, key, value, v) + } + return nil + } +} + +func testAccCheckAWSCodePipelineArtifactStoresAttrPair(p *codepipeline.PipelineDeclaration, region string, keyFirst, nameSecond, keySecond string) resource.TestCheckFunc { + return func(s *terraform.State) error { + as, ok := p.ArtifactStores[region] + if !ok { + return fmt.Errorf("Artifact Store for region %q not found", region) + } + values := flatmap.Flatten(flattenAwsCodePipelineArtifactStore(as)[0].(map[string]interface{})) + + isSecond, err := primaryInstanceState(s, nameSecond) + if err != nil { + return err + } + + vFirst, okFirst := values[keyFirst] + vSecond, okSecond := isSecond.Attributes[keySecond] + + if okFirst != okSecond { + if !okFirst { + return fmt.Errorf("ArtifactStores[%s]: Attribute %q not set, but %q is set in %s as %q", region, keyFirst, keySecond, nameSecond, vSecond) + } + return fmt.Errorf("ArtifactStores[%s]: Attribute %q is %q, but %q is not set in %s", region, keyFirst, vFirst, keySecond, nameSecond) + } + if !(okFirst || okSecond) { + // If they both don't exist then they are equally unset, so that's okay. + return nil + } + + if vFirst != vSecond { + return fmt.Errorf("ArtifactStores[%s]: Attribute '%s' expected %#v, got %#v", region, keyFirst, vSecond, vFirst) + } + + return nil + } +} From 2b32b08c12f498bbdb54e2b6a66d6fe723be4a00 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 30 Mar 2020 16:34:20 -0700 Subject: [PATCH 172/684] Adds tests for converting CodePipeline actions from single- to cross-region --- aws/resource_aws_codepipeline_test.go | 107 ++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 16 deletions(-) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 7183fe99abf..d1b6bb10137 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -249,14 +249,14 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "2"), testAccCheckAWSCodePipelineArtifactStoresAttr(&p, testAccGetRegion(), "type", "S3"), - testAccCheckAWSCodePipelineArtifactStoresAttrPair(&p, testAccGetRegion(), "location", "aws_s3_bucket.local", "bucket"), + testAccCheckAWSCodePipelineArtifactStoresAttrPair(&p, testAccGetRegion(), "location", "aws_s3_bucket.test", "bucket"), testAccCheckAWSCodePipelineArtifactStoresAttr(&p, testAccGetAlternateRegion(), "type", "S3"), testAccCheckAWSCodePipelineArtifactStoresAttrPair(&p, testAccGetAlternateRegion(), "location", "aws_s3_bucket.alternate", "bucket"), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", fmt.Sprintf("%s-Build", testAccGetRegion())), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", testAccGetRegion()), resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.name", fmt.Sprintf("%s-Build", testAccGetAlternateRegion())), resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.region", testAccGetAlternateRegion()), @@ -300,7 +300,7 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", fmt.Sprintf("%s-Build", testAccGetRegion())), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", testAccGetRegion()), resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.name", fmt.Sprintf("%s-Build", testAccGetAlternateRegion())), resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.region", testAccGetAlternateRegion()), @@ -318,7 +318,7 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), - resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", fmt.Sprintf("%s-BuildUpdated", testAccGetRegion())), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "BuildUpdated"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", testAccGetRegion()), resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.name", fmt.Sprintf("%s-BuildUpdated", testAccGetAlternateRegion())), resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.region", testAccGetAlternateRegion()), @@ -328,6 +328,74 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { }) } +func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { + var p1, p2 codepipeline.PipelineDeclaration + resourceName := "aws_codepipeline.test" + var providers []*schema.Provider + + name := acctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccMultipleRegionsPreCheck(t) + testAccAlternateRegionPreCheck(t) + }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckAWSCodePipelineDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCodePipelineConfig_basic(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCodePipelineExists(resourceName, &p1), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), + resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "0"), + + resource.TestCheckResourceAttrPair(resourceName, "artifact_store.0.location", "aws_s3_bucket.test", "bucket"), + + resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", ""), + ), + }, + { + Config: testAccAWSCodePipelineConfig_multiregion(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCodePipelineExists(resourceName, &p2), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "0"), + resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "2"), + + testAccCheckAWSCodePipelineArtifactStoresAttr(&p2, testAccGetRegion(), "encryption_key.0.id", "1234"), + testAccCheckAWSCodePipelineArtifactStoresAttr(&p2, testAccGetAlternateRegion(), "encryption_key.0.id", "5678"), + + resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", testAccGetRegion()), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.name", fmt.Sprintf("%s-Build", testAccGetAlternateRegion())), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.region", testAccGetAlternateRegion()), + ), + }, + { + Config: testAccAWSCodePipelineConfig_backToBasic(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCodePipelineExists(resourceName, &p1), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), + resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "0"), + + resource.TestCheckResourceAttrPair(resourceName, "artifact_store.0.location", "aws_s3_bucket.test", "bucket"), + + resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), + resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", testAccGetRegion()), + ), + }, + }, + }) +} + func testAccCheckAWSCodePipelineExists(n string, pipeline *codepipeline.PipelineDeclaration) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -886,7 +954,7 @@ resource "aws_codepipeline" "test" { func testAccAWSCodePipelineConfig_multiregion(rName string) string { return composeConfig( testAccAlternateRegionProviderConfig(), - testAccAWSCodePipelineS3Bucket("local", rName), + testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineS3BucketWithProvider("alternate", rName, "aws.alternate"), fmt.Sprintf(` resource "aws_iam_role" "codepipeline_role" { @@ -924,8 +992,8 @@ resource "aws_iam_role_policy" "codepipeline_policy" { "s3:GetBucketVersioning" ], "Resource": [ - "${aws_s3_bucket.local.arn}", - "${aws_s3_bucket.local.arn}/*", + "${aws_s3_bucket.test.arn}", + "${aws_s3_bucket.test.arn}/*", "${aws_s3_bucket.alternate.arn}", "${aws_s3_bucket.alternate.arn}/*" ] @@ -948,7 +1016,7 @@ resource "aws_codepipeline" "test" { role_arn = "${aws_iam_role.codepipeline_role.arn}" artifact_stores { - location = "${aws_s3_bucket.local.bucket}" + location = "${aws_s3_bucket.test.bucket}" type = "S3" encryption_key { id = "1234" @@ -989,7 +1057,7 @@ resource "aws_codepipeline" "test" { action { region = "%[2]s" - name = "%[2]s-Build" + name = "Build" category = "Build" owner = "AWS" provider = "CodeBuild" @@ -997,7 +1065,7 @@ resource "aws_codepipeline" "test" { version = "1" configuration = { - ProjectName = "%[2]s-Test" + ProjectName = "Test" } } action { @@ -1021,7 +1089,7 @@ resource "aws_codepipeline" "test" { func testAccAWSCodePipelineConfig_multiregionUpdated(rName string) string { return composeConfig( testAccAlternateRegionProviderConfig(), - testAccAWSCodePipelineS3Bucket("local", rName), + testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineS3BucketWithProvider("alternate", rName, "aws.alternate"), fmt.Sprintf(` resource "aws_iam_role" "codepipeline_role" { @@ -1059,8 +1127,8 @@ resource "aws_iam_role_policy" "codepipeline_policy" { "s3:GetBucketVersioning" ], "Resource": [ - "${aws_s3_bucket.local.arn}", - "${aws_s3_bucket.local.arn}/*", + "${aws_s3_bucket.test.arn}", + "${aws_s3_bucket.test.arn}/*", "${aws_s3_bucket.alternate.arn}", "${aws_s3_bucket.alternate.arn}/*" ] @@ -1083,7 +1151,7 @@ resource "aws_codepipeline" "test" { role_arn = "${aws_iam_role.codepipeline_role.arn}" artifact_stores { - location = "${aws_s3_bucket.local.bucket}" + location = "${aws_s3_bucket.test.bucket}" type = "S3" encryption_key { id = "4321" @@ -1124,7 +1192,7 @@ resource "aws_codepipeline" "test" { action { region = "%[2]s" - name = "%[2]s-BuildUpdated" + name = "BuildUpdated" category = "Build" owner = "AWS" provider = "CodeBuild" @@ -1132,7 +1200,7 @@ resource "aws_codepipeline" "test" { version = "1" configuration = { - ProjectName = "%[2]s-Test" + ProjectName = "Test" } } action { @@ -1153,6 +1221,13 @@ resource "aws_codepipeline" "test" { `, rName, testAccGetRegion(), testAccGetAlternateRegion())) } +func testAccAWSCodePipelineConfig_backToBasic(rName string) string { + return composeConfig( + testAccAlternateRegionProviderConfig(), + testAccAWSCodePipelineConfig_basic(rName), + ) +} + func testAccAWSCodePipelineS3DefaultBucket(rName string) string { return testAccAWSCodePipelineS3Bucket("test", rName) } From d192f0f9ff55fdf80cc789414d25e35e0f1eff36 Mon Sep 17 00:00:00 2001 From: Grzegorz Szczudlik Date: Tue, 3 Mar 2020 09:57:39 +0100 Subject: [PATCH 173/684] Add data source "aws_regions" Change the way that data source handles all the regions Readme for data.aws_regions Tests for data.aws_regions data source Add the data source to master document --- aws/data_source_aws_regions.go | 86 ++++++++++++++++++ aws/data_source_aws_regions_test.go | 125 +++++++++++++++++++++++++++ aws/provider.go | 1 + website/aws.erb | 3 + website/docs/d/regions.html.markdown | 61 +++++++++++++ 5 files changed, 276 insertions(+) create mode 100644 aws/data_source_aws_regions.go create mode 100644 aws/data_source_aws_regions_test.go create mode 100644 website/docs/d/regions.html.markdown diff --git a/aws/data_source_aws_regions.go b/aws/data_source_aws_regions.go new file mode 100644 index 00000000000..4e9273b1618 --- /dev/null +++ b/aws/data_source_aws_regions.go @@ -0,0 +1,86 @@ +package aws + +import ( + "fmt" + "log" + "sort" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func dataSourceAwsRegions() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsRegionsRead, + + Schema: map[string]*schema.Schema{ + "names": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "all_regions": { + Type: schema.TypeBool, + Optional: true, + }, + + "opt_in_status": { + Type: schema.TypeString, + Optional: true, + // There is no OptInStatus constants defined for Regions. + // Using those from AvailabilityZone definition. + ValidateFunc: validation.StringInSlice([]string{ + ec2.AvailabilityZoneOptInStatusOptInNotRequired, + ec2.AvailabilityZoneOptInStatusOptedIn, + ec2.AvailabilityZoneOptInStatusNotOptedIn, + }, false), + }, + }, + } +} + +func dataSourceAwsRegionsRead(d *schema.ResourceData, meta interface{}) error { + connection := meta.(*AWSClient).ec2conn + + log.Printf("[DEBUG] Reading regions.") + + request := &ec2.DescribeRegionsInput{} + + if v, ok := d.GetOk("all_regions"); ok { + request.AllRegions = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("opt_in_status"); ok { + log.Printf("[DEBUG] Adding region filters") + request.Filters = []*ec2.Filter{ + { + Name: aws.String("opt-in-status"), + Values: []*string{aws.String(v.(string))}, + }, + } + } + + log.Printf("[DEBUG] Reading regions for request: %s", request) + response, err := connection.DescribeRegions(request) + if err != nil { + return fmt.Errorf("Error fetching Regions: %s", err) + } + + names := []string{} + for _, v := range response.Regions { + names = append(names, aws.StringValue(v.RegionName)) + } + + sort.Slice(names, func(i, j int) bool { + return names[i] < names[j] + }) + + d.SetId(time.Now().UTC().String()) + d.Set("names", names) + + return nil +} diff --git a/aws/data_source_aws_regions_test.go b/aws/data_source_aws_regions_test.go new file mode 100644 index 00000000000..2f36287a8e2 --- /dev/null +++ b/aws/data_source_aws_regions_test.go @@ -0,0 +1,125 @@ +package aws + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccDataSourceAwsRegionsBasic(t *testing.T) { + resourceName := "data.aws_regions.empty" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsRegionsConfigEmpty(), + Check: resource.ComposeTestCheckFunc( + testAccDataSourceAwsRegionsCheck(resourceName), + resource.TestCheckNoResourceAttr(resourceName, "all_regions"), + resource.TestCheckNoResourceAttr(resourceName, "opt_in_status"), + ), + }, + }, + }) +} + +func TestAccDataSourceAwsRegionsOptIn(t *testing.T) { + resourceName := "data.aws_regions.opt_in_status" + + statusOptedIn := "opted-in" + statusNotOptedIn := "not-opted-in" + statusOptInNotRequired := "opt-in-not-required" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + // This resource has to be at the very top of the test scenario due to bug in Terrafom Plugin SDK + { + Config: testAccDataSourceAwsRegionsConfigOptIn("invalid-opt-in-status"), + ExpectError: regexp.MustCompile(`expected opt_in_status to be one of .*, got invalid-opt-in-status`), + }, + { + Config: testAccDataSourceAwsRegionsConfigOptIn(statusOptedIn), + Check: resource.ComposeTestCheckFunc( + testAccDataSourceAwsRegionsCheck(resourceName), + resource.TestCheckNoResourceAttr(resourceName, "all_regions"), + resource.TestCheckResourceAttr(resourceName, "opt_in_status", statusOptedIn), + ), + }, + { + Config: testAccDataSourceAwsRegionsConfigOptIn(statusOptInNotRequired), + Check: resource.ComposeTestCheckFunc( + testAccDataSourceAwsRegionsCheck(resourceName), + resource.TestCheckNoResourceAttr(resourceName, "all_regions"), + resource.TestCheckResourceAttr(resourceName, "opt_in_status", statusOptInNotRequired), + ), + }, + { + Config: testAccDataSourceAwsRegionsConfigOptIn(statusNotOptedIn), + Check: resource.ComposeTestCheckFunc( + testAccDataSourceAwsRegionsCheck(resourceName), + resource.TestCheckNoResourceAttr(resourceName, "all_regions"), + resource.TestCheckResourceAttr(resourceName, "opt_in_status", statusNotOptedIn), + ), + }, + }, + }) +} + +func TestAccDataSourceAwsRegionsAllRegions(t *testing.T) { + resourceAllRegions := "data.aws_regions.all_regions" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsRegionsConfigAllRegions(), + Check: resource.ComposeTestCheckFunc( + testAccDataSourceAwsRegionsCheck(resourceAllRegions), + resource.TestCheckResourceAttr(resourceAllRegions, "all_regions", "true"), + resource.TestCheckNoResourceAttr(resourceAllRegions, "opt_in_status"), + ), + }, + }, + }) +} + +func testAccDataSourceAwsRegionsCheck(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("root module has no resource called %s", name) + } + + return nil + } +} + +func testAccDataSourceAwsRegionsConfigEmpty() string { + return ` +data "aws_regions" "empty" {} +` +} + +func testAccDataSourceAwsRegionsConfigAllRegions() string { + return ` +data "aws_regions" "all_regions" { + all_regions = "true" +} +` +} + +func testAccDataSourceAwsRegionsConfigOptIn(optInStatus string) string { + return fmt.Sprintf(` +data "aws_regions" "opt_in_status" { + opt_in_status = "%s" +} +`, optInStatus) +} diff --git a/aws/provider.go b/aws/provider.go index be386f16d6b..506b11b9133 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -269,6 +269,7 @@ func Provider() terraform.ResourceProvider { "aws_redshift_cluster": dataSourceAwsRedshiftCluster(), "aws_redshift_service_account": dataSourceAwsRedshiftServiceAccount(), "aws_region": dataSourceAwsRegion(), + "aws_regions": dataSourceAwsRegions(), "aws_route": dataSourceAwsRoute(), "aws_route_table": dataSourceAwsRouteTable(), "aws_route_tables": dataSourceAwsRouteTables(), diff --git a/website/aws.erb b/website/aws.erb index b5b8540d4c4..ab21ce2c0d7 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -53,6 +53,9 @@
  • aws_region
  • +
  • + aws_regions +
  • diff --git a/website/docs/d/regions.html.markdown b/website/docs/d/regions.html.markdown new file mode 100644 index 00000000000..a556f1b0823 --- /dev/null +++ b/website/docs/d/regions.html.markdown @@ -0,0 +1,61 @@ +--- +subcategory: "" +layout: "aws" +page_title: "AWS: aws_regions" +description: |- + Provides list of all enabled AWS regions +--- + +# Data Source: aws_region + +`aws_regions` provides list of all enabled AWS regions. + +The data source provides list of AWS regions available. +Can be used to filter regions by Opt-In status or list only regions enabled for current account. +To get details like endpoint and description of each region the data source can be combined with `aws_region`. + +## Example Usage + +The following example shows how the resource might be used to obtain +the list of the AWS regions configured on the provider. + +Regions enabled for the user + +```hcl +data "aws_regions" "current" {} +``` + +All the regions regardless of the availability + +```hcl +data "aws_regions" "current" { + all_regions = true +} +``` + +To see regions that are `"not-opted-in"` `"all_regions"` need to be set to true +or nothing will be displayed. + +```hcl +data "aws_regions" "current" { + all_regions = true + opt_in_status = "not-opted-in" +} +``` + +## Argument Reference + +The arguments of this data source act as filters for querying the available +regions. The given filters must match exactly one region whose data will be +exported as attributes. + +* `all_regions` - (Optional) If true the source will query all regions regardless of availability. + +* `opt_in_status` - (Optional) Filter the list of regions according to op-in-status filter. Can be one of: `"opt-in-not-required"`, `"opted-in"` or `"not-opted-in"`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `names` - Names of regions that meets the criteria. + From 5da82fba33618c3f41aa35cc24abfdb1ca73a3a8 Mon Sep 17 00:00:00 2001 From: Grzegorz Szczudlik Date: Thu, 5 Mar 2020 13:46:52 +0100 Subject: [PATCH 174/684] Switch to filter for more flexibility --- aws/data_source_aws_regions.go | 29 ++++------------------------ aws/data_source_aws_regions_test.go | 24 +++++++++-------------- website/docs/d/regions.html.markdown | 19 ++++++++++++------ 3 files changed, 26 insertions(+), 46 deletions(-) diff --git a/aws/data_source_aws_regions.go b/aws/data_source_aws_regions.go index 4e9273b1618..79246f38c77 100644 --- a/aws/data_source_aws_regions.go +++ b/aws/data_source_aws_regions.go @@ -9,7 +9,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func dataSourceAwsRegions() *schema.Resource { @@ -17,6 +16,7 @@ func dataSourceAwsRegions() *schema.Resource { Read: dataSourceAwsRegionsRead, Schema: map[string]*schema.Schema{ + "filter": dataSourceFiltersSchema(), "names": { Type: schema.TypeSet, Computed: true, @@ -27,18 +27,6 @@ func dataSourceAwsRegions() *schema.Resource { Type: schema.TypeBool, Optional: true, }, - - "opt_in_status": { - Type: schema.TypeString, - Optional: true, - // There is no OptInStatus constants defined for Regions. - // Using those from AvailabilityZone definition. - ValidateFunc: validation.StringInSlice([]string{ - ec2.AvailabilityZoneOptInStatusOptInNotRequired, - ec2.AvailabilityZoneOptInStatusOptedIn, - ec2.AvailabilityZoneOptInStatusNotOptedIn, - }, false), - }, }, } } @@ -47,23 +35,14 @@ func dataSourceAwsRegionsRead(d *schema.ResourceData, meta interface{}) error { connection := meta.(*AWSClient).ec2conn log.Printf("[DEBUG] Reading regions.") - request := &ec2.DescribeRegionsInput{} - + if v, ok := d.GetOk("filter"); ok { + request.Filters = buildAwsDataSourceFilters(v.(*schema.Set)) + } if v, ok := d.GetOk("all_regions"); ok { request.AllRegions = aws.Bool(v.(bool)) } - if v, ok := d.GetOk("opt_in_status"); ok { - log.Printf("[DEBUG] Adding region filters") - request.Filters = []*ec2.Filter{ - { - Name: aws.String("opt-in-status"), - Values: []*string{aws.String(v.(string))}, - }, - } - } - log.Printf("[DEBUG] Reading regions for request: %s", request) response, err := connection.DescribeRegions(request) if err != nil { diff --git a/aws/data_source_aws_regions_test.go b/aws/data_source_aws_regions_test.go index 2f36287a8e2..9f054c0f8f6 100644 --- a/aws/data_source_aws_regions_test.go +++ b/aws/data_source_aws_regions_test.go @@ -2,7 +2,6 @@ package aws import ( "fmt" - "regexp" "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -21,7 +20,6 @@ func TestAccDataSourceAwsRegionsBasic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsRegionsCheck(resourceName), resource.TestCheckNoResourceAttr(resourceName, "all_regions"), - resource.TestCheckNoResourceAttr(resourceName, "opt_in_status"), ), }, }, @@ -41,31 +39,24 @@ func TestAccDataSourceAwsRegionsOptIn(t *testing.T) { Steps: []resource.TestStep{ // This resource has to be at the very top of the test scenario due to bug in Terrafom Plugin SDK { - Config: testAccDataSourceAwsRegionsConfigOptIn("invalid-opt-in-status"), - ExpectError: regexp.MustCompile(`expected opt_in_status to be one of .*, got invalid-opt-in-status`), - }, - { - Config: testAccDataSourceAwsRegionsConfigOptIn(statusOptedIn), + Config: testAccDataSourceAwsRegionsConfigAllRegionsFiltered(statusOptedIn), Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsRegionsCheck(resourceName), resource.TestCheckNoResourceAttr(resourceName, "all_regions"), - resource.TestCheckResourceAttr(resourceName, "opt_in_status", statusOptedIn), ), }, { - Config: testAccDataSourceAwsRegionsConfigOptIn(statusOptInNotRequired), + Config: testAccDataSourceAwsRegionsConfigAllRegionsFiltered(statusOptInNotRequired), Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsRegionsCheck(resourceName), resource.TestCheckNoResourceAttr(resourceName, "all_regions"), - resource.TestCheckResourceAttr(resourceName, "opt_in_status", statusOptInNotRequired), ), }, { - Config: testAccDataSourceAwsRegionsConfigOptIn(statusNotOptedIn), + Config: testAccDataSourceAwsRegionsConfigAllRegionsFiltered(statusNotOptedIn), Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsRegionsCheck(resourceName), resource.TestCheckNoResourceAttr(resourceName, "all_regions"), - resource.TestCheckResourceAttr(resourceName, "opt_in_status", statusNotOptedIn), ), }, }, @@ -116,10 +107,13 @@ data "aws_regions" "all_regions" { ` } -func testAccDataSourceAwsRegionsConfigOptIn(optInStatus string) string { +func testAccDataSourceAwsRegionsConfigAllRegionsFiltered(filter string) string { return fmt.Sprintf(` data "aws_regions" "opt_in_status" { - opt_in_status = "%s" + filter { + name = "opt-in-status" + values = ["%s"] + } } -`, optInStatus) +`, filter) } diff --git a/website/docs/d/regions.html.markdown b/website/docs/d/regions.html.markdown index a556f1b0823..efabcd972fa 100644 --- a/website/docs/d/regions.html.markdown +++ b/website/docs/d/regions.html.markdown @@ -11,7 +11,7 @@ description: |- `aws_regions` provides list of all enabled AWS regions. The data source provides list of AWS regions available. -Can be used to filter regions by Opt-In status or list only regions enabled for current account. +Can be used to filter regions i.e. by Opt-In status or list only regions enabled for current account. To get details like endpoint and description of each region the data source can be combined with `aws_region`. ## Example Usage @@ -19,7 +19,7 @@ To get details like endpoint and description of each region the data source can The following example shows how the resource might be used to obtain the list of the AWS regions configured on the provider. -Regions enabled for the user +To list regions enabled for the user: ```hcl data "aws_regions" "current" {} @@ -33,13 +33,17 @@ data "aws_regions" "current" { } ``` -To see regions that are `"not-opted-in"` `"all_regions"` need to be set to true -or nothing will be displayed. +To see regions that are filtered by `"not-opted-in"` `"all_regions"` need to be set to true +or probably nothing will be displayed. ```hcl data "aws_regions" "current" { all_regions = true - opt_in_status = "not-opted-in" + + filter { + name = "opt-in-status" + values = ["not-opted-in"] + } } ``` @@ -51,7 +55,8 @@ exported as attributes. * `all_regions` - (Optional) If true the source will query all regions regardless of availability. -* `opt_in_status` - (Optional) Filter the list of regions according to op-in-status filter. Can be one of: `"opt-in-not-required"`, `"opted-in"` or `"not-opted-in"`. +* `filter` - (Optional) One or more key/value pairs to use as filters. Full reference of valid keys +can be found [describe-regions in the AWS CLI reference][1]. ## Attributes Reference @@ -59,3 +64,5 @@ In addition to all arguments above, the following attributes are exported: * `names` - Names of regions that meets the criteria. +[1]: https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-regions.html + From efaaae68e27f786ca49b5e2dd6cd9f9285f41395 Mon Sep 17 00:00:00 2001 From: Grzegorz Szczudlik Date: Thu, 5 Mar 2020 20:48:56 +0100 Subject: [PATCH 175/684] Change naming according to #9950 --- aws/data_source_aws_regions_test.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/aws/data_source_aws_regions_test.go b/aws/data_source_aws_regions_test.go index 9f054c0f8f6..87b69de6667 100644 --- a/aws/data_source_aws_regions_test.go +++ b/aws/data_source_aws_regions_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/terraform" ) -func TestAccDataSourceAwsRegionsBasic(t *testing.T) { +func TestAccDataSourceAwsRegions_Basic(t *testing.T) { resourceName := "data.aws_regions.empty" resource.ParallelTest(t, resource.TestCase{ @@ -16,7 +16,7 @@ func TestAccDataSourceAwsRegionsBasic(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsRegionsConfigEmpty(), + Config: testAccDataSourceAwsRegionsConfig_empty(), Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsRegionsCheck(resourceName), resource.TestCheckNoResourceAttr(resourceName, "all_regions"), @@ -26,7 +26,7 @@ func TestAccDataSourceAwsRegionsBasic(t *testing.T) { }) } -func TestAccDataSourceAwsRegionsOptIn(t *testing.T) { +func TestAccDataSourceAwsRegions_OptIn(t *testing.T) { resourceName := "data.aws_regions.opt_in_status" statusOptedIn := "opted-in" @@ -39,21 +39,21 @@ func TestAccDataSourceAwsRegionsOptIn(t *testing.T) { Steps: []resource.TestStep{ // This resource has to be at the very top of the test scenario due to bug in Terrafom Plugin SDK { - Config: testAccDataSourceAwsRegionsConfigAllRegionsFiltered(statusOptedIn), + Config: testAccDataSourceAwsRegionsConfig_allRegionsFiltered(statusOptedIn), Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsRegionsCheck(resourceName), resource.TestCheckNoResourceAttr(resourceName, "all_regions"), ), }, { - Config: testAccDataSourceAwsRegionsConfigAllRegionsFiltered(statusOptInNotRequired), + Config: testAccDataSourceAwsRegionsConfig_allRegionsFiltered(statusOptInNotRequired), Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsRegionsCheck(resourceName), resource.TestCheckNoResourceAttr(resourceName, "all_regions"), ), }, { - Config: testAccDataSourceAwsRegionsConfigAllRegionsFiltered(statusNotOptedIn), + Config: testAccDataSourceAwsRegionsConfig_allRegionsFiltered(statusNotOptedIn), Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsRegionsCheck(resourceName), resource.TestCheckNoResourceAttr(resourceName, "all_regions"), @@ -63,7 +63,7 @@ func TestAccDataSourceAwsRegionsOptIn(t *testing.T) { }) } -func TestAccDataSourceAwsRegionsAllRegions(t *testing.T) { +func TestAccDataSourceAwsRegions_AllRegions(t *testing.T) { resourceAllRegions := "data.aws_regions.all_regions" resource.ParallelTest(t, resource.TestCase{ @@ -71,7 +71,7 @@ func TestAccDataSourceAwsRegionsAllRegions(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsRegionsConfigAllRegions(), + Config: testAccDataSourceAwsRegionsConfig_allRegions(), Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsRegionsCheck(resourceAllRegions), resource.TestCheckResourceAttr(resourceAllRegions, "all_regions", "true"), @@ -93,13 +93,13 @@ func testAccDataSourceAwsRegionsCheck(name string) resource.TestCheckFunc { } } -func testAccDataSourceAwsRegionsConfigEmpty() string { +func testAccDataSourceAwsRegionsConfig_empty() string { return ` data "aws_regions" "empty" {} ` } -func testAccDataSourceAwsRegionsConfigAllRegions() string { +func testAccDataSourceAwsRegionsConfig_allRegions() string { return ` data "aws_regions" "all_regions" { all_regions = "true" @@ -107,7 +107,7 @@ data "aws_regions" "all_regions" { ` } -func testAccDataSourceAwsRegionsConfigAllRegionsFiltered(filter string) string { +func testAccDataSourceAwsRegionsConfig_allRegionsFiltered(filter string) string { return fmt.Sprintf(` data "aws_regions" "opt_in_status" { filter { From 1592ad968ee81fe66d475dbb71d9c75f6964ed4a Mon Sep 17 00:00:00 2001 From: Grzegorz Szczudlik Date: Wed, 11 Mar 2020 18:09:17 +0100 Subject: [PATCH 176/684] Typo fix --- website/docs/d/regions.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/regions.html.markdown b/website/docs/d/regions.html.markdown index efabcd972fa..40678e7d6a9 100644 --- a/website/docs/d/regions.html.markdown +++ b/website/docs/d/regions.html.markdown @@ -6,7 +6,7 @@ description: |- Provides list of all enabled AWS regions --- -# Data Source: aws_region +# Data Source: aws_regions `aws_regions` provides list of all enabled AWS regions. From adc0909907d762287f1b72b8bd300f510793b58f Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 31 Mar 2020 16:55:47 -0700 Subject: [PATCH 177/684] Consolidates artifact stores into a single argument --- aws/resource_aws_codepipeline.go | 189 +++++++++++---------- aws/resource_aws_codepipeline_test.go | 236 ++++++++++++++++++++------ website/docs/r/codepipeline.markdown | 7 +- 3 files changed, 285 insertions(+), 147 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 4beb1107446..880b8d51698 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -1,6 +1,7 @@ package aws import ( + "errors" "fmt" "log" "os" @@ -8,7 +9,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/codepipeline" - "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" @@ -16,47 +16,6 @@ import ( ) func resourceAwsCodePipeline() *schema.Resource { - var artifactStoreSchema = map[string]*schema.Schema{ - "location": { - Type: schema.TypeString, - Required: true, - }, - - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - codepipeline.ArtifactStoreTypeS3, - }, false), - }, - - "encryption_key": { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Required: true, - }, - - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - codepipeline.EncryptionKeyTypeKms, - }, false), - }, - }, - }, - }, - "region": { - Type: schema.TypeString, - Optional: true, - }, - } - return &schema.Resource{ Create: resourceAwsCodePipelineCreate, Read: resourceAwsCodePipelineRead, @@ -83,18 +42,47 @@ func resourceAwsCodePipeline() *schema.Resource { Required: true, }, "artifact_store": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: artifactStoreSchema, - }, - }, - "artifact_stores": { Type: schema.TypeSet, - Optional: true, + Required: true, Elem: &schema.Resource{ - Schema: artifactStoreSchema, + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + codepipeline.ArtifactStoreTypeS3, + }, false), + }, + "encryption_key": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + codepipeline.EncryptionKeyTypeKms, + }, false), + }, + }, + }, + }, + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, }, }, "stage": { @@ -187,13 +175,18 @@ func resourceAwsCodePipeline() *schema.Resource { func resourceAwsCodePipelineCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).codepipelineconn + + pipeline, err := expandAwsCodePipeline(d) + if err != nil { + return err + } params := &codepipeline.CreatePipelineInput{ - Pipeline: expandAwsCodePipeline(d), + Pipeline: pipeline, Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().CodepipelineTags(), } var resp *codepipeline.CreatePipelineOutput - err := resource.Retry(2*time.Minute, func() *resource.RetryError { + err = resource.Retry(2*time.Minute, func() *resource.RetryError { var err error resp, err = conn.CreatePipeline(params) @@ -219,49 +212,57 @@ func resourceAwsCodePipelineCreate(d *schema.ResourceData, meta interface{}) err return resourceAwsCodePipelineRead(d, meta) } -func expandAwsCodePipeline(d *schema.ResourceData) *codepipeline.PipelineDeclaration { - pipelineStages := expandAwsCodePipelineStages(d) - pipelineArtifactStore := expandAwsCodePipelineArtifactStore(d) - pipelineArtifactStores := expandAwsCodePipelineArtifactStores(d) - +func expandAwsCodePipeline(d *schema.ResourceData) (*codepipeline.PipelineDeclaration, error) { pipeline := codepipeline.PipelineDeclaration{ - Name: aws.String(d.Get("name").(string)), - RoleArn: aws.String(d.Get("role_arn").(string)), - ArtifactStore: pipelineArtifactStore, - ArtifactStores: pipelineArtifactStores, - Stages: pipelineStages, + Name: aws.String(d.Get("name").(string)), + RoleArn: aws.String(d.Get("role_arn").(string)), + Stages: expandAwsCodePipelineStages(d), } - return &pipeline -} - -func expandAwsCodePipelineArtifactStore(d *schema.ResourceData) *codepipeline.ArtifactStore { - configs := d.Get("artifact_store").([]interface{}) - - if len(configs) == 0 { - return nil + pipelineArtifactStores, err := expandAwsCodePipelineArtifactStores(d.Get("artifact_store").(*schema.Set).List()) + if err != nil { + return nil, err + } + if len(pipelineArtifactStores) == 1 { + for _, v := range pipelineArtifactStores { + pipeline.ArtifactStore = v + } + } else { + pipeline.ArtifactStores = pipelineArtifactStores } - _, pipelineArtifactStore := expandAwsCodePipelineArtifactStoreData(configs[0].(map[string]interface{})) - - return pipelineArtifactStore + return &pipeline, nil } -func expandAwsCodePipelineArtifactStores(d *schema.ResourceData) map[string]*codepipeline.ArtifactStore { - configs := d.Get("artifact_stores").(*schema.Set).List() - +func expandAwsCodePipelineArtifactStores(configs []interface{}) (map[string]*codepipeline.ArtifactStore, error) { if len(configs) == 0 { - return nil + return nil, nil } + regions := make([]string, 0, len(configs)) pipelineArtifactStores := make(map[string]*codepipeline.ArtifactStore) - for _, config := range configs { region, store := expandAwsCodePipelineArtifactStoreData(config.(map[string]interface{})) + regions = append(regions, region) pipelineArtifactStores[region] = store } - return pipelineArtifactStores + if len(regions) == 1 { + if regions[0] != "" { + return nil, errors.New("region cannot be set for a single-region CodePipeline") + } + } else { + for _, v := range regions { + if v == "" { + return nil, errors.New("region must be set for a cross-region CodePipeline") + } + } + if len(configs) != len(pipelineArtifactStores) { + return nil, errors.New("only one Artifact Store can be defined per region for a cross-region CodePipeline") + } + } + + return pipelineArtifactStores, nil } func expandAwsCodePipelineArtifactStoreData(data map[string]interface{}) (string, *codepipeline.ArtifactStore) { @@ -516,11 +517,14 @@ func resourceAwsCodePipelineRead(d *schema.ResourceData, meta interface{}) error metadata := resp.Metadata pipeline := resp.Pipeline - if err := d.Set("artifact_store", flattenAwsCodePipelineArtifactStore(pipeline.ArtifactStore)); err != nil { - return err - } - if err := d.Set("artifact_stores", flattenAwsCodePipelineArtifactStores(pipeline.ArtifactStores)); err != nil { - return err + if pipeline.ArtifactStore != nil { + if err := d.Set("artifact_store", flattenAwsCodePipelineArtifactStore(pipeline.ArtifactStore)); err != nil { + return err + } + } else if pipeline.ArtifactStores != nil { + if err := d.Set("artifact_store", flattenAwsCodePipelineArtifactStores(pipeline.ArtifactStores)); err != nil { + return err + } } if err := d.Set("stage", flattenAwsCodePipelineStages(pipeline.Stages)); err != nil { @@ -548,11 +552,14 @@ func resourceAwsCodePipelineRead(d *schema.ResourceData, meta interface{}) error func resourceAwsCodePipelineUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).codepipelineconn - pipeline := expandAwsCodePipeline(d) + pipeline, err := expandAwsCodePipeline(d) + if err != nil { + return err + } params := &codepipeline.UpdatePipelineInput{ Pipeline: pipeline, } - _, err := conn.UpdatePipeline(params) + _, err = conn.UpdatePipeline(params) if err != nil { return fmt.Errorf( @@ -589,9 +596,3 @@ func resourceAwsCodePipelineDelete(d *schema.ResourceData, meta interface{}) err return err } - -func resourceAwsCodePipelineArtifactStoreHash(v interface{}) int { - m := v.(map[string]interface{}) - - return hashcode.String(m["region"].(string)) -} diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index d1b6bb10137..9a937658be4 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "regexp" + "strings" "testing" "github.com/aws/aws-sdk-go/aws" @@ -32,12 +33,12 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "role_arn", "aws_iam_role.codepipeline_role", "arn"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s", name))), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), - resource.TestCheckResourceAttr(resourceName, "artifact_store.0.type", "S3"), - resource.TestCheckResourceAttrPair(resourceName, "artifact_store.0.location", "aws_s3_bucket.test", "bucket"), - resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.#", "1"), - resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.id", "1234"), - resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.type", "KMS"), - resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "0"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "type", "S3"), + testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p1, "", "location", "aws_s3_bucket.test", "bucket"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.#", "1"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.0.id", "1234"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.0.type", "KMS"), + resource.TestCheckResourceAttr(resourceName, "stage.#", "2"), resource.TestCheckResourceAttr(resourceName, "stage.0.name", "Source"), @@ -84,12 +85,12 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { Config: testAccAWSCodePipelineConfig_basicUpdated(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), - resource.TestCheckResourceAttr(resourceName, "artifact_store.0.type", "S3"), - resource.TestCheckResourceAttrPair(resourceName, "artifact_store.0.location", "aws_s3_bucket.updated", "bucket"), - resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.#", "1"), - resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.id", "4567"), - resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.0.type", "KMS"), - resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "0"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "type", "S3"), + testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p1, "", "location", "aws_s3_bucket.test", "bucket"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.#", "1"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.0.id", "1234"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.0.type", "KMS"), + resource.TestCheckResourceAttr(resourceName, "stage.#", "2"), resource.TestCheckResourceAttr(resourceName, "stage.0.name", "Source"), @@ -132,8 +133,8 @@ func TestAccAWSCodePipeline_emptyArtifacts(t *testing.T) { testAccCheckAWSCodePipelineExists(resourceName, &p), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s", name))), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), - resource.TestCheckResourceAttr(resourceName, "artifact_store.0.type", "S3"), - resource.TestCheckResourceAttr(resourceName, "artifact_store.0.encryption_key.#", "0"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p, "", "type", "S3"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p, "", "encryption_key.#", "0"), ), ExpectNonEmptyPlan: true, }, @@ -245,14 +246,13 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { Config: testAccAWSCodePipelineConfig_multiregion(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p), - resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "0"), - resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "2"), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), - testAccCheckAWSCodePipelineArtifactStoresAttr(&p, testAccGetRegion(), "type", "S3"), - testAccCheckAWSCodePipelineArtifactStoresAttrPair(&p, testAccGetRegion(), "location", "aws_s3_bucket.test", "bucket"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p, testAccGetRegion(), "type", "S3"), + testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p, testAccGetRegion(), "location", "aws_s3_bucket.test", "bucket"), - testAccCheckAWSCodePipelineArtifactStoresAttr(&p, testAccGetAlternateRegion(), "type", "S3"), - testAccCheckAWSCodePipelineArtifactStoresAttrPair(&p, testAccGetAlternateRegion(), "location", "aws_s3_bucket.alternate", "bucket"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p, testAccGetAlternateRegion(), "type", "S3"), + testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p, testAccGetAlternateRegion(), "location", "aws_s3_bucket.alternate", "bucket"), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), @@ -292,11 +292,10 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { Config: testAccAWSCodePipelineConfig_multiregion(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), - resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "0"), - resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "2"), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), - testAccCheckAWSCodePipelineArtifactStoresAttr(&p1, testAccGetRegion(), "encryption_key.0.id", "1234"), - testAccCheckAWSCodePipelineArtifactStoresAttr(&p1, testAccGetAlternateRegion(), "encryption_key.0.id", "5678"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, testAccGetRegion(), "encryption_key.0.id", "1234"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, testAccGetAlternateRegion(), "encryption_key.0.id", "5678"), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), @@ -310,11 +309,10 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { Config: testAccAWSCodePipelineConfig_multiregionUpdated(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), - resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "0"), - resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "2"), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), - testAccCheckAWSCodePipelineArtifactStoresAttr(&p2, testAccGetRegion(), "encryption_key.0.id", "4321"), - testAccCheckAWSCodePipelineArtifactStoresAttr(&p2, testAccGetAlternateRegion(), "encryption_key.0.id", "8765"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p2, testAccGetRegion(), "encryption_key.0.id", "4321"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p2, testAccGetAlternateRegion(), "encryption_key.0.id", "8765"), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), @@ -349,9 +347,8 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), - resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "0"), - resource.TestCheckResourceAttrPair(resourceName, "artifact_store.0.location", "aws_s3_bucket.test", "bucket"), + testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p1, "", "location", "aws_s3_bucket.test", "bucket"), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), @@ -363,11 +360,10 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { Config: testAccAWSCodePipelineConfig_multiregion(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), - resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "0"), - resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "2"), + resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), - testAccCheckAWSCodePipelineArtifactStoresAttr(&p2, testAccGetRegion(), "encryption_key.0.id", "1234"), - testAccCheckAWSCodePipelineArtifactStoresAttr(&p2, testAccGetAlternateRegion(), "encryption_key.0.id", "5678"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p2, testAccGetRegion(), "encryption_key.0.id", "1234"), + testAccCheckAWSCodePipelineArtifactStoreAttr(&p2, testAccGetAlternateRegion(), "encryption_key.0.id", "5678"), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), @@ -382,9 +378,8 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), - resource.TestCheckResourceAttr(resourceName, "artifact_stores.#", "0"), - resource.TestCheckResourceAttrPair(resourceName, "artifact_store.0.location", "aws_s3_bucket.test", "bucket"), + testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p1, "", "location", "aws_s3_bucket.test", "bucket"), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), @@ -1015,7 +1010,7 @@ resource "aws_codepipeline" "test" { name = "test-pipeline-%[1]s" role_arn = "${aws_iam_role.codepipeline_role.arn}" - artifact_stores { + artifact_store { location = "${aws_s3_bucket.test.bucket}" type = "S3" encryption_key { @@ -1024,7 +1019,7 @@ resource "aws_codepipeline" "test" { } region = "%[2]s" } - artifact_stores { + artifact_store { location = "${aws_s3_bucket.alternate.bucket}" type = "S3" encryption_key { @@ -1150,7 +1145,7 @@ resource "aws_codepipeline" "test" { name = "test-pipeline-%[1]s" role_arn = "${aws_iam_role.codepipeline_role.arn}" - artifact_stores { + artifact_store { location = "${aws_s3_bucket.test.bucket}" type = "S3" encryption_key { @@ -1159,7 +1154,7 @@ resource "aws_codepipeline" "test" { } region = "%[2]s" } - artifact_stores { + artifact_store { location = "${aws_s3_bucket.alternate.bucket}" type = "S3" encryption_key { @@ -1251,15 +1246,23 @@ resource "aws_s3_bucket" "%[1]s" { `, bucket, rName, provider) } -func testAccCheckAWSCodePipelineArtifactStoresAttr(p *codepipeline.PipelineDeclaration, region string, key, value string) resource.TestCheckFunc { +func testAccCheckAWSCodePipelineArtifactStoreAttr(p *codepipeline.PipelineDeclaration, region string, key, value string) resource.TestCheckFunc { return func(s *terraform.State) error { - as, ok := p.ArtifactStores[region] - if !ok { - return fmt.Errorf("Artifact Store for region %q not found", region) + values, err := testAccCheckAWSCodePipelineArtifactStoreFlatmap(p, region) + if err != nil { + return err + } + + emptyCheck := false + if value == "0" && (strings.HasSuffix(key, ".#") || strings.HasSuffix(key, ".%")) { + emptyCheck = true } - values := flatmap.Flatten(flattenAwsCodePipelineArtifactStore(as)[0].(map[string]interface{})) if v, ok := values[key]; !ok || v != value { + if emptyCheck && !ok { + return nil + } + if !ok { return fmt.Errorf("ArtifactStores[%s]: Attribute %q not found", region, key) } @@ -1271,13 +1274,12 @@ func testAccCheckAWSCodePipelineArtifactStoresAttr(p *codepipeline.PipelineDecla } } -func testAccCheckAWSCodePipelineArtifactStoresAttrPair(p *codepipeline.PipelineDeclaration, region string, keyFirst, nameSecond, keySecond string) resource.TestCheckFunc { +func testAccCheckAWSCodePipelineArtifactStoreAttrPair(p *codepipeline.PipelineDeclaration, region string, keyFirst, nameSecond, keySecond string) resource.TestCheckFunc { return func(s *terraform.State) error { - as, ok := p.ArtifactStores[region] - if !ok { - return fmt.Errorf("Artifact Store for region %q not found", region) + values, err := testAccCheckAWSCodePipelineArtifactStoreFlatmap(p, region) + if err != nil { + return err } - values := flatmap.Flatten(flattenAwsCodePipelineArtifactStore(as)[0].(map[string]interface{})) isSecond, err := primaryInstanceState(s, nameSecond) if err != nil { @@ -1305,3 +1307,137 @@ func testAccCheckAWSCodePipelineArtifactStoresAttrPair(p *codepipeline.PipelineD return nil } } + +func testAccCheckAWSCodePipelineArtifactStoreFlatmap(p *codepipeline.PipelineDeclaration, region string) (flatmap.Map, error) { + var as *codepipeline.ArtifactStore + if region == "" { + as = p.ArtifactStore + } else { + v, ok := p.ArtifactStores[region] + if !ok { + return nil, fmt.Errorf("Artifact Store for region %q not found", region) + } + as = v + } + return flatmap.Flatten(flattenAwsCodePipelineArtifactStore(as)[0].(map[string]interface{})), nil +} + +func TestResourceAWSCodePipelineExpandArtifactStoresValidation(t *testing.T) { + cases := []struct { + Name string + Input []interface{} + ExpectedError string + }{ + { + Name: "Single-region", + Input: []interface{}{ + map[string]interface{}{ + "location": "", + "type": "", + "encryption_key": []interface{}{}, + "region": "", + }, + }, + }, + { + Name: "Single-region, names region", + Input: []interface{}{ + map[string]interface{}{ + "location": "", + "type": "", + "encryption_key": []interface{}{}, + "region": "us-west-2", + }, + }, + ExpectedError: "region cannot be set for a single-region CodePipeline", + }, + { + Name: "Cross-region", + Input: []interface{}{ + map[string]interface{}{ + "location": "", + "type": "", + "encryption_key": []interface{}{}, + "region": "us-west-2", + }, + map[string]interface{}{ + "location": "", + "type": "", + "encryption_key": []interface{}{}, + "region": "us-east-1", + }, + }, + }, + { + Name: "Cross-region, no regions", + Input: []interface{}{ + map[string]interface{}{ + "location": "", + "type": "", + "encryption_key": []interface{}{}, + "region": "", + }, + map[string]interface{}{ + "location": "", + "type": "", + "encryption_key": []interface{}{}, + "region": "", + }, + }, + ExpectedError: "region must be set for a cross-region CodePipeline", + }, + { + Name: "Cross-region, not all regions", + Input: []interface{}{ + map[string]interface{}{ + "location": "", + "type": "", + "encryption_key": []interface{}{}, + "region": "us-west-2", + }, + map[string]interface{}{ + "location": "", + "type": "", + "encryption_key": []interface{}{}, + "region": "", + }, + }, + ExpectedError: "region must be set for a cross-region CodePipeline", + }, + { + Name: "Duplicate regions", + Input: []interface{}{ + map[string]interface{}{ + "location": "", + "type": "", + "encryption_key": []interface{}{}, + "region": "us-west-2", + }, + map[string]interface{}{ + "location": "", + "type": "", + "encryption_key": []interface{}{}, + "region": "us-west-2", + }, + }, + ExpectedError: "only one Artifact Store can be defined per region for a cross-region CodePipeline", + }, + } + + for _, tc := range cases { + _, err := expandAwsCodePipelineArtifactStores(tc.Input) + if tc.ExpectedError == "" { + if err != nil { + t.Errorf("%s: Did not expect an error, but got: %q", tc.Name, err) + } + } else { + if err == nil { + t.Errorf("%s: Expected an error, but did not get one", tc.Name) + } else { + if err.Error() != tc.ExpectedError { + t.Errorf("%s: Expected error %q, got %q", tc.Name, tc.ExpectedError, err.Error()) + } + } + } + } +} diff --git a/website/docs/r/codepipeline.markdown b/website/docs/r/codepipeline.markdown index 3bd08d7909b..77c28db7594 100644 --- a/website/docs/r/codepipeline.markdown +++ b/website/docs/r/codepipeline.markdown @@ -157,16 +157,17 @@ The following arguments are supported: * `name` - (Required) The name of the pipeline. * `role_arn` - (Required) A service role Amazon Resource Name (ARN) that grants AWS CodePipeline permission to make calls to AWS services on your behalf. -* `artifact_store` (Required) An artifact_store block. Artifact stores are documented below. +* `artifact_store` (Required) One or more artifact_store blocks. Artifact stores are documented below. * `stage` (Minimum of at least two `stage` blocks is required) A stage block. Stages are documented below. * `tags` - (Optional) A mapping of tags to assign to the resource. An `artifact_store` block supports the following arguments: -* `location` - (Required) The location where AWS CodePipeline stores artifacts for a pipeline, such as an S3 bucket. +* `location` - (Required) The location where AWS CodePipeline stores artifacts for a pipeline; currently only `S3` is supported. * `type` - (Required) The type of the artifact store, such as Amazon S3 * `encryption_key` - (Optional) The encryption key block AWS CodePipeline uses to encrypt the data in the artifact store, such as an AWS Key Management Service (AWS KMS) key. If you don't specify a key, AWS CodePipeline uses the default key for Amazon Simple Storage Service (Amazon S3). An `encryption_key` block is documented below. +* `region` - (Optional) The region where the artifact store is located. Required for a cross-region CodePipeline, do not provide for a single-region CodePipeline. An `encryption_key` block supports the following arguments: @@ -178,7 +179,7 @@ A `stage` block supports the following arguments: * `name` - (Required) The name of the stage. * `action` - (Required) The action(s) to include in the stage. Defined as an `action` block below -A `action` block supports the following arguments: +An `action` block supports the following arguments: * `category` - (Required) A category defines what kind of action can be taken in the stage, and constrains the provider type for the action. Possible values are `Approval`, `Build`, `Deploy`, `Invoke`, `Source` and `Test`. * `owner` - (Required) The creator of the action being called. Possible values are `AWS`, `Custom` and `ThirdParty`. From 589ece74de83fc12cebba95af39f2584fe2fa92a Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:10:34 -0400 Subject: [PATCH 178/684] service/docdb: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12457) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_docdb_cluster.go:620:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_docdb_cluster.go:626:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_docdb_cluster.go:672:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_docdb_cluster_instance.go:345:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_docdb_cluster_instance.go:351:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_docdb_cluster_instance.go:357:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_docdb_cluster_instance.go:363:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_docdb_cluster_instance.go:413:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_docdb_cluster_parameter_group.go:185:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_docdb_cluster_parameter_group.go:230:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_docdb_cluster_parameter_group.go:241:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_docdb_cluster_parameter_group.go:244:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_docdb_subnet_group.go:179:3: R008: deprecated (schema.ResourceData).SetPartial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSDocDBCluster_backupsUpdate (260.19s) --- PASS: TestAccAWSDocDBCluster_basic (130.28s) --- PASS: TestAccAWSDocDBCluster_encrypted (203.87s) --- PASS: TestAccAWSDocDBCluster_generatedName (130.17s) --- PASS: TestAccAWSDocDBCluster_kmsKey (233.75s) --- PASS: TestAccAWSDocDBCluster_missingUserNameCausesError (4.93s) --- PASS: TestAccAWSDocDBCluster_namePrefix (129.97s) --- PASS: TestAccAWSDocDBCluster_Port (369.93s) --- PASS: TestAccAWSDocDBCluster_takeFinalSnapshot (252.47s) --- PASS: TestAccAWSDocDBCluster_updateCloudwatchLogsExports (227.06s) --- PASS: TestAccAWSDocDBCluster_updateTags (235.10s) --- PASS: TestAccAWSDocDBClusterInstance_az (714.97s) --- PASS: TestAccAWSDocDBClusterInstance_basic (1416.43s) --- PASS: TestAccAWSDocDBClusterInstance_disappears (748.64s) --- PASS: TestAccAWSDocDBClusterInstance_generatedName (753.18s) --- PASS: TestAccAWSDocDBClusterInstance_kmsKey (821.87s) --- PASS: TestAccAWSDocDBClusterInstance_namePrefix (764.04s) --- PASS: TestAccAWSDocDBClusterParameterGroup_basic (43.89s) --- PASS: TestAccAWSDocDBClusterParameterGroup_Description (31.42s) --- PASS: TestAccAWSDocDBClusterParameterGroup_disappears (13.72s) --- PASS: TestAccAWSDocDBClusterParameterGroup_generatedName (27.74s) --- PASS: TestAccAWSDocDBClusterParameterGroup_namePrefix (48.18s) --- PASS: TestAccAWSDocDBClusterParameterGroup_Parameter (50.36s) --- PASS: TestAccAWSDocDBClusterParameterGroup_Tags (65.89s) --- PASS: TestAccAWSDocDBSubnetGroup_basic (57.22s) --- PASS: TestAccAWSDocDBSubnetGroup_disappears (31.33s) --- PASS: TestAccAWSDocDBSubnetGroup_generatedName (44.49s) --- PASS: TestAccAWSDocDBSubnetGroup_namePrefix (46.41s) --- PASS: TestAccAWSDocDBSubnetGroup_updateDescription (67.20s) ``` --- aws/resource_aws_docdb_cluster.go | 3 --- aws/resource_aws_docdb_cluster_instance.go | 5 ----- aws/resource_aws_docdb_cluster_parameter_group.go | 7 ------- aws/resource_aws_docdb_subnet_group.go | 2 -- 4 files changed, 17 deletions(-) diff --git a/aws/resource_aws_docdb_cluster.go b/aws/resource_aws_docdb_cluster.go index 6a50c6e7f62..4dfbed9af70 100644 --- a/aws/resource_aws_docdb_cluster.go +++ b/aws/resource_aws_docdb_cluster.go @@ -617,13 +617,11 @@ func resourceAwsDocDBClusterUpdate(d *schema.ResourceData, meta interface{}) err } if d.HasChange("db_cluster_parameter_group_name") { - d.SetPartial("db_cluster_parameter_group_name") req.DBClusterParameterGroupName = aws.String(d.Get("db_cluster_parameter_group_name").(string)) requestUpdate = true } if d.HasChange("enabled_cloudwatch_logs_exports") { - d.SetPartial("enabled_cloudwatch_logs_exports") req.CloudwatchLogsExportConfiguration = buildDocDBCloudwatchLogsExportConfiguration(d) requestUpdate = true } @@ -669,7 +667,6 @@ func resourceAwsDocDBClusterUpdate(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("error updating DocumentDB Cluster (%s) tags: %s", d.Get("arn").(string), err) } - d.SetPartial("tags") } return resourceAwsDocDBClusterRead(d, meta) diff --git a/aws/resource_aws_docdb_cluster_instance.go b/aws/resource_aws_docdb_cluster_instance.go index 8ddf4ac2b44..572024e408f 100644 --- a/aws/resource_aws_docdb_cluster_instance.go +++ b/aws/resource_aws_docdb_cluster_instance.go @@ -342,25 +342,21 @@ func resourceAwsDocDBClusterInstanceUpdate(d *schema.ResourceData, meta interfac } if d.HasChange("preferred_maintenance_window") { - d.SetPartial("preferred_maintenance_window") req.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintenance_window").(string)) requestUpdate = true } if d.HasChange("auto_minor_version_upgrade") { - d.SetPartial("auto_minor_version_upgrade") req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) requestUpdate = true } if d.HasChange("promotion_tier") { - d.SetPartial("promotion_tier") req.PromotionTier = aws.Int64(int64(d.Get("promotion_tier").(int))) requestUpdate = true } if d.HasChange("ca_cert_identifier") { - d.SetPartial("ca_cert_identifier") req.CACertificateIdentifier = aws.String(d.Get("ca_cert_identifier").(string)) requestUpdate = true } @@ -410,7 +406,6 @@ func resourceAwsDocDBClusterInstanceUpdate(d *schema.ResourceData, meta interfac return fmt.Errorf("error updating DocumentDB Cluster Instance (%s) tags: %s", d.Get("arn").(string), err) } - d.SetPartial("tags") } return resourceAwsDocDBClusterInstanceRead(d, meta) diff --git a/aws/resource_aws_docdb_cluster_parameter_group.go b/aws/resource_aws_docdb_cluster_parameter_group.go index 1cfc3153130..6e142ed2ffd 100644 --- a/aws/resource_aws_docdb_cluster_parameter_group.go +++ b/aws/resource_aws_docdb_cluster_parameter_group.go @@ -182,8 +182,6 @@ func resourceAwsDocDBClusterParameterGroupRead(d *schema.ResourceData, meta inte func resourceAwsDocDBClusterParameterGroupUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).docdbconn - d.Partial(true) - if d.HasChange("parameter") { o, n := d.GetChange("parameter") if o == nil { @@ -227,7 +225,6 @@ func resourceAwsDocDBClusterParameterGroupUpdate(d *schema.ResourceData, meta in return fmt.Errorf("Error modifying DocDB Cluster Parameter Group: %s", err) } } - d.SetPartial("parameter") } } @@ -237,12 +234,8 @@ func resourceAwsDocDBClusterParameterGroupUpdate(d *schema.ResourceData, meta in if err := keyvaluetags.DocdbUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating DocumentDB Cluster Parameter Group (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } - d.Partial(false) - return resourceAwsDocDBClusterParameterGroupRead(d, meta) } diff --git a/aws/resource_aws_docdb_subnet_group.go b/aws/resource_aws_docdb_subnet_group.go index 568013c5c40..739c4545088 100644 --- a/aws/resource_aws_docdb_subnet_group.go +++ b/aws/resource_aws_docdb_subnet_group.go @@ -175,8 +175,6 @@ func resourceAwsDocDBSubnetGroupUpdate(d *schema.ResourceData, meta interface{}) if err := keyvaluetags.DocdbUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating DocumentDB Subnet Group (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } return resourceAwsDocDBSubnetGroupRead(d, meta) From c467831a327aa305b8163ffc4f368ec806587441 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:11:53 -0400 Subject: [PATCH 179/684] service/elb: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12459) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_elb.go:331:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_elb.go:332:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:333:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:334:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:335:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:336:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:337:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:479:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_elb.go:545:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:581:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:619:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:620:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:621:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:647:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:667:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:688:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:705:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:742:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:794:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_elb.go:810:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_proxy_protocol_policy.go:122:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_proxy_protocol_policy.go:151:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_proxy_protocol_policy.go:63:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_proxy_protocol_policy.go:65:2: R008: deprecated (schema.ResourceData).SetPartial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSELB_AccessLogs_disabled (275.08s) --- PASS: TestAccAWSELB_AccessLogs_enabled (88.33s) --- PASS: TestAccAWSELB_availabilityZones (67.63s) --- PASS: TestAccAWSELB_basic (40.56s) --- PASS: TestAccAWSELB_ConnectionDraining (222.97s) --- PASS: TestAccAWSELB_disappears (132.48s) --- PASS: TestAccAWSELB_fullCharacterRange (33.99s) --- PASS: TestAccAWSELB_generatedName (26.07s) --- PASS: TestAccAWSELB_generatesNameForZeroValue (84.50s) --- PASS: TestAccAWSELB_HealthCheck (219.59s) --- PASS: TestAccAWSELB_InstanceAttaching (173.37s) --- PASS: TestAccAWSELB_listener (101.85s) --- PASS: TestAccAWSELB_Listener_SSLCertificateID_IAMServerCertificate (42.66s) --- PASS: TestAccAWSELB_namePrefix (59.05s) --- PASS: TestAccAWSELB_SecurityGroups (171.23s) --- PASS: TestAccAWSELB_swap_subnets (276.60s) --- PASS: TestAccAWSELB_tags (95.49s) --- PASS: TestAccAWSELB_Timeout (141.20s) --- PASS: TestAccAWSProxyProtocolPolicy_basic (40.72s) ``` --- aws/resource_aws_elb.go | 37 ----------------------- aws/resource_aws_proxy_protocol_policy.go | 6 ---- 2 files changed, 43 deletions(-) diff --git a/aws/resource_aws_elb.go b/aws/resource_aws_elb.go index 3b00f2c844e..2e75451bd8e 100644 --- a/aws/resource_aws_elb.go +++ b/aws/resource_aws_elb.go @@ -327,15 +327,6 @@ func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error { d.SetId(elbName) log.Printf("[INFO] ELB ID: %s", d.Id()) - // Enable partial mode and record what we set - d.Partial(true) - d.SetPartial("name") - d.SetPartial("internal") - d.SetPartial("availability_zones") - d.SetPartial("listener") - d.SetPartial("security_groups") - d.SetPartial("subnets") - if err := d.Set("tags", keyvaluetags.ElbKeyValueTags(tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } @@ -476,8 +467,6 @@ func flattenAwsELbResource(d *schema.ResourceData, ec2conn *ec2.EC2, elbconn *el func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { elbconn := meta.(*AWSClient).elbconn - d.Partial(true) - if d.HasChange("listener") { o, n := d.GetChange("listener") os := o.(*schema.Set) @@ -541,8 +530,6 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Failure adding new or updated ELB listeners: %s", err) } } - - d.SetPartial("listener") } // If we currently have instances, or did have instances, @@ -577,8 +564,6 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Failure deregistering instances from ELB: %s", err) } } - - d.SetPartial("instances") } if d.HasChange("cross_zone_load_balancing") || d.HasChange("idle_timeout") || d.HasChange("access_logs") { @@ -615,10 +600,6 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("Failure configuring ELB attributes: %s", err) } - - d.SetPartial("cross_zone_load_balancing") - d.SetPartial("idle_timeout") - d.SetPartial("connection_draining_timeout") } // We have to do these changes separately from everything else since @@ -643,8 +624,6 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("Failure configuring ELB attributes: %s", err) } - - d.SetPartial("connection_draining_timeout") } // Then we always set connection draining even if there is no change. @@ -663,8 +642,6 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("Failure configuring ELB attributes: %s", err) } - - d.SetPartial("connection_draining") } if d.HasChange("health_check") { @@ -685,7 +662,6 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("Failure configuring health check for ELB: %s", err) } - d.SetPartial("health_check") } } @@ -701,8 +677,6 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("Failure applying security groups to ELB: %s", err) } - - d.SetPartial("security_groups") } if d.HasChange("availability_zones") { @@ -738,8 +712,6 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Failure disabling ELB availability zones: %s", err) } } - - d.SetPartial("availability_zones") } if d.HasChange("subnets") { @@ -790,8 +762,6 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Failure adding ELB subnets: %s", err) } } - - d.SetPartial("subnets") } if d.HasChange("tags") { @@ -802,13 +772,6 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { } } - //if err := setTagsELB(elbconn, d); err != nil { - // return err - //} - // - //d.SetPartial("tags") - d.Partial(false) - return resourceAwsElbRead(d, meta) } diff --git a/aws/resource_aws_proxy_protocol_policy.go b/aws/resource_aws_proxy_protocol_policy.go index 18c85f00627..94cf95823e0 100644 --- a/aws/resource_aws_proxy_protocol_policy.go +++ b/aws/resource_aws_proxy_protocol_policy.go @@ -59,10 +59,7 @@ func resourceAwsProxyProtocolPolicyCreate(d *schema.ResourceData, meta interface *input.PolicyName, err) } - // Assign the policy name for use later - d.Partial(true) d.SetId(fmt.Sprintf("%s:%s", *elbname, *input.PolicyName)) - d.SetPartial("load_balancer") log.Printf("[INFO] ELB PolicyName: %s", *input.PolicyName) return resourceAwsProxyProtocolPolicyUpdate(d, meta) @@ -119,7 +116,6 @@ func resourceAwsProxyProtocolPolicyUpdate(d *schema.ResourceData, meta interface backends := flattenBackendPolicies(resp.LoadBalancerDescriptions[0].BackendServerDescriptions) policyName := resourceAwsProxyProtocolPolicyParseId(d.Id()) - d.Partial(true) if d.HasChange("instance_ports") { o, n := d.GetChange("instance_ports") os := o.(*schema.Set) @@ -147,8 +143,6 @@ func resourceAwsProxyProtocolPolicyUpdate(d *schema.ResourceData, meta interface return fmt.Errorf("Error setting policy for backend: %s", err) } } - - d.SetPartial("instance_ports") } return resourceAwsProxyProtocolPolicyRead(d, meta) From 21f1ff5d9da48517ba61c24d90e74d5795404b7e Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:12:22 -0400 Subject: [PATCH 180/684] service/route53resolver: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12460) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_route53_resolver_endpoint.go:199:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_route53_resolver_endpoint.go:219:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_route53_resolver_endpoint.go:264:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_route53_resolver_endpoint.go:272:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_route53_resolver_endpoint.go:275:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_route53_resolver_rule.go:191:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_route53_resolver_rule.go:220:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_route53_resolver_rule.go:221:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_route53_resolver_rule.go:222:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_route53_resolver_rule.go:230:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_route53_resolver_rule.go:233:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAwsRoute53ResolverEndpoint_basicInbound (102.08s) --- PASS: TestAccAwsRoute53ResolverEndpoint_updateOutbound (446.81s) --- PASS: TestAccAwsRoute53ResolverRule_basic (39.84s) --- PASS: TestAccAwsRoute53ResolverRule_forward (316.33s) --- PASS: TestAccAwsRoute53ResolverRule_forwardEndpointRecreate (448.03s) --- PASS: TestAccAwsRoute53ResolverRule_tags (66.35s) --- PASS: TestAccAwsRoute53ResolverRule_updateName (62.64s) ``` --- aws/resource_aws_route53_resolver_endpoint.go | 7 ------- aws/resource_aws_route53_resolver_rule.go | 7 ------- 2 files changed, 14 deletions(-) diff --git a/aws/resource_aws_route53_resolver_endpoint.go b/aws/resource_aws_route53_resolver_endpoint.go index 964debf93b4..d4060f217f3 100644 --- a/aws/resource_aws_route53_resolver_endpoint.go +++ b/aws/resource_aws_route53_resolver_endpoint.go @@ -196,7 +196,6 @@ func resourceAwsRoute53ResolverEndpointRead(d *schema.ResourceData, meta interfa func resourceAwsRoute53ResolverEndpointUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).route53resolverconn - d.Partial(true) if d.HasChange("name") { req := &route53resolver.UpdateResolverEndpointInput{ ResolverEndpointId: aws.String(d.Id()), @@ -215,8 +214,6 @@ func resourceAwsRoute53ResolverEndpointUpdate(d *schema.ResourceData, meta inter if err != nil { return err } - - d.SetPartial("name") } if d.HasChange("ip_address") { @@ -260,8 +257,6 @@ func resourceAwsRoute53ResolverEndpointUpdate(d *schema.ResourceData, meta inter return err } } - - d.SetPartial("ip_address") } if d.HasChange("tags") { @@ -269,10 +264,8 @@ func resourceAwsRoute53ResolverEndpointUpdate(d *schema.ResourceData, meta inter if err := keyvaluetags.Route53resolverUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Route53 Resolver endpoint (%s) tags: %s", d.Get("arn").(string), err) } - d.SetPartial("tags") } - d.Partial(false) return resourceAwsRoute53ResolverEndpointRead(d, meta) } diff --git a/aws/resource_aws_route53_resolver_rule.go b/aws/resource_aws_route53_resolver_rule.go index ca185e04851..b9c69943c08 100644 --- a/aws/resource_aws_route53_resolver_rule.go +++ b/aws/resource_aws_route53_resolver_rule.go @@ -188,7 +188,6 @@ func resourceAwsRoute53ResolverRuleRead(d *schema.ResourceData, meta interface{} func resourceAwsRoute53ResolverRuleUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).route53resolverconn - d.Partial(true) if d.HasChange("name") || d.HasChange("resolver_endpoint_id") || d.HasChange("target_ip") { req := &route53resolver.UpdateResolverRuleInput{ ResolverRuleId: aws.String(d.Id()), @@ -216,10 +215,6 @@ func resourceAwsRoute53ResolverRuleUpdate(d *schema.ResourceData, meta interface if err != nil { return err } - - d.SetPartial("name") - d.SetPartial("resolver_endpoint_id") - d.SetPartial("target_ip") } if d.HasChange("tags") { @@ -227,10 +222,8 @@ func resourceAwsRoute53ResolverRuleUpdate(d *schema.ResourceData, meta interface if err := keyvaluetags.Route53resolverUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Route53 Resolver rule (%s) tags: %s", d.Get("arn").(string), err) } - d.SetPartial("tags") } - d.Partial(false) return resourceAwsRoute53ResolverRuleRead(d, meta) } From 2dbe6c7af5ebd9e45b9f065e531d3a736161b0c5 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:12:59 -0400 Subject: [PATCH 181/684] service/redshift: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12461) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_redshift_cluster.go:644:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_redshift_cluster.go:653:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_redshift_cluster.go:774:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_redshift_cluster.go:828:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_redshift_event_subscription.go:191:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_redshift_event_subscription.go:216:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_redshift_event_subscription.go:219:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_redshift_parameter_group.go:168:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_redshift_parameter_group.go:200:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_redshift_parameter_group.go:210:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_redshift_parameter_group.go:213:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_redshift_snapshot_copy_grant.go:118:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_redshift_snapshot_copy_grant.go:127:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_redshift_snapshot_copy_grant.go:130:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_redshift_snapshot_schedule.go:142:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_redshift_snapshot_schedule.go:151:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_redshift_snapshot_schedule.go:168:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_redshift_subnet_group.go:127:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_redshift_subnet_group.go:136:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_redshift_subnet_group.go:162:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing (failure present on master): ``` --- PASS: TestAccAWSRedshiftCluster_basic (374.33s) --- PASS: TestAccAWSRedshiftCluster_changeAvailabilityZone (664.68s) --- PASS: TestAccAWSRedshiftCluster_changeEncryption1 (2088.45s) --- PASS: TestAccAWSRedshiftCluster_changeEncryption2 (1868.48s) --- PASS: TestAccAWSRedshiftCluster_enhancedVpcRoutingEnabled (959.29s) --- PASS: TestAccAWSRedshiftCluster_forceNewUsername (1672.20s) --- PASS: TestAccAWSRedshiftCluster_iamRoles (824.30s) --- PASS: TestAccAWSRedshiftCluster_kmsKey (1387.64s) --- PASS: TestAccAWSRedshiftCluster_loggingEnabled (1178.50s) --- PASS: TestAccAWSRedshiftCluster_publiclyAccessible (1435.60s) --- PASS: TestAccAWSRedshiftCluster_snapshotCopy (434.54s) --- PASS: TestAccAWSRedshiftCluster_tags (476.81s) --- PASS: TestAccAWSRedshiftCluster_updateNodeCount (3699.47s) --- PASS: TestAccAWSRedshiftCluster_updateNodeType (1911.25s) --- PASS: TestAccAWSRedshiftCluster_withFinalSnapshot (1449.68s) --- PASS: TestAccAWSRedshiftEventSubscription_basicUpdate (41.61s) --- PASS: TestAccAWSRedshiftEventSubscription_categoryUpdate (51.13s) --- PASS: TestAccAWSRedshiftEventSubscription_tagsUpdate (145.74s) --- PASS: TestAccAWSRedshiftEventSubscription_withPrefix (44.47s) --- PASS: TestAccAWSRedshiftEventSubscription_withSourceIds (84.82s) --- PASS: TestAccAWSRedshiftParameterGroup_basic (44.40s) --- PASS: TestAccAWSRedshiftParameterGroup_withoutParameters (76.56s) --- PASS: TestAccAWSRedshiftParameterGroup_withParameters (27.47s) --- PASS: TestAccAWSRedshiftParameterGroup_withTags (101.82s) --- PASS: TestAccAWSRedshiftSnapshotCopyGrant_Basic (34.09s) --- PASS: TestAccAWSRedshiftSnapshotCopyGrant_Update (74.12s) --- FAIL: TestAccAWSRedshiftSnapshotSchedule_withForceDestroy (314.27s) --- PASS: TestAccAWSRedshiftSnapshotSchedule_basic (55.17s) --- PASS: TestAccAWSRedshiftSnapshotSchedule_withDescription (48.15s) --- PASS: TestAccAWSRedshiftSnapshotSchedule_withIdentifierPrefix (44.69s) --- PASS: TestAccAWSRedshiftSnapshotSchedule_withMultipleDefinition (37.15s) --- PASS: TestAccAWSRedshiftSnapshotSchedule_withTags (97.33s) --- PASS: TestAccAWSRedshiftSubnetGroup_basic (41.15s) --- PASS: TestAccAWSRedshiftSubnetGroup_tags (64.37s) --- PASS: TestAccAWSRedshiftSubnetGroup_updateDescription (67.68s) --- PASS: TestAccAWSRedshiftSubnetGroup_updateSubnetIds (59.10s) ``` --- aws/resource_aws_redshift_cluster.go | 7 ------- aws/resource_aws_redshift_event_subscription.go | 6 ------ aws/resource_aws_redshift_parameter_group.go | 6 ------ aws/resource_aws_redshift_snapshot_copy_grant.go | 6 ------ aws/resource_aws_redshift_snapshot_schedule.go | 4 ---- aws/resource_aws_redshift_subnet_group.go | 5 ----- 6 files changed, 34 deletions(-) diff --git a/aws/resource_aws_redshift_cluster.go b/aws/resource_aws_redshift_cluster.go index 95051bd3f59..81df78fe813 100644 --- a/aws/resource_aws_redshift_cluster.go +++ b/aws/resource_aws_redshift_cluster.go @@ -641,7 +641,6 @@ func resourceAwsRedshiftClusterRead(d *schema.ResourceData, meta interface{}) er func resourceAwsRedshiftClusterUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn - d.Partial(true) if d.HasChange("tags") { o, n := d.GetChange("tags") @@ -649,8 +648,6 @@ func resourceAwsRedshiftClusterUpdate(d *schema.ResourceData, meta interface{}) if err := keyvaluetags.RedshiftUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Redshift Cluster (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } requestUpdate := false @@ -770,8 +767,6 @@ func resourceAwsRedshiftClusterUpdate(d *schema.ResourceData, meta interface{}) if err != nil { return fmt.Errorf("Error modifying Redshift Cluster IAM Roles (%s): %s", d.Id(), err) } - - d.SetPartial("iam_roles") } if requestUpdate || d.HasChange("iam_roles") { @@ -825,8 +820,6 @@ func resourceAwsRedshiftClusterUpdate(d *schema.ResourceData, meta interface{}) } } - d.Partial(false) - return resourceAwsRedshiftClusterRead(d, meta) } diff --git a/aws/resource_aws_redshift_event_subscription.go b/aws/resource_aws_redshift_event_subscription.go index 1b8c8f88427..eedcfb9f52c 100644 --- a/aws/resource_aws_redshift_event_subscription.go +++ b/aws/resource_aws_redshift_event_subscription.go @@ -188,8 +188,6 @@ func resourceAwsRedshiftEventSubscriptionRetrieve(name string, conn *redshift.Re func resourceAwsRedshiftEventSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn - d.Partial(true) - req := &redshift.ModifyEventSubscriptionInput{ SubscriptionName: aws.String(d.Id()), SnsTopicArn: aws.String(d.Get("sns_topic_arn").(string)), @@ -212,12 +210,8 @@ func resourceAwsRedshiftEventSubscriptionUpdate(d *schema.ResourceData, meta int if err := keyvaluetags.RedshiftUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Redshift Event Subscription (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } - d.Partial(false) - return nil } diff --git a/aws/resource_aws_redshift_parameter_group.go b/aws/resource_aws_redshift_parameter_group.go index 8f417c9a16a..892052d5fc3 100644 --- a/aws/resource_aws_redshift_parameter_group.go +++ b/aws/resource_aws_redshift_parameter_group.go @@ -165,8 +165,6 @@ func resourceAwsRedshiftParameterGroupRead(d *schema.ResourceData, meta interfac func resourceAwsRedshiftParameterGroupUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn - d.Partial(true) - if d.HasChange("parameter") { o, n := d.GetChange("parameter") if o == nil { @@ -197,7 +195,6 @@ func resourceAwsRedshiftParameterGroupUpdate(d *schema.ResourceData, meta interf return fmt.Errorf("Error modifying Redshift Parameter Group: %s", err) } } - d.SetPartial("parameter") } if d.HasChange("tags") { @@ -206,11 +203,8 @@ func resourceAwsRedshiftParameterGroupUpdate(d *schema.ResourceData, meta interf if err := keyvaluetags.RedshiftUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Redshift Parameter Group (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } - d.Partial(false) return resourceAwsRedshiftParameterGroupRead(d, meta) } diff --git a/aws/resource_aws_redshift_snapshot_copy_grant.go b/aws/resource_aws_redshift_snapshot_copy_grant.go index 56121723e0d..939e56b600a 100644 --- a/aws/resource_aws_redshift_snapshot_copy_grant.go +++ b/aws/resource_aws_redshift_snapshot_copy_grant.go @@ -115,20 +115,14 @@ func resourceAwsRedshiftSnapshotCopyGrantRead(d *schema.ResourceData, meta inter func resourceAwsRedshiftSnapshotCopyGrantUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn - d.Partial(true) - if d.HasChange("tags") { o, n := d.GetChange("tags") if err := keyvaluetags.RedshiftUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Redshift Snapshot Copy Grant (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } - d.Partial(false) - return resourceAwsRedshiftSnapshotCopyGrantRead(d, meta) } diff --git a/aws/resource_aws_redshift_snapshot_schedule.go b/aws/resource_aws_redshift_snapshot_schedule.go index 05e83931209..237254c966f 100644 --- a/aws/resource_aws_redshift_snapshot_schedule.go +++ b/aws/resource_aws_redshift_snapshot_schedule.go @@ -139,7 +139,6 @@ func resourceAwsRedshiftSnapshotScheduleRead(d *schema.ResourceData, meta interf func resourceAwsRedshiftSnapshotScheduleUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn - d.Partial(true) if d.HasChange("tags") { o, n := d.GetChange("tags") @@ -147,8 +146,6 @@ func resourceAwsRedshiftSnapshotScheduleUpdate(d *schema.ResourceData, meta inte if err := keyvaluetags.RedshiftUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Redshift Snapshot Schedule (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } if d.HasChange("definitions") { @@ -165,7 +162,6 @@ func resourceAwsRedshiftSnapshotScheduleUpdate(d *schema.ResourceData, meta inte if err != nil { return fmt.Errorf("Error modifying Redshift Snapshot Schedule %s: %s", d.Id(), err) } - d.SetPartial("definitions") } return resourceAwsRedshiftSnapshotScheduleRead(d, meta) diff --git a/aws/resource_aws_redshift_subnet_group.go b/aws/resource_aws_redshift_subnet_group.go index bb51c7d9816..10eee867bf8 100644 --- a/aws/resource_aws_redshift_subnet_group.go +++ b/aws/resource_aws_redshift_subnet_group.go @@ -124,7 +124,6 @@ func resourceAwsRedshiftSubnetGroupRead(d *schema.ResourceData, meta interface{} func resourceAwsRedshiftSubnetGroupUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn - d.Partial(true) if d.HasChange("tags") { o, n := d.GetChange("tags") @@ -132,8 +131,6 @@ func resourceAwsRedshiftSubnetGroupUpdate(d *schema.ResourceData, meta interface if err := keyvaluetags.RedshiftUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Redshift Subnet Group (%s) tags: %s", d.Get("arn").(string), err) } - - d.SetPartial("tags") } if d.HasChange("subnet_ids") || d.HasChange("description") { @@ -159,8 +156,6 @@ func resourceAwsRedshiftSubnetGroupUpdate(d *schema.ResourceData, meta interface } } - d.Partial(false) - return resourceAwsRedshiftSubnetGroupRead(d, meta) } From e314710ee2475264174436c8731b4621e8e6215f Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:13:27 -0400 Subject: [PATCH 182/684] resource/aws_directory_service_directory: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12463) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_directory_service_directory.go:317:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_directory_service_directory.go:391:3: R008: deprecated (schema.ResourceData).SetPartial ``` Output from acceptance testing (failure present on master): ``` --- PASS: TestAccAWSDirectoryServiceDirectory_basic (488.80s) --- PASS: TestAccAWSDirectoryServiceDirectory_connector (968.66s) --- PASS: TestAccAWSDirectoryServiceDirectory_microsoft (1688.96s) --- PASS: TestAccAWSDirectoryServiceDirectory_microsoftStandard (1824.96s) --- PASS: TestAccAWSDirectoryServiceDirectory_tags (623.46s) --- PASS: TestAccAWSDirectoryServiceDirectory_withAliasAndSso (584.98s) ``` --- aws/resource_aws_directory_service_directory.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/aws/resource_aws_directory_service_directory.go b/aws/resource_aws_directory_service_directory.go index 75e5933c8a0..7e498a16417 100644 --- a/aws/resource_aws_directory_service_directory.go +++ b/aws/resource_aws_directory_service_directory.go @@ -314,8 +314,6 @@ func createActiveDirectoryService(dsconn *directoryservice.DirectoryService, d * } func enableDirectoryServiceSso(dsconn *directoryservice.DirectoryService, d *schema.ResourceData) error { - d.SetPartial("enable_sso") - if v, ok := d.GetOk("enable_sso"); ok && v.(bool) { log.Printf("[DEBUG] Enabling SSO for DS directory %q", d.Id()) if _, err := dsconn.EnableSso(&directoryservice.EnableSsoInput{ @@ -388,8 +386,6 @@ func resourceAwsDirectoryServiceDirectoryCreate(d *schema.ResourceData, meta int } if v, ok := d.GetOk("alias"); ok { - d.SetPartial("alias") - input := directoryservice.CreateAliasInput{ DirectoryId: aws.String(d.Id()), Alias: aws.String(v.(string)), From a95de61b85f6ca53ecaa54fc569d64e518bfbfc7 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:13:55 -0400 Subject: [PATCH 183/684] resource/aws_autoscaling_group: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12464) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_autoscaling_group.go:949:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_autoscaling_group.go:953:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_autoscaling_group.go:959:3: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSAutoScalingGroup_ALB_TargetGroups (221.26s) --- PASS: TestAccAWSAutoScalingGroup_ALB_TargetGroups_ELBCapacity (300.96s) --- PASS: TestAccAWSAutoScalingGroup_autoGeneratedName (82.26s) --- PASS: TestAccAWSAutoScalingGroup_basic (385.26s) --- PASS: TestAccAWSAutoScalingGroup_classicVpcZoneIdentifier (78.87s) --- PASS: TestAccAWSAutoScalingGroup_emptyAvailabilityZones (96.80s) --- PASS: TestAccAWSAutoScalingGroup_enablingMetrics (193.31s) --- PASS: TestAccAWSAutoScalingGroup_initialLifecycleHook (360.02s) --- PASS: TestAccAWSAutoScalingGroup_launchTemplate (73.68s) --- PASS: TestAccAWSAutoScalingGroup_LaunchTemplate_IAMInstanceProfile (55.71s) --- PASS: TestAccAWSAutoScalingGroup_launchTemplate_update (170.76s) --- PASS: TestAccAWSAutoScalingGroup_LoadBalancers (569.35s) --- PASS: TestAccAWSAutoScalingGroup_MaxInstanceLifetime (111.74s) --- PASS: TestAccAWSAutoScalingGroup_MixedInstancesPolicy (52.49s) --- PASS: TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_OnDemandAllocationStrategy (48.81s) --- PASS: TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_OnDemandBaseCapacity (145.14s) --- PASS: TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_OnDemandPercentageAboveBaseCapacity (80.84s) --- PASS: TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_SpotAllocationStrategy (45.67s) --- PASS: TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_SpotInstancePools (106.02s) --- PASS: TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_SpotMaxPrice (110.26s) --- PASS: TestAccAWSAutoScalingGroup_MixedInstancesPolicy_LaunchTemplate_LaunchTemplateSpecification_LaunchTemplateName (109.23s) --- PASS: TestAccAWSAutoScalingGroup_MixedInstancesPolicy_LaunchTemplate_LaunchTemplateSpecification_Version (81.39s) --- PASS: TestAccAWSAutoScalingGroup_MixedInstancesPolicy_LaunchTemplate_Override_InstanceType (81.21s) --- PASS: TestAccAWSAutoScalingGroup_MixedInstancesPolicy_LaunchTemplate_Override_WeightedCapacity (167.25s) --- PASS: TestAccAWSAutoScalingGroup_namePrefix (54.31s) --- PASS: TestAccAWSAutoScalingGroup_serviceLinkedRoleARN (164.35s) --- PASS: TestAccAWSAutoScalingGroup_suspendingProcesses (178.65s) --- PASS: TestAccAWSAutoScalingGroup_tags (215.41s) --- PASS: TestAccAWSAutoScalingGroup_TargetGroupArns (291.79s) --- PASS: TestAccAWSAutoScalingGroup_terminationPolicies (113.05s) --- PASS: TestAccAWSAutoScalingGroup_VpcUpdates (79.41s) --- PASS: TestAccAWSAutoScalingGroup_WithLoadBalancer (372.04s) --- PASS: TestAccAWSAutoScalingGroup_WithLoadBalancer_ToTargetGroup (353.81s) --- PASS: TestAccAWSAutoScalingGroup_withMetrics (173.70s) --- PASS: TestAccAWSAutoScalingGroup_withPlacementGroup (177.06s) ``` --- aws/resource_aws_autoscaling_group.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/aws/resource_aws_autoscaling_group.go b/aws/resource_aws_autoscaling_group.go index f7a1f82cffd..cea81ae1253 100644 --- a/aws/resource_aws_autoscaling_group.go +++ b/aws/resource_aws_autoscaling_group.go @@ -945,18 +945,9 @@ func resourceAwsAutoscalingGroupUpdate(d *schema.ResourceData, meta interface{}) return err } - if d.HasChange("tag") { - d.SetPartial("tag") - } - - if d.HasChange("tags") { - d.SetPartial("tags") - } - log.Printf("[DEBUG] AutoScaling Group update configuration: %#v", opts) _, err := conn.UpdateAutoScalingGroup(&opts) if err != nil { - d.Partial(true) return fmt.Errorf("Error updating Autoscaling group: %s", err) } From 4168e0d0348072284173efd391c3d96928742cb4 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:14:27 -0400 Subject: [PATCH 184/684] service/ec2: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12465) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_ami.go:414:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_ami.go:434:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_ami.go:437:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_ami_copy.go:218:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_ami_copy.go:220:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_ami_copy.go:221:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_ami_from_instance.go:200:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_ami_from_instance.go:202:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_ami_from_instance.go:203:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_default_network_acl.go:172:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_default_network_acl.go:244:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_ec2_client_vpn_endpoint.go:269:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_ec2_client_vpn_endpoint.go:337:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_instance.go:1217:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_instance.go:918:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_instance.go:927:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_instance.go:944:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_network_acl.go:254:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_network_acl.go:338:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_network_interface.go:264:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_network_interface.go:289:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_network_interface.go:330:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_network_interface.go:346:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_network_interface.go:388:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_network_interface.go:403:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_network_interface.go:417:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_network_interface.go:428:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_spot_fleet_request.go:1200:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_subnet.go:168:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_subnet.go:186:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_subnet.go:201:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_subnet.go:204:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_subnet.go:265:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_subnet.go:274:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_subnet.go:292:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_subnet.go:361:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_subnet.go:379:4: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_subnet.go:383:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_vpc.go:149:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_vpc.go:150:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:190:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:208:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:220:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:232:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:259:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:262:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_vpc.go:403:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_vpc.go:421:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:442:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:469:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:496:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:537:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:552:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:562:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc.go:565:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_vpc_endpoint_service.go:181:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_vpc_endpoint_service.go:205:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc_endpoint_service.go:218:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_vpc_endpoint_service.go:229:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSAMI_basic (78.71s) --- PASS: TestAccAWSAMI_disappears (57.61s) --- PASS: TestAccAWSAMI_snapshotSize (64.52s) --- PASS: TestAccAWSAMI_tags (93.26s) --- PASS: TestAccAWSAMICopy_basic (365.47s) --- PASS: TestAccAWSAMICopy_Description (405.15s) --- PASS: TestAccAWSAMICopy_EnaSupport (391.75s) --- PASS: TestAccAWSAMICopy_tags (419.90s) --- PASS: TestAccAWSAMIFromInstance_basic (369.65s) --- PASS: TestAccAWSAMIFromInstance_tags (421.26s) --- PASS: TestAccAWSDefaultNetworkAcl_basic (30.84s) --- PASS: TestAccAWSDefaultNetworkAcl_basicIpv6Vpc (40.38s) --- PASS: TestAccAWSDefaultNetworkAcl_deny_ingress (38.32s) --- PASS: TestAccAWSDefaultNetworkAcl_SubnetReassign (83.61s) --- PASS: TestAccAWSDefaultNetworkAcl_SubnetRemoval (74.22s) --- PASS: TestAccAWSDefaultNetworkAcl_withIpv6Ingress (33.89s) --- PASS: TestAccAwsEc2ClientVpnEndpoint_basic (22.69s) --- PASS: TestAccAwsEc2ClientVpnEndpoint_disappears (18.67s) --- PASS: TestAccAwsEc2ClientVpnEndpoint_msAD (1678.33s) --- PASS: TestAccAwsEc2ClientVpnEndpoint_splitTunnel (36.58s) --- PASS: TestAccAwsEc2ClientVpnEndpoint_tags (48.82s) --- PASS: TestAccAwsEc2ClientVpnEndpoint_withDNSServers (36.09s) --- PASS: TestAccAwsEc2ClientVpnEndpoint_withLogGroup (42.49s) --- PASS: TestAccAWSENI_attached (243.84s) --- PASS: TestAccAWSENI_basic (48.62s) --- PASS: TestAccAWSENI_computedIPs (40.94s) --- PASS: TestAccAWSENI_disappears (39.87s) --- PASS: TestAccAWSENI_ignoreExternalAttachment (114.17s) --- PASS: TestAccAWSENI_PrivateIpsCount (112.43s) --- PASS: TestAccAWSENI_sourceDestCheck (44.73s) --- PASS: TestAccAWSENI_updatedDescription (70.49s) --- PASS: TestAccAWSInstance_addSecondaryInterface (101.85s) --- PASS: TestAccAWSInstance_addSecurityGroupNetworkInterface (119.12s) --- PASS: TestAccAWSInstance_associatePublic_defaultPrivate (72.41s) --- PASS: TestAccAWSInstance_associatePublic_defaultPublic (82.27s) --- PASS: TestAccAWSInstance_associatePublic_explicitPrivate (89.32s) --- PASS: TestAccAWSInstance_associatePublic_explicitPublic (80.62s) --- PASS: TestAccAWSInstance_associatePublic_overridePrivate (91.49s) --- PASS: TestAccAWSInstance_associatePublic_overridePublic (72.13s) --- PASS: TestAccAWSInstance_associatePublicIPAndPrivateIP (81.44s) --- PASS: TestAccAWSInstance_basic (183.70s) --- PASS: TestAccAWSInstance_blockDevices (109.47s) --- PASS: TestAccAWSInstance_changeInstanceType (162.79s) --- PASS: TestAccAWSInstance_CreditSpecification_Empty_NonBurstable (325.46s) --- PASS: TestAccAWSInstance_creditSpecification_isNotAppliedToNonBurstable (101.10s) --- PASS: TestAccAWSInstance_creditSpecification_standardCpuCredits (103.72s) --- PASS: TestAccAWSInstance_creditSpecification_standardCpuCredits_t2Tot3Taint (400.62s) --- PASS: TestAccAWSInstance_creditSpecification_unknownCpuCredits_t2 (92.50s) --- PASS: TestAccAWSInstance_creditSpecification_unknownCpuCredits_t3 (285.59s) --- PASS: TestAccAWSInstance_creditSpecification_unlimitedCpuCredits (103.30s) --- PASS: TestAccAWSInstance_creditSpecification_unlimitedCpuCredits_t2Tot3Taint (379.85s) --- PASS: TestAccAWSInstance_creditSpecification_unspecifiedDefaultsToStandard (82.16s) --- PASS: TestAccAWSInstance_CreditSpecification_UnspecifiedToEmpty_NonBurstable (125.59s) --- PASS: TestAccAWSInstance_creditSpecification_updateCpuCredits (96.78s) --- PASS: TestAccAWSInstance_creditSpecificationT3_standardCpuCredits (84.68s) --- PASS: TestAccAWSInstance_creditSpecificationT3_unlimitedCpuCredits (62.70s) --- PASS: TestAccAWSInstance_creditSpecificationT3_unspecifiedDefaultsToUnlimited (326.84s) --- PASS: TestAccAWSInstance_creditSpecificationT3_updateCpuCredits (106.79s) --- PASS: TestAccAWSInstance_disableApiTermination (115.81s) --- PASS: TestAccAWSInstance_disappears (241.97s) --- PASS: TestAccAWSInstance_EbsBlockDevice_KmsKeyArn (148.32s) --- PASS: TestAccAWSInstance_forceNewAndTagsDrift (120.55s) --- PASS: TestAccAWSInstance_getPasswordData_falseToTrue (223.75s) --- PASS: TestAccAWSInstance_getPasswordData_trueToFalse (241.06s) --- PASS: TestAccAWSInstance_GP2IopsDevice (90.09s) --- PASS: TestAccAWSInstance_GP2WithIopsValue (113.39s) --- PASS: TestAccAWSInstance_hibernation (169.65s) --- PASS: TestAccAWSInstance_inDefaultVpcBySgId (77.63s) --- PASS: TestAccAWSInstance_inDefaultVpcBySgName (79.23s) --- PASS: TestAccAWSInstance_instanceProfileChange (208.56s) --- PASS: TestAccAWSInstance_ipv6_supportAddressCount (81.76s) --- PASS: TestAccAWSInstance_ipv6_supportAddressCountWithIpv4 (91.39s) --- PASS: TestAccAWSInstance_ipv6AddressCountAndSingleAddressCausesError (13.22s) --- PASS: TestAccAWSInstance_keyPairCheck (67.97s) --- PASS: TestAccAWSInstance_multipleRegions (260.89s) --- PASS: TestAccAWSInstance_NetworkInstanceRemovingAllSecurityGroups (91.04s) --- PASS: TestAccAWSInstance_NetworkInstanceSecurityGroups (163.04s) --- PASS: TestAccAWSInstance_NetworkInstanceVPCSecurityGroupIDs (83.27s) --- PASS: TestAccAWSInstance_noAMIEphemeralDevices (80.32s) --- PASS: TestAccAWSInstance_placementGroup (66.52s) --- PASS: TestAccAWSInstance_primaryNetworkInterface (84.04s) --- PASS: TestAccAWSInstance_primaryNetworkInterfaceSourceDestCheck (74.50s) --- PASS: TestAccAWSInstance_privateIP (81.69s) --- PASS: TestAccAWSInstance_RootBlockDevice_KmsKeyArn (173.75s) --- PASS: TestAccAWSInstance_rootBlockDeviceMismatch (109.59s) --- PASS: TestAccAWSInstance_rootInstanceStore (150.64s) --- PASS: TestAccAWSInstance_sourceDestCheck (126.46s) --- PASS: TestAccAWSInstance_tags (147.76s) --- PASS: TestAccAWSInstance_UserData_EmptyStringToUnspecified (91.50s) --- PASS: TestAccAWSInstance_UserData_UnspecifiedToEmptyString (91.89s) --- PASS: TestAccAWSInstance_userDataBase64 (239.10s) --- PASS: TestAccAWSInstance_volumeTags (152.07s) --- PASS: TestAccAWSInstance_volumeTagsComputed (142.92s) --- PASS: TestAccAWSInstance_volumeTagsComputed (146.73s) --- PASS: TestAccAWSInstance_vpc (79.83s) --- PASS: TestAccAWSInstance_withIamInstanceProfile (117.42s) --- PASS: TestAccAWSNetworkAcl_basic (38.51s) --- PASS: TestAccAWSNetworkAcl_CaseSensitivityNoChanges (46.29s) --- PASS: TestAccAWSNetworkAcl_disappears (33.69s) --- PASS: TestAccAWSNetworkAcl_Egress_ConfigMode (82.91s) --- PASS: TestAccAWSNetworkAcl_EgressAndIngressRules (38.77s) --- PASS: TestAccAWSNetworkAcl_espProtocol (36.38s) --- PASS: TestAccAWSNetworkAcl_Ingress_ConfigMode (80.27s) --- PASS: TestAccAWSNetworkAcl_ipv6ICMPRules (31.10s) --- PASS: TestAccAWSNetworkAcl_ipv6Rules (49.98s) --- PASS: TestAccAWSNetworkAcl_ipv6VpcRules (34.61s) --- PASS: TestAccAWSNetworkAcl_OnlyEgressRules (43.51s) --- PASS: TestAccAWSNetworkAcl_OnlyIngressRules_basic (47.89s) --- PASS: TestAccAWSNetworkAcl_OnlyIngressRules_update (71.35s) --- PASS: TestAccAWSNetworkAcl_SubnetChange (74.18s) --- PASS: TestAccAWSNetworkAcl_Subnets (74.71s) --- PASS: TestAccAWSNetworkAcl_SubnetsDelete (82.26s) --- PASS: TestAccAWSSpotFleetRequest_associatePublicIpAddress (372.99s) --- PASS: TestAccAWSSpotFleetRequest_basic (231.12s) --- PASS: TestAccAWSSpotFleetRequest_changePriceForcesNewRequest (582.29s) --- PASS: TestAccAWSSpotFleetRequest_diversifiedAllocation (350.94s) --- PASS: TestAccAWSSpotFleetRequest_fleetType (241.77s) --- PASS: TestAccAWSSpotFleetRequest_iamInstanceProfileArn (272.75s) --- PASS: TestAccAWSSpotFleetRequest_instanceInterruptionBehavior (242.11s) --- PASS: TestAccAWSSpotFleetRequest_LaunchSpecification_EbsBlockDevice_KmsKeyId (147.02s) --- PASS: TestAccAWSSpotFleetRequest_LaunchSpecification_RootBlockDevice_KmsKeyId (146.75s) --- PASS: TestAccAWSSpotFleetRequest_lowestPriceAzInGivenList (265.13s) --- PASS: TestAccAWSSpotFleetRequest_lowestPriceAzOrSubnetInRegion (355.97s) --- PASS: TestAccAWSSpotFleetRequest_lowestPriceSubnetInGivenList (264.26s) --- PASS: TestAccAWSSpotFleetRequest_multipleInstancePools (286.87s) --- PASS: TestAccAWSSpotFleetRequest_multipleInstanceTypesInSameAz (297.89s) --- PASS: TestAccAWSSpotFleetRequest_multipleInstanceTypesInSameSubnet (264.21s) --- PASS: TestAccAWSSpotFleetRequest_overriddingSpotPrice (261.23s) --- PASS: TestAccAWSSpotFleetRequest_placementTenancyAndGroup (60.68s) --- PASS: TestAccAWSSpotFleetRequest_updateExcessCapacityTerminationPolicy (554.15s) --- PASS: TestAccAWSSpotFleetRequest_updateTargetCapacity (750.82s) --- PASS: TestAccAWSSpotFleetRequest_withEBSDisk (333.68s) --- PASS: TestAccAWSSpotFleetRequest_WithELBs (345.96s) --- PASS: TestAccAWSSpotFleetRequest_withoutSpotPrice (266.18s) --- PASS: TestAccAWSSpotFleetRequest_withTags (254.92s) --- PASS: TestAccAWSSpotFleetRequest_WithTargetGroups (430.77s) --- PASS: TestAccAWSSpotFleetRequest_withWeightedCapacity (295.99s) --- PASS: TestAccAWSSubnet_availabilityZoneId (30.67s) --- PASS: TestAccAWSSubnet_basic (30.59s) --- PASS: TestAccAWSSubnet_enableIpv6 (50.96s) --- PASS: TestAccAWSSubnet_ignoreTags (56.29s) --- PASS: TestAccAWSSubnet_ipv6 (77.14s) --- PASS: TestAccAWSVpc_AssignGeneratedIpv6CidrBlock (73.30s) --- PASS: TestAccAWSVpc_basic (29.97s) --- PASS: TestAccAWSVpc_bothDnsOptionsSet (33.54s) --- PASS: TestAccAWSVpc_classiclinkDnsSupportOptionSet (31.49s) --- PASS: TestAccAWSVpc_classiclinkOptionSet (32.05s) --- PASS: TestAccAWSVpc_coreMismatchedDiffs (25.26s) --- PASS: TestAccAWSVpc_DisabledDnsSupport (31.22s) --- PASS: TestAccAWSVpc_disappears (16.78s) --- PASS: TestAccAWSVpc_ignoreTags (50.85s) --- PASS: TestAccAWSVpc_tags (51.10s) --- PASS: TestAccAWSVpc_Tenancy (74.07s) --- PASS: TestAccAWSVpc_update (44.39s) --- PASS: TestAccAWSVpcEndpointService_AllowedPrincipalsAndTags (286.82s) --- PASS: TestAccAWSVpcEndpointService_basic (266.19s) --- PASS: TestAccAWSVpcEndpointService_removed (303.85s) ``` --- aws/resource_aws_ami.go | 5 ---- aws/resource_aws_ami_copy.go | 3 -- aws/resource_aws_ami_from_instance.go | 3 -- aws/resource_aws_default_network_acl.go | 2 -- aws/resource_aws_ec2_client_vpn_endpoint.go | 3 -- aws/resource_aws_instance.go | 8 ----- aws/resource_aws_network_acl.go | 2 -- aws/resource_aws_network_interface.go | 15 ---------- aws/resource_aws_spot_fleet_request.go | 2 -- aws/resource_aws_subnet.go | 20 ------------- aws/resource_aws_vpc.go | 33 --------------------- aws/resource_aws_vpc_endpoint_service.go | 6 ---- 12 files changed, 102 deletions(-) diff --git a/aws/resource_aws_ami.go b/aws/resource_aws_ami.go index 81bd1322abb..55be5589059 100644 --- a/aws/resource_aws_ami.go +++ b/aws/resource_aws_ami.go @@ -411,8 +411,6 @@ func resourceAwsAmiRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsAmiUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*AWSClient).ec2conn - d.Partial(true) - if d.HasChange("tags") { o, n := d.GetChange("tags") @@ -431,11 +429,8 @@ func resourceAwsAmiUpdate(d *schema.ResourceData, meta interface{}) error { if err != nil { return err } - d.SetPartial("description") } - d.Partial(false) - return resourceAwsAmiRead(d, meta) } diff --git a/aws/resource_aws_ami_copy.go b/aws/resource_aws_ami_copy.go index 238bbfe1d91..f20148aec4b 100644 --- a/aws/resource_aws_ami_copy.go +++ b/aws/resource_aws_ami_copy.go @@ -215,10 +215,7 @@ func resourceAwsAmiCopyCreate(d *schema.ResourceData, meta interface{}) error { id := *res.ImageId d.SetId(id) - d.Partial(true) // make sure we record the id even if the rest of this gets interrupted d.Set("manage_ebs_snapshots", true) - d.SetPartial("manage_ebs_snapshots") - d.Partial(false) if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { if err := keyvaluetags.Ec2UpdateTags(client, id, nil, v); err != nil { diff --git a/aws/resource_aws_ami_from_instance.go b/aws/resource_aws_ami_from_instance.go index fd9d4013426..00b008ba65e 100644 --- a/aws/resource_aws_ami_from_instance.go +++ b/aws/resource_aws_ami_from_instance.go @@ -197,10 +197,7 @@ func resourceAwsAmiFromInstanceCreate(d *schema.ResourceData, meta interface{}) id := *res.ImageId d.SetId(id) - d.Partial(true) // make sure we record the id even if the rest of this gets interrupted d.Set("manage_ebs_snapshots", true) - d.SetPartial("manage_ebs_snapshots") - d.Partial(false) if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { if err := keyvaluetags.Ec2UpdateTags(client, id, nil, v); err != nil { diff --git a/aws/resource_aws_default_network_acl.go b/aws/resource_aws_default_network_acl.go index 80b5c86b41b..b7c376f2417 100644 --- a/aws/resource_aws_default_network_acl.go +++ b/aws/resource_aws_default_network_acl.go @@ -169,7 +169,6 @@ func resourceAwsDefaultNetworkAclCreate(d *schema.ResourceData, meta interface{} func resourceAwsDefaultNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - d.Partial(true) if d.HasChange("ingress") { err := updateNetworkAclEntries(d, "ingress", conn) @@ -241,7 +240,6 @@ func resourceAwsDefaultNetworkAclUpdate(d *schema.ResourceData, meta interface{} } } - d.Partial(false) // Re-use the exiting Network ACL Resources READ method return resourceAwsNetworkAclRead(d, meta) } diff --git a/aws/resource_aws_ec2_client_vpn_endpoint.go b/aws/resource_aws_ec2_client_vpn_endpoint.go index cb1e7cca2ef..3034f0bcf16 100644 --- a/aws/resource_aws_ec2_client_vpn_endpoint.go +++ b/aws/resource_aws_ec2_client_vpn_endpoint.go @@ -266,8 +266,6 @@ func resourceAwsEc2ClientVpnEndpointDelete(d *schema.ResourceData, meta interfac func resourceAwsEc2ClientVpnEndpointUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - d.Partial(true) - req := &ec2.ModifyClientVpnEndpointInput{ ClientVpnEndpointId: aws.String(d.Id()), } @@ -334,7 +332,6 @@ func resourceAwsEc2ClientVpnEndpointUpdate(d *schema.ResourceData, meta interfac } } - d.Partial(false) return resourceAwsEc2ClientVpnEndpointRead(d, meta) } diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index d35ac0db122..6fecb4179f9 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -949,16 +949,12 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - d.Partial(true) - if d.HasChange("tags") && !d.IsNewResource() { o, n := d.GetChange("tags") if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil { return fmt.Errorf("error updating tags: %s", err) } - - d.SetPartial("tags") } if d.HasChange("volume_tags") && !d.IsNewResource() { @@ -974,8 +970,6 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error updating volume_tags (%s): %s", volumeId, err) } } - - d.SetPartial("volume_tags") } if d.HasChange("iam_instance_profile") && !d.IsNewResource() { @@ -1269,8 +1263,6 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { // TODO(mitchellh): wait for the attributes we modified to // persist the change... - d.Partial(false) - return resourceAwsInstanceRead(d, meta) } diff --git a/aws/resource_aws_network_acl.go b/aws/resource_aws_network_acl.go index 6b2ee541a76..6456a98daed 100644 --- a/aws/resource_aws_network_acl.go +++ b/aws/resource_aws_network_acl.go @@ -251,7 +251,6 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - d.Partial(true) if d.HasChange("ingress") { err := updateNetworkAclEntries(d, "ingress", conn) @@ -335,7 +334,6 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error } } - d.Partial(false) return resourceAwsNetworkAclRead(d, meta) } diff --git a/aws/resource_aws_network_interface.go b/aws/resource_aws_network_interface.go index b568909a978..87563c23b05 100644 --- a/aws/resource_aws_network_interface.go +++ b/aws/resource_aws_network_interface.go @@ -261,7 +261,6 @@ func resourceAwsNetworkInterfaceDetach(oa *schema.Set, meta interface{}, eniId s func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - d.Partial(true) if d.HasChange("attachment") { oa, na := d.GetChange("attachment") @@ -285,8 +284,6 @@ func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Error attaching ENI: %s", attach_err) } } - - d.SetPartial("attachment") } if d.HasChange("private_ips") { @@ -326,8 +323,6 @@ func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Failure to assign Private IPs: %s", err) } } - - d.SetPartial("private_ips") } // ModifyNetworkInterfaceAttribute needs to be called after creating an ENI @@ -342,8 +337,6 @@ func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) if err != nil { return fmt.Errorf("Failure updating ENI: %s", err) } - - d.SetPartial("source_dest_check") } if d.HasChange("private_ips_count") && !d.IsNewResource() { @@ -384,8 +377,6 @@ func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Failure to unassign Private IPs: %s", err) } } - - d.SetPartial("private_ips_count") } } @@ -399,8 +390,6 @@ func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) if err != nil { return fmt.Errorf("Failure updating ENI: %s", err) } - - d.SetPartial("security_groups") } if d.HasChange("description") { @@ -413,8 +402,6 @@ func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) if err != nil { return fmt.Errorf("Failure updating ENI: %s", err) } - - d.SetPartial("description") } if d.HasChange("tags") { @@ -425,8 +412,6 @@ func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) } } - d.Partial(false) - return resourceAwsNetworkInterfaceRead(d, meta) } diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index ecc4d447852..5a33503b830 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -1197,8 +1197,6 @@ func resourceAwsSpotFleetRequestUpdate(d *schema.ResourceData, meta interface{}) // http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifySpotFleetRequest.html conn := meta.(*AWSClient).ec2conn - d.Partial(true) - req := &ec2.ModifySpotFleetRequestInput{ SpotFleetRequestId: aws.String(d.Id()), } diff --git a/aws/resource_aws_subnet.go b/aws/resource_aws_subnet.go index 4615e89eee2..bfd1bf2a695 100644 --- a/aws/resource_aws_subnet.go +++ b/aws/resource_aws_subnet.go @@ -164,8 +164,6 @@ func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("error adding tags: %s", err) } - - d.SetPartial("tags") } // You cannot modify multiple subnet attributes in the same request. @@ -182,8 +180,6 @@ func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error { if _, err := conn.ModifySubnetAttribute(input); err != nil { return fmt.Errorf("error enabling EC2 Subnet (%s) assign IPv6 address on creation: %s", d.Id(), err) } - - d.SetPartial("assign_ipv6_address_on_creation") } if d.Get("map_public_ip_on_launch").(bool) { @@ -197,12 +193,8 @@ func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error { if _, err := conn.ModifySubnetAttribute(input); err != nil { return fmt.Errorf("error enabling EC2 Subnet (%s) map public IP on launch: %s", d.Id(), err) } - - d.SetPartial("map_public_ip_on_launch") } - d.Partial(false) - return resourceAwsSubnetRead(d, meta) } @@ -262,16 +254,12 @@ func resourceAwsSubnetRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - d.Partial(true) - if d.HasChange("tags") { o, n := d.GetChange("tags") if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil { return fmt.Errorf("error updating EC2 Subnet (%s) tags: %s", d.Id(), err) } - - d.SetPartial("tags") } if d.HasChange("map_public_ip_on_launch") { @@ -288,8 +276,6 @@ func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error { if err != nil { return err - } else { - d.SetPartial("map_public_ip_on_launch") } } @@ -357,8 +343,6 @@ func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error { "Error waiting for IPv6 CIDR (%s) to become associated: %s", d.Id(), err) } - - d.SetPartial("ipv6_cidr_block") } if d.HasChange("assign_ipv6_address_on_creation") { @@ -375,13 +359,9 @@ func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error { if err != nil { return err - } else { - d.SetPartial("assign_ipv6_address_on_creation") } } - d.Partial(false) - return resourceAwsSubnetRead(d, meta) } diff --git a/aws/resource_aws_vpc.go b/aws/resource_aws_vpc.go index 82de72328d0..8485d1570a7 100644 --- a/aws/resource_aws_vpc.go +++ b/aws/resource_aws_vpc.go @@ -145,10 +145,6 @@ func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error { d.SetId(*vpc.VpcId) log.Printf("[INFO] VPC ID: %s", d.Id()) - // Set partial mode and say that we setup the cidr block - d.Partial(true) - d.SetPartial("cidr_block") - // Wait for the VPC to become available log.Printf( "[DEBUG] Waiting for VPC (%s) to become available", @@ -186,8 +182,6 @@ func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error { if _, err := conn.ModifyVpcAttribute(input); err != nil { return fmt.Errorf("error enabling VPC (%s) DNS hostnames: %s", d.Id(), err) } - - d.SetPartial("enable_dns_hostnames") } // By default, only the enableDnsSupport attribute is set to true in a VPC created any other way. @@ -204,8 +198,6 @@ func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error { if _, err := conn.ModifyVpcAttribute(input); err != nil { return fmt.Errorf("error disabling VPC (%s) DNS support: %s", d.Id(), err) } - - d.SetPartial("enable_dns_support") } if d.Get("enable_classiclink").(bool) { @@ -216,8 +208,6 @@ func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error { if _, err := conn.EnableVpcClassicLink(input); err != nil { return fmt.Errorf("error enabling VPC (%s) ClassicLink: %s", d.Id(), err) } - - d.SetPartial("enable_classiclink") } if d.Get("enable_classiclink_dns_support").(bool) { @@ -228,8 +218,6 @@ func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error { if _, err := conn.EnableVpcClassicLinkDnsSupport(input); err != nil { return fmt.Errorf("error enabling VPC (%s) ClassicLink DNS support: %s", d.Id(), err) } - - d.SetPartial("enable_classiclink_dns_support") } if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { @@ -255,12 +243,8 @@ func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("error adding tags: %s", err) } - - d.SetPartial("tags") } - d.Partial(false) - return resourceAwsVpcRead(d, meta) } @@ -399,8 +383,6 @@ func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - // Turn on partial mode - d.Partial(true) vpcid := d.Id() if d.HasChange("enable_dns_hostnames") { val := d.Get("enable_dns_hostnames").(bool) @@ -417,8 +399,6 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { if _, err := conn.ModifyVpcAttribute(modifyOpts); err != nil { return err } - - d.SetPartial("enable_dns_hostnames") } _, hasEnableDnsSupportOption := d.GetOk("enable_dns_support") @@ -438,8 +418,6 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { if _, err := conn.ModifyVpcAttribute(modifyOpts); err != nil { return err } - - d.SetPartial("enable_dns_support") } if d.HasChange("enable_classiclink") { @@ -465,8 +443,6 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { return err } } - - d.SetPartial("enable_classiclink") } if d.HasChange("enable_classiclink_dns_support") { @@ -492,8 +468,6 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { return err } } - - d.SetPartial("enable_classiclink_dns_support") } if d.HasChange("assign_generated_ipv6_cidr_block") { @@ -533,8 +507,6 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error waiting for EC2 VPC (%s) IPv6 CIDR to become disassociated: %s", d.Id(), err) } } - - d.SetPartial("assign_generated_ipv6_cidr_block") } if d.HasChange("instance_tenancy") { @@ -548,8 +520,6 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { if _, err := conn.ModifyVpcTenancy(modifyOpts); err != nil { return err } - - d.SetPartial("instance_tenancy") } if d.HasChange("tags") { @@ -558,11 +528,8 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil { return fmt.Errorf("error updating tags: %s", err) } - - d.SetPartial("tags") } - d.Partial(false) return resourceAwsVpcRead(d, meta) } diff --git a/aws/resource_aws_vpc_endpoint_service.go b/aws/resource_aws_vpc_endpoint_service.go index 823ed654216..06e0d4600d6 100644 --- a/aws/resource_aws_vpc_endpoint_service.go +++ b/aws/resource_aws_vpc_endpoint_service.go @@ -178,7 +178,6 @@ func resourceAwsVpcEndpointServiceRead(d *schema.ResourceData, meta interface{}) func resourceAwsVpcEndpointServiceUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - d.Partial(true) svcId := d.Id() modifyCfgReq := &ec2.ModifyVpcEndpointServiceConfigurationInput{ @@ -201,8 +200,6 @@ func resourceAwsVpcEndpointServiceUpdate(d *schema.ResourceData, meta interface{ if err := vpcEndpointServiceWaitUntilAvailable(d, conn); err != nil { return err } - - d.SetPartial("network_load_balancer_arns") } modifyPermReq := &ec2.ModifyVpcEndpointServicePermissionsInput{ @@ -214,8 +211,6 @@ func resourceAwsVpcEndpointServiceUpdate(d *schema.ResourceData, meta interface{ if _, err := conn.ModifyVpcEndpointServicePermissions(modifyPermReq); err != nil { return fmt.Errorf("Error modifying VPC Endpoint Service permissions: %s", err.Error()) } - - d.SetPartial("allowed_principals") } if d.HasChange("tags") { @@ -226,7 +221,6 @@ func resourceAwsVpcEndpointServiceUpdate(d *schema.ResourceData, meta interface{ } } - d.Partial(false) return resourceAwsVpcEndpointServiceRead(d, meta) } From 6ea97beaf27bb2d3d68aad48d87dbf53054dac87 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:15:26 -0400 Subject: [PATCH 185/684] resource/aws_lambda_function: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12466) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_lambda_function.go:674:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_lambda_function.go:841:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lambda_function.go:842:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lambda_function.go:843:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lambda_function.go:844:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lambda_function.go:845:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lambda_function.go:884:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lambda_function.go:885:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lambda_function.go:886:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lambda_function.go:887:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lambda_function.go:888:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lambda_function.go:931:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSLambdaFunction_basic (64.06s) --- PASS: TestAccAWSLambdaFunction_concurrency (493.45s) --- PASS: TestAccAWSLambdaFunction_concurrencyCycle (529.28s) --- PASS: TestAccAWSLambdaFunction_DeadLetterConfig (536.23s) --- PASS: TestAccAWSLambdaFunction_DeadLetterConfigUpdated (148.43s) --- PASS: TestAccAWSLambdaFunction_disappears (94.71s) --- PASS: TestAccAWSLambdaFunction_EmptyVpcConfig (68.70s) --- PASS: TestAccAWSLambdaFunction_encryptedEnvVariables (561.28s) --- PASS: TestAccAWSLambdaFunction_envVariables (579.67s) --- PASS: TestAccAWSLambdaFunction_expectFilenameAndS3Attributes (24.88s) --- PASS: TestAccAWSLambdaFunction_KmsKeyArn_NoEnvironmentVariables (151.22s) --- PASS: TestAccAWSLambdaFunction_Layers (514.42s) --- PASS: TestAccAWSLambdaFunction_LayersUpdate (170.54s) --- PASS: TestAccAWSLambdaFunction_localUpdate (523.11s) --- PASS: TestAccAWSLambdaFunction_localUpdate_nameOnly (486.27s) --- PASS: TestAccAWSLambdaFunction_nilDeadLetterConfig (492.13s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_java11 (83.49s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_java8 (78.16s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_NodeJs10x (514.99s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_NodeJs12x (513.46s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_noRuntime (2.32s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_provided (71.48s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python27 (56.73s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python36 (97.54s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python37 (50.94s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python38 (89.93s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_ruby25 (109.39s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_ruby27 (117.27s) --- PASS: TestAccAWSLambdaFunction_s3 (44.11s) --- PASS: TestAccAWSLambdaFunction_s3Update_basic (74.22s) --- PASS: TestAccAWSLambdaFunction_s3Update_unversioned (68.76s) --- PASS: TestAccAWSLambdaFunction_tags (140.89s) --- PASS: TestAccAWSLambdaFunction_tracingConfig (535.70s) --- PASS: TestAccAWSLambdaFunction_updateRuntime (511.04s) --- PASS: TestAccAWSLambdaFunction_versioned (514.26s) --- PASS: TestAccAWSLambdaFunction_versionedUpdate (607.45s) --- PASS: TestAccAWSLambdaFunction_VPC (2148.53s) --- PASS: TestAccAWSLambdaFunction_VPC_withInvocation (1848.27s) --- PASS: TestAccAWSLambdaFunction_VpcConfig_ProperIamDependencies (1568.41s) --- PASS: TestAccAWSLambdaFunction_VPCRemoval (2046.17s) --- PASS: TestAccAWSLambdaFunction_VPCUpdate (2526.06s) ``` --- aws/resource_aws_lambda_function.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/aws/resource_aws_lambda_function.go b/aws/resource_aws_lambda_function.go index 020f1d7440f..c82647cfecf 100644 --- a/aws/resource_aws_lambda_function.go +++ b/aws/resource_aws_lambda_function.go @@ -671,8 +671,6 @@ func needsFunctionCodeUpdate(d resourceDiffer) bool { func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).lambdaconn - d.Partial(true) - arn := d.Get("arn").(string) if d.HasChange("tags") { o, n := d.GetChange("tags") @@ -837,12 +835,6 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e if err := waitForLambdaFunctionUpdate(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { return fmt.Errorf("error waiting for Lambda Function (%s) update: %s", d.Id(), err) } - - d.SetPartial("description") - d.SetPartial("handler") - d.SetPartial("memory_size") - d.SetPartial("role") - d.SetPartial("timeout") } codeUpdate := needsFunctionCodeUpdate(d) @@ -880,12 +872,6 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e if err != nil { return fmt.Errorf("Error modifying Lambda Function Code %s: %s", d.Id(), err) } - - d.SetPartial("filename") - d.SetPartial("source_code_hash") - d.SetPartial("s3_bucket") - d.SetPartial("s3_key") - d.SetPartial("s3_object_version") } if d.HasChange("reserved_concurrent_executions") { @@ -928,8 +914,6 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e } } - d.Partial(false) - return resourceAwsLambdaFunctionRead(d, meta) } From 31eccb028898018a3e71e87355bea9abaf5dd187 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:15:54 -0400 Subject: [PATCH 186/684] resource/aws_api_gateway_stage: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12467) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_api_gateway_stage.go:134:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_api_gateway_stage.go:178:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:179:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:180:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:181:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:182:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:183:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:205:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:206:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:207:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_api_gateway_stage.go:291:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_api_gateway_stage.go:398:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:399:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:400:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:401:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:402:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:428:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:429:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_api_gateway_stage.go:430:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSAPIGatewayStage_accessLogSettings (260.87s) --- PASS: TestAccAWSAPIGatewayStage_accessLogSettings_kinesis (388.36s) --- PASS: TestAccAWSAPIGatewayStage_basic (469.04s) ``` --- aws/resource_aws_api_gateway_stage.go | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/aws/resource_aws_api_gateway_stage.go b/aws/resource_aws_api_gateway_stage.go index c3dbf58b23a..eb68a42cd45 100644 --- a/aws/resource_aws_api_gateway_stage.go +++ b/aws/resource_aws_api_gateway_stage.go @@ -131,8 +131,6 @@ func resourceAwsApiGatewayStage() *schema.Resource { func resourceAwsApiGatewayStageCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayconn - d.Partial(true) - input := apigateway.CreateStageInput{ RestApiId: aws.String(d.Get("rest_api_id").(string)), StageName: aws.String(d.Get("stage_name").(string)), @@ -175,13 +173,6 @@ func resourceAwsApiGatewayStageCreate(d *schema.ResourceData, meta interface{}) d.SetId(fmt.Sprintf("ags-%s-%s", d.Get("rest_api_id").(string), d.Get("stage_name").(string))) - d.SetPartial("rest_api_id") - d.SetPartial("stage_name") - d.SetPartial("deployment_id") - d.SetPartial("description") - d.SetPartial("variables") - d.SetPartial("xray_tracing_enabled") - if waitForCache && *out.CacheClusterStatus != apigateway.CacheClusterStatusNotAvailable { stateConf := &resource.StateChangeConf{ Pending: []string{ @@ -202,10 +193,6 @@ func resourceAwsApiGatewayStageCreate(d *schema.ResourceData, meta interface{}) } } - d.SetPartial("cache_cluster_enabled") - d.SetPartial("cache_cluster_size") - d.Partial(false) - if _, ok := d.GetOk("client_certificate_id"); ok { return resourceAwsApiGatewayStageUpdate(d, meta) } @@ -288,8 +275,6 @@ func resourceAwsApiGatewayStageRead(d *schema.ResourceData, meta interface{}) er func resourceAwsApiGatewayStageUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).apigatewayconn - d.Partial(true) - stageArn := arn.ARN{ Partition: meta.(*AWSClient).partition, Region: meta.(*AWSClient).region, @@ -395,12 +380,6 @@ func resourceAwsApiGatewayStageUpdate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Updating API Gateway Stage failed: %s", err) } - d.SetPartial("client_certificate_id") - d.SetPartial("deployment_id") - d.SetPartial("description") - d.SetPartial("xray_tracing_enabled") - d.SetPartial("variables") - if waitForCache && *out.CacheClusterStatus != apigateway.CacheClusterStatusNotAvailable { stateConf := &resource.StateChangeConf{ Pending: []string{ @@ -425,10 +404,6 @@ func resourceAwsApiGatewayStageUpdate(d *schema.ResourceData, meta interface{}) } } - d.SetPartial("cache_cluster_enabled") - d.SetPartial("cache_cluster_size") - d.Partial(false) - return resourceAwsApiGatewayStageRead(d, meta) } From 4094649e848cca2e72668683b14d99831edf0110 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:16:16 -0400 Subject: [PATCH 187/684] resource/aws_lb_listener: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12468) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_lb_listener_rule.go:1083:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lb_listener_rule.go:1093:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_lb_listener_rule.go:1107:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_lb_listener_rule.go:931:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_lb_listener_rule.go:948:3: R008: deprecated (schema.ResourceData).SetPartial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSLBListenerRule_Action_Order (192.70s) --- PASS: TestAccAWSLBListenerRule_Action_Order_Recreates (223.40s) --- PASS: TestAccAWSLBListenerRule_basic (267.91s) --- PASS: TestAccAWSLBListenerRule_changeListenerRuleArnForcesNew (216.77s) --- PASS: TestAccAWSLBListenerRule_cognito (211.46s) --- PASS: TestAccAWSLBListenerRule_conditionAttributesCount (29.28s) --- PASS: TestAccAWSLBListenerRule_conditionHostHeader (191.30s) --- PASS: TestAccAWSLBListenerRule_conditionHostHeader_deprecated (190.31s) --- PASS: TestAccAWSLBListenerRule_conditionHttpHeader (181.36s) --- PASS: TestAccAWSLBListenerRule_conditionHttpHeader_invalid (2.67s) --- PASS: TestAccAWSLBListenerRule_conditionHttpRequestMethod (180.78s) --- PASS: TestAccAWSLBListenerRule_conditionMultiple (219.93s) --- PASS: TestAccAWSLBListenerRule_conditionPathPattern (221.77s) --- PASS: TestAccAWSLBListenerRule_conditionPathPattern_deprecated (220.00s) --- PASS: TestAccAWSLBListenerRule_conditionQueryString (191.65s) --- PASS: TestAccAWSLBListenerRule_conditionSourceIp (275.03s) --- PASS: TestAccAWSLBListenerRule_conditionUpdateMixed (284.65s) --- PASS: TestAccAWSLBListenerRule_conditionUpdateMultiple (258.87s) --- PASS: TestAccAWSLBListenerRule_conditionUpdatePathPattern_deprecated (355.25s) --- PASS: TestAccAWSLBListenerRule_fixedResponse (217.28s) --- PASS: TestAccAWSLBListenerRule_multipleConditionThrowsError (2.66s) --- PASS: TestAccAWSLBListenerRule_oidc (188.46s) --- PASS: TestAccAWSLBListenerRule_priority (406.08s) --- PASS: TestAccAWSLBListenerRule_redirect (189.54s) --- PASS: TestAccAWSLBListenerRule_updateFixedResponse (222.80s) --- PASS: TestAccAWSLBListenerRule_updateRulePriority (225.24s) ``` --- aws/resource_aws_lb_listener_rule.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/aws/resource_aws_lb_listener_rule.go b/aws/resource_aws_lb_listener_rule.go index 3b7c9c8adc1..ab72c11dc20 100644 --- a/aws/resource_aws_lb_listener_rule.go +++ b/aws/resource_aws_lb_listener_rule.go @@ -928,8 +928,6 @@ func resourceAwsLbListenerRuleRead(d *schema.ResourceData, meta interface{}) err func resourceAwsLbListenerRuleUpdate(d *schema.ResourceData, meta interface{}) error { elbconn := meta.(*AWSClient).elbv2conn - d.Partial(true) - if d.HasChange("priority") { params := &elbv2.SetRulePrioritiesInput{ RulePriorities: []*elbv2.RulePriorityPair{ @@ -944,8 +942,6 @@ func resourceAwsLbListenerRuleUpdate(d *schema.ResourceData, meta interface{}) e if err != nil { return err } - - d.SetPartial("priority") } requestUpdate := false @@ -1080,7 +1076,6 @@ func resourceAwsLbListenerRuleUpdate(d *schema.ResourceData, meta interface{}) e params.Actions[i] = action } requestUpdate = true - d.SetPartial("action") } if d.HasChange("condition") { @@ -1090,7 +1085,6 @@ func resourceAwsLbListenerRuleUpdate(d *schema.ResourceData, meta interface{}) e return err } requestUpdate = true - d.SetPartial("condition") } if requestUpdate { @@ -1104,8 +1098,6 @@ func resourceAwsLbListenerRuleUpdate(d *schema.ResourceData, meta interface{}) e } } - d.Partial(false) - return resourceAwsLbListenerRuleRead(d, meta) } From c46c4dcb154a5e81238e2c0bcccc9391c4429ee3 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:16:34 -0400 Subject: [PATCH 188/684] resource/aws_codestarnotifications_notification_rule: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12469) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_codestarnotifications_notification_rule.go:236:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_codestarnotifications_notification_rule.go:251:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_codestarnotifications_notification_rule.go:252:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_codestarnotifications_notification_rule.go:253:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_codestarnotifications_notification_rule.go:254:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_codestarnotifications_notification_rule.go:270:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSCodeStarNotificationsNotificationRule_Basic (26.58s) --- PASS: TestAccAWSCodeStarNotificationsNotificationRule_EventTypeIds (49.15s) --- PASS: TestAccAWSCodeStarNotificationsNotificationRule_Status (61.55s) --- PASS: TestAccAWSCodeStarNotificationsNotificationRule_Tags (49.81s) --- PASS: TestAccAWSCodeStarNotificationsNotificationRule_Targets (48.94s) ``` --- ...source_aws_codestarnotifications_notification_rule.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/aws/resource_aws_codestarnotifications_notification_rule.go b/aws/resource_aws_codestarnotifications_notification_rule.go index feb4d21602b..a981ac91534 100644 --- a/aws/resource_aws_codestarnotifications_notification_rule.go +++ b/aws/resource_aws_codestarnotifications_notification_rule.go @@ -233,8 +233,6 @@ func cleanupCodeStarNotificationsNotificationRuleTargets(conn *codestarnotificat func resourceAwsCodeStarNotificationsNotificationRuleUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).codestarnotificationsconn - d.Partial(true) - params := &codestarnotifications.UpdateNotificationRuleInput{ Arn: aws.String(d.Id()), DetailType: aws.String(d.Get("detail_type").(string)), @@ -248,11 +246,6 @@ func resourceAwsCodeStarNotificationsNotificationRuleUpdate(d *schema.ResourceDa return fmt.Errorf("error updating codestar notification rule: %s", err) } - d.SetPartial("detail_type") - d.SetPartial("event_type_ids") - d.SetPartial("name") - d.SetPartial("target") - if d.HasChange("tags") { o, n := d.GetChange("tags") if err := keyvaluetags.CodestarnotificationsUpdateTags(conn, d.Id(), o, n); err != nil { @@ -267,8 +260,6 @@ func resourceAwsCodeStarNotificationsNotificationRuleUpdate(d *schema.ResourceDa } } - d.Partial(false) - return resourceAwsCodeStarNotificationsNotificationRuleRead(d, meta) } From c59455f354087b107c7440af1010d5b05e8d1f8c Mon Sep 17 00:00:00 2001 From: Nishimura Yoshitaka Date: Wed, 1 Apr 2020 09:47:24 +0900 Subject: [PATCH 189/684] resource/aws_codebuild_project: Fix typo of buildspec (#12590) https://www.terraform.io/docs/providers/aws/r/codebuild_project.html#buildspec --- aws/resource_aws_codebuild_project.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_codebuild_project.go b/aws/resource_aws_codebuild_project.go index 45b4093e0e7..fd3ea037e24 100644 --- a/aws/resource_aws_codebuild_project.go +++ b/aws/resource_aws_codebuild_project.go @@ -634,7 +634,7 @@ func resourceAwsCodeBuildProjectCreate(d *schema.ResourceData, meta interface{}) if aws.StringValue(projectSource.Type) == codebuild.SourceTypeNoSource { if aws.StringValue(projectSource.Buildspec) == "" { - return fmt.Errorf("`build_spec` must be set when source's `type` is `NO_SOURCE`") + return fmt.Errorf("`buildspec` must be set when source's `type` is `NO_SOURCE`") } if aws.StringValue(projectSource.Location) != "" { From 2363385bc0f7fd0060d8764f8192c4642184b814 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 20:49:54 -0400 Subject: [PATCH 190/684] tests/resource/aws_codebuild_project: Fix typo in error message testing for buildspec Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/12590 Output from acceptance testing: ``` --- PASS: TestAccAWSCodeBuildProject_Source_Type_NoSourceInvalid (12.19s) ``` --- aws/resource_aws_codebuild_project_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_codebuild_project_test.go b/aws/resource_aws_codebuild_project_test.go index 9e4724114f6..3de34543222 100644 --- a/aws/resource_aws_codebuild_project_test.go +++ b/aws/resource_aws_codebuild_project_test.go @@ -989,7 +989,7 @@ phases: Steps: []resource.TestStep{ { Config: testAccAWSCodeBuildProjectConfig_Source_Type_NoSource(rName, "", ""), - ExpectError: regexp.MustCompile("`build_spec` must be set when source's `type` is `NO_SOURCE`"), + ExpectError: regexp.MustCompile("`buildspec` must be set when source's `type` is `NO_SOURCE`"), }, { Config: testAccAWSCodeBuildProjectConfig_Source_Type_NoSource(rName, "location", rBuildspec), From a836c89258ce0a9595ce920b3612560f6c7cfb10 Mon Sep 17 00:00:00 2001 From: Dmytro Shkyra <38437899+dshkyra@users.noreply.github.com> Date: Tue, 31 Mar 2020 21:15:30 -0400 Subject: [PATCH 191/684] resource/aws_kms_grant: Remove resource from Terraform state instead of error if removed outside Terraform (#12560) * Fix #12555: Error "grant not found for key id" When a KMS grant was not found, terraform apply failed during refreshing state with an error "grant not found for key id". Now, when a KMS grant is not found, it is treated as revoked and terraform shows the change in the plan and recreates it during apply. Output from acceptance testing: ``` --- PASS: TestAccAWSKmsGrant_Basic (36.00s) --- PASS: TestAccAWSKmsGrant_ARN (43.76s) --- PASS: TestAccAWSKmsGrant_bare (44.22s) --- PASS: TestAccAWSKmsGrant_withRetiringPrincipal (44.30s) --- PASS: TestAccAWSKmsGrant_withConstraints (50.11s) --- PASS: TestAccAWSKmsGrant_disappears (233.92s) ``` --- aws/resource_aws_kms_grant.go | 8 ++++++ aws/resource_aws_kms_grant_test.go | 42 ++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/aws/resource_aws_kms_grant.go b/aws/resource_aws_kms_grant.go index 02287042b10..9bfdc4b207f 100644 --- a/aws/resource_aws_kms_grant.go +++ b/aws/resource_aws_kms_grant.go @@ -209,6 +209,11 @@ func resourceAwsKmsGrantRead(d *schema.ResourceData, meta interface{}) error { grant, err := findKmsGrantByIdWithRetry(conn, keyId, grantId) if err != nil { + if isResourceNotFoundError(err) { + log.Printf("[WARN] %s KMS grant id not found for key id %s, removing from state file", grantId, keyId) + d.SetId("") + return nil + } return err } @@ -306,6 +311,9 @@ func resourceAwsKmsGrantExists(d *schema.ResourceData, meta interface{}) (bool, grant, err := findKmsGrantByIdWithRetry(conn, keyId, grantId) if err != nil { + if isResourceNotFoundError(err) { + return false, nil + } return true, err } if grant != nil { diff --git a/aws/resource_aws_kms_grant_test.go b/aws/resource_aws_kms_grant_test.go index ad6d2760eee..5a8ee3a082c 100644 --- a/aws/resource_aws_kms_grant_test.go +++ b/aws/resource_aws_kms_grant_test.go @@ -4,6 +4,8 @@ import ( "fmt" "testing" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/kms" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" @@ -168,6 +170,27 @@ func TestAccAWSKmsGrant_ARN(t *testing.T) { }) } +func TestAccAWSKmsGrant_disappears(t *testing.T) { + resourceName := "aws_kms_grant.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSKmsGrantDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSKmsGrant_Basic(rName, "\"Encrypt\", \"Decrypt\""), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSKmsGrantExists(resourceName), + testAccCheckAWSKmsGrantDisappears(resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAWSKmsGrantDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).kmsconn @@ -194,6 +217,25 @@ func testAccCheckAWSKmsGrantExists(name string) resource.TestCheckFunc { } } +func testAccCheckAWSKmsGrantDisappears(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("not found: %s", name) + } + + conn := testAccProvider.Meta().(*AWSClient).kmsconn + + revokeInput := kms.RevokeGrantInput{ + GrantId: aws.String(rs.Primary.Attributes["grant_id"]), + KeyId: aws.String(rs.Primary.Attributes["key_id"]), + } + + _, err := conn.RevokeGrant(&revokeInput) + return err + } +} + func testAccAWSKmsGrantConfigBase(rName string) string { return fmt.Sprintf(` resource "aws_kms_key" "test" { From 266e07b74fef815a8e8622ddec99347538802449 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 21:16:38 -0400 Subject: [PATCH 192/684] Update CHANGELOG for #12560 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e72ba13b6c5..ade0ea56ba5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ENHANCEMENTS: BUG FIXES: * resource/aws_codedeploy_deployment_group: Fix `blue_green_deployment_config` updates for ECS [GH-11885] +* resource/aws_kms_grant: Remove resource from Terraform state instead of error if removed outside Terraform [GH-12560] ## 2.55.0 (March 27, 2020) From c7817f70d39fdf7610972ceaa54496925a22b27d Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Wed, 1 Apr 2020 04:35:44 +0300 Subject: [PATCH 193/684] resource/aws_elastic_transcoder_preset: Remove `getStringPtr` calls, refactor tests, validate role argument (#12575) Output from acceptance testing: ``` --- PASS: TestAccAWSElasticTranscoderPreset_disappears (5.70s) --- PASS: TestAccAWSElasticTranscoderPreset_basic (18.29s) ``` --- ...esource_aws_elastic_transcoder_pipeline.go | 50 ++-- ...ce_aws_elastic_transcoder_pipeline_test.go | 274 +++++++++++------- 2 files changed, 192 insertions(+), 132 deletions(-) diff --git a/aws/resource_aws_elastic_transcoder_pipeline.go b/aws/resource_aws_elastic_transcoder_pipeline.go index 69c22a2c1eb..c3b1fb2b426 100644 --- a/aws/resource_aws_elastic_transcoder_pipeline.go +++ b/aws/resource_aws_elastic_transcoder_pipeline.go @@ -6,7 +6,6 @@ import ( "regexp" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/elastictranscoder" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -139,8 +138,9 @@ func resourceAwsElasticTranscoderPipeline() *schema.Resource { }, "role": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, }, "thumbnail_config": { @@ -191,18 +191,21 @@ func resourceAwsElasticTranscoderPipeline() *schema.Resource { } func resourceAwsElasticTranscoderPipelineCreate(d *schema.ResourceData, meta interface{}) error { - elastictranscoderconn := meta.(*AWSClient).elastictranscoderconn + conn := meta.(*AWSClient).elastictranscoderconn req := &elastictranscoder.CreatePipelineInput{ - AwsKmsKeyArn: getStringPtr(d, "aws_kms_key_arn"), + AwsKmsKeyArn: aws.String(d.Get("aws_kms_key_arn").(string)), ContentConfig: expandETPiplineOutputConfig(d, "content_config"), InputBucket: aws.String(d.Get("input_bucket").(string)), Notifications: expandETNotifications(d), - OutputBucket: getStringPtr(d, "output_bucket"), - Role: getStringPtr(d, "role"), + Role: aws.String(d.Get("role").(string)), ThumbnailConfig: expandETPiplineOutputConfig(d, "thumbnail_config"), } + if v, ok := d.GetOk("output_bucket"); ok && v.(string) != "" { + req.OutputBucket = aws.String(v.(string)) + } + if name, ok := d.GetOk("name"); ok { req.Name = aws.String(name.(string)) } else { @@ -217,7 +220,7 @@ func resourceAwsElasticTranscoderPipelineCreate(d *schema.ResourceData, meta int } log.Printf("[DEBUG] Elastic Transcoder Pipeline create opts: %s", req) - resp, err := elastictranscoderconn.CreatePipeline(req) + resp, err := conn.CreatePipeline(req) if err != nil { return fmt.Errorf("Error creating Elastic Transcoder Pipeline: %s", err) } @@ -299,8 +302,8 @@ func expandETPiplineOutputConfig(d *schema.ResourceData, key string) *elastictra cc := s.List()[0].(map[string]interface{}) cfg := &elastictranscoder.PipelineOutputConfig{ - Bucket: getStringPtr(cc, "bucket"), - StorageClass: getStringPtr(cc, "storage_class"), + Bucket: aws.String(cc["bucket"].(string)), + StorageClass: aws.String(cc["storage_class"].(string)), } switch key { @@ -334,8 +337,8 @@ func expandETPermList(permissions *schema.Set) []*elastictranscoder.Permission { perm := &elastictranscoder.Permission{ Access: expandStringList(m["access"].([]interface{})), - Grantee: getStringPtr(p, "grantee"), - GranteeType: getStringPtr(p, "grantee_type"), + Grantee: aws.String(m["grantee"].(string)), + GranteeType: aws.String(m["grantee_type"].(string)), } perms = append(perms, perm) @@ -358,14 +361,14 @@ func flattenETPermList(perms []*elastictranscoder.Permission) []map[string]inter } func resourceAwsElasticTranscoderPipelineUpdate(d *schema.ResourceData, meta interface{}) error { - elastictranscoderconn := meta.(*AWSClient).elastictranscoderconn + conn := meta.(*AWSClient).elastictranscoderconn req := &elastictranscoder.UpdatePipelineInput{ Id: aws.String(d.Id()), } if d.HasChange("aws_kms_key_arn") { - req.AwsKmsKeyArn = getStringPtr(d, "aws_kms_key_arn") + req.AwsKmsKeyArn = aws.String(d.Get("aws_kms_key_arn").(string)) } if d.HasChange("content_config") { @@ -373,11 +376,11 @@ func resourceAwsElasticTranscoderPipelineUpdate(d *schema.ResourceData, meta int } if d.HasChange("input_bucket") { - req.InputBucket = getStringPtr(d, "input_bucket") + req.InputBucket = aws.String(d.Get("input_bucket").(string)) } if d.HasChange("name") { - req.Name = getStringPtr(d, "name") + req.Name = aws.String(d.Get("name").(string)) } if d.HasChange("notifications") { @@ -385,7 +388,7 @@ func resourceAwsElasticTranscoderPipelineUpdate(d *schema.ResourceData, meta int } if d.HasChange("role") { - req.Role = getStringPtr(d, "role") + req.Role = aws.String(d.Get("role").(string)) } if d.HasChange("thumbnail_config") { @@ -393,7 +396,7 @@ func resourceAwsElasticTranscoderPipelineUpdate(d *schema.ResourceData, meta int } log.Printf("[DEBUG] Updating Elastic Transcoder Pipeline: %#v", req) - output, err := elastictranscoderconn.UpdatePipeline(req) + output, err := conn.UpdatePipeline(req) if err != nil { return fmt.Errorf("Error updating Elastic Transcoder pipeline: %s", err) } @@ -406,14 +409,15 @@ func resourceAwsElasticTranscoderPipelineUpdate(d *schema.ResourceData, meta int } func resourceAwsElasticTranscoderPipelineRead(d *schema.ResourceData, meta interface{}) error { - elastictranscoderconn := meta.(*AWSClient).elastictranscoderconn + conn := meta.(*AWSClient).elastictranscoderconn - resp, err := elastictranscoderconn.ReadPipeline(&elastictranscoder.ReadPipelineInput{ + resp, err := conn.ReadPipeline(&elastictranscoder.ReadPipelineInput{ Id: aws.String(d.Id()), }) if err != nil { - if err, ok := err.(awserr.Error); ok && err.Code() == "ResourceNotFoundException" { + if isAWSErr(err, elastictranscoder.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] No such resource found for Elastic Transcoder Pipeline (%s)", d.Id()) d.SetId("") return nil } @@ -478,10 +482,10 @@ func resourceAwsElasticTranscoderPipelineRead(d *schema.ResourceData, meta inter } func resourceAwsElasticTranscoderPipelineDelete(d *schema.ResourceData, meta interface{}) error { - elastictranscoderconn := meta.(*AWSClient).elastictranscoderconn + conn := meta.(*AWSClient).elastictranscoderconn log.Printf("[DEBUG] Elastic Transcoder Delete Pipeline: %s", d.Id()) - _, err := elastictranscoderconn.DeletePipeline(&elastictranscoder.DeletePipelineInput{ + _, err := conn.DeletePipeline(&elastictranscoder.DeletePipelineInput{ Id: aws.String(d.Id()), }) if err != nil { diff --git a/aws/resource_aws_elastic_transcoder_pipeline_test.go b/aws/resource_aws_elastic_transcoder_pipeline_test.go index 7498c4d375a..4cf938f6c19 100644 --- a/aws/resource_aws_elastic_transcoder_pipeline_test.go +++ b/aws/resource_aws_elastic_transcoder_pipeline_test.go @@ -6,8 +6,6 @@ import ( "sort" "testing" - "regexp" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/elastictranscoder" @@ -18,12 +16,12 @@ import ( func TestAccAWSElasticTranscoderPipeline_basic(t *testing.T) { pipeline := &elastictranscoder.Pipeline{} - resourceName := "aws_elastictranscoder_pipeline.bar" + resourceName := "aws_elastictranscoder_pipeline.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSElasticTranscoder(t) }, - IDRefreshName: "aws_elastictranscoder_pipeline.bar", + IDRefreshName: resourceName, Providers: testAccProviders, CheckDestroy: testAccCheckElasticTranscoderPipelineDestroy, Steps: []resource.TestStep{ @@ -44,51 +42,61 @@ func TestAccAWSElasticTranscoderPipeline_basic(t *testing.T) { func TestAccAWSElasticTranscoderPipeline_kmsKey(t *testing.T) { pipeline := &elastictranscoder.Pipeline{} - ri := acctest.RandInt() - config := fmt.Sprintf(awsElasticTranscoderPipelineConfigKmsKey, ri, ri, ri) - keyRegex := regexp.MustCompile(`^arn:aws:([a-zA-Z0-9\-])+:([a-z]{2}-[a-z]+-\d{1})?:(\d{12})?:(.*)$`) + resourceName := "aws_elastictranscoder_pipeline.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + keyResourceName := "aws_kms_key.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSElasticTranscoder(t) }, - IDRefreshName: "aws_elastictranscoder_pipeline.bar", + IDRefreshName: resourceName, Providers: testAccProviders, CheckDestroy: testAccCheckElasticTranscoderPipelineDestroy, Steps: []resource.TestStep{ { - Config: config, + Config: awsElasticTranscoderPipelineConfigKmsKey(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.bar", pipeline), - resource.TestMatchResourceAttr("aws_elastictranscoder_pipeline.bar", "aws_kms_key_arn", keyRegex), + testAccCheckAWSElasticTranscoderPipelineExists(resourceName, pipeline), + resource.TestCheckResourceAttrPair(resourceName, "aws_kms_key_arn", keyResourceName, "arn"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } func TestAccAWSElasticTranscoderPipeline_notifications(t *testing.T) { pipeline := elastictranscoder.Pipeline{} + resourceName := "aws_elastictranscoder_pipeline.test" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSElasticTranscoder(t) }, - IDRefreshName: "aws_elastictranscoder_pipeline.bar", + IDRefreshName: resourceName, Providers: testAccProviders, CheckDestroy: testAccCheckElasticTranscoderPipelineDestroy, Steps: []resource.TestStep{ { - Config: awsElasticTranscoderNotifications(rInt), + Config: awsElasticTranscoderNotifications(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.bar", &pipeline), + testAccCheckAWSElasticTranscoderPipelineExists(resourceName, &pipeline), testAccCheckAWSElasticTranscoderPipeline_notifications(&pipeline, []string{"warning", "completed"}), ), }, - + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, // update and check that we have 1 less notification { - Config: awsElasticTranscoderNotifications_update(rInt), + Config: awsElasticTranscoderNotifications_update(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.bar", &pipeline), + testAccCheckAWSElasticTranscoderPipelineExists(resourceName, &pipeline), testAccCheckAWSElasticTranscoderPipeline_notifications(&pipeline, []string{"completed"}), ), }, @@ -132,25 +140,31 @@ func testAccCheckAWSElasticTranscoderPipeline_notifications( func TestAccAWSElasticTranscoderPipeline_withContentConfig(t *testing.T) { pipeline := &elastictranscoder.Pipeline{} + resourceName := "aws_elastictranscoder_pipeline.test" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSElasticTranscoder(t) }, - IDRefreshName: "aws_elastictranscoder_pipeline.bar", + IDRefreshName: resourceName, Providers: testAccProviders, CheckDestroy: testAccCheckElasticTranscoderPipelineDestroy, Steps: []resource.TestStep{ { - Config: awsElasticTranscoderPipelineWithContentConfig(rInt), + Config: awsElasticTranscoderPipelineWithContentConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.bar", pipeline), + testAccCheckAWSElasticTranscoderPipelineExists(resourceName, pipeline), ), }, { - Config: awsElasticTranscoderPipelineWithContentConfigUpdate(rInt), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: awsElasticTranscoderPipelineWithContentConfigUpdate(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.bar", pipeline), + testAccCheckAWSElasticTranscoderPipelineExists(resourceName, pipeline), ), }, }, @@ -159,21 +173,49 @@ func TestAccAWSElasticTranscoderPipeline_withContentConfig(t *testing.T) { func TestAccAWSElasticTranscoderPipeline_withPermissions(t *testing.T) { pipeline := &elastictranscoder.Pipeline{} + resourceName := "aws_elastictranscoder_pipeline.test" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSElasticTranscoder(t) }, - IDRefreshName: "aws_elastictranscoder_pipeline.baz", + IDRefreshName: resourceName, Providers: testAccProviders, CheckDestroy: testAccCheckElasticTranscoderPipelineDestroy, Steps: []resource.TestStep{ { - Config: awsElasticTranscoderPipelineWithPerms(rInt), + Config: awsElasticTranscoderPipelineWithPerms(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.baz", pipeline), + testAccCheckAWSElasticTranscoderPipelineExists(resourceName, pipeline), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSElasticTranscoderPipeline_disappears(t *testing.T) { + pipeline := &elastictranscoder.Pipeline{} + resourceName := "aws_elastictranscoder_pipeline.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSElasticTranscoder(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckElasticTranscoderPipelineDestroy, + Steps: []resource.TestStep{ + { + Config: awsElasticTranscoderPipelineConfigBasic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSElasticTranscoderPipelineExists(resourceName, pipeline), + testAccCheckAWSElasticTranscoderPipelineDisappears(pipeline), + ), + ExpectNonEmptyPlan: true, + }, }, }) } @@ -205,6 +247,18 @@ func testAccCheckAWSElasticTranscoderPipelineExists(n string, res *elastictransc } } +func testAccCheckAWSElasticTranscoderPipelineDisappears(res *elastictranscoder.Pipeline) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).elastictranscoderconn + + _, err := conn.DeletePipeline(&elastictranscoder.DeletePipelineInput{ + Id: res.Id, + }) + + return err + } +} + func testAccCheckElasticTranscoderPipelineDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).elastictranscoderconn @@ -254,14 +308,14 @@ func testAccPreCheckAWSElasticTranscoder(t *testing.T) { func awsElasticTranscoderPipelineConfigBasic(rName string) string { return fmt.Sprintf(` -resource "aws_elastictranscoder_pipeline" "bar" { - input_bucket = "${aws_s3_bucket.test_bucket.bucket}" - output_bucket = "${aws_s3_bucket.test_bucket.bucket}" +resource "aws_elastictranscoder_pipeline" "test" { + input_bucket = "${aws_s3_bucket.test.bucket}" + output_bucket = "${aws_s3_bucket.test.bucket}" name = %[1]q - role = "${aws_iam_role.test_role.arn}" + role = "${aws_iam_role.test.arn}" } -resource "aws_iam_role" "test_role" { +resource "aws_iam_role" "test" { name = %[1]q assume_role_policy = < Date: Tue, 31 Mar 2020 21:38:10 -0400 Subject: [PATCH 194/684] Update CHANGELOG for #12575 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ade0ea56ba5..1434725f32f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ENHANCEMENTS: * data-source/aws_launch_template: Add `hibernation_options` attribute [GH-12492] * resource/aws_dx_connection: Support `2Gbps` and `5Gbps` values in plan-time validation for `bandwidth` argument [GH-12559] * resource/aws_dx_lag: Support `2Gbps` and `5Gbps` values in plan-time validation for `bandwidth` argument [GH-12559] +* resource/aws_elastic_transcoder_preset: Support plan-time validation for `role` argument [GH-12575] * resource/aws_kms_grant: Support resource import [GH-11991] * resource/aws_launch_template: Add `hibernation_options` configuration block [GH-12492] From cbf9a9b219742faaf291d267d95ed46fea64e3c4 Mon Sep 17 00:00:00 2001 From: Wyatt Preul Date: Tue, 31 Mar 2020 22:12:55 -0500 Subject: [PATCH 195/684] resource/aws_volume_attachment: Do not swallow error when detaching volume (#12596) Output from acceptance testing: ``` --- PASS: TestAccAWSVolumeAttachment_update (84.99s) --- PASS: TestAccAWSVolumeAttachment_basic (99.04s) --- PASS: TestAccAWSVolumeAttachment_skipDestroy (200.97s) --- PASS: TestAccAWSVolumeAttachment_attachStopped (226.76s) ``` --- aws/resource_aws_volume_attachment.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_volume_attachment.go b/aws/resource_aws_volume_attachment.go index b39720d3ba1..4be7986dd65 100644 --- a/aws/resource_aws_volume_attachment.go +++ b/aws/resource_aws_volume_attachment.go @@ -245,8 +245,8 @@ func resourceAwsVolumeAttachmentDelete(d *schema.ResourceData, meta interface{}) _, err = stateConf.WaitForState() if err != nil { return fmt.Errorf( - "Error waiting for Volume (%s) to detach from Instance: %s", - vID, iID) + "Error waiting for Volume (%s) to detach from Instance (%s): %s", + vID, iID, err) } return nil From fe775b2e21e21b1031da2a6928bdc51d9ca5b285 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 31 Mar 2020 23:14:07 -0400 Subject: [PATCH 196/684] Update CHANGELOG for #12596 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1434725f32f..18af9c02e1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ BUG FIXES: * resource/aws_codedeploy_deployment_group: Fix `blue_green_deployment_config` updates for ECS [GH-11885] * resource/aws_kms_grant: Remove resource from Terraform state instead of error if removed outside Terraform [GH-12560] +* resource/aws_volume_attachment: Ensure any error is shown while waiting for volume to detach [GH-12596] ## 2.55.0 (March 27, 2020) From 2bdc734c531268b28e73499a8fa8c02076cbceba Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Wed, 1 Apr 2020 17:10:11 +0300 Subject: [PATCH 197/684] resource/aws_elastic_transcoder_preset: Remove stringptr and refactor tests (#12581) Output from acceptance testing: ``` --- PASS: TestAccAWSElasticTranscoderPreset_disappears (5.83s) --- PASS: TestAccAWSElasticTranscoderPreset_basic (18.17s) ``` --- aws/resource_aws_elastic_transcoder_preset.go | 205 ++++++++++++------ ...urce_aws_elastic_transcoder_preset_test.go | 149 +++++++------ aws/structure.go | 32 --- 3 files changed, 228 insertions(+), 158 deletions(-) diff --git a/aws/resource_aws_elastic_transcoder_preset.go b/aws/resource_aws_elastic_transcoder_preset.go index 22f3c2ef02b..0a61472d53e 100644 --- a/aws/resource_aws_elastic_transcoder_preset.go +++ b/aws/resource_aws_elastic_transcoder_preset.go @@ -5,7 +5,6 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/elastictranscoder" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -320,12 +319,12 @@ func resourceAwsElasticTranscoderPreset() *schema.Resource { } func resourceAwsElasticTranscoderPresetCreate(d *schema.ResourceData, meta interface{}) error { - elastictranscoderconn := meta.(*AWSClient).elastictranscoderconn + conn := meta.(*AWSClient).elastictranscoderconn req := &elastictranscoder.CreatePresetInput{ Audio: expandETAudioParams(d), Container: aws.String(d.Get("container").(string)), - Description: getStringPtr(d, "description"), + Description: aws.String(d.Get("description").(string)), Thumbnails: expandETThumbnails(d), Video: expandETVideoParams(d), } @@ -339,7 +338,7 @@ func resourceAwsElasticTranscoderPresetCreate(d *schema.ResourceData, meta inter } log.Printf("[DEBUG] Elastic Transcoder Preset create opts: %s", req) - resp, err := elastictranscoderconn.CreatePreset(req) + resp, err := conn.CreatePreset(req) if err != nil { return fmt.Errorf("Error creating Elastic Transcoder Preset: %s", err) } @@ -366,16 +365,41 @@ func expandETThumbnails(d *schema.ResourceData) *elastictranscoder.Thumbnails { } t := s.List()[0].(map[string]interface{}) - return &elastictranscoder.Thumbnails{ - AspectRatio: getStringPtr(t, "aspect_ratio"), - Format: getStringPtr(t, "format"), - Interval: getStringPtr(t, "interval"), - MaxHeight: getStringPtr(t, "max_height"), - MaxWidth: getStringPtr(t, "max_width"), - PaddingPolicy: getStringPtr(t, "padding_policy"), - Resolution: getStringPtr(t, "resolution"), - SizingPolicy: getStringPtr(t, "sizing_policy"), + thumbnails := &elastictranscoder.Thumbnails{} + + if v, ok := t["aspect_ratio"]; ok && v.(string) != "" { + thumbnails.AspectRatio = aws.String(v.(string)) + } + + if v, ok := t["interval"]; ok && v.(string) != "" { + thumbnails.Interval = aws.String(v.(string)) + } + + if v, ok := t["format"]; ok && v.(string) != "" { + thumbnails.Format = aws.String(v.(string)) + } + + if v, ok := t["max_height"]; ok && v.(string) != "" { + thumbnails.MaxHeight = aws.String(v.(string)) + } + + if v, ok := t["max_width"]; ok && v.(string) != "" { + thumbnails.MaxWidth = aws.String(v.(string)) + } + + if v, ok := t["padding_policy"]; ok && v.(string) != "" { + thumbnails.PaddingPolicy = aws.String(v.(string)) + } + + if v, ok := t["resolution"]; ok && v.(string) != "" { + thumbnails.Resolution = aws.String(v.(string)) + } + + if v, ok := t["sizing_policy"]; ok && v.(string) != "" { + thumbnails.SizingPolicy = aws.String(v.(string)) } + + return thumbnails } func expandETAudioParams(d *schema.ResourceData) *elastictranscoder.AudioParameters { @@ -391,12 +415,12 @@ func expandETAudioParams(d *schema.ResourceData) *elastictranscoder.AudioParamet audio := s.List()[0].(map[string]interface{}) return &elastictranscoder.AudioParameters{ - AudioPackingMode: getStringPtr(audio, "audio_packing_mode"), - BitRate: getStringPtr(audio, "bit_rate"), - Channels: getStringPtr(audio, "channels"), - Codec: getStringPtr(audio, "codec"), + AudioPackingMode: aws.String(audio["audio_packing_mode"].(string)), + BitRate: aws.String(audio["bit_rate"].(string)), + Channels: aws.String(audio["channels"].(string)), + Codec: aws.String(audio["codec"].(string)), CodecOptions: expandETAudioCodecOptions(d), - SampleRate: getStringPtr(audio, "sample_rate"), + SampleRate: aws.String(audio["sample_rate"].(string)), } } @@ -408,11 +432,22 @@ func expandETAudioCodecOptions(d *schema.ResourceData) *elastictranscoder.AudioC codec := s.List()[0].(map[string]interface{}) - codecOpts := &elastictranscoder.AudioCodecOptions{ - BitDepth: getStringPtr(codec, "bit_depth"), - BitOrder: getStringPtr(codec, "bit_order"), - Profile: getStringPtr(codec, "profile"), - Signed: getStringPtr(codec, "signed"), + codecOpts := &elastictranscoder.AudioCodecOptions{} + + if v, ok := codec["signed"]; ok && v.(string) != "" { + codecOpts.Signed = aws.String(v.(string)) + } + + if v, ok := codec["profile"]; ok && v.(string) != "" { + codecOpts.Profile = aws.String(v.(string)) + } + + if v, ok := codec["bit_order"]; ok && v.(string) != "" { + codecOpts.BitOrder = aws.String(v.(string)) + } + + if v, ok := codec["bit_depth"]; ok && v.(string) != "" { + codecOpts.BitDepth = aws.String(v.(string)) } return codecOpts @@ -425,23 +460,76 @@ func expandETVideoParams(d *schema.ResourceData) *elastictranscoder.VideoParamet } p := s.List()[0].(map[string]interface{}) - return &elastictranscoder.VideoParameters{ - AspectRatio: getStringPtr(p, "aspect_ratio"), - BitRate: getStringPtr(p, "bit_rate"), - Codec: getStringPtr(p, "codec"), - CodecOptions: stringMapToPointers(d.Get("video_codec_options").(map[string]interface{})), - DisplayAspectRatio: getStringPtr(p, "display_aspect_ratio"), - FixedGOP: getStringPtr(p, "fixed_gop"), - FrameRate: getStringPtr(p, "frame_rate"), - KeyframesMaxDist: getStringPtr(p, "keyframes_max_dist"), - MaxFrameRate: getStringPtr(p, "max_frame_rate"), - MaxHeight: getStringPtr(p, "max_height"), - MaxWidth: getStringPtr(p, "max_width"), - PaddingPolicy: getStringPtr(p, "padding_policy"), - Resolution: getStringPtr(p, "resolution"), - SizingPolicy: getStringPtr(p, "sizing_policy"), - Watermarks: expandETVideoWatermarks(d), + etVideoParams := &elastictranscoder.VideoParameters{ + Watermarks: expandETVideoWatermarks(d), + } + + if v, ok := d.GetOk("video_codec_options"); ok { + codecOpts := make(map[string]string) + for k, va := range v.(map[string]interface{}) { + codecOpts[k] = va.(string) + } + + etVideoParams.CodecOptions = aws.StringMap(codecOpts) + } + + if v, ok := p["aspect_ratio"]; ok && v.(string) != "" { + etVideoParams.AspectRatio = aws.String(v.(string)) + } + + if v, ok := p["bit_rate"]; ok && v.(string) != "" { + etVideoParams.BitRate = aws.String(v.(string)) } + + if v, ok := p["display_aspect_ratio"]; ok && v.(string) != "" { + etVideoParams.DisplayAspectRatio = aws.String(v.(string)) + } + + if v, ok := p["aspect_ratio"]; ok && v.(string) != "" { + etVideoParams.AspectRatio = aws.String(v.(string)) + } + + if v, ok := p["fixed_gop"]; ok && v.(string) != "" { + etVideoParams.FixedGOP = aws.String(v.(string)) + } + + if v, ok := p["frame_rate"]; ok && v.(string) != "" { + etVideoParams.FrameRate = aws.String(v.(string)) + } + + if v, ok := p["keyframes_max_dist"]; ok && v.(string) != "" { + etVideoParams.KeyframesMaxDist = aws.String(v.(string)) + } + + if v, ok := p["max_frame_rate"]; ok && v.(string) != "" { + etVideoParams.MaxFrameRate = aws.String(v.(string)) + } + + if v, ok := p["max_height"]; ok && v.(string) != "" { + etVideoParams.MaxHeight = aws.String(v.(string)) + } + + if v, ok := p["max_width"]; ok && v.(string) != "" { + etVideoParams.MaxWidth = aws.String(v.(string)) + } + + if v, ok := p["padding_policy"]; ok && v.(string) != "" { + etVideoParams.PaddingPolicy = aws.String(v.(string)) + } + + if v, ok := p["resolution"]; ok && v.(string) != "" { + etVideoParams.Resolution = aws.String(v.(string)) + } + + if v, ok := p["sizing_policy"]; ok && v.(string) != "" { + etVideoParams.SizingPolicy = aws.String(v.(string)) + } + + if v, ok := p["codec"]; ok && v.(string) != "" { + etVideoParams.Codec = aws.String(v.(string)) + } + + return etVideoParams } func expandETVideoWatermarks(d *schema.ResourceData) []*elastictranscoder.PresetWatermark { @@ -452,17 +540,18 @@ func expandETVideoWatermarks(d *schema.ResourceData) []*elastictranscoder.Preset var watermarks []*elastictranscoder.PresetWatermark for _, w := range s.List() { + p := w.(map[string]interface{}) watermark := &elastictranscoder.PresetWatermark{ - HorizontalAlign: getStringPtr(w, "horizontal_align"), - HorizontalOffset: getStringPtr(w, "horizontal_offset"), - Id: getStringPtr(w, "id"), - MaxHeight: getStringPtr(w, "max_height"), - MaxWidth: getStringPtr(w, "max_width"), - Opacity: getStringPtr(w, "opacity"), - SizingPolicy: getStringPtr(w, "sizing_policy"), - Target: getStringPtr(w, "target"), - VerticalAlign: getStringPtr(w, "vertical_align"), - VerticalOffset: getStringPtr(w, "vertical_offset"), + HorizontalAlign: aws.String(p["horizontal_align"].(string)), + HorizontalOffset: aws.String(p["horizontal_offset"].(string)), + Id: aws.String(p["id"].(string)), + MaxHeight: aws.String(p["max_height"].(string)), + MaxWidth: aws.String(p["max_width"].(string)), + Opacity: aws.String(p["opacity"].(string)), + SizingPolicy: aws.String(p["sizing_policy"].(string)), + Target: aws.String(p["target"].(string)), + VerticalAlign: aws.String(p["vertical_align"].(string)), + VerticalOffset: aws.String(p["vertical_offset"].(string)), } watermarks = append(watermarks, watermark) } @@ -471,14 +560,14 @@ func expandETVideoWatermarks(d *schema.ResourceData) []*elastictranscoder.Preset } func resourceAwsElasticTranscoderPresetRead(d *schema.ResourceData, meta interface{}) error { - elastictranscoderconn := meta.(*AWSClient).elastictranscoderconn + conn := meta.(*AWSClient).elastictranscoderconn - resp, err := elastictranscoderconn.ReadPreset(&elastictranscoder.ReadPresetInput{ + resp, err := conn.ReadPreset(&elastictranscoder.ReadPresetInput{ Id: aws.String(d.Id()), }) if err != nil { - if err, ok := err.(awserr.Error); ok && err.Code() == "ResourceNotFoundException" { + if isAWSErr(err, elastictranscoder.ErrCodeResourceNotFoundException, "") { d.SetId("") return nil } @@ -521,7 +610,7 @@ func resourceAwsElasticTranscoderPresetRead(d *schema.ResourceData, meta interfa } if preset.Video.CodecOptions != nil { - d.Set("video_codec_options", flattenETVideoCodecOptions(preset.Video.CodecOptions)) + d.Set("video_codec_options", aws.StringValueMap(preset.Video.CodecOptions)) } if preset.Video.Watermarks != nil { @@ -594,16 +683,6 @@ func flattenETVideoParams(video *elastictranscoder.VideoParameters) []map[string return m.MapList() } -func flattenETVideoCodecOptions(opts map[string]*string) map[string]interface{} { - codecOpts := setMap(make(map[string]interface{})) - - for k, v := range opts { - codecOpts.SetString(k, v) - } - - return codecOpts.Map() -} - func flattenETWatermarks(watermarks []*elastictranscoder.PresetWatermark) []map[string]interface{} { var watermarkSet []map[string]interface{} diff --git a/aws/resource_aws_elastic_transcoder_preset_test.go b/aws/resource_aws_elastic_transcoder_preset_test.go index 9d18a31f3c3..7c229f4bb33 100644 --- a/aws/resource_aws_elastic_transcoder_preset_test.go +++ b/aws/resource_aws_elastic_transcoder_preset_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/elastictranscoder" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" ) @@ -14,44 +14,7 @@ import ( func TestAccAWSElasticTranscoderPreset_basic(t *testing.T) { preset := &elastictranscoder.Preset{} name := "aws_elastictranscoder_preset.test" - - // make sure the old preset was destroyed on each intermediate step - // these are very easy to leak - checkExists := func(replaced bool) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).elastictranscoderconn - - if replaced { - _, err := conn.ReadPreset(&elastictranscoder.ReadPresetInput{Id: preset.Id}) - if err != nil { - return nil - } - - return fmt.Errorf("Preset Id %v should not exist", *preset.Id) - } - - rs, ok := s.RootModule().Resources[name] - if !ok { - return fmt.Errorf("Not found: %s", name) - } - if rs.Primary.ID == "" { - return fmt.Errorf("No Preset ID is set") - } - - out, err := conn.ReadPreset(&elastictranscoder.ReadPresetInput{ - Id: aws.String(rs.Primary.ID), - }) - - if err != nil { - return err - } - - preset = out.Preset - - return nil - - } - } + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSElasticTranscoder(t) }, @@ -59,9 +22,9 @@ func TestAccAWSElasticTranscoderPreset_basic(t *testing.T) { CheckDestroy: testAccCheckElasticTranscoderPresetDestroy, Steps: []resource.TestStep{ { - Config: awsElasticTranscoderPresetConfig, + Config: awsElasticTranscoderPresetConfig(rName), Check: resource.ComposeTestCheckFunc( - checkExists(false), + testAccCheckElasticTranscoderPresetExists(name, preset), ), }, { @@ -70,9 +33,9 @@ func TestAccAWSElasticTranscoderPreset_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: awsElasticTranscoderPresetConfig2, + Config: awsElasticTranscoderPresetConfig2(rName), Check: resource.ComposeTestCheckFunc( - checkExists(true), + testAccCheckElasticTranscoderPresetExists(name, preset), ), }, { @@ -81,9 +44,9 @@ func TestAccAWSElasticTranscoderPreset_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: awsElasticTranscoderPresetConfig3, + Config: awsElasticTranscoderPresetConfig3(rName), Check: resource.ComposeTestCheckFunc( - checkExists(true), + testAccCheckElasticTranscoderPresetExists(name, preset), ), }, { @@ -95,6 +58,65 @@ func TestAccAWSElasticTranscoderPreset_basic(t *testing.T) { }) } +func TestAccAWSElasticTranscoderPreset_disappears(t *testing.T) { + preset := &elastictranscoder.Preset{} + name := "aws_elastictranscoder_preset.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSElasticTranscoder(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckElasticTranscoderPresetDestroy, + Steps: []resource.TestStep{ + { + Config: awsElasticTranscoderPresetConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckElasticTranscoderPresetExists(name, preset), + testAccCheckElasticTranscoderPresetDisappears(preset), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckElasticTranscoderPresetExists(name string, preset *elastictranscoder.Preset) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).elastictranscoderconn + + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No Preset ID is set") + } + + out, err := conn.ReadPreset(&elastictranscoder.ReadPresetInput{ + Id: aws.String(rs.Primary.ID), + }) + + if err != nil { + return err + } + + *preset = *out.Preset + + return nil + } +} + +func testAccCheckElasticTranscoderPresetDisappears(preset *elastictranscoder.Preset) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).elastictranscoderconn + _, err := conn.DeletePreset(&elastictranscoder.DeletePresetInput{ + Id: preset.Id, + }) + + return err + } +} + func testAccCheckElasticTranscoderPresetDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).elastictranscoderconn @@ -113,24 +135,20 @@ func testAccCheckElasticTranscoderPresetDestroy(s *terraform.State) error { } } - awsErr, ok := err.(awserr.Error) - if !ok { - return err - } - - if awsErr.Code() != "ResourceNotFoundException" { - return fmt.Errorf("unexpected error: %s", awsErr) + if !isAWSErr(err, elastictranscoder.ErrCodeResourceNotFoundException, "") { + return fmt.Errorf("unexpected error: %s", err) } } return nil } -const awsElasticTranscoderPresetConfig = ` +func awsElasticTranscoderPresetConfig(rName string) string { + return fmt.Sprintf(` resource "aws_elastictranscoder_preset" "test" { container = "mp4" description = "elastic transcoder preset test 1" - name = "aws_elastictranscoder_preset_tf_test_" + name = %[1]q audio { audio_packing_mode = "SingleTrack" @@ -140,13 +158,15 @@ resource "aws_elastictranscoder_preset" "test" { sample_rate = 44100 } } -` +`, rName) +} -const awsElasticTranscoderPresetConfig2 = ` +func awsElasticTranscoderPresetConfig2(rName string) string { + return fmt.Sprintf(` resource "aws_elastictranscoder_preset" "test" { container = "mp4" description = "elastic transcoder preset test 2" - name = "aws_elastictranscoder_preset_tf_test_" + name = %[1]q audio { audio_packing_mode = "SingleTrack" @@ -190,13 +210,15 @@ resource "aws_elastictranscoder_preset" "test" { sizing_policy = "Fit" } } -` +`, rName) +} -const awsElasticTranscoderPresetConfig3 = ` +func awsElasticTranscoderPresetConfig3(rName string) string { + return fmt.Sprintf(` resource "aws_elastictranscoder_preset" "test" { container = "mp4" description = "elastic transcoder preset test 3" - name = "aws_elastictranscoder_preset_tf_test_" + name = %[1]q audio { audio_packing_mode = "SingleTrack" @@ -234,8 +256,8 @@ resource "aws_elastictranscoder_preset" "test" { video_watermarks { id = "Terraform Test" - max_width = "20%" - max_height = "20%" + max_width = "20%%" + max_height = "20%%" sizing_policy = "ShrinkToFit" horizontal_align = "Right" horizontal_offset = "10px" @@ -254,4 +276,5 @@ resource "aws_elastictranscoder_preset" "test" { sizing_policy = "Fit" } } -` +`, rName) +} diff --git a/aws/structure.go b/aws/structure.go index 378aa7754c8..f1184cc0afb 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -2067,38 +2067,6 @@ func flattenApiGatewayThrottleSettings(settings *apigateway.ThrottleSettings) [] // TODO: refactor some of these helper functions and types in the terraform/helper packages -// getStringPtr returns a *string version of the value taken from m, where m -// can be a map[string]interface{} or a *schema.ResourceData. If the key isn't -// present or is empty, getNilString returns nil. -func getStringPtr(m interface{}, key string) *string { - switch m := m.(type) { - case map[string]interface{}: - v := m[key] - - if v == nil { - return nil - } - - s := v.(string) - if s == "" { - return nil - } - - return &s - - case *schema.ResourceData: - if v, ok := m.GetOk(key); ok { - if v == nil || v.(string) == "" { - return nil - } - s := v.(string) - return &s - } - } - - return nil -} - // a convenience wrapper type for the schema.Set map[string]interface{} // Set operations only alter the underlying map if the value is not nil type setMap map[string]interface{} From edcfcbba192f51eb380a67437148dad68f06271c Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 1 Apr 2020 10:58:51 -0700 Subject: [PATCH 198/684] Update CHANGELOG for #12389 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18af9c02e1b..d4a7ace8878 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 2.56.0 (Unreleased) +NOTES: + +* resource/aws_emr_cluster: The bug fix in this release will potentially re-create EMR Clusters with multiple bootstrap actions, since bootstrap actions cannot be modified in place. To avoid re-creation, temporarily add the [`ignore_changes` lifecycle configuration argument](https://www.terraform.io/docs/configuration/resources.html#ignore_changes) and/or update the order in your Terraform configuration. + ENHANCEMENTS: * data-source/aws_launch_template: Add `hibernation_options` attribute [GH-12492] @@ -12,6 +16,7 @@ ENHANCEMENTS: BUG FIXES: * resource/aws_codedeploy_deployment_group: Fix `blue_green_deployment_config` updates for ECS [GH-11885] +* resource/aws_emr_cluster: Now properly sets the order when multiple bootstrap actions are defined * resource/aws_kms_grant: Remove resource from Terraform state instead of error if removed outside Terraform [GH-12560] * resource/aws_volume_attachment: Ensure any error is shown while waiting for volume to detach [GH-12596] From 63d187a14b19bb852d7310c686f816b76c5c2316 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 1 Apr 2020 11:53:58 -0700 Subject: [PATCH 199/684] Removes nested resource testing in favour of `ImportStateVerify` and adds missing CodePipeline precheck --- aws/resource_aws_codepipeline_test.go | 131 +++++--------------------- 1 file changed, 21 insertions(+), 110 deletions(-) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 9a937658be4..6ef04c76f3b 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -4,7 +4,6 @@ import ( "fmt" "os" "regexp" - "strings" "testing" "github.com/aws/aws-sdk-go/aws" @@ -13,7 +12,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/terraform" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/flatmap" ) func TestAccAWSCodePipeline_basic(t *testing.T) { @@ -33,11 +31,6 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "role_arn", "aws_iam_role.codepipeline_role", "arn"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s", name))), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "type", "S3"), - testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p1, "", "location", "aws_s3_bucket.test", "bucket"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.#", "1"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.0.id", "1234"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.0.type", "KMS"), resource.TestCheckResourceAttr(resourceName, "stage.#", "2"), @@ -85,11 +78,6 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { Config: testAccAWSCodePipelineConfig_basicUpdated(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "type", "S3"), - testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p1, "", "location", "aws_s3_bucket.test", "bucket"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.#", "1"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.0.id", "1234"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, "", "encryption_key.0.type", "KMS"), resource.TestCheckResourceAttr(resourceName, "stage.#", "2"), @@ -113,6 +101,11 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.configuration.ProjectName", "test"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -133,8 +126,6 @@ func TestAccAWSCodePipeline_emptyArtifacts(t *testing.T) { testAccCheckAWSCodePipelineExists(resourceName, &p), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s", name))), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p, "", "type", "S3"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p, "", "encryption_key.#", "0"), ), ExpectNonEmptyPlan: true, }, @@ -238,6 +229,7 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { testAccPreCheck(t) testAccMultipleRegionsPreCheck(t) testAccAlternateRegionPreCheck(t) + testAccPreCheckAWSCodePipeline(t) }, ProviderFactories: testAccProviderFactories(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -248,12 +240,6 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { testAccCheckAWSCodePipelineExists(resourceName, &p), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p, testAccGetRegion(), "type", "S3"), - testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p, testAccGetRegion(), "location", "aws_s3_bucket.test", "bucket"), - - testAccCheckAWSCodePipelineArtifactStoreAttr(&p, testAccGetAlternateRegion(), "type", "S3"), - testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p, testAccGetAlternateRegion(), "location", "aws_s3_bucket.alternate", "bucket"), - resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), @@ -284,6 +270,7 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { testAccPreCheck(t) testAccMultipleRegionsPreCheck(t) testAccAlternateRegionPreCheck(t) + testAccPreCheckAWSCodePipeline(t) }, ProviderFactories: testAccProviderFactories(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -294,9 +281,6 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, testAccGetRegion(), "encryption_key.0.id", "1234"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p1, testAccGetAlternateRegion(), "encryption_key.0.id", "5678"), - resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), @@ -311,9 +295,6 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { testAccCheckAWSCodePipelineExists(resourceName, &p2), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p2, testAccGetRegion(), "encryption_key.0.id", "4321"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p2, testAccGetAlternateRegion(), "encryption_key.0.id", "8765"), - resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "BuildUpdated"), @@ -322,6 +303,12 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stage.1.action.1.region", testAccGetAlternateRegion()), ), }, + { + Config: testAccAWSCodePipelineConfig_multiregionUpdated(name), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -338,6 +325,7 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { testAccPreCheck(t) testAccMultipleRegionsPreCheck(t) testAccAlternateRegionPreCheck(t) + testAccPreCheckAWSCodePipeline(t) }, ProviderFactories: testAccProviderFactories(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -348,8 +336,6 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), - testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p1, "", "location", "aws_s3_bucket.test", "bucket"), - resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), @@ -362,9 +348,6 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { testAccCheckAWSCodePipelineExists(resourceName, &p2), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p2, testAccGetRegion(), "encryption_key.0.id", "1234"), - testAccCheckAWSCodePipelineArtifactStoreAttr(&p2, testAccGetAlternateRegion(), "encryption_key.0.id", "5678"), - resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "2"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), @@ -379,14 +362,18 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), - testAccCheckAWSCodePipelineArtifactStoreAttrPair(&p1, "", "location", "aws_s3_bucket.test", "bucket"), - resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", testAccGetRegion()), ), }, + { + Config: testAccAWSCodePipelineConfig_backToBasic(name), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -433,7 +420,7 @@ func testAccCheckAWSCodePipelineDestroy(s *terraform.State) error { return fmt.Errorf("Expected AWS CodePipeline to be gone, but was still found") } if isAWSErr(err, "PipelineNotFoundException", "") { - return nil + continue } return err } @@ -1246,82 +1233,6 @@ resource "aws_s3_bucket" "%[1]s" { `, bucket, rName, provider) } -func testAccCheckAWSCodePipelineArtifactStoreAttr(p *codepipeline.PipelineDeclaration, region string, key, value string) resource.TestCheckFunc { - return func(s *terraform.State) error { - values, err := testAccCheckAWSCodePipelineArtifactStoreFlatmap(p, region) - if err != nil { - return err - } - - emptyCheck := false - if value == "0" && (strings.HasSuffix(key, ".#") || strings.HasSuffix(key, ".%")) { - emptyCheck = true - } - - if v, ok := values[key]; !ok || v != value { - if emptyCheck && !ok { - return nil - } - - if !ok { - return fmt.Errorf("ArtifactStores[%s]: Attribute %q not found", region, key) - } - - return fmt.Errorf( - "ArtifactStores[%s]: Attribute %q expected %#v, got %#v", region, key, value, v) - } - return nil - } -} - -func testAccCheckAWSCodePipelineArtifactStoreAttrPair(p *codepipeline.PipelineDeclaration, region string, keyFirst, nameSecond, keySecond string) resource.TestCheckFunc { - return func(s *terraform.State) error { - values, err := testAccCheckAWSCodePipelineArtifactStoreFlatmap(p, region) - if err != nil { - return err - } - - isSecond, err := primaryInstanceState(s, nameSecond) - if err != nil { - return err - } - - vFirst, okFirst := values[keyFirst] - vSecond, okSecond := isSecond.Attributes[keySecond] - - if okFirst != okSecond { - if !okFirst { - return fmt.Errorf("ArtifactStores[%s]: Attribute %q not set, but %q is set in %s as %q", region, keyFirst, keySecond, nameSecond, vSecond) - } - return fmt.Errorf("ArtifactStores[%s]: Attribute %q is %q, but %q is not set in %s", region, keyFirst, vFirst, keySecond, nameSecond) - } - if !(okFirst || okSecond) { - // If they both don't exist then they are equally unset, so that's okay. - return nil - } - - if vFirst != vSecond { - return fmt.Errorf("ArtifactStores[%s]: Attribute '%s' expected %#v, got %#v", region, keyFirst, vSecond, vFirst) - } - - return nil - } -} - -func testAccCheckAWSCodePipelineArtifactStoreFlatmap(p *codepipeline.PipelineDeclaration, region string) (flatmap.Map, error) { - var as *codepipeline.ArtifactStore - if region == "" { - as = p.ArtifactStore - } else { - v, ok := p.ArtifactStores[region] - if !ok { - return nil, fmt.Errorf("Artifact Store for region %q not found", region) - } - as = v - } - return flatmap.Flatten(flattenAwsCodePipelineArtifactStore(as)[0].(map[string]interface{})), nil -} - func TestResourceAWSCodePipelineExpandArtifactStoresValidation(t *testing.T) { cases := []struct { Name string From 6f757d5b021f045465516c220e5c63ff8d33cd85 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Wed, 1 Apr 2020 15:36:34 -0400 Subject: [PATCH 200/684] resource/aws_s3_bucket: Prevent various panics with empty configuration blocks (#12614) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/11420 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12480 This does not contain a fully reproducible configuration for #12480 after a few timeboxed attempts, but left a test that adds `access_control_translation` since that most closely mimics what was reported and was previously untested. The addition of an empty configuration block in the plan difference appears to be a bug in the Terraform Plugin SDK or Terraform core logic. If/when these various S3 configurations are potentially moved to their own resources, we should try to remove the Set hashing functions then. Generally they are unnecessary except in specific situations. Previously: ``` === CONT TestAccAWSS3Bucket_LifecycleRule_Expiration_EmptyConfigurationBlock panic: interface conversion: interface {} is nil, not map[string]interface {} goroutine 228 [running]: github.com/terraform-providers/terraform-provider-aws/aws.expirationHash(0x0, 0x0, 0xc000e4bf10) /Users/bflad/src/github.com/terraform-providers/terraform-provider-aws/aws/resource_aws_s3_bucket.go:2503 +0x3d6 github.com/hashicorp/terraform-plugin-sdk/helper/schema.(*Set).hash(0xc000e4bf00, 0x0, 0x0, 0x746172697078652e, 0x2e302e6e6f69) /Users/bflad/go/pkg/mod/github.com/hashicorp/terraform-plugin-sdk@v1.8.0/helper/schema/set.go:221 +0x3d ``` Output from acceptance testing: ``` --- PASS: TestAccAWSS3Bucket_acceleration (62.39s) --- PASS: TestAccAWSS3Bucket_AclToGrant (62.44s) --- PASS: TestAccAWSS3Bucket_basic (37.44s) --- PASS: TestAccAWSS3Bucket_Bucket_EmptyString (35.25s) --- PASS: TestAccAWSS3Bucket_Cors_Delete (30.46s) --- PASS: TestAccAWSS3Bucket_Cors_EmptyOrigin (37.46s) --- PASS: TestAccAWSS3Bucket_Cors_Update (64.62s) --- PASS: TestAccAWSS3Bucket_disableDefaultEncryption_whenDefaultEncryptionIsEnabled (62.63s) --- PASS: TestAccAWSS3Bucket_enableDefaultEncryption_whenAES256IsUsed (36.77s) --- PASS: TestAccAWSS3Bucket_enableDefaultEncryption_whenTypical (64.54s) --- PASS: TestAccAWSS3Bucket_forceDestroy (34.28s) --- PASS: TestAccAWSS3Bucket_forceDestroyWithEmptyPrefixes (33.82s) --- PASS: TestAccAWSS3Bucket_forceDestroyWithObjectLockEnabled (40.74s) --- PASS: TestAccAWSS3Bucket_generatedName (34.28s) --- PASS: TestAccAWSS3Bucket_GrantToAcl (55.10s) --- PASS: TestAccAWSS3Bucket_LifecycleBasic (85.90s) --- PASS: TestAccAWSS3Bucket_LifecycleExpireMarkerOnly (60.69s) --- PASS: TestAccAWSS3Bucket_LifecycleRule_Expiration_EmptyConfigurationBlock (29.75s) --- PASS: TestAccAWSS3Bucket_Logging (53.50s) --- PASS: TestAccAWSS3Bucket_namePrefix (34.09s) --- PASS: TestAccAWSS3Bucket_objectLock (61.56s) --- PASS: TestAccAWSS3Bucket_Policy (88.91s) --- PASS: TestAccAWSS3Bucket_region (35.91s) --- PASS: TestAccAWSS3Bucket_Replication (173.40s) --- PASS: TestAccAWSS3Bucket_ReplicationConfiguration_Rule_Destination_AccessControlTranslation (109.21s) --- PASS: TestAccAWSS3Bucket_ReplicationConfiguration_Rule_Destination_AddAccessControlTranslation (87.98s) --- PASS: TestAccAWSS3Bucket_ReplicationExpectVersioningValidationError (27.38s) --- PASS: TestAccAWSS3Bucket_ReplicationSchemaV2 (150.14s) --- PASS: TestAccAWSS3Bucket_ReplicationWithoutPrefix (51.20s) --- PASS: TestAccAWSS3Bucket_ReplicationWithoutStorageClass (51.04s) --- PASS: TestAccAWSS3Bucket_RequestPayer (61.18s) --- PASS: TestAccAWSS3Bucket_shouldFailNotFound (17.00s) --- PASS: TestAccAWSS3Bucket_tagsWithNoSystemTags (114.98s) --- PASS: TestAccAWSS3Bucket_tagsWithSystemTags (148.05s) --- PASS: TestAccAWSS3Bucket_UpdateAcl (60.53s) --- PASS: TestAccAWSS3Bucket_UpdateGrant (90.89s) --- PASS: TestAccAWSS3Bucket_Versioning (89.97s) --- PASS: TestAccAWSS3Bucket_Website_Simple (89.17s) --- PASS: TestAccAWSS3Bucket_WebsiteRedirect (89.72s) --- PASS: TestAccAWSS3Bucket_WebsiteRoutingRules (63.15s) ``` --- aws/resource_aws_s3_bucket.go | 62 +++++++++--- aws/resource_aws_s3_bucket_test.go | 150 +++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+), 15 deletions(-) diff --git a/aws/resource_aws_s3_bucket.go b/aws/resource_aws_s3_bucket.go index 11b8bf09623..4ff8517b56d 100644 --- a/aws/resource_aws_s3_bucket.go +++ b/aws/resource_aws_s3_bucket.go @@ -2482,7 +2482,12 @@ func validateS3BucketName(value string, region string) error { func grantHash(v interface{}) int { var buf bytes.Buffer - m := v.(map[string]interface{}) + m, ok := v.(map[string]interface{}) + + if !ok { + return 0 + } + if v, ok := m["id"]; ok { buf.WriteString(fmt.Sprintf("%s-", v.(string))) } @@ -2500,7 +2505,12 @@ func grantHash(v interface{}) int { func expirationHash(v interface{}) int { var buf bytes.Buffer - m := v.(map[string]interface{}) + m, ok := v.(map[string]interface{}) + + if !ok { + return 0 + } + if v, ok := m["date"]; ok { buf.WriteString(fmt.Sprintf("%s-", v.(string))) } @@ -2515,7 +2525,12 @@ func expirationHash(v interface{}) int { func transitionHash(v interface{}) int { var buf bytes.Buffer - m := v.(map[string]interface{}) + m, ok := v.(map[string]interface{}) + + if !ok { + return 0 + } + if v, ok := m["date"]; ok { buf.WriteString(fmt.Sprintf("%s-", v.(string))) } @@ -2530,7 +2545,11 @@ func transitionHash(v interface{}) int { func rulesHash(v interface{}) int { var buf bytes.Buffer - m := v.(map[string]interface{}) + m, ok := v.(map[string]interface{}) + + if !ok { + return 0 + } if v, ok := m["id"]; ok { buf.WriteString(fmt.Sprintf("%s-", v.(string))) @@ -2558,7 +2577,12 @@ func rulesHash(v interface{}) int { func replicationRuleFilterHash(v interface{}) int { var buf bytes.Buffer - m := v.(map[string]interface{}) + m, ok := v.(map[string]interface{}) + + if !ok { + return 0 + } + if v, ok := m["prefix"]; ok { buf.WriteString(fmt.Sprintf("%s-", v.(string))) } @@ -2570,7 +2594,11 @@ func replicationRuleFilterHash(v interface{}) int { func destinationHash(v interface{}) int { var buf bytes.Buffer - m := v.(map[string]interface{}) + m, ok := v.(map[string]interface{}) + + if !ok { + return 0 + } if v, ok := m["bucket"]; ok { buf.WriteString(fmt.Sprintf("%s-", v.(string))) @@ -2591,12 +2619,12 @@ func destinationHash(v interface{}) int { } func accessControlTranslationHash(v interface{}) int { - // v is nil if empty access_control_translation is given. - if v == nil { + var buf bytes.Buffer + m, ok := v.(map[string]interface{}) + + if !ok { return 0 } - var buf bytes.Buffer - m := v.(map[string]interface{}) if v, ok := m["owner"]; ok { buf.WriteString(fmt.Sprintf("%s-", v.(string))) @@ -2605,12 +2633,12 @@ func accessControlTranslationHash(v interface{}) int { } func sourceSelectionCriteriaHash(v interface{}) int { - // v is nil if empty source_selection_criteria is given. - if v == nil { + var buf bytes.Buffer + m, ok := v.(map[string]interface{}) + + if !ok { return 0 } - var buf bytes.Buffer - m := v.(map[string]interface{}) if v, ok := m["sse_kms_encrypted_objects"].(*schema.Set); ok && v.Len() > 0 { buf.WriteString(fmt.Sprintf("%d-", sourceSseKmsObjectsHash(v.List()[0]))) @@ -2620,7 +2648,11 @@ func sourceSelectionCriteriaHash(v interface{}) int { func sourceSseKmsObjectsHash(v interface{}) int { var buf bytes.Buffer - m := v.(map[string]interface{}) + m, ok := v.(map[string]interface{}) + + if !ok { + return 0 + } if v, ok := m["enabled"]; ok { buf.WriteString(fmt.Sprintf("%t-", v.(bool))) diff --git a/aws/resource_aws_s3_bucket_test.go b/aws/resource_aws_s3_bucket_test.go index e18f5ae5c18..b3385669a6c 100644 --- a/aws/resource_aws_s3_bucket_test.go +++ b/aws/resource_aws_s3_bucket_test.go @@ -1463,6 +1463,26 @@ func TestAccAWSS3Bucket_LifecycleExpireMarkerOnly(t *testing.T) { }) } +// Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/11420 +func TestAccAWSS3Bucket_LifecycleRule_Expiration_EmptyConfigurationBlock(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_s3_bucket.bucket" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSS3BucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSS3BucketConfigLifecycleRuleExpirationEmptyConfigurationBlock(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSS3BucketExists(resourceName), + ), + }, + }, + }) +} + func TestAccAWSS3Bucket_Replication(t *testing.T) { rInt := acctest.RandInt() alternateRegion := testAccGetAlternateRegion() @@ -1680,6 +1700,90 @@ func TestAccAWSS3Bucket_ReplicationConfiguration_Rule_Destination_AccessControlT }) } +// Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12480 +func TestAccAWSS3Bucket_ReplicationConfiguration_Rule_Destination_AddAccessControlTranslation(t *testing.T) { + rInt := acctest.RandInt() + region := testAccGetRegion() + partition := testAccGetPartition() + iamRoleResourceName := "aws_iam_role.role" + resourceName := "aws_s3_bucket.bucket" + + // record the initialized providers so that we can use them to check for the instances in each region + var providers []*schema.Provider + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccMultipleRegionsPreCheck(t) + testAccAlternateRegionPreCheck(t) + }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckWithProviders(testAccCheckAWSS3BucketDestroyWithProvider, &providers), + Steps: []resource.TestStep{ + { + Config: testAccAWSS3BucketConfigReplicationConfigurationRulesDestination(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSS3BucketExistsWithProvider(resourceName, testAccAwsRegionProviderFunc(region, &providers)), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "replication_configuration.0.role", iamRoleResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rules.#", "1"), + testAccCheckAWSS3BucketReplicationRules( + resourceName, + testAccAwsRegionProviderFunc(region, &providers), + []*s3.ReplicationRule{ + { + ID: aws.String("foobar"), + Destination: &s3.Destination{ + Account: aws.String("${data.aws_caller_identity.current.account_id}"), + Bucket: aws.String(fmt.Sprintf("arn:%s:s3:::tf-test-bucket-destination-%d", partition, rInt)), + StorageClass: aws.String(s3.ObjectStorageClassStandard), + }, + Prefix: aws.String("foo"), + Status: aws.String(s3.ReplicationRuleStatusEnabled), + }, + }, + ), + ), + }, + { + Config: testAccAWSS3BucketConfigReplicationWithAccessControlTranslation(rInt), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy", "acl", "versioning"}, + }, + { + Config: testAccAWSS3BucketConfigReplicationWithAccessControlTranslation(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSS3BucketExistsWithProvider(resourceName, testAccAwsRegionProviderFunc(region, &providers)), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "replication_configuration.0.role", iamRoleResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rules.#", "1"), + testAccCheckAWSS3BucketReplicationRules( + resourceName, + testAccAwsRegionProviderFunc(region, &providers), + []*s3.ReplicationRule{ + { + ID: aws.String("foobar"), + Destination: &s3.Destination{ + Account: aws.String("${data.aws_caller_identity.current.account_id}"), + Bucket: aws.String(fmt.Sprintf("arn:%s:s3:::tf-test-bucket-destination-%d", partition, rInt)), + StorageClass: aws.String(s3.ObjectStorageClassStandard), + AccessControlTranslation: &s3.AccessControlTranslation{ + Owner: aws.String("Destination"), + }, + }, + Prefix: aws.String("foo"), + Status: aws.String(s3.ReplicationRuleStatusEnabled), + }, + }, + ), + ), + }, + }, + }) +} + // StorageClass issue: https://github.com/hashicorp/terraform/issues/10909 func TestAccAWSS3Bucket_ReplicationWithoutStorageClass(t *testing.T) { rInt := acctest.RandInt() @@ -3633,6 +3737,21 @@ resource "aws_s3_bucket" "bucket" { `, randInt) } +func testAccAWSS3BucketConfigLifecycleRuleExpirationEmptyConfigurationBlock(rName string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "bucket" { + bucket = %[1]q + + lifecycle_rule { + enabled = true + id = "id1" + + expiration {} + } +} +`, rName) +} + func testAccAWSS3BucketConfigReplicationBasic(randInt int) string { return testAccAlternateRegionProviderConfig() + fmt.Sprintf(` data "aws_partition" "current" {} @@ -3781,6 +3900,37 @@ resource "aws_s3_bucket" "bucket" { `, randInt) } +func testAccAWSS3BucketConfigReplicationConfigurationRulesDestination(randInt int) string { + return testAccAWSS3BucketConfigReplicationBasic(randInt) + fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +resource "aws_s3_bucket" "bucket" { + acl = "private" + bucket = "tf-test-bucket-%[1]d" + + replication_configuration { + role = aws_iam_role.role.arn + + rules { + id = "foobar" + prefix = "foo" + status = "Enabled" + + destination { + account_id = data.aws_caller_identity.current.account_id + bucket = aws_s3_bucket.destination.arn + storage_class = "STANDARD" + } + } + } + + versioning { + enabled = true + } +} +`, randInt) +} + func testAccAWSS3BucketConfigReplicationWithSseKmsEncryptedObjectsAndAccessControlTranslation(randInt int) string { return testAccAWSS3BucketConfigReplicationBasic(randInt) + fmt.Sprintf(` data "aws_caller_identity" "current" {} From c5e26ae4e683f5eee4724acb25355f665cb5e1ff Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Wed, 1 Apr 2020 15:38:12 -0400 Subject: [PATCH 201/684] Update CHANGELOG for #12614 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4a7ace8878..3c88e2fa0ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ BUG FIXES: * resource/aws_codedeploy_deployment_group: Fix `blue_green_deployment_config` updates for ECS [GH-11885] * resource/aws_emr_cluster: Now properly sets the order when multiple bootstrap actions are defined * resource/aws_kms_grant: Remove resource from Terraform state instead of error if removed outside Terraform [GH-12560] +* resource/aws_s3_bucket: Prevent various panics with empty configuration blocks [GH-12614] * resource/aws_volume_attachment: Ensure any error is shown while waiting for volume to detach [GH-12596] ## 2.55.0 (March 27, 2020) From 52b84fb11ad4e0b4c35778c2eb39cf812385ed7e Mon Sep 17 00:00:00 2001 From: Gerard Costa Date: Sat, 12 Aug 2017 22:14:24 +0200 Subject: [PATCH 202/684] resource_aws_instance: Modify root volume size without instance recreation Fixes: #768 make testacc TEST=./aws TESTARGS='-run=TestAccAWSInstance_changeRootBlockDeviceVolumeSize' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -run=TestAccAWSInstance_changeRootBlockDeviceVolumeSize -timeout 120m === RUN TestAccAWSInstance_changeRootBlockDeviceVolumeSize --- PASS: TestAccAWSInstance_changeRootBlockDeviceVolumeSize (514.63s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 514.642s --- aws/resource_aws_instance.go | 82 ++++++++++++++++++++++++++++++- aws/resource_aws_instance_test.go | 46 +++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index 6fecb4179f9..cda12ef48ef 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -472,7 +472,6 @@ func resourceAwsInstance() *schema.Resource { Type: schema.TypeInt, Optional: true, Computed: true, - ForceNew: true, }, "volume_type": { @@ -1260,6 +1259,58 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { } } + if d.HasChange("root_block_device") { + if rbd, ok := d.GetOk("root_block_device"); ok { + rbdL := rbd.([]interface{}) + if len(rbdL) > 1 { + return fmt.Errorf("Cannot specify more than one root_block_device.") + } + for _, r := range rbdL { + bd := r.(map[string]interface{}) + if volumeSize, ok := bd["volume_size"].(int); ok && volumeSize != 0 { + volumeIds, err := getAwsInstanceVolumeIds(conn, d) + if err != nil { + return fmt.Errorf("Error retrieving volumes: %s", err) + } + + volResp, err := conn.DescribeVolumes(&ec2.DescribeVolumesInput{ + VolumeIds: volumeIds, + }) + if err != nil { + return err + } + + if len(volResp.Volumes) < 1 { + return fmt.Errorf("Cannot fetch volume info") + } + if int64(volumeSize) != *volResp.Volumes[0].Size { + _, err = conn.ModifyVolume(&ec2.ModifyVolumeInput{ + Size: aws.Int64(int64(volumeSize)), + VolumeId: volumeIds[0], + }) + if err != nil { + return err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"modifying", "optimizing"}, + Target: []string{"completed"}, + Refresh: VolumeStateRefreshFunc(conn, *volumeIds[0], "failed"), + Timeout: d.Timeout(schema.TimeoutUpdate), + Delay: 30 * time.Second, + MinTimeout: 30 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("Error waiting for volume (%s) to be modified: %s", *volumeIds[0], err) + } + } + } + } + } + } + // TODO(mitchellh): wait for the attributes we modified to // persist the change... @@ -1315,6 +1366,35 @@ func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string, failStates []str } } +// VolumeStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch +// an EC2 root device volume. +func VolumeStateRefreshFunc(conn *ec2.EC2, volumeID, failState string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + resp, err := conn.DescribeVolumesModifications(&ec2.DescribeVolumesModificationsInput{ + VolumeIds: []*string{aws.String(volumeID)}, + }) + if err != nil { + if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVolumeID.NotFound" { + resp = nil + } else { + log.Printf("Error on VolumeStateRefresh: %s", err) + return nil, "", err + } + } + if resp == nil { + return nil, "", nil + } + + i := resp.VolumesModifications[0] + state := *i.ModificationState + if state == failState { + return i, state, fmt.Errorf("Failed to reach target state. Reason: %s", *i.StatusMessage) + } + + return i, state, nil + } +} + func stringifyStateReason(sr *ec2.StateReason) string { if sr.Message != nil { return *sr.Message diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index a260b3f93e1..4db0ef74891 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -1544,6 +1544,35 @@ func TestAccAWSInstance_changeInstanceType(t *testing.T) { }) } +func TestAccAWSInstance_changeRootBlockDeviceVolumeSize(t *testing.T) { + var before ec2.Instance + var after ec2.Instance + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccInstanceGP2IopsDevice, + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists("aws_instance.foo", &before), + ), + }, + { + Config: testAccInstanceGP2IopsDeviceVolumeSizeUpdate, + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists("aws_instance.foo", &after), + testAccCheckInstanceNotRecreated( + t, &before, &after), + resource.TestCheckResourceAttr( + "aws_instance.foo", "root_block_device.0.volume_size", "20"), + ), + }, + }, + }) +} + func TestAccAWSInstance_primaryNetworkInterface(t *testing.T) { var instance ec2.Instance var eni ec2.NetworkInterface @@ -3008,6 +3037,23 @@ resource "aws_instance" "test" { } ` +const testAccInstanceGP2IopsDeviceVolumeSizeUpdate = ` +resource "aws_instance" "foo" { + # us-west-2 + ami = "ami-55a7ea65" + + # In order to attach an encrypted volume to an instance you need to have an + # m3.medium or larger. See "Supported Instance Types" in: + # http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html + instance_type = "m3.medium" + + root_block_device { + volume_type = "gp2" + volume_size = 12 + } +} +` + const testAccInstanceConfigBlockDevices = ` resource "aws_instance" "test" { # us-west-2 From ce7c8c0e94cc2d29a2e7e788fa0d49cc14664d88 Mon Sep 17 00:00:00 2001 From: Gerard Costa Date: Wed, 2 May 2018 02:40:47 +0200 Subject: [PATCH 203/684] Improve code quality and fix tests as requested --- aws/resource_aws_instance.go | 84 ++++++++++++++----------------- aws/resource_aws_instance_test.go | 2 +- 2 files changed, 39 insertions(+), 47 deletions(-) diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index cda12ef48ef..3677b8a9046 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -1259,55 +1259,51 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { } } - if d.HasChange("root_block_device") { - if rbd, ok := d.GetOk("root_block_device"); ok { - rbdL := rbd.([]interface{}) - if len(rbdL) > 1 { - return fmt.Errorf("Cannot specify more than one root_block_device.") - } - for _, r := range rbdL { - bd := r.(map[string]interface{}) - if volumeSize, ok := bd["volume_size"].(int); ok && volumeSize != 0 { - volumeIds, err := getAwsInstanceVolumeIds(conn, d) - if err != nil { - return fmt.Errorf("Error retrieving volumes: %s", err) - } + if d.HasChange("root_block_device.0.volume_size") { + if vs, ok := d.GetOk("root_block_device.0.volume_size"); ok { + volumeSize := vs.(int) + if volumeSize != 0 { + volumeIds, err := getAwsInstanceVolumeIds(conn, d) + if err != nil { + return fmt.Errorf("Error retrieving volumes: %s.", err) + } + + volResp, err := conn.DescribeVolumes(&ec2.DescribeVolumesInput{ + VolumeIds: volumeIds, + }) + if err != nil { + return err + } - volResp, err := conn.DescribeVolumes(&ec2.DescribeVolumesInput{ - VolumeIds: volumeIds, + if len(volResp.Volumes) < 1 { + return fmt.Errorf("No volumes found for %s.", d.Id()) + } + + if int64(volumeSize) != *volResp.Volumes[0].Size { + _, err = conn.ModifyVolume(&ec2.ModifyVolumeInput{ + Size: aws.Int64(int64(volumeSize)), + VolumeId: volumeIds[0], }) if err != nil { return err } - if len(volResp.Volumes) < 1 { - return fmt.Errorf("Cannot fetch volume info") + stateConf := &resource.StateChangeConf{ + Pending: []string{"modifying", "optimizing"}, + Target: []string{"completed"}, + Refresh: VolumeStateRefreshFunc(conn, *volumeIds[0], "failed"), + Timeout: d.Timeout(schema.TimeoutUpdate), + Delay: 30 * time.Second, + MinTimeout: 30 * time.Second, } - if int64(volumeSize) != *volResp.Volumes[0].Size { - _, err = conn.ModifyVolume(&ec2.ModifyVolumeInput{ - Size: aws.Int64(int64(volumeSize)), - VolumeId: volumeIds[0], - }) - if err != nil { - return err - } - - stateConf := &resource.StateChangeConf{ - Pending: []string{"modifying", "optimizing"}, - Target: []string{"completed"}, - Refresh: VolumeStateRefreshFunc(conn, *volumeIds[0], "failed"), - Timeout: d.Timeout(schema.TimeoutUpdate), - Delay: 30 * time.Second, - MinTimeout: 30 * time.Second, - } - _, err = stateConf.WaitForState() - if err != nil { - return fmt.Errorf("Error waiting for volume (%s) to be modified: %s", *volumeIds[0], err) - } + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("Error waiting for volume (%s) to be modified: %s", *volumeIds[0], err) } } } + } } @@ -1374,15 +1370,11 @@ func VolumeStateRefreshFunc(conn *ec2.EC2, volumeID, failState string) resource. VolumeIds: []*string{aws.String(volumeID)}, }) if err != nil { - if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVolumeID.NotFound" { - resp = nil - } else { - log.Printf("Error on VolumeStateRefresh: %s", err) - return nil, "", err + if isAWSErr(err, "InvalidVolumeID.NotFound", "does not exist") { + return nil, "", nil } - } - if resp == nil { - return nil, "", nil + log.Printf("Error on VolumeStateRefresh: %s", err) + return nil, "", err } i := resp.VolumesModifications[0] diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index 4db0ef74891..cc26719390e 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -1566,7 +1566,7 @@ func TestAccAWSInstance_changeRootBlockDeviceVolumeSize(t *testing.T) { testAccCheckInstanceNotRecreated( t, &before, &after), resource.TestCheckResourceAttr( - "aws_instance.foo", "root_block_device.0.volume_size", "20"), + "aws_instance.foo", "root_block_device.0.volume_size", "12"), ), }, }, From a06f0776133bc828db61439141c006c3b94b28ba Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 1 Apr 2020 13:54:39 -0700 Subject: [PATCH 204/684] Updates to current framework --- aws/resource_aws_instance.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index 3677b8a9046..c7b6b0c941d 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -1263,13 +1263,13 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { if vs, ok := d.GetOk("root_block_device.0.volume_size"); ok { volumeSize := vs.(int) if volumeSize != 0 { - volumeIds, err := getAwsInstanceVolumeIds(conn, d) + volumeIds, err := getAwsInstanceVolumeIds(conn, d.Id()) if err != nil { return fmt.Errorf("Error retrieving volumes: %s.", err) } volResp, err := conn.DescribeVolumes(&ec2.DescribeVolumesInput{ - VolumeIds: volumeIds, + VolumeIds: aws.StringSlice(volumeIds), }) if err != nil { return err @@ -1282,7 +1282,7 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { if int64(volumeSize) != *volResp.Volumes[0].Size { _, err = conn.ModifyVolume(&ec2.ModifyVolumeInput{ Size: aws.Int64(int64(volumeSize)), - VolumeId: volumeIds[0], + VolumeId: aws.String(volumeIds[0]), }) if err != nil { return err @@ -1291,7 +1291,7 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { stateConf := &resource.StateChangeConf{ Pending: []string{"modifying", "optimizing"}, Target: []string{"completed"}, - Refresh: VolumeStateRefreshFunc(conn, *volumeIds[0], "failed"), + Refresh: VolumeStateRefreshFunc(conn, volumeIds[0], "failed"), Timeout: d.Timeout(schema.TimeoutUpdate), Delay: 30 * time.Second, MinTimeout: 30 * time.Second, @@ -1299,7 +1299,7 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf("Error waiting for volume (%s) to be modified: %s", *volumeIds[0], err) + return fmt.Errorf("Error waiting for volume (%s) to be modified: %s", volumeIds[0], err) } } } From 4b425d2cbfdbbb48159439485e2a38ed691db46e Mon Sep 17 00:00:00 2001 From: HIRAMATSU Kentaro Date: Thu, 2 Apr 2020 21:51:16 +0900 Subject: [PATCH 205/684] resource/aws_s3_bucket: Fix lint error (#12626) --- website/docs/r/s3_bucket.html.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/r/s3_bucket.html.markdown b/website/docs/r/s3_bucket.html.markdown index c5b2a02d953..0e9a6481b51 100644 --- a/website/docs/r/s3_bucket.html.markdown +++ b/website/docs/r/s3_bucket.html.markdown @@ -318,15 +318,15 @@ resource "aws_s3_bucket" "bucket" { bucket = "mybucket" grant { - id = "${data.aws_canonical_user_id.current_user.id}" - type = "CanonicalUser" + id = "${data.aws_canonical_user_id.current_user.id}" + type = "CanonicalUser" permissions = ["FULL_CONTROL"] } grant { - type = "Group" + type = "Group" permissions = ["READ", "WRITE"] - uri = "http://acs.amazonaws.com/groups/s3/LogDelivery" + uri = "http://acs.amazonaws.com/groups/s3/LogDelivery" } } ``` From 524f0f67c14403d99c6845a2f785273e11a6f9e1 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 2 Apr 2020 14:51:12 -0400 Subject: [PATCH 206/684] service/sagemaker: Remove deprecated (helper/schema.ResourceData).Partial() and (helper/schema.ResourceData).SetPartial() (#12462) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12083 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/12087 Previously: ``` aws/resource_aws_sagemaker_endpoint.go:135:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_sagemaker_endpoint.go:144:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_sagemaker_endpoint.go:156:3: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_sagemaker_endpoint.go:168:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_sagemaker_model.go:284:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_sagemaker_model.go:294:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_sagemaker_notebook_instance.go:217:2: R007: deprecated (schema.ResourceData).Partial aws/resource_aws_sagemaker_notebook_instance.go:226:2: R008: deprecated (schema.ResourceData).SetPartial aws/resource_aws_sagemaker_notebook_instance.go:328:2: R007: deprecated (schema.ResourceData).Partial ``` Output from acceptance testing: ``` --- PASS: TestAccAWSSagemakerEndpoint_basic (485.91s) --- PASS: TestAccAWSSagemakerEndpoint_EndpointConfigName (852.16s) --- PASS: TestAccAWSSagemakerEndpoint_Tags (525.67s) --- PASS: TestAccAWSSagemakerModel_basic (47.36s) --- PASS: TestAccAWSSagemakerModel_containers (35.84s) --- PASS: TestAccAWSSagemakerModel_networkIsolation (59.84s) --- PASS: TestAccAWSSagemakerModel_primaryContainerEnvironment (33.08s) --- PASS: TestAccAWSSagemakerModel_primaryContainerHostname (30.86s) --- PASS: TestAccAWSSagemakerModel_primaryContainerModelDataUrl (57.54s) --- PASS: TestAccAWSSagemakerModel_tags (42.35s) --- PASS: TestAccAWSSagemakerModel_vpcConfig (62.13s) --- PASS: TestAccAWSSagemakerNotebookInstance_basic (359.34s) --- PASS: TestAccAWSSagemakerNotebookInstance_direct_internet_access (714.40s) --- PASS: TestAccAWSSagemakerNotebookInstance_disappears (396.62s) --- PASS: TestAccAWSSagemakerNotebookInstance_LifecycleConfigName (296.66s) --- PASS: TestAccAWSSagemakerNotebookInstance_tags (411.90s) --- PASS: TestAccAWSSagemakerNotebookInstance_update (625.72s) ``` --- aws/resource_aws_sagemaker_endpoint.go | 6 ------ aws/resource_aws_sagemaker_model.go | 4 ---- aws/resource_aws_sagemaker_notebook_instance.go | 5 ----- 3 files changed, 15 deletions(-) diff --git a/aws/resource_aws_sagemaker_endpoint.go b/aws/resource_aws_sagemaker_endpoint.go index b48c215a47b..726c06d4a78 100644 --- a/aws/resource_aws_sagemaker_endpoint.go +++ b/aws/resource_aws_sagemaker_endpoint.go @@ -132,8 +132,6 @@ func resourceAwsSagemakerEndpointRead(d *schema.ResourceData, meta interface{}) func resourceAwsSagemakerEndpointUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).sagemakerconn - d.Partial(true) - if d.HasChange("tags") { o, n := d.GetChange("tags") @@ -141,7 +139,6 @@ func resourceAwsSagemakerEndpointUpdate(d *schema.ResourceData, meta interface{} return fmt.Errorf("error updating Sagemaker Endpoint (%s) tags: %s", d.Id(), err) } } - d.SetPartial("tags") if d.HasChange("endpoint_config_name") { modifyOpts := &sagemaker.UpdateEndpointInput{ @@ -153,7 +150,6 @@ func resourceAwsSagemakerEndpointUpdate(d *schema.ResourceData, meta interface{} if _, err := conn.UpdateEndpoint(modifyOpts); err != nil { return fmt.Errorf("error updating SageMaker Endpoint (%s): %s", d.Id(), err) } - d.SetPartial("endpoint_config_name") describeInput := &sagemaker.DescribeEndpointInput{ EndpointName: aws.String(d.Id()), @@ -165,8 +161,6 @@ func resourceAwsSagemakerEndpointUpdate(d *schema.ResourceData, meta interface{} } } - d.Partial(false) - return resourceAwsSagemakerEndpointRead(d, meta) } diff --git a/aws/resource_aws_sagemaker_model.go b/aws/resource_aws_sagemaker_model.go index ba977fa3aa2..bfcc831ed4b 100644 --- a/aws/resource_aws_sagemaker_model.go +++ b/aws/resource_aws_sagemaker_model.go @@ -281,8 +281,6 @@ func flattenSageMakerVpcConfigResponse(vpcConfig *sagemaker.VpcConfig) []map[str func resourceAwsSagemakerModelUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).sagemakerconn - d.Partial(true) - if d.HasChange("tags") { o, n := d.GetChange("tags") @@ -291,8 +289,6 @@ func resourceAwsSagemakerModelUpdate(d *schema.ResourceData, meta interface{}) e } } - d.Partial(false) - return resourceAwsSagemakerModelRead(d, meta) } diff --git a/aws/resource_aws_sagemaker_notebook_instance.go b/aws/resource_aws_sagemaker_notebook_instance.go index 5ce1d792a64..ea657473bdb 100644 --- a/aws/resource_aws_sagemaker_notebook_instance.go +++ b/aws/resource_aws_sagemaker_notebook_instance.go @@ -214,8 +214,6 @@ func resourceAwsSagemakerNotebookInstanceRead(d *schema.ResourceData, meta inter func resourceAwsSagemakerNotebookInstanceUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).sagemakerconn - d.Partial(true) - if d.HasChange("tags") { o, n := d.GetChange("tags") @@ -223,7 +221,6 @@ func resourceAwsSagemakerNotebookInstanceUpdate(d *schema.ResourceData, meta int return fmt.Errorf("error updating Sagemaker Notebook Instance (%s) tags: %s", d.Id(), err) } } - d.SetPartial("tags") hasChanged := false // Update @@ -325,8 +322,6 @@ func resourceAwsSagemakerNotebookInstanceUpdate(d *schema.ResourceData, meta int } } - d.Partial(false) - return resourceAwsSagemakerNotebookInstanceRead(d, meta) } From 67a34091b67e6bef680b4303abc9e72fd4fdc65e Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 2 Apr 2020 13:38:56 -0700 Subject: [PATCH 207/684] Update CHANGELOG for #12549 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c88e2fa0ea..50fbfd6f7c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ NOTES: ENHANCEMENTS: * data-source/aws_launch_template: Add `hibernation_options` attribute [GH-12492] +* resource/aws_codepipeline: Adds cross-region action support [GH-12549] * resource/aws_dx_connection: Support `2Gbps` and `5Gbps` values in plan-time validation for `bandwidth` argument [GH-12559] * resource/aws_dx_lag: Support `2Gbps` and `5Gbps` values in plan-time validation for `bandwidth` argument [GH-12559] * resource/aws_elastic_transcoder_preset: Support plan-time validation for `role` argument [GH-12575] From 9b9fbf0b8773cd319c8e5fac555b022bdb59c482 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 2 Apr 2020 15:00:32 -0700 Subject: [PATCH 208/684] Consolidates EC2 instance retrieval --- aws/resource_aws_instance.go | 71 ++++++++++++------- aws/resource_aws_spot_instance_request.go | 10 +-- ...resource_aws_spot_instance_request_test.go | 62 ++++++---------- aws/resource_aws_ssm_association_test.go | 10 +-- 4 files changed, 76 insertions(+), 77 deletions(-) diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index c7b6b0c941d..59c10cc118a 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -697,9 +697,7 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error { func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{ - InstanceIds: []*string{aws.String(d.Id())}, - }) + instance, err := resourceAwsInstanceFindByID(conn, d.Id()) if err != nil { // If the instance was not found, return nil so that we can show // that the instance is gone. @@ -713,13 +711,11 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error { } // If nothing was found, then return no state - if len(resp.Reservations) == 0 { + if instance == nil { d.SetId("") return nil } - instance := resp.Reservations[0].Instances[0] - if instance.State != nil { // If the instance is terminated, then it is gone if *instance.State.Name == "terminated" { @@ -1099,13 +1095,10 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { // Thus, we need to actually modify the primary network interface for the new security groups, as the primary // network interface is where we modify/create security group assignments during Create. log.Printf("[INFO] Modifying `vpc_security_group_ids` on Instance %q", d.Id()) - instances, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{ - InstanceIds: []*string{aws.String(d.Id())}, - }) + instance, err := resourceAwsInstanceFindByID(conn, d.Id()) if err != nil { - return err + return fmt.Errorf("error retrieving instance %q: %w", d.Id(), err) } - instance := instances.Reservations[0].Instances[0] var primaryInterface ec2.InstanceNetworkInterface for _, ni := range instance.NetworkInterfaces { if *ni.Attachment.DeviceIndex == 0 { @@ -1329,36 +1322,30 @@ func resourceAwsInstanceDelete(d *schema.ResourceData, meta interface{}) error { // an EC2 instance. func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string, failStates []string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{ - InstanceIds: []*string{aws.String(instanceID)}, - }) + instance, err := resourceAwsInstanceFindByID(conn, instanceID) if err != nil { - if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidInstanceID.NotFound" { - // Set this to nil as if we didn't find anything. - resp = nil - } else { + if !isAWSErr(err, "InvalidInstanceID.NotFound", "") { log.Printf("Error on InstanceStateRefresh: %s", err) return nil, "", err } } - if resp == nil || len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 { + if instance == nil { // Sometimes AWS just has consistency issues and doesn't see // our instance yet. Return an empty state. return nil, "", nil } - i := resp.Reservations[0].Instances[0] - state := *i.State.Name + state := *instance.State.Name for _, failState := range failStates { if state == failState { - return i, state, fmt.Errorf("Failed to reach target state. Reason: %s", - stringifyStateReason(i.StateReason)) + return instance, state, fmt.Errorf("Failed to reach target state. Reason: %s", + stringifyStateReason(instance.StateReason)) } } - return i, state, nil + return instance, state, nil } } @@ -2262,3 +2249,39 @@ func flattenEc2InstanceMetadataOptions(opts *ec2.InstanceMetadataOptionsResponse return []interface{}{m} } + +// resourceAwsInstanceFindByID returns the EC2 instance by ID +// * If the instance is found, returns the instance and nil +// * If no instance is found, returns nil and nil +// * If an error occurs, returns nil and the error +func resourceAwsInstanceFindByID(conn *ec2.EC2, id string) (*ec2.Instance, error) { + instances, err := resourceAwsInstanceFind(conn, &ec2.DescribeInstancesInput{ + InstanceIds: aws.StringSlice([]string{id}), + }) + if err != nil { + return nil, err + } + + if len(instances) == 0 { + return nil, nil + } + + return instances[0], nil +} + +// resourceAwsInstanceFind returns EC2 instances matching the input parameters +// * If instances are found, returns a slice of instances and nil +// * If no instances are found, returns an empty slice and nil +// * If an error occurs, returns nil and the error +func resourceAwsInstanceFind(conn *ec2.EC2, params *ec2.DescribeInstancesInput) ([]*ec2.Instance, error) { + resp, err := conn.DescribeInstances(params) + if err != nil { + return nil, err + } + + if len(resp.Reservations) == 0 { + return []*ec2.Instance{}, nil + } + + return resp.Reservations[0].Instances, nil +} diff --git a/aws/resource_aws_spot_instance_request.go b/aws/resource_aws_spot_instance_request.go index c44c872e4b9..93e1da8c920 100644 --- a/aws/resource_aws_spot_instance_request.go +++ b/aws/resource_aws_spot_instance_request.go @@ -299,13 +299,11 @@ func resourceAwsSpotInstanceRequestRead(d *schema.ResourceData, meta interface{} func readInstance(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{ - InstanceIds: []*string{aws.String(d.Get("spot_instance_id").(string))}, - }) + instance, err := resourceAwsInstanceFindByID(conn, d.Get("spot_instance_id").(string)) if err != nil { // If the instance was not found, return nil so that we can show // that the instance is gone. - if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidInstanceID.NotFound" { + if isAWSErr(err, "InvalidInstanceID.NotFound", "") { return fmt.Errorf("no instance found") } @@ -314,12 +312,10 @@ func readInstance(d *schema.ResourceData, meta interface{}) error { } // If nothing was found, then return no state - if len(resp.Reservations) == 0 { + if instance == nil { return fmt.Errorf("no instances found") } - instance := resp.Reservations[0].Instances[0] - // Set these fields for connection information if instance != nil { d.Set("public_dns", instance.PublicDnsName) diff --git a/aws/resource_aws_spot_instance_request_test.go b/aws/resource_aws_spot_instance_request_test.go index 87bb7a90eac..36efe0b4442 100644 --- a/aws/resource_aws_spot_instance_request_test.go +++ b/aws/resource_aws_spot_instance_request_test.go @@ -6,7 +6,6 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -283,9 +282,13 @@ func testAccCheckAWSSpotInstanceRequestDestroy(s *terraform.State) error { SpotInstanceRequestIds: []*string{aws.String(rs.Primary.ID)}, } - resp, err := conn.DescribeSpotInstanceRequests(req) + resp, spotErr := conn.DescribeSpotInstanceRequests(req) + // Verify the error is what we expect + if !isAWSErr(spotErr, "InvalidSpotInstanceRequestID.NotFound", "") { + return spotErr + } var s *ec2.SpotInstanceRequest - if err == nil { + if spotErr == nil { for _, sir := range resp.SpotInstanceRequests { if sir.SpotInstanceRequestId != nil && *sir.SpotInstanceRequestId == rs.Primary.ID { s = sir @@ -293,47 +296,29 @@ func testAccCheckAWSSpotInstanceRequestDestroy(s *terraform.State) error { continue } } - if s == nil { // not found - return nil + continue } - - if *s.State == "canceled" || *s.State == "closed" { + if aws.StringValue(s.State) == "canceled" || aws.StringValue(s.State) == "closed" { // Requests stick around for a while, so we make sure it's cancelled // or closed. - return nil - } - - // Verify the error is what we expect - ec2err, ok := err.(awserr.Error) - if !ok { - return err - } - if ec2err.Code() != "InvalidSpotInstanceRequestID.NotFound" { - return err + continue } // Now check if the associated Spot Instance was also destroyed - instId := rs.Primary.Attributes["spot_instance_id"] - instResp, instErr := conn.DescribeInstances(&ec2.DescribeInstancesInput{ - InstanceIds: []*string{aws.String(instId)}, - }) + instanceID := rs.Primary.Attributes["spot_instance_id"] + instance, instErr := resourceAwsInstanceFindByID(conn, instanceID) if instErr == nil { - if len(instResp.Reservations) > 0 { - return fmt.Errorf("Instance still exists.") + if instance != nil { + return fmt.Errorf("instance %q still exists", instanceID) } - - return nil + continue } // Verify the error is what we expect - ec2err, ok = err.(awserr.Error) - if !ok { - return err - } - if ec2err.Code() != "InvalidInstanceID.NotFound" { - return err + if !isAWSErr(instErr, "InvalidInstanceID.NotFound", "") { + return instErr } } @@ -412,27 +397,22 @@ func testAccCheckAWSSpotInstanceRequestAttributesCheckSIRWithoutSpot( } } -func testAccCheckAWSSpotInstanceRequest_InstanceAttributes( - sir *ec2.SpotInstanceRequest, rInt int) resource.TestCheckFunc { +func testAccCheckAWSSpotInstanceRequest_InstanceAttributes(sir *ec2.SpotInstanceRequest, rInt int) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ec2conn - resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{ - InstanceIds: []*string{sir.InstanceId}, - }) + instance, err := resourceAwsInstanceFindByID(conn, aws.StringValue(sir.InstanceId)) if err != nil { - if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidInstanceID.NotFound" { - return fmt.Errorf("Spot Instance not found") + if isAWSErr(err, "InvalidInstanceID.NotFound", "") { + return fmt.Errorf("Spot Instance %q not found", aws.StringValue(sir.InstanceId)) } return err } // If nothing was found, then return no state - if len(resp.Reservations) == 0 { + if instance == nil { return fmt.Errorf("Spot Instance not found") } - instance := resp.Reservations[0].Instances[0] - var sgMatch bool for _, s := range instance.SecurityGroups { // Hardcoded name for the security group that should be added inside the diff --git a/aws/resource_aws_ssm_association_test.go b/aws/resource_aws_ssm_association_test.go index b4a610e1a58..f0c703854fa 100644 --- a/aws/resource_aws_ssm_association_test.go +++ b/aws/resource_aws_ssm_association_test.go @@ -20,7 +20,7 @@ func TestAccAWSSSMAssociation_basic(t *testing.T) { ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn ssmconn := testAccProvider.Meta().(*AWSClient).ssmconn - ins, err := ec2conn.DescribeInstances(&ec2.DescribeInstancesInput{ + ins, err := resourceAwsInstanceFind(ec2conn, &ec2.DescribeInstancesInput{ Filters: []*ec2.Filter{ { Name: aws.String("tag:Name"), @@ -31,17 +31,17 @@ func TestAccAWSSSMAssociation_basic(t *testing.T) { if err != nil { t.Fatalf("Error getting instance with tag:Name %s: %s", name, err) } - if len(ins.Reservations) == 0 || len(ins.Reservations[0].Instances) == 0 { + if len(ins) == 0 { t.Fatalf("No instance exists with tag:Name %s", name) } - instanceId := ins.Reservations[0].Instances[0].InstanceId + instanceID := ins[0].InstanceId _, err = ssmconn.DeleteAssociation(&ssm.DeleteAssociationInput{ Name: aws.String(name), - InstanceId: instanceId, + InstanceId: instanceID, }) if err != nil { - t.Fatalf("Error deleting ssm association %s/%s: %s", name, aws.StringValue(instanceId), err) + t.Fatalf("Error deleting ssm association %s/%s: %s", name, aws.StringValue(instanceID), err) } } From a9ff5701c62a25177ad4d89272bfa0ac0670e7ca Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 2 Apr 2020 15:01:10 -0700 Subject: [PATCH 209/684] Uses AWS SDK provided functions for value dereference --- aws/resource_aws_instance.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index 59c10cc118a..00c423debe4 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -1483,35 +1483,35 @@ func readBlockDevicesFromInstance(instance *ec2.Instance, conn *ec2.EC2) (map[st instanceBd := instanceBlockDevices[*vol.VolumeId] bd := make(map[string]interface{}) - bd["volume_id"] = *vol.VolumeId + bd["volume_id"] = aws.StringValue(vol.VolumeId) if instanceBd.Ebs != nil && instanceBd.Ebs.DeleteOnTermination != nil { - bd["delete_on_termination"] = *instanceBd.Ebs.DeleteOnTermination + bd["delete_on_termination"] = aws.BoolValue(instanceBd.Ebs.DeleteOnTermination) } if vol.Size != nil { - bd["volume_size"] = *vol.Size + bd["volume_size"] = aws.Int64Value(vol.Size) } if vol.VolumeType != nil { - bd["volume_type"] = *vol.VolumeType + bd["volume_type"] = aws.StringValue(vol.VolumeType) } if vol.Iops != nil { - bd["iops"] = *vol.Iops + bd["iops"] = aws.Int64Value(vol.Iops) } if vol.Encrypted != nil { - bd["encrypted"] = *vol.Encrypted + bd["encrypted"] = aws.BoolValue(vol.Encrypted) } if vol.KmsKeyId != nil { - bd["kms_key_id"] = *vol.KmsKeyId + bd["kms_key_id"] = aws.StringValue(vol.KmsKeyId) } if blockDeviceIsRoot(instanceBd, instance) { blockDevices["root"] = bd } else { if instanceBd.DeviceName != nil { - bd["device_name"] = *instanceBd.DeviceName + bd["device_name"] = aws.StringValue(instanceBd.DeviceName) } if vol.SnapshotId != nil { - bd["snapshot_id"] = *vol.SnapshotId + bd["snapshot_id"] = aws.StringValue(vol.SnapshotId) } blockDevices["ebs"] = append(blockDevices["ebs"].([]map[string]interface{}), bd) From 739e70d7d6f8fbbd1d47e7000e4383827ccd3448 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 2 Apr 2020 15:24:45 -0700 Subject: [PATCH 210/684] Updates root volume resize to work when multiple EBS volumes are attached --- aws/resource_aws_instance.go | 35 +-- aws/resource_aws_instance_test.go | 396 ++++++++++++-------------- website/docs/r/instance.html.markdown | 2 +- 3 files changed, 199 insertions(+), 234 deletions(-) diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index 00c423debe4..00047f8e34c 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -37,7 +37,7 @@ func resourceAwsInstance() *schema.Resource { Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), Delete: schema.DefaultTimeout(20 * time.Minute), }, @@ -1252,30 +1252,34 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { } } - if d.HasChange("root_block_device.0.volume_size") { + if d.HasChange("root_block_device.0.volume_size") && !d.IsNewResource() { if vs, ok := d.GetOk("root_block_device.0.volume_size"); ok { volumeSize := vs.(int) if volumeSize != 0 { - volumeIds, err := getAwsInstanceVolumeIds(conn, d.Id()) + instance, err := resourceAwsInstanceFindByID(conn, d.Id()) if err != nil { - return fmt.Errorf("Error retrieving volumes: %s.", err) + return fmt.Errorf("error retrieving instance %q: %w", d.Id(), err) } - - volResp, err := conn.DescribeVolumes(&ec2.DescribeVolumesInput{ - VolumeIds: aws.StringSlice(volumeIds), - }) + blockDevices, err := readBlockDevicesFromInstance(instance, conn) if err != nil { - return err + return fmt.Errorf("error retrieving volumes for instance %q: %w", d.Id(), err) } - if len(volResp.Volumes) < 1 { - return fmt.Errorf("No volumes found for %s.", d.Id()) + rd, ok := blockDevices["root"] + if !ok { + return fmt.Errorf("root volume no found for instance %q", d.Id()) } - if int64(volumeSize) != *volResp.Volumes[0].Size { + rootDevice := rd.(map[string]interface{}) + currSize, ok := rootDevice["volume_size"].(int64) + if !ok { + return fmt.Errorf("root volume size no found for instance %q", d.Id()) + } + if int64(volumeSize) != currSize { + volumeID := rootDevice["volume_id"].(string) _, err = conn.ModifyVolume(&ec2.ModifyVolumeInput{ Size: aws.Int64(int64(volumeSize)), - VolumeId: aws.String(volumeIds[0]), + VolumeId: aws.String(volumeID), }) if err != nil { return err @@ -1284,7 +1288,7 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { stateConf := &resource.StateChangeConf{ Pending: []string{"modifying", "optimizing"}, Target: []string{"completed"}, - Refresh: VolumeStateRefreshFunc(conn, volumeIds[0], "failed"), + Refresh: VolumeStateRefreshFunc(conn, volumeID, "failed"), Timeout: d.Timeout(schema.TimeoutUpdate), Delay: 30 * time.Second, MinTimeout: 30 * time.Second, @@ -1292,11 +1296,10 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf("Error waiting for volume (%s) to be modified: %s", volumeIds[0], err) + return fmt.Errorf("error waiting for volume (%s) to be modified: %s", volumeID, err) } } } - } } diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index cc26719390e..820ceb68f85 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -10,7 +10,6 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/ec2" @@ -159,8 +158,7 @@ func TestAccAWSInstance_inDefaultVpcBySgName(t *testing.T) { { Config: testAccInstanceConfigInDefaultVpcBySgName(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), + testAccCheckInstanceExists(resourceName, &v), ), }, { @@ -185,8 +183,7 @@ func TestAccAWSInstance_inDefaultVpcBySgId(t *testing.T) { { Config: testAccInstanceConfigInDefaultVpcBySgId(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), + testAccCheckInstanceExists(resourceName, &v), ), }, { @@ -216,8 +213,7 @@ func TestAccAWSInstance_inEc2Classic(t *testing.T) { { Config: testAccInstanceConfigInEc2Classic(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), + testAccCheckInstanceExists(resourceName, &v), ), }, { @@ -277,19 +273,11 @@ func TestAccAWSInstance_basic(t *testing.T) { { Config: testAccInstanceConfig(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), + testAccCheckInstanceExists(resourceName, &v), testCheck(rInt), - resource.TestCheckResourceAttr( - resourceName, - "user_data", - "3dc39dda39be1205215e776bad998da361a5955d"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.#", "0"), - resource.TestMatchResourceAttr( - resourceName, - "arn", - regexp.MustCompile(`^arn:[^:]+:ec2:[^:]+:\d{12}:instance/i-.+`)), + resource.TestCheckResourceAttr(resourceName, "user_data", "3dc39dda39be1205215e776bad998da361a5955d"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.#", "0"), + resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile(`^arn:[^:]+:ec2:[^:]+:\d{12}:instance/i-.+`)), ), }, { @@ -303,15 +291,10 @@ func TestAccAWSInstance_basic(t *testing.T) { { Config: testAccInstanceConfig(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), + testAccCheckInstanceExists(resourceName, &v), testCheck(rInt), - resource.TestCheckResourceAttr( - resourceName, - "user_data", - "3dc39dda39be1205215e776bad998da361a5955d"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.#", "0"), + resource.TestCheckResourceAttr(resourceName, "user_data", "3dc39dda39be1205215e776bad998da361a5955d"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.#", "0"), ), }, // Clean up volume created above @@ -392,12 +375,8 @@ func TestAccAWSInstance_userDataBase64(t *testing.T) { { Config: testAccInstanceConfigWithUserDataBase64(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, - "user_data_base64", - "aGVsbG8gd29ybGQ="), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "user_data_base64", "aGVsbG8gd29ybGQ="), ), }, { @@ -443,16 +422,11 @@ func TestAccAWSInstance_GP2IopsDevice(t *testing.T) { Config: testAccInstanceGP2IopsDevice, //Config: testAccInstanceConfigBlockDevices, Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.0.volume_size", "11"), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.0.volume_type", "gp2"), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.0.iops", "100"), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "root_block_device.#", "1"), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_size", "11"), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_type", "gp2"), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.iops", "100"), testCheck(), ), }, @@ -541,50 +515,28 @@ func TestAccAWSInstance_blockDevices(t *testing.T) { { Config: testAccInstanceConfigBlockDevices, Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.#", "1"), - resource.TestMatchResourceAttr( - resourceName, "root_block_device.0.volume_id", regexp.MustCompile("vol-[a-z0-9]+")), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.0.volume_size", "11"), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.0.volume_type", "gp2"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.#", "3"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.2576023345.device_name", "/dev/sdb"), - resource.TestMatchResourceAttr( - resourceName, "ebs_block_device.2576023345.volume_id", regexp.MustCompile("vol-[a-z0-9]+")), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.2576023345.volume_size", "9"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.2576023345.volume_type", "gp2"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.2554893574.device_name", "/dev/sdc"), - resource.TestMatchResourceAttr( - resourceName, "ebs_block_device.2554893574.volume_id", regexp.MustCompile("vol-[a-z0-9]+")), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.2554893574.volume_size", "10"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.2554893574.volume_type", "io1"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.2554893574.iops", "100"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.2634515331.device_name", "/dev/sdd"), - resource.TestMatchResourceAttr( - resourceName, "ebs_block_device.2634515331.volume_id", regexp.MustCompile("vol-[a-z0-9]+")), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.2634515331.encrypted", "true"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.2634515331.volume_size", "12"), - resource.TestCheckResourceAttr( - resourceName, "ephemeral_block_device.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "ephemeral_block_device.1692014856.device_name", "/dev/sde"), - resource.TestCheckResourceAttr( - resourceName, "ephemeral_block_device.1692014856.virtual_name", "ephemeral0"), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "root_block_device.#", "1"), + resource.TestMatchResourceAttr(resourceName, "root_block_device.0.volume_id", regexp.MustCompile("vol-[a-z0-9]+")), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_size", "11"), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_type", "gp2"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.#", "3"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2576023345.device_name", "/dev/sdb"), + resource.TestMatchResourceAttr(resourceName, "ebs_block_device.2576023345.volume_id", regexp.MustCompile("vol-[a-z0-9]+")), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2576023345.volume_size", "9"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2576023345.volume_type", "gp2"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2554893574.device_name", "/dev/sdc"), + resource.TestMatchResourceAttr(resourceName, "ebs_block_device.2554893574.volume_id", regexp.MustCompile("vol-[a-z0-9]+")), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2554893574.volume_size", "10"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2554893574.volume_type", "io1"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2554893574.iops", "100"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2634515331.device_name", "/dev/sdd"), + resource.TestMatchResourceAttr(resourceName, "ebs_block_device.2634515331.volume_id", regexp.MustCompile("vol-[a-z0-9]+")), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2634515331.encrypted", "true"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2634515331.volume_size", "12"), + resource.TestCheckResourceAttr(resourceName, "ephemeral_block_device.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ephemeral_block_device.1692014856.device_name", "/dev/sde"), + resource.TestCheckResourceAttr(resourceName, "ephemeral_block_device.1692014856.virtual_name", "ephemeral0"), testCheck(), ), }, @@ -621,18 +573,12 @@ func TestAccAWSInstance_rootInstanceStore(t *testing.T) { instance_type = "m3.medium" }`, Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "ami", "ami-44c36524"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.#", "0"), - resource.TestCheckResourceAttr( - resourceName, "ebs_optimized", "false"), - resource.TestCheckResourceAttr( - resourceName, "instance_type", "m3.medium"), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.#", "0"), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "ami", "ami-44c36524"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.#", "0"), + resource.TestCheckResourceAttr(resourceName, "ebs_optimized", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_type", "m3.medium"), + resource.TestCheckResourceAttr(resourceName, "root_block_device.#", "0"), ), }, { @@ -704,32 +650,19 @@ func TestAccAWSInstance_noAMIEphemeralDevices(t *testing.T) { } }`, Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "ami", "ami-01f05461"), - resource.TestCheckResourceAttr( - resourceName, "ebs_optimized", "false"), - resource.TestCheckResourceAttr( - resourceName, "instance_type", "c3.large"), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.0.volume_size", "11"), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.0.volume_type", "gp2"), - resource.TestCheckResourceAttr( - resourceName, "ebs_block_device.#", "0"), - resource.TestCheckResourceAttr( - resourceName, "ephemeral_block_device.#", "2"), - resource.TestCheckResourceAttr( - resourceName, "ephemeral_block_device.172787947.device_name", "/dev/sdb"), - resource.TestCheckResourceAttr( - resourceName, "ephemeral_block_device.172787947.no_device", "true"), - resource.TestCheckResourceAttr( - resourceName, "ephemeral_block_device.3336996981.device_name", "/dev/sdc"), - resource.TestCheckResourceAttr( - resourceName, "ephemeral_block_device.3336996981.no_device", "true"), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "ami", "ami-01f05461"), + resource.TestCheckResourceAttr(resourceName, "ebs_optimized", "false"), + resource.TestCheckResourceAttr(resourceName, "instance_type", "c3.large"), + resource.TestCheckResourceAttr(resourceName, "root_block_device.#", "1"), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_size", "11"), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_type", "gp2"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.#", "0"), + resource.TestCheckResourceAttr(resourceName, "ephemeral_block_device.#", "2"), + resource.TestCheckResourceAttr(resourceName, "ephemeral_block_device.172787947.device_name", "/dev/sdb"), + resource.TestCheckResourceAttr(resourceName, "ephemeral_block_device.172787947.no_device", "true"), + resource.TestCheckResourceAttr(resourceName, "ephemeral_block_device.3336996981.device_name", "/dev/sdc"), + resource.TestCheckResourceAttr(resourceName, "ephemeral_block_device.3336996981.no_device", "true"), testCheck(), ), }, @@ -864,12 +797,8 @@ func TestAccAWSInstance_vpc(t *testing.T) { { Config: testAccInstanceConfigVPC(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, - "user_data", - "562a3e32810edf6ff09994f050f12e799452379d"), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "user_data", "562a3e32810edf6ff09994f050f12e799452379d"), ), }, { @@ -897,12 +826,8 @@ func TestAccAWSInstance_placementGroup(t *testing.T) { { Config: testAccInstanceConfigPlacementGroup(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, - "placement_group", - rName), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "placement_group", rName), ), }, { @@ -927,12 +852,8 @@ func TestAccAWSInstance_ipv6_supportAddressCount(t *testing.T) { { Config: testAccInstanceConfigIpv6Support(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, - "ipv6_address_count", - "1"), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "ipv6_address_count", "1"), ), }, { @@ -973,12 +894,8 @@ func TestAccAWSInstance_ipv6_supportAddressCountWithIpv4(t *testing.T) { { Config: testAccInstanceConfigIpv6SupportWithIpv4(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, - "ipv6_address_count", - "1"), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "ipv6_address_count", "1"), ), }, { @@ -1006,10 +923,8 @@ func TestAccAWSInstance_multipleRegions(t *testing.T) { { Config: testAccInstanceConfigMultipleRegions, Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExistsWithProvider(resourceName, &v, - testAccAwsRegionProviderFunc("us-west-2", &providers)), - testAccCheckInstanceExistsWithProvider("aws_instance.test2", &v, - testAccAwsRegionProviderFunc("us-east-1", &providers)), + testAccCheckInstanceExistsWithProvider(resourceName, &v, testAccAwsRegionProviderFunc("us-west-2", &providers)), + testAccCheckInstanceExistsWithProvider("aws_instance.test2", &v, testAccAwsRegionProviderFunc("us-east-1", &providers)), ), }, }, @@ -1031,8 +946,7 @@ func TestAccAWSInstance_NetworkInstanceSecurityGroups(t *testing.T) { { Config: testAccInstanceNetworkInstanceSecurityGroups(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), + testAccCheckInstanceExists(resourceName, &v), ), }, { @@ -1058,12 +972,9 @@ func TestAccAWSInstance_NetworkInstanceRemovingAllSecurityGroups(t *testing.T) { { Config: testAccInstanceNetworkInstanceVPCSecurityGroupIDs(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "security_groups.#", "0"), - resource.TestCheckResourceAttr( - resourceName, "vpc_security_group_ids.#", "1"), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "security_groups.#", "0"), + resource.TestCheckResourceAttr(resourceName, "vpc_security_group_ids.#", "1"), ), }, { @@ -1074,12 +985,9 @@ func TestAccAWSInstance_NetworkInstanceRemovingAllSecurityGroups(t *testing.T) { { Config: testAccInstanceNetworkInstanceVPCRemoveSecurityGroupIDs(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "security_groups.#", "0"), - resource.TestCheckResourceAttr( - resourceName, "vpc_security_group_ids.#", "1"), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "security_groups.#", "0"), + resource.TestCheckResourceAttr(resourceName, "vpc_security_group_ids.#", "1"), ), ExpectError: regexp.MustCompile(`VPC-based instances require at least one security group to be attached`), }, @@ -1101,12 +1009,9 @@ func TestAccAWSInstance_NetworkInstanceVPCSecurityGroupIDs(t *testing.T) { { Config: testAccInstanceNetworkInstanceVPCSecurityGroupIDs(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists( - resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "security_groups.#", "0"), - resource.TestCheckResourceAttr( - resourceName, "vpc_security_group_ids.#", "1"), + testAccCheckInstanceExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "security_groups.#", "0"), + resource.TestCheckResourceAttr(resourceName, "vpc_security_group_ids.#", "1"), ), }, { @@ -1165,8 +1070,7 @@ func TestAccAWSInstance_volumeTags(t *testing.T) { Config: testAccCheckInstanceConfigNoVolumeTags, Check: resource.ComposeTestCheckFunc( testAccCheckInstanceExists(resourceName, &v), - resource.TestCheckNoResourceAttr( - resourceName, "volume_tags"), + resource.TestCheckNoResourceAttr(resourceName, "volume_tags"), ), }, { @@ -1179,30 +1083,24 @@ func TestAccAWSInstance_volumeTags(t *testing.T) { Config: testAccCheckInstanceConfigWithVolumeTags, Check: resource.ComposeTestCheckFunc( testAccCheckInstanceExists(resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "volume_tags.%", "1"), - resource.TestCheckResourceAttr( - resourceName, "volume_tags.Name", "acceptance-test-volume-tag"), + resource.TestCheckResourceAttr(resourceName, "volume_tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "volume_tags.Name", "acceptance-test-volume-tag"), ), }, { Config: testAccCheckInstanceConfigWithVolumeTagsUpdate, Check: resource.ComposeTestCheckFunc( testAccCheckInstanceExists(resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "volume_tags.%", "2"), - resource.TestCheckResourceAttr( - resourceName, "volume_tags.Name", "acceptance-test-volume-tag"), - resource.TestCheckResourceAttr( - resourceName, "volume_tags.Environment", "dev"), + resource.TestCheckResourceAttr(resourceName, "volume_tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "volume_tags.Name", "acceptance-test-volume-tag"), + resource.TestCheckResourceAttr(resourceName, "volume_tags.Environment", "dev"), ), }, { Config: testAccCheckInstanceConfigNoVolumeTags, Check: resource.ComposeTestCheckFunc( testAccCheckInstanceExists(resourceName, &v), - resource.TestCheckNoResourceAttr( - resourceName, "volume_tags"), + resource.TestCheckNoResourceAttr(resourceName, "volume_tags"), ), }, }, @@ -1454,8 +1352,7 @@ func TestAccAWSInstance_rootBlockDeviceMismatch(t *testing.T) { Config: testAccInstanceConfigRootBlockDeviceMismatch(rName), Check: resource.ComposeTestCheckFunc( testAccCheckInstanceExists(resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "root_block_device.0.volume_size", "13"), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_size", "13"), ), }, { @@ -1536,17 +1433,17 @@ func TestAccAWSInstance_changeInstanceType(t *testing.T) { Config: testAccInstanceConfigUpdateInstanceType, Check: resource.ComposeTestCheckFunc( testAccCheckInstanceExists(resourceName, &after), - testAccCheckInstanceNotRecreated( - t, &before, &after), + testAccCheckInstanceNotRecreated(t, &before, &after), ), }, }, }) } -func TestAccAWSInstance_changeRootBlockDeviceVolumeSize(t *testing.T) { +func TestAccAWSInstance_changeRootBlockDeviceVolumeSize_basic(t *testing.T) { var before ec2.Instance var after ec2.Instance + resourceName := "aws_instance.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -1556,17 +1453,49 @@ func TestAccAWSInstance_changeRootBlockDeviceVolumeSize(t *testing.T) { { Config: testAccInstanceGP2IopsDevice, Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists("aws_instance.foo", &before), + testAccCheckInstanceExists(resourceName, &before), ), }, { Config: testAccInstanceGP2IopsDeviceVolumeSizeUpdate, Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists("aws_instance.foo", &after), - testAccCheckInstanceNotRecreated( - t, &before, &after), - resource.TestCheckResourceAttr( - "aws_instance.foo", "root_block_device.0.volume_size", "12"), + testAccCheckInstanceExists(resourceName, &after), + testAccCheckInstanceNotRecreated(t, &before, &after), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_size", "12"), + ), + }, + }, + }) +} + +func TestAccAWSInstance_changeRootBlockDeviceVolumeSize_MultipleBlockDevices(t *testing.T) { + var before ec2.Instance + var after ec2.Instance + resourceName := "aws_instance.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccInstanceConfigBlockDevices, + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resourceName, &before), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2576023345.volume_size", "9"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2554893574.volume_size", "10"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2634515331.volume_size", "12"), + ), + }, + { + Config: testAccInstanceConfigBlockDevicesRootSizeUpdated, + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resourceName, &after), + testAccCheckInstanceNotRecreated(t, &before, &after), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_size", "14"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2576023345.volume_size", "9"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2554893574.volume_size", "10"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.2634515331.volume_size", "12"), ), }, }, @@ -2637,21 +2566,15 @@ func testAccCheckInstanceDestroyWithProvider(s *terraform.State, provider *schem } // Try to find the resource - resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{ - InstanceIds: []*string{aws.String(rs.Primary.ID)}, - }) + instance, err := resourceAwsInstanceFindByID(conn, rs.Primary.ID) if err == nil { - for _, r := range resp.Reservations { - for _, i := range r.Instances { - if i.State != nil && *i.State.Name != "terminated" { - return fmt.Errorf("Found unterminated instance: %s", i) - } - } + if instance.State != nil && *instance.State.Name != "terminated" { + return fmt.Errorf("Found unterminated instance: %s", rs.Primary.ID) } } // Verify the error is what we want - if ae, ok := err.(awserr.Error); ok && ae.Code() == "InvalidInstanceID.NotFound" { + if isAWSErr(err, "InvalidInstanceID.NotFound", "") { continue } @@ -2679,15 +2602,13 @@ func testAccCheckInstanceExistsWithProvider(n string, i *ec2.Instance, providerF provider := providerF() conn := provider.Meta().(*AWSClient).ec2conn - resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{ - InstanceIds: []*string{aws.String(rs.Primary.ID)}, - }) + instance, err := resourceAwsInstanceFindByID(conn, rs.Primary.ID) if err != nil { return err } - if len(resp.Reservations) > 0 { - *i = *resp.Reservations[0].Instances[0] + if instance != nil { + *i = *instance return nil } @@ -2711,18 +2632,18 @@ func testAccCheckInstanceDisappears(conf *ec2.Instance) resource.TestCheckFunc { } } -func testAccCheckStopInstance(conf *ec2.Instance) resource.TestCheckFunc { +func testAccCheckStopInstance(instance *ec2.Instance) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ec2conn params := &ec2.StopInstancesInput{ - InstanceIds: []*string{conf.InstanceId}, + InstanceIds: []*string{instance.InstanceId}, } if _, err := conn.StopInstances(params); err != nil { return err } - return waitForInstanceStopping(conn, *conf.InstanceId, 10*time.Minute) + return waitForInstanceStopping(conn, *instance.InstanceId, 10*time.Minute) } } @@ -3038,7 +2959,7 @@ resource "aws_instance" "test" { ` const testAccInstanceGP2IopsDeviceVolumeSizeUpdate = ` -resource "aws_instance" "foo" { +resource "aws_instance" "test" { # us-west-2 ami = "ami-55a7ea65" @@ -3095,6 +3016,47 @@ resource "aws_instance" "test" { } ` +const testAccInstanceConfigBlockDevicesRootSizeUpdated = ` +resource "aws_instance" "test" { + # us-west-2 + ami = "ami-55a7ea65" + + # In order to attach an encrypted volume to an instance you need to have an + # m3.medium or larger. See "Supported Instance Types" in: + # http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html + instance_type = "m3.medium" + + root_block_device { + volume_type = "gp2" + volume_size = 14 + } + + ebs_block_device { + device_name = "/dev/sdb" + volume_size = 9 + } + + ebs_block_device { + device_name = "/dev/sdc" + volume_size = 10 + volume_type = "io1" + iops = 100 + } + + # Encrypted ebs block device + ebs_block_device { + device_name = "/dev/sdd" + volume_size = 12 + encrypted = true + } + + ephemeral_block_device { + device_name = "/dev/sde" + virtual_name = "ephemeral0" + } +} +` + func testAccInstanceConfigSourceDestEnable(rName string) string { return testAccLatestAmazonLinuxHvmEbsAmiConfig() + testAccAwsInstanceVpcConfig(rName, false) + fmt.Sprintf(` resource "aws_instance" "test" { diff --git a/website/docs/r/instance.html.markdown b/website/docs/r/instance.html.markdown index 1b56547543d..1379d0c0ab9 100644 --- a/website/docs/r/instance.html.markdown +++ b/website/docs/r/instance.html.markdown @@ -113,7 +113,7 @@ instances. See [Shutdown Behavior](https://docs.aws.amazon.com/AWSEC2/latest/Use The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: * `create` - (Defaults to 10 mins) Used when launching the instance (until it reaches the initial `running` state) -* `update` - (Defaults to 10 mins) Used when stopping and starting the instance when necessary during update - e.g. when changing instance type +* `update` - (Defaults to 20 mins) Used when stopping and starting the instance when necessary during update - e.g. when changing instance type * `delete` - (Defaults to 20 mins) Used when terminating the instance ### Block devices From 9dbb61ec55c92f04eac60e8da062c57d6326659d Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 2 Apr 2020 16:54:08 -0700 Subject: [PATCH 211/684] Stops waiting for volume update when state is `optimizing`, since the volume is useable in that state --- aws/resource_aws_instance.go | 9 ++++++--- website/docs/r/instance.html.markdown | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index 00047f8e34c..c460078aaa7 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -37,7 +37,7 @@ func resourceAwsInstance() *schema.Resource { Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), Delete: schema.DefaultTimeout(20 * time.Minute), }, @@ -1285,9 +1285,12 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { return err } + // The volume is useable once the state is "optimizing", but will not be at full performance. + // Optimization can take hours. e.g. a full 1 TiB drive takes approximately 6 hours to optimize, + // according to https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-volume-modifications.html stateConf := &resource.StateChangeConf{ - Pending: []string{"modifying", "optimizing"}, - Target: []string{"completed"}, + Pending: []string{"modifying"}, + Target: []string{"completed", "optimizing"}, Refresh: VolumeStateRefreshFunc(conn, volumeID, "failed"), Timeout: d.Timeout(schema.TimeoutUpdate), Delay: 30 * time.Second, diff --git a/website/docs/r/instance.html.markdown b/website/docs/r/instance.html.markdown index 1379d0c0ab9..1b56547543d 100644 --- a/website/docs/r/instance.html.markdown +++ b/website/docs/r/instance.html.markdown @@ -113,7 +113,7 @@ instances. See [Shutdown Behavior](https://docs.aws.amazon.com/AWSEC2/latest/Use The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: * `create` - (Defaults to 10 mins) Used when launching the instance (until it reaches the initial `running` state) -* `update` - (Defaults to 20 mins) Used when stopping and starting the instance when necessary during update - e.g. when changing instance type +* `update` - (Defaults to 10 mins) Used when stopping and starting the instance when necessary during update - e.g. when changing instance type * `delete` - (Defaults to 20 mins) Used when terminating the instance ### Block devices From 46d5fe0c7d61974915f25f8cf1eda6a5bc4a965e Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 2 Apr 2020 17:20:44 -0700 Subject: [PATCH 212/684] Updates documentation --- website/docs/r/instance.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/instance.html.markdown b/website/docs/r/instance.html.markdown index 1b56547543d..967a287ff6b 100644 --- a/website/docs/r/instance.html.markdown +++ b/website/docs/r/instance.html.markdown @@ -136,7 +136,7 @@ The `root_block_device` mapping supports the following: * `encrypted` - (Optional) Enable volume encryption. (Default: `false`). Must be configured to perform drift detection. * `kms_key_id` - (Optional) Amazon Resource Name (ARN) of the KMS Key to use when encrypting the volume. Must be configured to perform drift detection. -Modifying any of the `root_block_device` settings requires resource +Modifying any of the `root_block_device` settings other than `volume_size` requires resource replacement. Each `ebs_block_device` supports the following: From 02afaa62e2ab9b136af361b5d827e1112a8dd141 Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Fri, 3 Apr 2020 00:41:02 +0000 Subject: [PATCH 213/684] v2.56.0 --- CHANGELOG.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50fbfd6f7c6..8237c57359a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.56.0 (Unreleased) +## 2.56.0 (April 03, 2020) NOTES: @@ -6,21 +6,21 @@ NOTES: ENHANCEMENTS: -* data-source/aws_launch_template: Add `hibernation_options` attribute [GH-12492] -* resource/aws_codepipeline: Adds cross-region action support [GH-12549] -* resource/aws_dx_connection: Support `2Gbps` and `5Gbps` values in plan-time validation for `bandwidth` argument [GH-12559] -* resource/aws_dx_lag: Support `2Gbps` and `5Gbps` values in plan-time validation for `bandwidth` argument [GH-12559] -* resource/aws_elastic_transcoder_preset: Support plan-time validation for `role` argument [GH-12575] -* resource/aws_kms_grant: Support resource import [GH-11991] -* resource/aws_launch_template: Add `hibernation_options` configuration block [GH-12492] +* data-source/aws_launch_template: Add `hibernation_options` attribute ([#12492](https://github.com/terraform-providers/terraform-provider-aws/issues/12492)) +* resource/aws_codepipeline: Adds cross-region action support ([#12549](https://github.com/terraform-providers/terraform-provider-aws/issues/12549)) +* resource/aws_dx_connection: Support `2Gbps` and `5Gbps` values in plan-time validation for `bandwidth` argument ([#12559](https://github.com/terraform-providers/terraform-provider-aws/issues/12559)) +* resource/aws_dx_lag: Support `2Gbps` and `5Gbps` values in plan-time validation for `bandwidth` argument ([#12559](https://github.com/terraform-providers/terraform-provider-aws/issues/12559)) +* resource/aws_elastic_transcoder_preset: Support plan-time validation for `role` argument ([#12575](https://github.com/terraform-providers/terraform-provider-aws/issues/12575)) +* resource/aws_kms_grant: Support resource import ([#11991](https://github.com/terraform-providers/terraform-provider-aws/issues/11991)) +* resource/aws_launch_template: Add `hibernation_options` configuration block ([#12492](https://github.com/terraform-providers/terraform-provider-aws/issues/12492)) BUG FIXES: -* resource/aws_codedeploy_deployment_group: Fix `blue_green_deployment_config` updates for ECS [GH-11885] +* resource/aws_codedeploy_deployment_group: Fix `blue_green_deployment_config` updates for ECS ([#11885](https://github.com/terraform-providers/terraform-provider-aws/issues/11885)) * resource/aws_emr_cluster: Now properly sets the order when multiple bootstrap actions are defined -* resource/aws_kms_grant: Remove resource from Terraform state instead of error if removed outside Terraform [GH-12560] -* resource/aws_s3_bucket: Prevent various panics with empty configuration blocks [GH-12614] -* resource/aws_volume_attachment: Ensure any error is shown while waiting for volume to detach [GH-12596] +* resource/aws_kms_grant: Remove resource from Terraform state instead of error if removed outside Terraform ([#12560](https://github.com/terraform-providers/terraform-provider-aws/issues/12560)) +* resource/aws_s3_bucket: Prevent various panics with empty configuration blocks ([#12614](https://github.com/terraform-providers/terraform-provider-aws/issues/12614)) +* resource/aws_volume_attachment: Ensure any error is shown while waiting for volume to detach ([#12596](https://github.com/terraform-providers/terraform-provider-aws/issues/12596)) ## 2.55.0 (March 27, 2020) From a9ff1bec253ea8a52b3537f603cba5be4ad534db Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Fri, 3 Apr 2020 00:57:29 +0000 Subject: [PATCH 214/684] Cleanup after v2.56.0 release --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8237c57359a..275bda0f46d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +## 2.57.0 (Unreleased) ## 2.56.0 (April 03, 2020) NOTES: From 8f146ff63efd8acde661553b6a85ad46cc2a85a9 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 3 Apr 2020 15:53:48 -0700 Subject: [PATCH 215/684] Adds test for retrieving computed root EBS device values --- aws/resource_aws_instance_test.go | 53 ++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index 820ceb68f85..a0a4423fcf4 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -256,7 +256,7 @@ func TestAccAWSInstance_basic(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckInstanceDestroy, Steps: []resource.TestStep{ - // Create a volume to cover #1249 + // Create a volume to cover https://github.com/hashicorp/terraform/issues/1249 { // Need a resource in this config so the provisioner will be available Config: testAccInstanceConfig_pre(rInt), @@ -276,6 +276,7 @@ func TestAccAWSInstance_basic(t *testing.T) { testAccCheckInstanceExists(resourceName, &v), testCheck(rInt), resource.TestCheckResourceAttr(resourceName, "user_data", "3dc39dda39be1205215e776bad998da361a5955d"), + resource.TestCheckResourceAttr(resourceName, "root_block_device.#", "0"), // This is an instance store AMI resource.TestCheckResourceAttr(resourceName, "ebs_block_device.#", "0"), resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile(`^arn:[^:]+:ec2:[^:]+:\d{12}:instance/i-.+`)), ), @@ -1440,6 +1441,32 @@ func TestAccAWSInstance_changeInstanceType(t *testing.T) { }) } +func TestAccAWSInstance_EbsRootDevice_basic(t *testing.T) { + var instance ec2.Instance + resourceName := "aws_instance.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsEc2InstanceEbsRootDeviceBasic(), + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resourceName, &instance), + resource.TestCheckResourceAttr(resourceName, "root_block_device.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "root_block_device.0.delete_on_termination"), + resource.TestCheckResourceAttrSet(resourceName, "root_block_device.0.encrypted"), + resource.TestCheckResourceAttrSet(resourceName, "root_block_device.0.iops"), + resource.TestCheckResourceAttrSet(resourceName, "root_block_device.0.volume_size"), + resource.TestCheckResourceAttrSet(resourceName, "root_block_device.0.volume_type"), + resource.TestCheckResourceAttrSet(resourceName, "root_block_device.0.volume_id"), + ), + }, + }, + }) +} + func TestAccAWSInstance_changeRootBlockDeviceVolumeSize_basic(t *testing.T) { var before ec2.Instance var after ec2.Instance @@ -2958,6 +2985,30 @@ resource "aws_instance" "test" { } ` +func testAccAwsEc2InstanceEbsRootDeviceBasic() string { + return fmt.Sprintf(` + data "aws_ami" "ami" { + owners = ["amazon"] + most_recent = true + + filter { + name = "name" + values = ["amzn2-ami-*"] + } + filter { + name = "root-device-type" + values = ["ebs"] + } + } + + resource "aws_instance" "test" { + ami = data.aws_ami.ami.id + + instance_type = "t2.small" +} +`) +} + const testAccInstanceGP2IopsDeviceVolumeSizeUpdate = ` resource "aws_instance" "test" { # us-west-2 From af00c4474dcf5c758c9aabe2296265f027d7e3cf Mon Sep 17 00:00:00 2001 From: Simon Davis Date: Mon, 30 Mar 2020 18:31:48 -0700 Subject: [PATCH 216/684] enable s20 lint check and fix issues --- GNUmakefile | 1 + aws/resource_aws_ami.go | 1 - aws/resource_aws_ami_copy.go | 1 - aws/resource_aws_ami_from_instance.go | 1 - aws/resource_aws_inspector_assessment_template.go | 1 - 5 files changed, 1 insertion(+), 4 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 6a4e4ae3c89..a070a9aad93 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -91,6 +91,7 @@ lint: -S016 \ -S017 \ -S019 \ + -S020 \ -S021 \ -S025 \ -S026 \ diff --git a/aws/resource_aws_ami.go b/aws/resource_aws_ami.go index 55be5589059..067e8cc9343 100644 --- a/aws/resource_aws_ami.go +++ b/aws/resource_aws_ami.go @@ -171,7 +171,6 @@ func resourceAwsAmi() *schema.Resource { "manage_ebs_snapshots": { Type: schema.TypeBool, Computed: true, - ForceNew: true, }, "name": { Type: schema.TypeString, diff --git a/aws/resource_aws_ami_copy.go b/aws/resource_aws_ami_copy.go index f20148aec4b..9cba97195c2 100644 --- a/aws/resource_aws_ami_copy.go +++ b/aws/resource_aws_ami_copy.go @@ -145,7 +145,6 @@ func resourceAwsAmiCopy() *schema.Resource { "manage_ebs_snapshots": { Type: schema.TypeBool, Computed: true, - ForceNew: true, }, "name": { Type: schema.TypeString, diff --git a/aws/resource_aws_ami_from_instance.go b/aws/resource_aws_ami_from_instance.go index 00b008ba65e..dfb31874bb9 100644 --- a/aws/resource_aws_ami_from_instance.go +++ b/aws/resource_aws_ami_from_instance.go @@ -132,7 +132,6 @@ func resourceAwsAmiFromInstance() *schema.Resource { "manage_ebs_snapshots": { Type: schema.TypeBool, Computed: true, - ForceNew: true, }, "name": { Type: schema.TypeString, diff --git a/aws/resource_aws_inspector_assessment_template.go b/aws/resource_aws_inspector_assessment_template.go index 9ee3f37bd4e..f5448efb2fb 100644 --- a/aws/resource_aws_inspector_assessment_template.go +++ b/aws/resource_aws_inspector_assessment_template.go @@ -35,7 +35,6 @@ func resourceAWSInspectorAssessmentTemplate() *schema.Resource { "arn": { Type: schema.TypeString, Computed: true, - ForceNew: true, }, "duration": { Type: schema.TypeInt, From 496084e5a682a3a49177649537236520c6a13f93 Mon Sep 17 00:00:00 2001 From: HIRAMATSU Kentaro Date: Mon, 6 Apr 2020 21:35:42 +0900 Subject: [PATCH 217/684] docs/resource/aws_neptune_cluster: Fix attribute name typo deletion_protection (#12649) --- website/docs/r/neptune_cluster.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/neptune_cluster.html.markdown b/website/docs/r/neptune_cluster.html.markdown index d47e9a25992..c6dae414f80 100644 --- a/website/docs/r/neptune_cluster.html.markdown +++ b/website/docs/r/neptune_cluster.html.markdown @@ -62,7 +62,7 @@ The following arguments are supported: * `storage_encrypted` - (Optional) Specifies whether the Neptune cluster is encrypted. The default is `false` if not specified. * `tags` - (Optional) A mapping of tags to assign to the Neptune cluster. * `vpc_security_group_ids` - (Optional) List of VPC security groups to associate with the Cluster -* `delete_protection` - (Optional) A value that indicates whether the DB cluster has deletion protection enabled.The database can't be deleted when deletion protection is enabled. By default, deletion protection is disabled. +* `deletion_protection` - (Optional) A value that indicates whether the DB cluster has deletion protection enabled.The database can't be deleted when deletion protection is enabled. By default, deletion protection is disabled. ## Attributes Reference From b0a1dc5e9dd1424f60908316e61251b0ec256544 Mon Sep 17 00:00:00 2001 From: andrew bernard Date: Mon, 6 Apr 2020 08:43:22 -0400 Subject: [PATCH 218/684] docs/resource/aws_launch_template: fix documentation for EBS block kms_key_id property (#12672) --- website/docs/r/launch_template.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/launch_template.html.markdown b/website/docs/r/launch_template.html.markdown index 2e1645eb836..81b8323cbd9 100644 --- a/website/docs/r/launch_template.html.markdown +++ b/website/docs/r/launch_template.html.markdown @@ -174,7 +174,7 @@ The `ebs` block supports the following: * `iops` - 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"`. -* `kms_key_id` - AWS Key Management Service (AWS KMS) customer master key (CMK) to use when creating the encrypted volume. +* `kms_key_id` - The ARN of the AWS Key Management Service (AWS KMS) customer master key (CMK) to use when creating the encrypted volume. `encrypted` must be set to `true` when this is set. * `snapshot_id` - The Snapshot ID to mount. * `volume_size` - The size of the volume in gigabytes. From 1a405c848184aafbaa475cf8e9873e692d898816 Mon Sep 17 00:00:00 2001 From: Rob Hoelz Date: Mon, 6 Apr 2020 07:50:46 -0500 Subject: [PATCH 219/684] docs/resource/aws_cloudtrail: Fix broken link to Cloudtrail Data Events (#12687) The current link just goes to the top level page for the Cloudtrail User Guide --- website/docs/r/cloudtrail.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cloudtrail.html.markdown b/website/docs/r/cloudtrail.html.markdown index f8cff519f51..ef3f3a75f71 100644 --- a/website/docs/r/cloudtrail.html.markdown +++ b/website/docs/r/cloudtrail.html.markdown @@ -70,7 +70,7 @@ POLICY ### Data Event Logging -CloudTrail can log [Data Events](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-management-and-data-events-with-cloudtrail.html#logging-data-events) for certain services such as S3 bucket objects and Lambda function invocations. Additional information about data event configuration can be found in the [CloudTrail API DataResource documentation](https://docs.aws.amazon.com/awscloudtrail/latest/APIReference/API_DataResource.html). +CloudTrail can log [Data Events](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-data-events-with-cloudtrail.html) for certain services such as S3 bucket objects and Lambda function invocations. Additional information about data event configuration can be found in the [CloudTrail API DataResource documentation](https://docs.aws.amazon.com/awscloudtrail/latest/APIReference/API_DataResource.html). #### Logging All Lambda Function Invocations From 620769e2d2541450f22d739029cdc2f3de376609 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Mon, 6 Apr 2020 18:27:37 +0300 Subject: [PATCH 220/684] service/elastictranscoder: Refactor out SetMap usage (#12641) Output from acceptance testing: ``` --- PASS: TestAccAWSElasticTranscoderPreset_disappears (6.50s) --- PASS: TestAccAWSElasticTranscoderPreset_basic (20.25s) --- PASS: TestAccAWSElasticTranscoderPipeline_disappears (11.44s) --- PASS: TestAccAWSElasticTranscoderPipeline_basic (12.42s) --- PASS: TestAccAWSElasticTranscoderPipeline_withContentConfig (19.02s) --- PASS: TestAccAWSElasticTranscoderPipeline_notifications (19.06s) --- PASS: TestAccAWSElasticTranscoderPipeline_withPermissions (24.06s) --- PASS: TestAccAWSElasticTranscoderPipeline_kmsKey (32.35s) ``` --- ...esource_aws_elastic_transcoder_pipeline.go | 36 +++-- aws/resource_aws_elastic_transcoder_preset.go | 128 ++++++++++-------- aws/structure.go | 40 +----- 3 files changed, 95 insertions(+), 109 deletions(-) diff --git a/aws/resource_aws_elastic_transcoder_pipeline.go b/aws/resource_aws_elastic_transcoder_pipeline.go index c3b1fb2b426..edd1d5c63af 100644 --- a/aws/resource_aws_elastic_transcoder_pipeline.go +++ b/aws/resource_aws_elastic_transcoder_pipeline.go @@ -279,13 +279,14 @@ func flattenETNotifications(n *elastictranscoder.Notifications) []map[string]int return nil } - m := setMap(make(map[string]interface{})) + result := map[string]interface{}{ + "completed": aws.StringValue(n.Completed), + "error": aws.StringValue(n.Error), + "progressing": aws.StringValue(n.Progressing), + "warning": aws.StringValue(n.Warning), + } - m.SetString("completed", n.Completed) - m.SetString("error", n.Error) - m.SetString("progressing", n.Progressing) - m.SetString("warning", n.Warning) - return m.MapList() + return []map[string]interface{}{result} } func expandETPiplineOutputConfig(d *schema.ResourceData, key string) *elastictranscoder.PipelineOutputConfig { @@ -317,12 +318,16 @@ func expandETPiplineOutputConfig(d *schema.ResourceData, key string) *elastictra } func flattenETPipelineOutputConfig(cfg *elastictranscoder.PipelineOutputConfig) []map[string]interface{} { - m := setMap(make(map[string]interface{})) + if cfg == nil { + return nil + } - m.SetString("bucket", cfg.Bucket) - m.SetString("storage_class", cfg.StorageClass) + result := map[string]interface{}{ + "bucket": aws.StringValue(cfg.Bucket), + "storage_class": aws.StringValue(cfg.StorageClass), + } - return m.MapList() + return []map[string]interface{}{result} } func expandETPermList(permissions *schema.Set) []*elastictranscoder.Permission { @@ -350,12 +355,13 @@ func flattenETPermList(perms []*elastictranscoder.Permission) []map[string]inter var set []map[string]interface{} for _, p := range perms { - m := setMap(make(map[string]interface{})) - m.Set("access", flattenStringList(p.Access)) - m.SetString("grantee", p.Grantee) - m.SetString("grantee_type", p.GranteeType) + result := map[string]interface{}{ + "access": flattenStringList(p.Access), + "grantee": aws.StringValue(p.Grantee), + "grantee_type": aws.StringValue(p.GranteeType), + } - set = append(set, m) + set = append(set, result) } return set } diff --git a/aws/resource_aws_elastic_transcoder_preset.go b/aws/resource_aws_elastic_transcoder_preset.go index 0a61472d53e..2273b12b2be 100644 --- a/aws/resource_aws_elastic_transcoder_preset.go +++ b/aws/resource_aws_elastic_transcoder_preset.go @@ -622,15 +622,19 @@ func resourceAwsElasticTranscoderPresetRead(d *schema.ResourceData, meta interfa } func flattenETAudioParameters(audio *elastictranscoder.AudioParameters) []map[string]interface{} { - m := setMap(make(map[string]interface{})) + if audio == nil { + return nil + } - m.SetString("audio_packing_mode", audio.AudioPackingMode) - m.SetString("bit_rate", audio.BitRate) - m.SetString("channels", audio.Channels) - m.SetString("codec", audio.Codec) - m.SetString("sample_rate", audio.SampleRate) + result := map[string]interface{}{ + "audio_packing_mode": aws.StringValue(audio.AudioPackingMode), + "bit_rate": aws.StringValue(audio.BitRate), + "channels": aws.StringValue(audio.Channels), + "codec": aws.StringValue(audio.Codec), + "sample_rate": aws.StringValue(audio.SampleRate), + } - return m.MapList() + return []map[string]interface{}{result} } func flattenETAudioCodecOptions(opts *elastictranscoder.AudioCodecOptions) []map[string]interface{} { @@ -638,79 +642,87 @@ func flattenETAudioCodecOptions(opts *elastictranscoder.AudioCodecOptions) []map return nil } - m := setMap(make(map[string]interface{})) - - m.SetString("bit_depth", opts.BitDepth) - m.SetString("bit_order", opts.BitOrder) - m.SetString("profile", opts.Profile) - m.SetString("signed", opts.Signed) + result := map[string]interface{}{ + "bit_depth": aws.StringValue(opts.BitDepth), + "bit_order": aws.StringValue(opts.BitOrder), + "profile": aws.StringValue(opts.Profile), + "signed": aws.StringValue(opts.Signed), + } - return m.MapList() + return []map[string]interface{}{result} } func flattenETThumbnails(thumbs *elastictranscoder.Thumbnails) []map[string]interface{} { - m := setMap(make(map[string]interface{})) - - m.SetString("aspect_ratio", thumbs.AspectRatio) - m.SetString("format", thumbs.Format) - m.SetString("interval", thumbs.Interval) - m.SetString("max_height", thumbs.MaxHeight) - m.SetString("max_width", thumbs.MaxWidth) - m.SetString("padding_policy", thumbs.PaddingPolicy) - m.SetString("resolution", thumbs.Resolution) - m.SetString("sizing_policy", thumbs.SizingPolicy) - - return m.MapList() + if thumbs == nil { + return nil + } + + result := map[string]interface{}{ + "aspect_ratio": aws.StringValue(thumbs.AspectRatio), + "format": aws.StringValue(thumbs.Format), + "interval": aws.StringValue(thumbs.Interval), + "max_height": aws.StringValue(thumbs.MaxHeight), + "max_width": aws.StringValue(thumbs.MaxWidth), + "padding_policy": aws.StringValue(thumbs.PaddingPolicy), + "resolution": aws.StringValue(thumbs.Resolution), + "sizing_policy": aws.StringValue(thumbs.SizingPolicy), + } + + return []map[string]interface{}{result} } func flattenETVideoParams(video *elastictranscoder.VideoParameters) []map[string]interface{} { - m := setMap(make(map[string]interface{})) - - m.SetString("aspect_ratio", video.AspectRatio) - m.SetString("bit_rate", video.BitRate) - m.SetString("codec", video.Codec) - m.SetString("display_aspect_ratio", video.DisplayAspectRatio) - m.SetString("fixed_gop", video.FixedGOP) - m.SetString("frame_rate", video.FrameRate) - m.SetString("keyframes_max_dist", video.KeyframesMaxDist) - m.SetString("max_frame_rate", video.MaxFrameRate) - m.SetString("max_height", video.MaxHeight) - m.SetString("max_width", video.MaxWidth) - m.SetString("padding_policy", video.PaddingPolicy) - m.SetString("resolution", video.Resolution) - m.SetString("sizing_policy", video.SizingPolicy) - - return m.MapList() + if video == nil { + return nil + } + + result := map[string]interface{}{ + "aspect_ratio": aws.StringValue(video.AspectRatio), + "bit_rate": aws.StringValue(video.BitRate), + "codec": aws.StringValue(video.Codec), + "display_aspect_ratio": aws.StringValue(video.DisplayAspectRatio), + "fixed_gop": aws.StringValue(video.FixedGOP), + "frame_rate": aws.StringValue(video.FrameRate), + "keyframes_max_dist": aws.StringValue(video.KeyframesMaxDist), + "max_frame_rate": aws.StringValue(video.MaxFrameRate), + "max_height": aws.StringValue(video.MaxHeight), + "max_width": aws.StringValue(video.MaxWidth), + "padding_policy": aws.StringValue(video.PaddingPolicy), + "resolution": aws.StringValue(video.Resolution), + "sizing_policy": aws.StringValue(video.SizingPolicy), + } + + return []map[string]interface{}{result} } func flattenETWatermarks(watermarks []*elastictranscoder.PresetWatermark) []map[string]interface{} { var watermarkSet []map[string]interface{} for _, w := range watermarks { - watermark := setMap(make(map[string]interface{})) - - watermark.SetString("horizontal_align", w.HorizontalAlign) - watermark.SetString("horizontal_offset", w.HorizontalOffset) - watermark.SetString("id", w.Id) - watermark.SetString("max_height", w.MaxHeight) - watermark.SetString("max_width", w.MaxWidth) - watermark.SetString("opacity", w.Opacity) - watermark.SetString("sizing_policy", w.SizingPolicy) - watermark.SetString("target", w.Target) - watermark.SetString("vertical_align", w.VerticalAlign) - watermark.SetString("vertical_offset", w.VerticalOffset) + watermark := map[string]interface{}{ + "horizontal_align": aws.StringValue(w.HorizontalAlign), + "horizontal_offset": aws.StringValue(w.HorizontalOffset), + "id": aws.StringValue(w.Id), + "max_height": aws.StringValue(w.MaxHeight), + "max_width": aws.StringValue(w.MaxWidth), + "opacity": aws.StringValue(w.Opacity), + "sizing_policy": aws.StringValue(w.SizingPolicy), + "target": aws.StringValue(w.Target), + "vertical_align": aws.StringValue(w.VerticalAlign), + "vertical_offset": aws.StringValue(w.VerticalOffset), + } - watermarkSet = append(watermarkSet, watermark.Map()) + watermarkSet = append(watermarkSet, watermark) } return watermarkSet } func resourceAwsElasticTranscoderPresetDelete(d *schema.ResourceData, meta interface{}) error { - elastictranscoderconn := meta.(*AWSClient).elastictranscoderconn + conn := meta.(*AWSClient).elastictranscoderconn log.Printf("[DEBUG] Elastic Transcoder Delete Preset: %s", d.Id()) - _, err := elastictranscoderconn.DeletePreset(&elastictranscoder.DeletePresetInput{ + _, err := conn.DeletePreset(&elastictranscoder.DeletePresetInput{ Id: aws.String(d.Id()), }) diff --git a/aws/structure.go b/aws/structure.go index f1184cc0afb..7f0dc4fb2f1 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -2067,39 +2067,6 @@ func flattenApiGatewayThrottleSettings(settings *apigateway.ThrottleSettings) [] // TODO: refactor some of these helper functions and types in the terraform/helper packages -// a convenience wrapper type for the schema.Set map[string]interface{} -// Set operations only alter the underlying map if the value is not nil -type setMap map[string]interface{} - -// SetString sets m[key] = *value only if `value != nil` -func (s setMap) SetString(key string, value *string) { - if value == nil { - return - } - - s[key] = *value -} - -// Set assigns value to s[key] if value isn't nil -func (s setMap) Set(key string, value interface{}) { - if reflect.ValueOf(value).IsNil() { - return - } - - s[key] = value -} - -// Map returns the raw map type for a shorter type conversion -func (s setMap) Map() map[string]interface{} { - return map[string]interface{}(s) -} - -// MapList returns the map[string]interface{} as a single element in a slice to -// match the schema.Set data type used for structs. -func (s setMap) MapList() []map[string]interface{} { - return []map[string]interface{}{s.Map()} -} - // Takes the result of flatmap.Expand for an array of policy attributes and // returns ELB API compatible objects func expandPolicyAttributes(configured []interface{}) ([]*elb.PolicyAttribute, error) { @@ -3681,10 +3648,11 @@ func flattenWafAction(n *waf.WafAction) []map[string]interface{} { return nil } - m := setMap(make(map[string]interface{})) + result := map[string]interface{}{ + "type": aws.StringValue(n.Type), + } - m.SetString("type", n.Type) - return m.MapList() + return []map[string]interface{}{result} } func flattenWafWebAclRules(ts []*waf.ActivatedRule) []map[string]interface{} { From 80b5f1d50e517f1e06e183bf91e3a02502fca19f Mon Sep 17 00:00:00 2001 From: Derrick Petzold Date: Mon, 6 Apr 2020 10:03:58 -0700 Subject: [PATCH 221/684] New Data Source: aws_cloudfront_distribution (#6468) Output from acceptance testing: ``` --- PASS: TestAccAWSDataSourceCloudFrontDistribution_basic (628.20s) ``` --- ...data_source_aws_cloudfront_distribution.go | 94 +++++++++++++++++++ ...source_aws_cloudfront_distribution_test.go | 41 ++++++++ aws/provider.go | 1 + aws/resource_aws_cloudfront_distribution.go | 1 + website/aws.erb | 8 ++ .../d/cloudfront_distribution.html.markdown | 51 ++++++++++ 6 files changed, 196 insertions(+) create mode 100644 aws/data_source_aws_cloudfront_distribution.go create mode 100644 aws/data_source_aws_cloudfront_distribution_test.go create mode 100644 website/docs/d/cloudfront_distribution.html.markdown diff --git a/aws/data_source_aws_cloudfront_distribution.go b/aws/data_source_aws_cloudfront_distribution.go new file mode 100644 index 00000000000..e03fa1d8a8f --- /dev/null +++ b/aws/data_source_aws_cloudfront_distribution.go @@ -0,0 +1,94 @@ +package aws + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudfront" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func dataSourceAwsCloudFrontDistribution() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsCloudFrontDistributionRead, + + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "domain_name": { + Type: schema.TypeString, + Computed: true, + }, + "last_modified_time": { + Type: schema.TypeString, + Computed: true, + }, + "in_progress_validation_batches": { + Type: schema.TypeInt, + Computed: true, + }, + "hosted_zone_id": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + + "tags": tagsSchema(), + }, + } +} + +func dataSourceAwsCloudFrontDistributionRead(d *schema.ResourceData, meta interface{}) error { + d.SetId(d.Get("id").(string)) + conn := meta.(*AWSClient).cloudfrontconn + input := &cloudfront.GetDistributionInput{ + Id: aws.String(d.Id()), + } + + output, err := conn.GetDistribution(input) + if err != nil { + return fmt.Errorf("error getting CloudFront Distribution (%s): %w", d.Id(), err) + } + if output == nil { + return fmt.Errorf("error getting CloudFront Distribution (%s): empty response", d.Id()) + } + d.Set("etag", output.ETag) + if distribution := output.Distribution; distribution != nil { + d.Set("arn", distribution.ARN) + d.Set("domain_name", distribution.DomainName) + d.Set("in_progress_validation_batches", distribution.InProgressInvalidationBatches) + d.Set("last_modified_time", aws.String(distribution.LastModifiedTime.String())) + d.Set("status", distribution.Status) + if distributionConfig := distribution.DistributionConfig; distributionConfig != nil { + d.Set("enabled", distributionConfig.Enabled) + } + } + tags, err := keyvaluetags.CloudfrontListTags(conn, d.Get("arn").(string)) + if err != nil { + return fmt.Errorf("error listing tags for CloudFront Distribution (%s): %w", d.Id(), err) + } + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + d.Set("hosted_zone_id", cloudFrontRoute53ZoneID) + return nil +} diff --git a/aws/data_source_aws_cloudfront_distribution_test.go b/aws/data_source_aws_cloudfront_distribution_test.go new file mode 100644 index 00000000000..04de77aa303 --- /dev/null +++ b/aws/data_source_aws_cloudfront_distribution_test.go @@ -0,0 +1,41 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccAWSDataSourceCloudFrontDistribution_basic(t *testing.T) { + dataSourceName := "data.aws_cloudfront_distribution.test" + resourceName := "aws_cloudfront_distribution.s3_distribution" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudFrontDistributionData, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "domain_name", resourceName, "domain_name"), + resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), + resource.TestCheckResourceAttrPair(dataSourceName, "hosted_zone_id", resourceName, "hosted_zone_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "in_progress_validation_batches", resourceName, "in_progress_validation_batches"), + resource.TestCheckResourceAttrPair(dataSourceName, "last_modified_time", resourceName, "last_modified_time"), + resource.TestCheckResourceAttrPair(dataSourceName, "status", resourceName, "status"), + ), + }, + }, + }) +} + +var testAccAWSCloudFrontDistributionData = fmt.Sprintf(` +%s + +data aws_cloudfront_distribution test { + id = aws_cloudfront_distribution.s3_distribution.id +} +`, fmt.Sprintf(testAccAWSCloudFrontDistributionS3ConfigWithTags, acctest.RandInt(), originBucket, logBucket, testAccAWSCloudFrontDistributionRetainConfig())) diff --git a/aws/provider.go b/aws/provider.go index be386f16d6b..097516c291a 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -177,6 +177,7 @@ func Provider() terraform.ResourceProvider { "aws_canonical_user_id": dataSourceAwsCanonicalUserId(), "aws_cloudformation_export": dataSourceAwsCloudFormationExport(), "aws_cloudformation_stack": dataSourceAwsCloudFormationStack(), + "aws_cloudfront_distribution": dataSourceAwsCloudFrontDistribution(), "aws_cloudhsm_v2_cluster": dataSourceCloudHsmV2Cluster(), "aws_cloudtrail_service_account": dataSourceAwsCloudTrailServiceAccount(), "aws_cloudwatch_log_group": dataSourceAwsCloudwatchLogGroup(), diff --git a/aws/resource_aws_cloudfront_distribution.go b/aws/resource_aws_cloudfront_distribution.go index b54b1b3612c..245a90a4fe6 100644 --- a/aws/resource_aws_cloudfront_distribution.go +++ b/aws/resource_aws_cloudfront_distribution.go @@ -821,6 +821,7 @@ func resourceAwsCloudFrontDistributionRead(d *schema.ResourceData, meta interfac if err != nil { return err } + // Update other attributes outside of DistributionConfig err = d.Set("active_trusted_signers", flattenActiveTrustedSigners(resp.Distribution.ActiveTrustedSigners)) if err != nil { diff --git a/website/aws.erb b/website/aws.erb index b5b8540d4c4..6f62cbc9ba8 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -460,6 +460,14 @@
  • CloudFront