From b90c85984322ee0815309905b91be22d488e626a Mon Sep 17 00:00:00 2001 From: Tamir Date: Thu, 27 Apr 2023 17:46:37 +0300 Subject: [PATCH 01/18] add `copy_tags_to_snapshot` --- internal/service/docdb/cluster_instance.go | 12 ++++ .../service/docdb/cluster_instance_test.go | 65 +++++++++++++++++++ .../r/docdb_cluster_instance.html.markdown | 9 +++ 3 files changed, 86 insertions(+) diff --git a/internal/service/docdb/cluster_instance.go b/internal/service/docdb/cluster_instance.go index 2b9679fc88b..f6ba11baab6 100644 --- a/internal/service/docdb/cluster_instance.go +++ b/internal/service/docdb/cluster_instance.go @@ -73,6 +73,11 @@ func ResourceClusterInstance() *schema.Resource { Required: true, ForceNew: true, }, + "copy_tags_to_snapshot": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, "db_subnet_group_name": { Type: schema.TypeString, Computed: true, @@ -181,6 +186,7 @@ func resourceClusterInstanceCreate(ctx context.Context, d *schema.ResourceData, conn := meta.(*conns.AWSClient).DocDBConn() input := &docdb.CreateDBInstanceInput{ + CopyTagsToSnapshot: aws.Bool(d.Get("copy_tags_to_snapshot").(bool)), DBInstanceClass: aws.String(d.Get("instance_class").(string)), DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)), Engine: aws.String(d.Get("engine").(string)), @@ -309,6 +315,7 @@ func resourceClusterInstanceRead(ctx context.Context, d *schema.ResourceData, me d.Set("auto_minor_version_upgrade", db.AutoMinorVersionUpgrade) d.Set("availability_zone", db.AvailabilityZone) d.Set("cluster_identifier", db.DBClusterIdentifier) + d.Set("copy_tags_to_snapshot", db.CopyTagsToSnapshot) d.Set("dbi_resource_id", db.DbiResourceId) // The AWS API does not expose 'EnablePerformanceInsights' the line below should be uncommented // as soon as it is available in the DescribeDBClusters output. @@ -341,6 +348,11 @@ func resourceClusterInstanceUpdate(ctx context.Context, d *schema.ResourceData, DBInstanceIdentifier: aws.String(d.Id()), } + if d.HasChange("copy_tags_to_snapshot") { + req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool)) + requestUpdate = true + } + if d.HasChange("instance_class") { req.DBInstanceClass = aws.String(d.Get("instance_class").(string)) requestUpdate = true diff --git a/internal/service/docdb/cluster_instance_test.go b/internal/service/docdb/cluster_instance_test.go index 8c9fd976abf..eed0c6e5ee5 100644 --- a/internal/service/docdb/cluster_instance_test.go +++ b/internal/service/docdb/cluster_instance_test.go @@ -270,6 +270,46 @@ func TestAccDocDBClusterInstance_disappears(t *testing.T) { }) } +func TestAccDocDBClusterInstance_copyTagsToSnapshot(t *testing.T) { + ctx := acctest.Context(t) + var v docdb.DBInstance + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_docdb_cluster_instance.cluster_instances" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, docdb.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccClusterInstanceConfig_copyTagsToSnapshot(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckClusterInstanceExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "copy_tags_to_snapshot", "true"), + ), + }, + { + Config: testAccClusterInstanceConfig_copyTagsToSnapshot(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckClusterInstanceExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "copy_tags_to_snapshot", "false"), + ), + }, + + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "apply_immediately", + "identifier_prefix", + }, + }, + }, + }) +} + func testAccCheckClusterInstanceAttributes(v *docdb.DBInstance) resource.TestCheckFunc { return func(s *terraform.State) error { if *v.Engine != "docdb" { @@ -621,3 +661,28 @@ resource "aws_docdb_cluster_instance" "cluster_instances" { } `, rName)) } + +func testAccClusterInstanceConfig_copyTagsToSnapshot(rName string, flag bool) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +resource "aws_docdb_cluster" "default" { + cluster_identifier = %[1]q + availability_zones = [data.aws_availability_zones.available.names[0], data.aws_availability_zones.available.names[1], data.aws_availability_zones.available.names[2]] + master_username = "foo" + master_password = "mustbeeightcharaters" + skip_final_snapshot = true +} + +data "aws_docdb_orderable_db_instance" "test" { + engine = "docdb" + preferred_instance_classes = ["db.t3.medium", "db.t4g.medium", "db.r4.large", "db.r5.large", "db.r5.xlarge"] +} + +resource "aws_docdb_cluster_instance" "cluster_instances" { + identifier = %[1]q + cluster_identifier = aws_docdb_cluster.default.id + copy_tags_to_snapshot = %[2]t + instance_class = data.aws_docdb_orderable_db_instance.test.instance_class + promotion_tier = "3" +} +`, rName, flag)) +} diff --git a/website/docs/r/docdb_cluster_instance.html.markdown b/website/docs/r/docdb_cluster_instance.html.markdown index 629a59f0331..2ce6d2e6612 100644 --- a/website/docs/r/docdb_cluster_instance.html.markdown +++ b/website/docs/r/docdb_cluster_instance.html.markdown @@ -47,6 +47,7 @@ The following arguments are supported: * `auto_minor_version_upgrade` - (Optional) This parameter does not apply to Amazon DocumentDB. Amazon DocumentDB does not perform minor version upgrades regardless of the value set (see [docs](https://docs.aws.amazon.com/documentdb/latest/developerguide/API_DBInstance.html)). Default `true`. * `availability_zone` - (Optional, Computed) The EC2 Availability Zone that the DB instance is created in. See [docs](https://docs.aws.amazon.com/documentdb/latest/developerguide/API_CreateDBInstance.html) about the details. * `cluster_identifier` - (Required) The identifier of the [`aws_docdb_cluster`](/docs/providers/aws/r/docdb_cluster.html) in which to launch this instance. +* `copy_tags_to_snapshot` – (Optional, boolean) Copy all DB instance `tags` to snapshots. Default is `false`. * `enable_performance_insights` - (Optional) A value that indicates whether to enable Performance Insights for the DB Instance. Default `false`. See [docs] (https://docs.aws.amazon.com/documentdb/latest/developerguide/performance-insights.html) about the details. * `engine` - (Optional) The name of the database engine to be used for the DocumentDB instance. Defaults to `docdb`. Valid Values: `docdb`. * `identifier` - (Optional, Forces new resource) The identifier for the DocumentDB instance, if omitted, Terraform will assign a random, unique identifier. @@ -54,6 +55,13 @@ The following arguments are supported: * `instance_class` - (Required) The instance class to use. For details on CPU and memory, see [Scaling for DocumentDB Instances][2]. DocumentDB currently supports the below instance classes. Please see [AWS Documentation][4] for complete details. + - db.r6g.large + - db.r6g.xlarge + - db.r6g.2xlarge + - db.r6g.4xlarge + - db.r6g.8xlarge + - db.r6g.12xlarge + - db.r6g.16xlarge - db.r5.large - db.r5.xlarge - db.r5.2xlarge @@ -66,6 +74,7 @@ The following arguments are supported: - db.r4.4xlarge - db.r4.8xlarge - db.r4.16xlarge + - db.t4g.medium - db.t3.medium * `performance_insights_kms_key_id` - (Optional) The KMS key identifier is the key ARN, key ID, alias ARN, or alias name for the KMS key. If you do not specify a value for PerformanceInsightsKMSKeyId, then Amazon DocumentDB uses your default KMS key. * `preferred_maintenance_window` - (Optional) The window to perform maintenance in. From 1c41994d5a86b3a1daf2939b3aa11b452803522c Mon Sep 17 00:00:00 2001 From: Tamir Date: Thu, 27 Apr 2023 17:58:34 +0300 Subject: [PATCH 02/18] cl and stuff --- .changelog/31022.txt | 3 +++ internal/service/docdb/cluster_instance_test.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 .changelog/31022.txt diff --git a/.changelog/31022.txt b/.changelog/31022.txt new file mode 100644 index 00000000000..c0e163a2e23 --- /dev/null +++ b/.changelog/31022.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_docdb_cluster_instance: Add optional argument `copy_tags_to_snapshot` +``` \ No newline at end of file diff --git a/internal/service/docdb/cluster_instance_test.go b/internal/service/docdb/cluster_instance_test.go index eed0c6e5ee5..aa1c1c2f093 100644 --- a/internal/service/docdb/cluster_instance_test.go +++ b/internal/service/docdb/cluster_instance_test.go @@ -273,8 +273,8 @@ func TestAccDocDBClusterInstance_disappears(t *testing.T) { func TestAccDocDBClusterInstance_copyTagsToSnapshot(t *testing.T) { ctx := acctest.Context(t) var v docdb.DBInstance - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_docdb_cluster_instance.cluster_instances" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, From 752bb463d61cf88c6551a5d9cf6abc2f53500a68 Mon Sep 17 00:00:00 2001 From: Tamir Date: Thu, 27 Apr 2023 18:01:53 +0300 Subject: [PATCH 03/18] terrafmt --- internal/service/docdb/cluster_instance_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/docdb/cluster_instance_test.go b/internal/service/docdb/cluster_instance_test.go index aa1c1c2f093..c03928d12e8 100644 --- a/internal/service/docdb/cluster_instance_test.go +++ b/internal/service/docdb/cluster_instance_test.go @@ -683,6 +683,6 @@ resource "aws_docdb_cluster_instance" "cluster_instances" { copy_tags_to_snapshot = %[2]t instance_class = data.aws_docdb_orderable_db_instance.test.instance_class promotion_tier = "3" -} +} `, rName, flag)) } From 82f15642de68c924d12d3153a7f9f1050370d988 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 09:14:30 -0400 Subject: [PATCH 04/18] Tweak CHANGELOG entry. --- .changelog/31022.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/31022.txt b/.changelog/31022.txt index c0e163a2e23..279299a7a89 100644 --- a/.changelog/31022.txt +++ b/.changelog/31022.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_docdb_cluster_instance: Add optional argument `copy_tags_to_snapshot` +resource/aws_docdb_cluster_instance: Add `copy_tags_to_snapshot` argument ``` \ No newline at end of file From 2d5358ebb75afa28e218a7de0ec0a5dc19088865 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 09:21:27 -0400 Subject: [PATCH 05/18] r/aws_docdb_cluster_instance: Move functions around. --- internal/service/docdb/cluster_instance.go | 73 ++++++++++++++++++++++ internal/service/docdb/find.go | 29 --------- internal/service/docdb/status.go | 16 ----- internal/service/docdb/wait.go | 23 ------- 4 files changed, 73 insertions(+), 68 deletions(-) diff --git a/internal/service/docdb/cluster_instance.go b/internal/service/docdb/cluster_instance.go index 9f8bd8d6ea8..205d1b74c4a 100644 --- a/internal/service/docdb/cluster_instance.go +++ b/internal/service/docdb/cluster_instance.go @@ -5,6 +5,7 @@ package docdb import ( "context" + "fmt" "log" "strings" "time" @@ -522,3 +523,75 @@ var resourceClusterInstanceDeletePendingStates = []string{ "modifying", "deleting", } + +func FindDBInstanceById(ctx context.Context, conn *docdb.DocDB, dBInstanceID string) (*docdb.DBInstance, error) { + var dBInstance *docdb.DBInstance + + input := &docdb.DescribeDBInstancesInput{ + DBInstanceIdentifier: aws.String(dBInstanceID), + } + + err := conn.DescribeDBInstancesPagesWithContext(ctx, input, func(page *docdb.DescribeDBInstancesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, dbi := range page.DBInstances { + if dbi == nil { + continue + } + + if aws.StringValue(dbi.DBInstanceIdentifier) == dBInstanceID { + dBInstance = dbi + return false + } + } + + return !lastPage + }) + + return dBInstance, err +} + +func statusDBInstanceRefreshFunc(ctx context.Context, conn *docdb.DocDB, dBInstanceID string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + dBInstance, err := FindDBInstanceById(ctx, conn, dBInstanceID) + + if tfawserr.ErrCodeEquals(err, docdb.ErrCodeDBInstanceNotFoundFault) || dBInstance == nil { + return nil, DBInstanceStatusDeleted, nil + } + + if err != nil { + return nil, "", fmt.Errorf("reading DocumentDB Instance (%s): %w", dBInstanceID, err) + } + + return dBInstance, aws.StringValue(dBInstance.DBInstanceStatus), nil + } +} + +const ( + DBInstanceDeleteTimeout = 5 * time.Minute + + DBInstanceStatusAvailable = "available" + DBInstanceStatusDeleted = "deleted" + DBInstanceStatusDeleting = "deleting" +) + +func WaitForDBInstanceDeletion(ctx context.Context, conn *docdb.DocDB, dBInstanceID string, timeout time.Duration) error { + stateConf := &retry.StateChangeConf{ + Pending: []string{DBInstanceStatusAvailable, DBInstanceStatusDeleting}, + Target: []string{DBInstanceStatusDeleted}, + Refresh: statusDBInstanceRefreshFunc(ctx, conn, dBInstanceID), + Timeout: timeout, + NotFoundChecks: 1, + } + + log.Printf("[DEBUG] Waiting for DocumentDB Instance (%s) deletion", dBInstanceID) + _, err := stateConf.WaitForStateContext(ctx) + + if tfresource.NotFound(err) { + return nil + } + + return err +} diff --git a/internal/service/docdb/find.go b/internal/service/docdb/find.go index 865455de871..ee37e0f37d8 100644 --- a/internal/service/docdb/find.go +++ b/internal/service/docdb/find.go @@ -91,35 +91,6 @@ func FindDBClusterSnapshotById(ctx context.Context, conn *docdb.DocDB, dBCluster return dBClusterSnapshot, err } -func FindDBInstanceById(ctx context.Context, conn *docdb.DocDB, dBInstanceID string) (*docdb.DBInstance, error) { - var dBInstance *docdb.DBInstance - - input := &docdb.DescribeDBInstancesInput{ - DBInstanceIdentifier: aws.String(dBInstanceID), - } - - err := conn.DescribeDBInstancesPagesWithContext(ctx, input, func(page *docdb.DescribeDBInstancesOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } - - for _, dbi := range page.DBInstances { - if dbi == nil { - continue - } - - if aws.StringValue(dbi.DBInstanceIdentifier) == dBInstanceID { - dBInstance = dbi - return false - } - } - - return !lastPage - }) - - return dBInstance, err -} - func FindGlobalClusterById(ctx context.Context, conn *docdb.DocDB, globalClusterID string) (*docdb.GlobalCluster, error) { var globalCluster *docdb.GlobalCluster diff --git a/internal/service/docdb/status.go b/internal/service/docdb/status.go index ef589d35fe9..388b50ca842 100644 --- a/internal/service/docdb/status.go +++ b/internal/service/docdb/status.go @@ -46,22 +46,6 @@ func statusDBClusterSnapshotRefreshFunc(ctx context.Context, conn *docdb.DocDB, } } -func statusDBInstanceRefreshFunc(ctx context.Context, conn *docdb.DocDB, dBInstanceID string) retry.StateRefreshFunc { - return func() (interface{}, string, error) { - dBInstance, err := FindDBInstanceById(ctx, conn, dBInstanceID) - - if tfawserr.ErrCodeEquals(err, docdb.ErrCodeDBInstanceNotFoundFault) || dBInstance == nil { - return nil, DBInstanceStatusDeleted, nil - } - - if err != nil { - return nil, "", fmt.Errorf("reading DocumentDB Instance (%s): %w", dBInstanceID, err) - } - - return dBInstance, aws.StringValue(dBInstance.DBInstanceStatus), nil - } -} - func statusDBSubnetGroupRefreshFunc(ctx context.Context, conn *docdb.DocDB, dBSubnetGroupName string) retry.StateRefreshFunc { return func() (interface{}, string, error) { dBSubnetGroup, err := FindDBSubnetGroupByName(ctx, conn, dBSubnetGroupName) diff --git a/internal/service/docdb/wait.go b/internal/service/docdb/wait.go index ba19652c502..0270ec19272 100644 --- a/internal/service/docdb/wait.go +++ b/internal/service/docdb/wait.go @@ -16,7 +16,6 @@ import ( const ( DBClusterSnapshotDeleteTimeout = 5 * time.Minute - DBInstanceDeleteTimeout = 5 * time.Minute DBSubnetGroupDeleteTimeout = 5 * time.Minute EventSubscriptionDeleteTimeout = 5 * time.Minute GlobalClusterCreateTimeout = 5 * time.Minute @@ -25,9 +24,6 @@ const ( ) const ( - DBInstanceStatusAvailable = "available" - DBInstanceStatusDeleted = "deleted" - DBInstanceStatusDeleting = "deleting" DBClusterSnapshotStatusAvailable = "available" DBClusterSnapshotStatusDeleted = "deleted" DBClusterSnapshotStatusDeleting = "deleting" @@ -125,25 +121,6 @@ func WaitForDBClusterSnapshotDeletion(ctx context.Context, conn *docdb.DocDB, dB return err } -func WaitForDBInstanceDeletion(ctx context.Context, conn *docdb.DocDB, dBInstanceID string, timeout time.Duration) error { - stateConf := &retry.StateChangeConf{ - Pending: []string{DBInstanceStatusAvailable, DBInstanceStatusDeleting}, - Target: []string{DBInstanceStatusDeleted}, - Refresh: statusDBInstanceRefreshFunc(ctx, conn, dBInstanceID), - Timeout: timeout, - NotFoundChecks: 1, - } - - log.Printf("[DEBUG] Waiting for DocumentDB Instance (%s) deletion", dBInstanceID) - _, err := stateConf.WaitForStateContext(ctx) - - if tfresource.NotFound(err) { - return nil - } - - return err -} - func WaitForGlobalClusterDeletion(ctx context.Context, conn *docdb.DocDB, globalClusterID string, timeout time.Duration) error { stateConf := &retry.StateChangeConf{ Pending: []string{GlobalClusterStatusAvailable, GlobalClusterStatusDeleting}, From f8634487e2337c3f5510c403bdae0848be9bc54f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 09:36:14 -0400 Subject: [PATCH 06/18] r/aws_docdb_cluster_instance: Start to tidy up Create. --- internal/service/docdb/cluster_instance.go | 69 +++++++++------------- 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/internal/service/docdb/cluster_instance.go b/internal/service/docdb/cluster_instance.go index 205d1b74c4a..68208e81887 100644 --- a/internal/service/docdb/cluster_instance.go +++ b/internal/service/docdb/cluster_instance.go @@ -34,6 +34,7 @@ func ResourceClusterInstance() *schema.Resource { ReadWithoutTimeout: resourceClusterInstanceRead, UpdateWithoutTimeout: resourceClusterInstanceUpdate, DeleteWithoutTimeout: resourceClusterInstanceDelete, + Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -45,8 +46,6 @@ func ResourceClusterInstance() *schema.Resource { }, Schema: map[string]*schema.Schema{ - // apply_immediately is used to determine when the update modifications take place. - // See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html "apply_immediately": { Type: schema.TypeBool, Optional: true, @@ -64,8 +63,8 @@ func ResourceClusterInstance() *schema.Resource { "availability_zone": { Type: schema.TypeString, Optional: true, - ForceNew: true, Computed: true, + ForceNew: true, }, "ca_cert_identifier": { Type: schema.TypeString, @@ -80,7 +79,6 @@ func ResourceClusterInstance() *schema.Resource { "copy_tags_to_snapshot": { Type: schema.TypeBool, Optional: true, - Default: false, }, "db_subnet_group_name": { Type: schema.TypeString, @@ -189,62 +187,53 @@ func resourceClusterInstanceCreate(ctx context.Context, d *schema.ResourceData, var diags diag.Diagnostics conn := meta.(*conns.AWSClient).DocDBConn(ctx) + var identifier string + if v, ok := d.GetOk("identifier"); ok { + identifier = v.(string) + } else if v, ok := d.GetOk("identifier_prefix"); ok { + identifier = id.PrefixedUniqueId(v.(string)) + } else { + identifier = id.PrefixedUniqueId("tf-") + } input := &docdb.CreateDBInstanceInput{ - CopyTagsToSnapshot: aws.Bool(d.Get("copy_tags_to_snapshot").(bool)), - DBInstanceClass: aws.String(d.Get("instance_class").(string)), + AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)), DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)), + DBInstanceClass: aws.String(d.Get("instance_class").(string)), + DBInstanceIdentifier: aws.String(identifier), Engine: aws.String(d.Get("engine").(string)), PromotionTier: aws.Int64(int64(d.Get("promotion_tier").(int))), - AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)), Tags: getTagsIn(ctx), } - if attr, ok := d.GetOk("availability_zone"); ok { - input.AvailabilityZone = aws.String(attr.(string)) + if v, ok := d.GetOk("availability_zone"); ok { + input.AvailabilityZone = aws.String(v.(string)) } - if attr, ok := d.GetOk("enable_performance_insights"); ok { - input.EnablePerformanceInsights = aws.Bool(attr.(bool)) + if v, ok := d.GetOk("copy_tags_to_snapshot"); ok { + input.CopyTagsToSnapshot = aws.Bool(v.(bool)) } - if v, ok := d.GetOk("identifier"); ok { - input.DBInstanceIdentifier = aws.String(v.(string)) - } else { - if v, ok := d.GetOk("identifier_prefix"); ok { - input.DBInstanceIdentifier = aws.String(id.PrefixedUniqueId(v.(string))) - } else { - input.DBInstanceIdentifier = aws.String(id.PrefixedUniqueId("tf-")) - } + if v, ok := d.GetOk("enable_performance_insights"); ok { + input.EnablePerformanceInsights = aws.Bool(v.(bool)) } - if attr, ok := d.GetOk("performance_insights_kms_key_id"); ok { - input.PerformanceInsightsKMSKeyId = aws.String(attr.(string)) + if v, ok := d.GetOk("performance_insights_kms_key_id"); ok { + input.PerformanceInsightsKMSKeyId = aws.String(v.(string)) } - if attr, ok := d.GetOk("preferred_maintenance_window"); ok { - input.PreferredMaintenanceWindow = aws.String(attr.(string)) + if v, ok := d.GetOk("preferred_maintenance_window"); ok { + input.PreferredMaintenanceWindow = aws.String(v.(string)) } - var resp *docdb.CreateDBInstanceOutput - err := retry.RetryContext(ctx, propagationTimeout, func() *retry.RetryError { - var err error - resp, err = conn.CreateDBInstanceWithContext(ctx, input) - if err != nil { - if tfawserr.ErrMessageContains(err, "InvalidParameterValue", "IAM role ARN value is invalid or does not include the required permissions") { - return retry.RetryableError(err) - } - return retry.NonRetryableError(err) - } - return nil - }) - if tfresource.TimedOut(err) { - resp, err = conn.CreateDBInstanceWithContext(ctx, input) - } + _, err := tfresource.RetryWhenAWSErrMessageContains(ctx, propagationTimeout, func() (interface{}, error) { + return conn.CreateDBInstanceWithContext(ctx, input) + }, errCodeInvalidParameterValue, "IAM role ARN value is invalid or does not include the required permissions") + if err != nil { - return sdkdiag.AppendErrorf(diags, "creating DocumentDB Cluster Instance: %s", err) + return sdkdiag.AppendErrorf(diags, "creating DocumentDB Cluster Instance (%s): %s", identifier, err) } - d.SetId(aws.StringValue(resp.DBInstance.DBInstanceIdentifier)) + d.SetId(identifier) // reuse db_instance refresh func stateConf := &retry.StateChangeConf{ From cb9485584092fda0f54af958172e53e4895ab4b4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 10:55:17 -0400 Subject: [PATCH 07/18] r/aws_docdb_cluster_instance: Tidy up Delete. --- internal/service/docdb/cluster_instance.go | 119 +++++++++++++-------- 1 file changed, 73 insertions(+), 46 deletions(-) diff --git a/internal/service/docdb/cluster_instance.go b/internal/service/docdb/cluster_instance.go index 68208e81887..01a5e1f8807 100644 --- a/internal/service/docdb/cluster_instance.go +++ b/internal/service/docdb/cluster_instance.go @@ -5,7 +5,6 @@ package docdb import ( "context" - "fmt" "log" "strings" "time" @@ -423,25 +422,17 @@ func resourceClusterInstanceDelete(ctx context.Context, d *schema.ResourceData, var diags diag.Diagnostics conn := meta.(*conns.AWSClient).DocDBConn(ctx) - opts := docdb.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())} + log.Printf("[DEBUG] Deleting DocumentDB Cluster Instance: %s", d.Id()) + _, err := conn.DeleteDBInstanceWithContext(ctx, &docdb.DeleteDBInstanceInput{ + DBInstanceIdentifier: aws.String(d.Id()), + }) - if _, err := conn.DeleteDBInstanceWithContext(ctx, &opts); err != nil { + if err != nil { return sdkdiag.AppendErrorf(diags, "deleting DocumentDB Cluster Instance (%s): %s", d.Id(), err) } - // re-uses db_instance refresh func - log.Println("[INFO] Waiting for DocumentDB Cluster Instance to be destroyed") - stateConf := &retry.StateChangeConf{ - Pending: resourceClusterInstanceDeletePendingStates, - Target: []string{}, - Refresh: resourceInstanceStateRefreshFunc(ctx, conn, d.Id()), - Timeout: d.Timeout(schema.TimeoutDelete), - MinTimeout: 10 * time.Second, - Delay: 30 * time.Second, // Wait 30 secs before starting - } - - if _, err := stateConf.WaitForStateContext(ctx); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for DocumentDB Cluster Instance (%s) deletion: %s", d.Id(), err) + if _, err := waitDBInstanceDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for DocumentDB Cluster Instance (%s) delete: %s", d.Id(), err) } return diags @@ -513,48 +504,80 @@ var resourceClusterInstanceDeletePendingStates = []string{ "deleting", } -func FindDBInstanceById(ctx context.Context, conn *docdb.DocDB, dBInstanceID string) (*docdb.DBInstance, error) { - var dBInstance *docdb.DBInstance - +func FindDBInstanceByID(ctx context.Context, conn *docdb.DocDB, id string) (*docdb.DBInstance, error) { input := &docdb.DescribeDBInstancesInput{ - DBInstanceIdentifier: aws.String(dBInstanceID), + DBInstanceIdentifier: aws.String(id), + } + output, err := findDBInstance(ctx, conn, input) + + if err != nil { + return nil, err + } + + // Eventual consistency check. + if aws.StringValue(output.DBInstanceIdentifier) != id { + return nil, &retry.NotFoundError{ + LastRequest: input, + } + } + + return output, nil +} + +func findDBInstance(ctx context.Context, conn *docdb.DocDB, input *docdb.DescribeDBInstancesInput) (*docdb.DBInstance, error) { + output, err := findDBInstances(ctx, conn, input) + + if err != nil { + return nil, err } + return tfresource.AssertSinglePtrResult(output) +} + +func findDBInstances(ctx context.Context, conn *docdb.DocDB, input *docdb.DescribeDBInstancesInput) ([]*docdb.DBInstance, error) { + var output []*docdb.DBInstance + err := conn.DescribeDBInstancesPagesWithContext(ctx, input, func(page *docdb.DescribeDBInstancesOutput, lastPage bool) bool { if page == nil { return !lastPage } - for _, dbi := range page.DBInstances { - if dbi == nil { - continue - } - - if aws.StringValue(dbi.DBInstanceIdentifier) == dBInstanceID { - dBInstance = dbi - return false + for _, v := range page.DBInstances { + if v != nil { + output = append(output, v) } } return !lastPage }) - return dBInstance, err + if tfawserr.ErrCodeEquals(err, docdb.ErrCodeDBInstanceNotFoundFault) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + return output, nil } -func statusDBInstanceRefreshFunc(ctx context.Context, conn *docdb.DocDB, dBInstanceID string) retry.StateRefreshFunc { +func statusDBInstance(ctx context.Context, conn *docdb.DocDB, id string) retry.StateRefreshFunc { return func() (interface{}, string, error) { - dBInstance, err := FindDBInstanceById(ctx, conn, dBInstanceID) + output, err := FindDBInstanceByID(ctx, conn, id) - if tfawserr.ErrCodeEquals(err, docdb.ErrCodeDBInstanceNotFoundFault) || dBInstance == nil { - return nil, DBInstanceStatusDeleted, nil + if tfresource.NotFound(err) { + return nil, "", nil } if err != nil { - return nil, "", fmt.Errorf("reading DocumentDB Instance (%s): %w", dBInstanceID, err) + return nil, "", err } - return dBInstance, aws.StringValue(dBInstance.DBInstanceStatus), nil + return output, aws.StringValue(output.DBInstanceStatus), nil } } @@ -566,21 +589,25 @@ const ( DBInstanceStatusDeleting = "deleting" ) -func WaitForDBInstanceDeletion(ctx context.Context, conn *docdb.DocDB, dBInstanceID string, timeout time.Duration) error { +func waitDBInstanceDeleted(ctx context.Context, conn *docdb.DocDB, id string, timeout time.Duration) (*docdb.DBInstance, error) { stateConf := &retry.StateChangeConf{ - Pending: []string{DBInstanceStatusAvailable, DBInstanceStatusDeleting}, - Target: []string{DBInstanceStatusDeleted}, - Refresh: statusDBInstanceRefreshFunc(ctx, conn, dBInstanceID), - Timeout: timeout, - NotFoundChecks: 1, + Pending: []string{ + "configuring-log-exports", + "modifying", + "deleting", + }, + Target: []string{}, + Refresh: statusDBInstance(ctx, conn, id), + Timeout: timeout, + MinTimeout: 10 * time.Second, + Delay: 30 * time.Second, } - log.Printf("[DEBUG] Waiting for DocumentDB Instance (%s) deletion", dBInstanceID) - _, err := stateConf.WaitForStateContext(ctx) + outputRaw, err := stateConf.WaitForStateContext(ctx) - if tfresource.NotFound(err) { - return nil + if output, ok := outputRaw.(*docdb.DBInstance); ok { + return output, err } - return err + return nil, err } From e5d3d1595942ce8e746b80757b5d00775f4dfd01 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 11:13:40 -0400 Subject: [PATCH 08/18] r/aws_docdb_cluster_instance: Tidy up Read. --- internal/service/docdb/cluster_instance.go | 64 +++++++++------------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/internal/service/docdb/cluster_instance.go b/internal/service/docdb/cluster_instance.go index 01a5e1f8807..b20652d3182 100644 --- a/internal/service/docdb/cluster_instance.go +++ b/internal/service/docdb/cluster_instance.go @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -257,63 +258,44 @@ func resourceClusterInstanceRead(ctx context.Context, d *schema.ResourceData, me var diags diag.Diagnostics conn := meta.(*conns.AWSClient).DocDBConn(ctx) - db, err := resourceInstanceRetrieve(ctx, conn, d.Id()) + db, err := FindDBInstanceByID(ctx, conn, d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { - log.Printf("[WARN] DocumentDB Cluster Instance (%s): not found, removing from state.", d.Id()) + log.Printf("[WARN] DocumentDB Cluster Instance (%s) not found, removing from state", d.Id()) d.SetId("") - return diags - } - if err != nil { - return sdkdiag.AppendErrorf(diags, "retrieving DocumentDB Cluster Instance (%s): %s", d.Id(), err) - } - - // Retrieve DB Cluster information, to determine if this Instance is a writer - resp, err := conn.DescribeDBClustersWithContext(ctx, &docdb.DescribeDBClustersInput{ - DBClusterIdentifier: db.DBClusterIdentifier, - }) - - var dbc *docdb.DBCluster - for _, c := range resp.DBClusters { - if aws.StringValue(c.DBClusterIdentifier) == aws.StringValue(db.DBClusterIdentifier) { - dbc = c - } + return nil } - if dbc == nil { - return sdkdiag.AppendErrorf(diags, "finding DocumentDB Cluster (%s) for Cluster Instance (%s): %s", - aws.StringValue(db.DBClusterIdentifier), aws.StringValue(db.DBInstanceIdentifier), err) - } - - for _, m := range dbc.DBClusterMembers { - if aws.StringValue(db.DBInstanceIdentifier) == aws.StringValue(m.DBInstanceIdentifier) { - if *m.IsClusterWriter { - d.Set("writer", true) - } else { - d.Set("writer", false) - } - } + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading DocumentDB Cluster Instance (%s): %s", d.Id(), err) } - if db.Endpoint != nil { - d.Set("endpoint", db.Endpoint.Address) - d.Set("port", db.Endpoint.Port) - } + clusterID := aws.StringValue(db.DBClusterIdentifier) + dbc, err := FindDBClusterByID(ctx, conn, clusterID) - if db.DBSubnetGroup != nil { - d.Set("db_subnet_group_name", db.DBSubnetGroup.DBSubnetGroupName) + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading DocumentDB Cluster (%s): %s", clusterID, err) } d.Set("arn", db.DBInstanceArn) d.Set("auto_minor_version_upgrade", db.AutoMinorVersionUpgrade) d.Set("availability_zone", db.AvailabilityZone) + d.Set("ca_cert_identifier", db.CACertificateIdentifier) d.Set("cluster_identifier", db.DBClusterIdentifier) d.Set("copy_tags_to_snapshot", db.CopyTagsToSnapshot) + if db.DBSubnetGroup != nil { + d.Set("db_subnet_group_name", db.DBSubnetGroup.DBSubnetGroupName) + } d.Set("dbi_resource_id", db.DbiResourceId) // The AWS API does not expose 'EnablePerformanceInsights' the line below should be uncommented // as soon as it is available in the DescribeDBClusters output. //d.Set("enable_performance_insights", db.EnablePerformanceInsights) - d.Set("engine_version", db.EngineVersion) + if db.Endpoint != nil { + d.Set("endpoint", db.Endpoint.Address) + d.Set("port", db.Endpoint.Port) + } d.Set("engine", db.Engine) + d.Set("engine_version", db.EngineVersion) d.Set("identifier", db.DBInstanceIdentifier) d.Set("instance_class", db.DBInstanceClass) d.Set("kms_key_id", db.KmsKeyId) @@ -325,7 +307,11 @@ func resourceClusterInstanceRead(ctx context.Context, d *schema.ResourceData, me d.Set("promotion_tier", db.PromotionTier) d.Set("publicly_accessible", db.PubliclyAccessible) d.Set("storage_encrypted", db.StorageEncrypted) - d.Set("ca_cert_identifier", db.CACertificateIdentifier) + if v := tfslices.Filter(dbc.DBClusterMembers, func(v *docdb.DBClusterMember) bool { + return aws.StringValue(v.DBInstanceIdentifier) == d.Id() + }); len(v) == 1 { + d.Set("writer", v[0].IsClusterWriter) + } return diags } From c2a2ccb82f7435eca20fd715a0c80cbe4bad7666 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 11:17:39 -0400 Subject: [PATCH 09/18] r/aws_docdb_cluster_instance: Tidy up Create. --- internal/service/docdb/cluster_instance.go | 49 +++++++++++++++------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/internal/service/docdb/cluster_instance.go b/internal/service/docdb/cluster_instance.go index b20652d3182..e170bfa53df 100644 --- a/internal/service/docdb/cluster_instance.go +++ b/internal/service/docdb/cluster_instance.go @@ -235,20 +235,8 @@ func resourceClusterInstanceCreate(ctx context.Context, d *schema.ResourceData, d.SetId(identifier) - // reuse db_instance refresh func - stateConf := &retry.StateChangeConf{ - Pending: resourceClusterInstanceCreateUpdatePendingStates, - Target: []string{"available"}, - Refresh: resourceInstanceStateRefreshFunc(ctx, conn, d.Id()), - Timeout: d.Timeout(schema.TimeoutCreate), - MinTimeout: 10 * time.Second, - Delay: 30 * time.Second, - } - - // Wait, catching any errors - _, err = stateConf.WaitForStateContext(ctx) - if err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for DocumentDB Cluster Instance (%s) to become available: %s", d.Id(), err) + if _, err := waitDBInstanceAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for DocumentDB Cluster Instance (%s) create: %s", d.Id(), err) } return append(diags, resourceClusterInstanceRead(ctx, d, meta)...) @@ -575,6 +563,39 @@ const ( DBInstanceStatusDeleting = "deleting" ) +func waitDBInstanceAvailable(ctx context.Context, conn *docdb.DocDB, id string, timeout time.Duration) (*docdb.DBInstance, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{ + "backing-up", + "configuring-enhanced-monitoring", + "configuring-iam-database-auth", + "configuring-log-exports", + "creating", + "maintenance", + "modifying", + "rebooting", + "renaming", + "resetting-master-credentials", + "starting", + "storage-optimization", + "upgrading", + }, + Target: []string{"available"}, + Refresh: statusDBInstance(ctx, conn, id), + Timeout: timeout, + MinTimeout: 10 * time.Second, + Delay: 30 * time.Second, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*docdb.DBInstance); ok { + return output, err + } + + return nil, err +} + func waitDBInstanceDeleted(ctx context.Context, conn *docdb.DocDB, id string, timeout time.Duration) (*docdb.DBInstance, error) { stateConf := &retry.StateChangeConf{ Pending: []string{ From f37ac82a92fb2a69c34b6bba4d693bc50e24c6cf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 11:23:51 -0400 Subject: [PATCH 10/18] r/aws_docdb_cluster_instance: Tidy up Update. --- internal/service/docdb/cluster_instance.go | 174 +++++---------------- 1 file changed, 35 insertions(+), 139 deletions(-) diff --git a/internal/service/docdb/cluster_instance.go b/internal/service/docdb/cluster_instance.go index e170bfa53df..d78ee1e4e4a 100644 --- a/internal/service/docdb/cluster_instance.go +++ b/internal/service/docdb/cluster_instance.go @@ -307,84 +307,54 @@ func resourceClusterInstanceRead(ctx context.Context, d *schema.ResourceData, me func resourceClusterInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).DocDBConn(ctx) - requestUpdate := false - req := &docdb.ModifyDBInstanceInput{ - ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), - DBInstanceIdentifier: aws.String(d.Id()), - } - - if d.HasChange("copy_tags_to_snapshot") { - req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool)) - requestUpdate = true - } - - if d.HasChange("instance_class") { - req.DBInstanceClass = aws.String(d.Get("instance_class").(string)) - requestUpdate = true - } - - if d.HasChange("preferred_maintenance_window") { - req.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintenance_window").(string)) - requestUpdate = true - } + if d.HasChangesExcept("tags", "tags_all") { + input := &docdb.ModifyDBInstanceInput{ + ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), + DBInstanceIdentifier: aws.String(d.Id()), + } - if d.HasChange("auto_minor_version_upgrade") { - req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) - requestUpdate = true - } + if d.HasChange("auto_minor_version_upgrade") { + input.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) + } - if d.HasChange("promotion_tier") { - req.PromotionTier = aws.Int64(int64(d.Get("promotion_tier").(int))) - requestUpdate = true - } + if d.HasChange("ca_cert_identifier") { + input.CACertificateIdentifier = aws.String(d.Get("ca_cert_identifier").(string)) + } - if d.HasChange("ca_cert_identifier") { - req.CACertificateIdentifier = aws.String(d.Get("ca_cert_identifier").(string)) - requestUpdate = true - } + if d.HasChange("copy_tags_to_snapshot") { + input.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool)) + } - if d.HasChange("enable_performance_insights") { - req.EnablePerformanceInsights = aws.Bool(d.Get("enable_performance_insights").(bool)) - requestUpdate = true - } + if d.HasChange("enable_performance_insights") { + input.EnablePerformanceInsights = aws.Bool(d.Get("enable_performance_insights").(bool)) + } - if d.HasChange("performance_insights_kms_key_id") { - req.PerformanceInsightsKMSKeyId = aws.String(d.Get("performance_insights_kms_key_id").(string)) - requestUpdate = true - } + if d.HasChange("instance_class") { + input.DBInstanceClass = aws.String(d.Get("instance_class").(string)) + } - if requestUpdate { - err := retry.RetryContext(ctx, propagationTimeout, func() *retry.RetryError { - _, err := conn.ModifyDBInstanceWithContext(ctx, req) - if err != nil { - if tfawserr.ErrMessageContains(err, "InvalidParameterValue", "IAM role ARN value is invalid or does not include the required permissions") { - return retry.RetryableError(err) - } - return retry.NonRetryableError(err) - } - return nil - }) - if tfresource.TimedOut(err) { - _, err = conn.ModifyDBInstanceWithContext(ctx, req) + if d.HasChange("performance_insights_kms_key_id") { + input.PerformanceInsightsKMSKeyId = aws.String(d.Get("performance_insights_kms_key_id").(string)) } - if err != nil { - return sdkdiag.AppendErrorf(diags, "modifying DB Instance %s: %s", d.Id(), err) + + if d.HasChange("preferred_maintenance_window") { + input.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintenance_window").(string)) } - // reuse db_instance refresh func - stateConf := &retry.StateChangeConf{ - Pending: resourceClusterInstanceCreateUpdatePendingStates, - Target: []string{"available"}, - Refresh: resourceInstanceStateRefreshFunc(ctx, conn, d.Id()), - Timeout: d.Timeout(schema.TimeoutUpdate), - MinTimeout: 10 * time.Second, - Delay: 30 * time.Second, // Wait 30 secs before starting + if d.HasChange("promotion_tier") { + input.PromotionTier = aws.Int64(int64(d.Get("promotion_tier").(int))) } - // Wait, catching any errors - _, err = stateConf.WaitForStateContext(ctx) + _, err := tfresource.RetryWhenAWSErrMessageContains(ctx, propagationTimeout, func() (interface{}, error) { + return conn.ModifyDBInstanceWithContext(ctx, input) + }, errCodeInvalidParameterValue, "IAM role ARN value is invalid or does not include the required permissions") + if err != nil { + return sdkdiag.AppendErrorf(diags, "modifying DocumentDB Cluster Instance (%s): %s", d.Id(), err) + } + + if _, err := waitDBInstanceAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { return sdkdiag.AppendErrorf(diags, "waiting for DocumentDB Cluster Instance (%s) update: %s", d.Id(), err) } } @@ -412,72 +382,6 @@ func resourceClusterInstanceDelete(ctx context.Context, d *schema.ResourceData, return diags } -func resourceInstanceStateRefreshFunc(ctx context.Context, conn *docdb.DocDB, id string) retry.StateRefreshFunc { - return func() (interface{}, string, error) { - v, err := resourceInstanceRetrieve(ctx, conn, id) - - if tfresource.NotFound(err) { - return nil, "", nil - } - if err != nil { - return nil, "", err - } - - return v, aws.StringValue(v.DBInstanceStatus), nil - } -} - -// resourceInstanceRetrieve fetches DBInstance information from the AWS -// API. It returns an error if there is a communication problem or unexpected -// error with AWS. When the DBInstance is not found, it returns no error and a -// nil pointer. -func resourceInstanceRetrieve(ctx context.Context, conn *docdb.DocDB, id string) (*docdb.DBInstance, error) { - input := docdb.DescribeDBInstancesInput{ - DBInstanceIdentifier: aws.String(id), - } - out, err := conn.DescribeDBInstancesWithContext(ctx, &input) - if tfawserr.ErrCodeEquals(err, docdb.ErrCodeDBInstanceNotFoundFault) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: input, - } - } - if err != nil { - return nil, err - } - - switch count := len(out.DBInstances); count { - case 0: - return nil, tfresource.NewEmptyResultError(input) - case 1: - return out.DBInstances[0], nil - default: - return nil, tfresource.NewTooManyResultsError(count, input) - } -} - -var resourceClusterInstanceCreateUpdatePendingStates = []string{ - "backing-up", - "configuring-enhanced-monitoring", - "configuring-iam-database-auth", - "configuring-log-exports", - "creating", - "maintenance", - "modifying", - "rebooting", - "renaming", - "resetting-master-credentials", - "starting", - "storage-optimization", - "upgrading", -} - -var resourceClusterInstanceDeletePendingStates = []string{ - "configuring-log-exports", - "modifying", - "deleting", -} - func FindDBInstanceByID(ctx context.Context, conn *docdb.DocDB, id string) (*docdb.DBInstance, error) { input := &docdb.DescribeDBInstancesInput{ DBInstanceIdentifier: aws.String(id), @@ -555,14 +459,6 @@ func statusDBInstance(ctx context.Context, conn *docdb.DocDB, id string) retry.S } } -const ( - DBInstanceDeleteTimeout = 5 * time.Minute - - DBInstanceStatusAvailable = "available" - DBInstanceStatusDeleted = "deleted" - DBInstanceStatusDeleting = "deleting" -) - func waitDBInstanceAvailable(ctx context.Context, conn *docdb.DocDB, id string, timeout time.Duration) (*docdb.DBInstance, error) { stateConf := &retry.StateChangeConf{ Pending: []string{ From f55236e080836fb02050e03ea241d5b3f9f700b1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 11:30:15 -0400 Subject: [PATCH 11/18] r/aws_docdb_cluster_instance: Use 'FindDBInstanceByID' in acceptance tests. --- .../service/docdb/cluster_instance_test.go | 97 ++++++------------- 1 file changed, 31 insertions(+), 66 deletions(-) diff --git a/internal/service/docdb/cluster_instance_test.go b/internal/service/docdb/cluster_instance_test.go index b042e2bdaa4..076a7505886 100644 --- a/internal/service/docdb/cluster_instance_test.go +++ b/internal/service/docdb/cluster_instance_test.go @@ -6,20 +6,17 @@ package docdb_test import ( "context" "fmt" - "strings" "testing" - "time" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/docdb" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfdocdb "github.com/hashicorp/terraform-provider-aws/internal/service/docdb" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func TestAccDocDBClusterInstance_basic(t *testing.T) { @@ -32,13 +29,12 @@ func TestAccDocDBClusterInstance_basic(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, docdb.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckClusterDestroy(ctx), + CheckDestroy: testAccCheckClusterInstanceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccClusterInstanceConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckClusterInstanceExists(ctx, resourceName, &v), - testAccCheckClusterInstanceAttributes(&v), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "rds", regexache.MustCompile(`db:.+`)), resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "true"), resource.TestCheckResourceAttrSet(resourceName, "preferred_maintenance_window"), @@ -54,7 +50,6 @@ func TestAccDocDBClusterInstance_basic(t *testing.T) { Config: testAccClusterInstanceConfig_modified(rName), Check: resource.ComposeTestCheckFunc( testAccCheckClusterInstanceExists(ctx, resourceName, &v), - testAccCheckClusterInstanceAttributes(&v), resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "false"), ), }, @@ -83,13 +78,12 @@ func TestAccDocDBClusterInstance_performanceInsights(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, docdb.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckClusterDestroy(ctx), + CheckDestroy: testAccCheckClusterInstanceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccClusterInstanceConfig_performanceInsights(rName), Check: resource.ComposeTestCheckFunc( testAccCheckClusterInstanceExists(ctx, resourceName, &v), - testAccCheckClusterInstanceAttributes(&v), resource.TestCheckResourceAttrSet(resourceName, "enable_performance_insights"), resource.TestCheckResourceAttrSet(resourceName, "performance_insights_kms_key_id"), ), @@ -120,13 +114,12 @@ func TestAccDocDBClusterInstance_az(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, docdb.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckClusterDestroy(ctx), + CheckDestroy: testAccCheckClusterInstanceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccClusterInstanceConfig_az(rName), Check: resource.ComposeTestCheckFunc( testAccCheckClusterInstanceExists(ctx, resourceName, &v), - testAccCheckClusterInstanceAttributes(&v), resource.TestCheckResourceAttrSet(resourceName, "availability_zone"), ), }, @@ -155,13 +148,12 @@ func TestAccDocDBClusterInstance_namePrefix(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, docdb.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckClusterDestroy(ctx), + CheckDestroy: testAccCheckClusterInstanceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccClusterInstanceConfig_namePrefix(rName, rNamePrefix), Check: resource.ComposeTestCheckFunc( testAccCheckClusterInstanceExists(ctx, resourceName, &v), - testAccCheckClusterInstanceAttributes(&v), resource.TestCheckResourceAttr(resourceName, "db_subnet_group_name", rName), resource.TestMatchResourceAttr(resourceName, "identifier", regexache.MustCompile(fmt.Sprintf("^%s", rNamePrefix))), ), @@ -190,13 +182,12 @@ func TestAccDocDBClusterInstance_generatedName(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, docdb.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckClusterDestroy(ctx), + CheckDestroy: testAccCheckClusterInstanceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccClusterInstanceConfig_generatedName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckClusterInstanceExists(ctx, resourceName, &v), - testAccCheckClusterInstanceAttributes(&v), resource.TestMatchResourceAttr(resourceName, "identifier", regexache.MustCompile("^tf-")), ), }, @@ -224,7 +215,7 @@ func TestAccDocDBClusterInstance_kmsKey(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, docdb.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckClusterDestroy(ctx), + CheckDestroy: testAccCheckClusterInstanceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccClusterInstanceConfig_kmsKey(rName), @@ -258,15 +249,14 @@ func TestAccDocDBClusterInstance_disappears(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, docdb.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckClusterDestroy(ctx), + CheckDestroy: testAccCheckClusterInstanceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccClusterInstanceConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckClusterInstanceExists(ctx, resourceName, &v), - testAccClusterInstanceDisappears(ctx, &v), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfdocdb.ResourceClusterInstance(), resourceName), ), - // A non-empty plan is what we want. A crash is what we don't want. :) ExpectNonEmptyPlan: true, }, }, @@ -283,7 +273,7 @@ func TestAccDocDBClusterInstance_copyTagsToSnapshot(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, docdb.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckClusterDestroy(ctx), + CheckDestroy: testAccCheckClusterInstanceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccClusterInstanceConfig_copyTagsToSnapshot(rName, true), @@ -313,44 +303,29 @@ func TestAccDocDBClusterInstance_copyTagsToSnapshot(t *testing.T) { }) } -func testAccCheckClusterInstanceAttributes(v *docdb.DBInstance) resource.TestCheckFunc { +func testAccCheckClusterInstanceDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - if *v.Engine != "docdb" { - return fmt.Errorf("bad engine, expected \"docdb\": %#v", *v.Engine) - } + conn := acctest.Provider.Meta().(*conns.AWSClient).DocDBConn(ctx) - if !strings.HasPrefix(*v.DBClusterIdentifier, acctest.ResourcePrefix) { - return fmt.Errorf("Bad Cluster Identifier prefix:\nexpected: %s-*\ngot: %s", acctest.ResourcePrefix, *v.DBClusterIdentifier) - } + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_docdb_cluster_instance" { + continue + } - return nil - } -} + _, err := tfdocdb.FindDBInstanceByID(ctx, conn, rs.Primary.ID) -func testAccClusterInstanceDisappears(ctx context.Context, v *docdb.DBInstance) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).DocDBConn(ctx) - opts := &docdb.DeleteDBInstanceInput{ - DBInstanceIdentifier: v.DBInstanceIdentifier, - } - if _, err := conn.DeleteDBInstanceWithContext(ctx, opts); err != nil { - return err - } - return retry.RetryContext(ctx, 40*time.Minute, func() *retry.RetryError { - opts := &docdb.DescribeDBInstancesInput{ - DBInstanceIdentifier: v.DBInstanceIdentifier, + if tfresource.NotFound(err) { + continue } - _, err := conn.DescribeDBInstancesWithContext(ctx, opts) + if err != nil { - if tfawserr.ErrCodeEquals(err, docdb.ErrCodeDBInstanceNotFoundFault) { - return nil - } - return retry.NonRetryableError( - fmt.Errorf("Error retrieving DB Instances: %s", err)) + return err } - return retry.RetryableError(fmt.Errorf( - "Waiting for instance to be deleted: %v", v.DBInstanceIdentifier)) - }) + + return fmt.Errorf("DocumentDB Cluster Instance %s still exists", rs.Primary.ID) + } + + return nil } } @@ -361,27 +336,17 @@ func testAccCheckClusterInstanceExists(ctx context.Context, n string, v *docdb.D return fmt.Errorf("Not found: %s", n) } - if rs.Primary.ID == "" { - return fmt.Errorf("No DB Instance ID is set") - } - conn := acctest.Provider.Meta().(*conns.AWSClient).DocDBConn(ctx) - resp, err := conn.DescribeDBInstancesWithContext(ctx, &docdb.DescribeDBInstancesInput{ - DBInstanceIdentifier: aws.String(rs.Primary.ID), - }) + + output, err := tfdocdb.FindDBInstanceByID(ctx, conn, rs.Primary.ID) if err != nil { return err } - for _, d := range resp.DBInstances { - if *d.DBInstanceIdentifier == rs.Primary.ID { - *v = *d - return nil - } - } + *v = *output - return fmt.Errorf("DB Cluster (%s) not found", rs.Primary.ID) + return nil } } From 698307df801dc2888f892491f972c67fab30a347 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 11:36:24 -0400 Subject: [PATCH 12/18] r/aws_docdb_cluster_instance: Tidy up sweeper. --- internal/service/docdb/sweep.go | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/internal/service/docdb/sweep.go b/internal/service/docdb/sweep.go index 91f9d1ac633..1715af02b6d 100644 --- a/internal/service/docdb/sweep.go +++ b/internal/service/docdb/sweep.go @@ -13,7 +13,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/docdb" - multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-provider-aws/internal/sweep" ) @@ -215,25 +214,22 @@ func sweepDBClusterParameterGroups(region string) error { func sweepDBInstances(region string) error { ctx := sweep.Context(region) client, err := sweep.SharedRegionalSweepClient(ctx, region) - if err != nil { - return fmt.Errorf("error getting client: %w", err) + return fmt.Errorf("error getting client: %s", err) } - conn := client.DocDBConn(ctx) - sweepResources := make([]sweep.Sweepable, 0) - var errs *multierror.Error input := &docdb.DescribeDBInstancesInput{} + sweepResources := make([]sweep.Sweepable, 0) err = conn.DescribeDBInstancesPagesWithContext(ctx, input, func(page *docdb.DescribeDBInstancesOutput, lastPage bool) bool { if page == nil { return !lastPage } - for _, dBInstance := range page.DBInstances { + for _, v := range page.DBInstances { r := ResourceClusterInstance() d := r.Data(nil) - d.SetId(aws.StringValue(dBInstance.DBInstanceIdentifier)) + d.SetId(aws.StringValue(v.DBInstanceIdentifier)) sweepResources = append(sweepResources, sweep.NewSweepResource(r, d, client)) } @@ -241,20 +237,22 @@ func sweepDBInstances(region string) error { return !lastPage }) - if err != nil { - errs = multierror.Append(errs, fmt.Errorf("listing DocumentDB Instances for %s: %w", region, err)) + if sweep.SkipSweepError(err) { + log.Printf("[WARN] Skipping DocumentDB Cluster Instance sweep for %s: %s", region, err) + return nil } - if err = sweep.SweepOrchestrator(ctx, sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("sweeping DocumentDB Instances for %s: %w", region, err)) + if err != nil { + return fmt.Errorf("error listing DocumentDB Cluster Instances (%s): %w", region, err) } - if sweep.SkipSweepError(errs.ErrorOrNil()) { - log.Printf("[WARN] Skipping DocumentDB Instance sweep for %s: %s", region, errs) - return nil + err = sweep.SweepOrchestrator(ctx, sweepResources) + + if err != nil { + return fmt.Errorf("error sweeping DocumentDB Cluster Instances (%s): %w", region, err) } - return errs.ErrorOrNil() + return nil } func sweepGlobalClusters(region string) error { From 118e11cb8c0b62377fe2df35294c06ca0869081b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 11:39:55 -0400 Subject: [PATCH 13/18] 'apply_immediately' is not Computed. --- internal/service/docdb/cluster_instance.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/docdb/cluster_instance.go b/internal/service/docdb/cluster_instance.go index d78ee1e4e4a..436808828b8 100644 --- a/internal/service/docdb/cluster_instance.go +++ b/internal/service/docdb/cluster_instance.go @@ -49,7 +49,6 @@ func ResourceClusterInstance() *schema.Resource { "apply_immediately": { Type: schema.TypeBool, Optional: true, - Computed: true, }, "arn": { Type: schema.TypeString, From 6b334e63aaf8fab473b23aa1bab08d962566eb6c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 11:44:04 -0400 Subject: [PATCH 14/18] 'enable_performance_insights' is not Computed. --- internal/service/docdb/cluster_instance.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/docdb/cluster_instance.go b/internal/service/docdb/cluster_instance.go index 436808828b8..e233aa47355 100644 --- a/internal/service/docdb/cluster_instance.go +++ b/internal/service/docdb/cluster_instance.go @@ -90,7 +90,6 @@ func ResourceClusterInstance() *schema.Resource { "enable_performance_insights": { Type: schema.TypeBool, Optional: true, - Computed: true, }, "endpoint": { Type: schema.TypeString, From 2483ba8bab02074c554ad3028b54f84b8e4183c4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 12:45:05 -0400 Subject: [PATCH 15/18] Tidy up 'TestAccDocDBClusterInstance_basic'. --- .../service/docdb/cluster_instance_test.go | 74 ++++++++++++------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/internal/service/docdb/cluster_instance_test.go b/internal/service/docdb/cluster_instance_test.go index 076a7505886..fd490fd48d9 100644 --- a/internal/service/docdb/cluster_instance_test.go +++ b/internal/service/docdb/cluster_instance_test.go @@ -22,7 +22,7 @@ import ( func TestAccDocDBClusterInstance_basic(t *testing.T) { ctx := acctest.Context(t) var v docdb.DBInstance - resourceName := "aws_docdb_cluster_instance.cluster_instances" + resourceName := "aws_docdb_cluster_instance.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ @@ -33,27 +33,44 @@ func TestAccDocDBClusterInstance_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccClusterInstanceConfig_basic(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckClusterInstanceExists(ctx, resourceName, &v), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "rds", regexache.MustCompile(`db:.+`)), + resource.TestCheckNoResourceAttr(resourceName, "apply_immediately"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "rds", regexache.MustCompile(fmt.Sprintf("db:%s", rName))), resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "true"), - resource.TestCheckResourceAttrSet(resourceName, "preferred_maintenance_window"), - resource.TestCheckResourceAttrSet(resourceName, "preferred_backup_window"), - resource.TestCheckResourceAttrSet(resourceName, "dbi_resource_id"), resource.TestCheckResourceAttrSet(resourceName, "availability_zone"), - resource.TestCheckResourceAttrSet(resourceName, "engine_version"), resource.TestCheckResourceAttrSet(resourceName, "ca_cert_identifier"), + resource.TestCheckResourceAttrSet(resourceName, "cluster_identifier"), + resource.TestCheckResourceAttr(resourceName, "copy_tags_to_snapshot", "false"), + resource.TestCheckResourceAttrSet(resourceName, "db_subnet_group_name"), + resource.TestCheckResourceAttrSet(resourceName, "dbi_resource_id"), + resource.TestCheckNoResourceAttr(resourceName, "enable_performance_insights"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint"), resource.TestCheckResourceAttr(resourceName, "engine", "docdb"), + resource.TestCheckResourceAttrSet(resourceName, "engine_version"), + resource.TestCheckResourceAttr(resourceName, "identifier", rName), + resource.TestCheckNoResourceAttr(resourceName, "identifier_prefix"), + resource.TestCheckResourceAttrSet(resourceName, "instance_class"), + resource.TestCheckResourceAttr(resourceName, "kms_key_id", ""), + resource.TestCheckNoResourceAttr(resourceName, "performance_insights_kms_key_id"), + resource.TestCheckResourceAttrSet(resourceName, "port"), + resource.TestCheckResourceAttrSet(resourceName, "preferred_backup_window"), + resource.TestCheckResourceAttrSet(resourceName, "preferred_maintenance_window"), + resource.TestCheckResourceAttr(resourceName, "promotion_tier", "0"), + resource.TestCheckResourceAttrSet(resourceName, "publicly_accessible"), + resource.TestCheckResourceAttrSet(resourceName, "storage_encrypted"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "writer", "true"), ), }, - { - Config: testAccClusterInstanceConfig_modified(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckClusterInstanceExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "false"), - ), - }, - + // TODO separate test + // { + // Config: testAccClusterInstanceConfig_modified(rName), + // Check: resource.ComposeTestCheckFunc( + // testAccCheckClusterInstanceExists(ctx, resourceName, &v), + // resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "false"), + // ), + // }, { ResourceName: resourceName, ImportState: true, @@ -242,7 +259,7 @@ func TestAccDocDBClusterInstance_kmsKey(t *testing.T) { func TestAccDocDBClusterInstance_disappears(t *testing.T) { ctx := acctest.Context(t) var v docdb.DBInstance - resourceName := "aws_docdb_cluster_instance.cluster_instances" + resourceName := "aws_docdb_cluster_instance.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ @@ -350,27 +367,28 @@ func testAccCheckClusterInstanceExists(ctx context.Context, n string, v *docdb.D } } -// Add some random to the name, to avoid collision -func testAccClusterInstanceConfig_basic(rName string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` -resource "aws_docdb_cluster" "default" { +func testAccClusterInstanceConfig_base(rName string) string { + return fmt.Sprintf(` +resource "aws_docdb_cluster" "test" { cluster_identifier = %[1]q - availability_zones = [data.aws_availability_zones.available.names[0], data.aws_availability_zones.available.names[1], data.aws_availability_zones.available.names[2]] - master_username = "foo" - master_password = "mustbeeightcharaters" + master_password = "avoid-plaintext-passwords" + master_username = "tfacctest" skip_final_snapshot = true } data "aws_docdb_orderable_db_instance" "test" { - engine = "docdb" - preferred_instance_classes = ["db.t3.medium", "db.r4.large", "db.r5.large", "db.r5.xlarge"] + engine = aws_docdb_cluster.test.engine + preferred_instance_classes = ["db.t3.medium", "db.4tg.medium", "db.r5.large", "db.r6g.large"] +} +`, rName) } -resource "aws_docdb_cluster_instance" "cluster_instances" { +func testAccClusterInstanceConfig_basic(rName string) string { + return acctest.ConfigCompose(testAccClusterInstanceConfig_base(rName), fmt.Sprintf(` +resource "aws_docdb_cluster_instance" "test" { identifier = %[1]q - cluster_identifier = aws_docdb_cluster.default.id + cluster_identifier = aws_docdb_cluster.test.id instance_class = data.aws_docdb_orderable_db_instance.test.instance_class - promotion_tier = "3" } `, rName)) } From ed2a828d6f1cdd686907e6015af92cf2844ff2af Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 12:45:17 -0400 Subject: [PATCH 16/18] Acceptance test output: % make testacc TESTARGS='-run=TestAccDocDBClusterInstance_basic' PKG=docdb ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/docdb/... -v -count 1 -parallel 20 -run=TestAccDocDBClusterInstance_basic -timeout 360m === RUN TestAccDocDBClusterInstance_basic === PAUSE TestAccDocDBClusterInstance_basic === CONT TestAccDocDBClusterInstance_basic --- PASS: TestAccDocDBClusterInstance_basic (1190.80s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/docdb 1195.872s From 8535776f62316af09ec01df6c93980f33e76e49b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 12:50:36 -0400 Subject: [PATCH 17/18] Tweak 'TestAccDocDBClusterInstance_basic'. --- .../service/docdb/cluster_instance_test.go | 37 ++++++------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/internal/service/docdb/cluster_instance_test.go b/internal/service/docdb/cluster_instance_test.go index fd490fd48d9..b86b22cac95 100644 --- a/internal/service/docdb/cluster_instance_test.go +++ b/internal/service/docdb/cluster_instance_test.go @@ -63,14 +63,6 @@ func TestAccDocDBClusterInstance_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "writer", "true"), ), }, - // TODO separate test - // { - // Config: testAccClusterInstanceConfig_modified(rName), - // Check: resource.ComposeTestCheckFunc( - // testAccCheckClusterInstanceExists(ctx, resourceName, &v), - // resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "false"), - // ), - // }, { ResourceName: resourceName, ImportState: true, @@ -80,6 +72,14 @@ func TestAccDocDBClusterInstance_basic(t *testing.T) { "identifier_prefix", }, }, + { + Config: testAccClusterInstanceConfig_modified(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckClusterInstanceExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "false"), + resource.TestCheckResourceAttr(resourceName, "promotion_tier", "3"), + ), + }, }, }) } @@ -394,26 +394,13 @@ resource "aws_docdb_cluster_instance" "test" { } func testAccClusterInstanceConfig_modified(rName string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` -resource "aws_docdb_cluster" "default" { - cluster_identifier = %[1]q - availability_zones = [data.aws_availability_zones.available.names[0], data.aws_availability_zones.available.names[1], data.aws_availability_zones.available.names[2]] - master_username = "foo" - master_password = "mustbeeightcharaters" - skip_final_snapshot = true -} - -data "aws_docdb_orderable_db_instance" "test" { - engine = "docdb" - preferred_instance_classes = ["db.t3.medium", "db.r4.large", "db.r5.large", "db.r5.xlarge"] -} - -resource "aws_docdb_cluster_instance" "cluster_instances" { + return acctest.ConfigCompose(testAccClusterInstanceConfig_base(rName), fmt.Sprintf(` +resource "aws_docdb_cluster_instance" "test" { identifier = %[1]q - cluster_identifier = aws_docdb_cluster.default.id + cluster_identifier = aws_docdb_cluster.test.id instance_class = data.aws_docdb_orderable_db_instance.test.instance_class auto_minor_version_upgrade = false - promotion_tier = "3" + promotion_tier = 3 } `, rName)) } From 65743af12527fc6ff8f6f13050d2899104ca3aa8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 11 Oct 2023 12:57:09 -0400 Subject: [PATCH 18/18] Fix golangci-lint 'unparam'. --- internal/service/docdb/cluster_instance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/docdb/cluster_instance.go b/internal/service/docdb/cluster_instance.go index e233aa47355..347506acaea 100644 --- a/internal/service/docdb/cluster_instance.go +++ b/internal/service/docdb/cluster_instance.go @@ -457,7 +457,7 @@ func statusDBInstance(ctx context.Context, conn *docdb.DocDB, id string) retry.S } } -func waitDBInstanceAvailable(ctx context.Context, conn *docdb.DocDB, id string, timeout time.Duration) (*docdb.DBInstance, error) { +func waitDBInstanceAvailable(ctx context.Context, conn *docdb.DocDB, id string, timeout time.Duration) (*docdb.DBInstance, error) { //nolint:unparam stateConf := &retry.StateChangeConf{ Pending: []string{ "backing-up",