From 955b974a210debb0717e7810bbf8615d07927860 Mon Sep 17 00:00:00 2001 From: "marcin.janas" Date: Thu, 5 Aug 2021 15:51:22 +0200 Subject: [PATCH 01/32] feat: add aws_db_instance_automated_backups_replication Signed-off-by: marcin.janas --- aws/internal/service/rds/finder/finder.go | 28 ++++ aws/internal/service/rds/waiter/status.go | 19 +++ aws/internal/service/rds/waiter/waiter.go | 46 +++++ aws/provider.go | 1 + ..._instance_automated_backups_replication.go | 150 +++++++++++++++++ ...ance_automated_backups_replication_test.go | 158 ++++++++++++++++++ ...nce_automated_backups_replication.markdown | 46 +++++ 7 files changed, 448 insertions(+) create mode 100644 aws/resource_aws_db_instance_automated_backups_replication.go create mode 100644 aws/resource_aws_db_instance_automated_backups_replication_test.go create mode 100644 website/docs/r/db_instance_automated_backups_replication.markdown diff --git a/aws/internal/service/rds/finder/finder.go b/aws/internal/service/rds/finder/finder.go index a401d39b5b22..434f6fd1116c 100644 --- a/aws/internal/service/rds/finder/finder.go +++ b/aws/internal/service/rds/finder/finder.go @@ -1,6 +1,8 @@ package finder import ( + "context" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/aws-sdk-go-base/tfawserr" @@ -120,3 +122,29 @@ func DBClusterByID(conn *rds.RDS, id string) (*rds.DBCluster, error) { return dbCluster, nil } + +// DBInstanceAutomatedBackup returns matching DBInstanceAutomatedBackup +func DBInstanceAutomatedBackup(ctx context.Context, conn *rds.RDS, dbInstanceAutomatedBackupsArn string) (*rds.DBInstanceAutomatedBackup, error) { + input := &rds.DescribeDBInstanceAutomatedBackupsInput{ + DBInstanceAutomatedBackupsArn: aws.String(dbInstanceAutomatedBackupsArn), + } + + var dbInstanceAutomatedBackup *rds.DBInstanceAutomatedBackup + + err := conn.DescribeDBInstanceAutomatedBackupsPagesWithContext(ctx, input, func(page *rds.DescribeDBInstanceAutomatedBackupsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, backup := range page.DBInstanceAutomatedBackups { + if aws.StringValue(backup.DBInstanceAutomatedBackupsArn) == dbInstanceAutomatedBackupsArn { + dbInstanceAutomatedBackup = backup + return false + } + } + + return !lastPage + }) + + return dbInstanceAutomatedBackup, err +} diff --git a/aws/internal/service/rds/waiter/status.go b/aws/internal/service/rds/waiter/status.go index 870f1b58e8e5..9ae1f2f17b1a 100644 --- a/aws/internal/service/rds/waiter/status.go +++ b/aws/internal/service/rds/waiter/status.go @@ -1,6 +1,8 @@ package waiter import ( + "context" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -75,3 +77,20 @@ func DBClusterRoleStatus(conn *rds.RDS, dbClusterID, roleARN string) resource.St return output, aws.StringValue(output.Status), nil } } + +// DBInstanceAutomatedBackupsReplicationStatus fetches the DBInstanceAutomatedBackup and its Status +func DBInstanceAutomatedBackupsReplicationStatus(ctx context.Context, conn *rds.RDS, dbInstanceAutomatedBackupsArn string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.DBInstanceAutomatedBackup(ctx, conn, dbInstanceAutomatedBackupsArn) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} diff --git a/aws/internal/service/rds/waiter/waiter.go b/aws/internal/service/rds/waiter/waiter.go index d3ad5da52d03..db329bdfab7c 100644 --- a/aws/internal/service/rds/waiter/waiter.go +++ b/aws/internal/service/rds/waiter/waiter.go @@ -1,6 +1,7 @@ package waiter import ( + "context" "time" "github.com/aws/aws-sdk-go/service/rds" @@ -15,6 +16,15 @@ const ( DBClusterRoleAssociationCreatedTimeout = 5 * time.Minute DBClusterRoleAssociationDeletedTimeout = 5 * time.Minute + + // DB Instance Automated Backups Replication timeouts + DBInstanceAutomatedBackupsReplicationStartedTimeout = 30 * time.Minute + DBInstanceAutomatedBackupsReplicationDeletedTimeout = 5 * time.Minute + + // DB Instance Automated Backups Replication states + DBInstanceAutomatedBackupsPending = "pending" + DBInstanceAutomatedBackupsReplicating = "replicating" + DBInstanceAutomatedBackupsDeleting = "deleting" ) // EventSubscriptionDeleted waits for a EventSubscription to return Deleted @@ -107,3 +117,39 @@ func DBClusterRoleAssociationDeleted(conn *rds.RDS, dbClusterID, roleARN string) return nil, err } + +// DBInstanceAutomatedBackupsReplicationStarted waits for a DBInstanceAutomatedBackup to return replicating +func DBInstanceAutomatedBackupsReplicationStarted(ctx context.Context, conn *rds.RDS, dbInstanceAutomatedBackupsArn string) (*rds.DBInstanceAutomatedBackup, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{DBInstanceAutomatedBackupsPending}, + Target: []string{DBInstanceAutomatedBackupsReplicating}, + Refresh: DBInstanceAutomatedBackupsReplicationStatus(ctx, conn, dbInstanceAutomatedBackupsArn), + Timeout: DBInstanceAutomatedBackupsReplicationStartedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*rds.DBInstanceAutomatedBackup); ok { + return output, err + } + + return nil, err +} + +// DBInstanceAutomatedBackupsReplicationDeleted waits for a DBInstanceAutomatedBackup to return deleting +func DBInstanceAutomatedBackupsReplicationDeleted(ctx context.Context, conn *rds.RDS, dbInstanceAutomatedBackupsArn string) (*rds.DBInstanceAutomatedBackup, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{DBInstanceAutomatedBackupsReplicating}, + Target: []string{DBInstanceAutomatedBackupsDeleting}, + Refresh: DBInstanceAutomatedBackupsReplicationStatus(ctx, conn, dbInstanceAutomatedBackupsArn), + Timeout: DBInstanceAutomatedBackupsReplicationDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*rds.DBInstanceAutomatedBackup); ok { + return output, err + } + + return nil, err +} diff --git a/aws/provider.go b/aws/provider.go index 872662fcedc6..feeffb30e2b5 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -639,6 +639,7 @@ func Provider() *schema.Provider { "aws_db_cluster_snapshot": resourceAwsDbClusterSnapshot(), "aws_db_event_subscription": resourceAwsDbEventSubscription(), "aws_db_instance": resourceAwsDbInstance(), + "aws_db_instance_automated_backups_replication": resourceAwsDbInstanceAutomatedBackupsReplication(), "aws_db_instance_role_association": resourceAwsDbInstanceRoleAssociation(), "aws_db_option_group": resourceAwsDbOptionGroup(), "aws_db_parameter_group": resourceAwsDbParameterGroup(), diff --git a/aws/resource_aws_db_instance_automated_backups_replication.go b/aws/resource_aws_db_instance_automated_backups_replication.go new file mode 100644 index 000000000000..4176e46933e5 --- /dev/null +++ b/aws/resource_aws_db_instance_automated_backups_replication.go @@ -0,0 +1,150 @@ +package aws + +import ( + "context" + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/rds" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds/waiter" +) + +func resourceAwsDbInstanceAutomatedBackupsReplication() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceAwsDbInstanceAutomatedBackupsReplicationCreate, + ReadContext: resourceAwsDbInstanceAutomatedBackupsReplicationRead, + DeleteContext: resourceAwsDbInstanceAutomatedBackupsReplicationDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "backup_retention_period": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Default: 1, + }, + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "pre_signed_url": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "source_db_instance_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateArn, + }, + }, + } +} + +func resourceAwsDbInstanceAutomatedBackupsReplicationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).rdsconn + + input := &rds.StartDBInstanceAutomatedBackupsReplicationInput{ + SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), + } + + if attr, ok := d.GetOk("backup_retention_period"); ok { + input.BackupRetentionPeriod = aws.Int64(int64(attr.(int))) + } + + if attr, ok := d.GetOk("kms_key_id"); ok { + input.KmsKeyId = aws.String(attr.(string)) + } + + if attr, ok := d.GetOk("pre_signed_url"); ok { + input.PreSignedUrl = aws.String(attr.(string)) + } + + log.Printf("[DEBUG] RDS DB Instance Start Automated Backups Replication: (%s)", input) + output, err := conn.StartDBInstanceAutomatedBackupsReplicationWithContext(ctx, input) + if err != nil { + return diag.FromErr(fmt.Errorf("unable to Start Automated Backup Replication: %s", err)) + } + + if output == nil || output.DBInstanceAutomatedBackup == nil { + return diag.FromErr(fmt.Errorf("error starting RDS DB Instance Start Automated Backups Replication: empty output")) + } + + dbInstanceAutomatedBackupsArn := aws.StringValue(output.DBInstanceAutomatedBackup.DBInstanceAutomatedBackupsArn) + d.SetId(dbInstanceAutomatedBackupsArn) + + if _, err := waiter.DBInstanceAutomatedBackupsReplicationStarted(ctx, conn, dbInstanceAutomatedBackupsArn); err != nil { + return diag.FromErr(fmt.Errorf("error waiting to RDS DB Instance Start Automated Backups Replication: %s", err)) + } + + return resourceAwsDbInstanceAutomatedBackupsReplicationRead(ctx, d, meta) +} + +func resourceAwsDbInstanceAutomatedBackupsReplicationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).rdsconn + + dbInstanceAutomatedBackup, err := finder.DBInstanceAutomatedBackup(ctx, conn, d.Id()) + if isAWSErr(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault, "") { + log.Printf("[WARN] RDS DB Instance Automated Backups Replication not found (%s), removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return diag.FromErr(fmt.Errorf("error describe RDS DB Instance Automated Backups Replication: %s", err)) + } + + if err := d.Set("backup_retention_period", dbInstanceAutomatedBackup.BackupRetentionPeriod); err != nil { + return diag.FromErr(fmt.Errorf("error setting backup retention period for RDS DB Instance: %s", err)) + } + if err := d.Set("kms_key_id", dbInstanceAutomatedBackup.KmsKeyId); err != nil { + return diag.FromErr(fmt.Errorf("error setting kms key id for RDS DB Instance: %s", err)) + } + if err := d.Set("source_db_instance_arn", dbInstanceAutomatedBackup.DBInstanceArn); err != nil { + return diag.FromErr(fmt.Errorf("error setting source db instance arn for RDS DB Instance: (%s)", err)) + } + + return nil +} + +func resourceAwsDbInstanceAutomatedBackupsReplicationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).rdsconn + + input := &rds.DeleteDBInstanceAutomatedBackupInput{ + DBInstanceAutomatedBackupsArn: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Delete RDS DB Instance Automated Backups Replication: %s", d.Id()) + _, err := conn.DeleteDBInstanceAutomatedBackupWithContext(ctx, input) + + if isAWSErr(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault, "") { + return nil + } + + if isAWSErr(err, rds.ErrCodeInvalidDBInstanceAutomatedBackupStateFault, "") { + return nil + } + + if isAWSErr(err, rds.ErrCodeInvalidDBInstanceStateFault, "") { + return nil + } + + if err != nil { + return diag.FromErr(fmt.Errorf("error delete RDS DB Instance Automated Backups Replication: %s", err)) + } + + if _, err = waiter.DBInstanceAutomatedBackupsReplicationDeleted(ctx, conn, d.Id()); err != nil { + return diag.FromErr(fmt.Errorf("error waiting to delete RDS DB Instance Automated Backups Replication: %s", err)) + } + + return nil +} diff --git a/aws/resource_aws_db_instance_automated_backups_replication_test.go b/aws/resource_aws_db_instance_automated_backups_replication_test.go new file mode 100644 index 000000000000..a05950951fb4 --- /dev/null +++ b/aws/resource_aws_db_instance_automated_backups_replication_test.go @@ -0,0 +1,158 @@ +package aws + +import ( + "context" + "fmt" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/service/rds" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds/finder" +) + +func TestAccAWSDbInstanceAutomatedBackupsReplication_basic(t *testing.T) { + var providers []*schema.Provider + var dbInstanceAutomatedBackup rds.DBInstanceAutomatedBackup + + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_db_instance_automated_backups_replication.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccMultipleRegionPreCheck(t, 2) + }, + ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), + ProviderFactories: testAccProviderFactoriesMultipleRegion(&providers, 2), + CheckDestroy: testAccCheckAWSDbInstanceAutomatedBackupsReplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDbInstanceAutomatedBackupsReplicationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDbInstanceAutomatedBackupsReplicationExists(resourceName, &dbInstanceAutomatedBackup), + testAccCheckResourceAttrRegionalARNIgnoreRegionAndAccount(resourceName, "source_db_instance_arn", "rds", regexp.MustCompile(`db:.+`).String()), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSDbInstanceAutomatedBackupsReplication_disappears(t *testing.T) { + var providers []*schema.Provider + var dbInstanceAutomatedBackup rds.DBInstanceAutomatedBackup + + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_db_instance_automated_backups_replication.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccMultipleRegionPreCheck(t, 2) + testAccAlternateAccountPreCheck(t) + }, + ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), + ProviderFactories: testAccProviderFactoriesMultipleRegion(&providers, 2), + CheckDestroy: testAccCheckAWSDbInstanceAutomatedBackupsReplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDbInstanceAutomatedBackupsReplicationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDbInstanceAutomatedBackupsReplicationExists(resourceName, &dbInstanceAutomatedBackup), + testAccCheckResourceDisappears(testAccProvider, resourceAwsDbInstanceAutomatedBackupsReplication(), resourceName), + ), + ExpectNonEmptyPlan: false, + }, + }, + }) +} + +func testAccCheckAWSDbInstanceAutomatedBackupsReplicationExists(resourceName string, dbInstanceAutomatedBackup *rds.DBInstanceAutomatedBackup) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + + if !ok { + return fmt.Errorf("Resource not found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).rdsconn + + backup, err := finder.DBInstanceAutomatedBackup(context.Background(), conn, rs.Primary.ID) + if err != nil { + return err + } + + if backup == nil { + return fmt.Errorf("RDS DB Instance Automated Backup not found (%s)", rs.Primary.ID) + } + + *dbInstanceAutomatedBackup = *backup + + return nil + } +} + +func testAccCheckAWSDbInstanceAutomatedBackupsReplicationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).rdsconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_db_instance_automated_backups_replication" { + continue + } + + backup, err := finder.DBInstanceAutomatedBackup(context.Background(), conn, rs.Primary.ID) + if isAWSErr(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault, "") { + continue + } + + if isAWSErr(err, rds.ErrCodeInvalidDBInstanceAutomatedBackupStateFault, "") { + continue + } + + if isAWSErr(err, rds.ErrCodeInvalidDBInstanceStateFault, "") { + return nil + } + + if err != nil { + return err + } + + if backup == nil { + continue + } + + return fmt.Errorf("RDS DB Instance Automated Backups Replication still exists %s", rs.Primary.ID) + } + + return nil +} + +func testAccAWSDbInstanceAutomatedBackupsReplicationConfig(rName string) string { + return composeConfig( + testAccMultipleRegionProviderConfig(2), fmt.Sprintf(` +resource "aws_db_instance" "test" { + allocated_storage = 10 + engine = "postgres" + identifier = %[1]q + instance_class = "db.t3.micro" + password = "avoid-plaintext-passwords" + username = "tfacctest" + skip_final_snapshot = true + delete_automated_backups = true + backup_retention_period = 1 + provider = awsalternate +} + +resource "aws_db_instance_automated_backups_replication" "test" { + source_db_instance_arn = aws_db_instance.test.arn +} +`, rName)) +} diff --git a/website/docs/r/db_instance_automated_backups_replication.markdown b/website/docs/r/db_instance_automated_backups_replication.markdown new file mode 100644 index 000000000000..3753d57f3b8e --- /dev/null +++ b/website/docs/r/db_instance_automated_backups_replication.markdown @@ -0,0 +1,46 @@ +--- +subcategory: "RDS" +layout: "aws" +page_title: "AWS: aws_db_instance_automated_backups_replication" +description: |- + Manages an RDS DB Instance Automated Backups Replication. +--- + +# Resource: aws_db_instance_automated_backups_replication + +Manages an RDS DB Instance Automated Backups Replication. + +~> **NOTE:** This resource requires a second AWS provider to be defined in another region. + +* [Replicating automated backups to another AWS Region](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReplicateBackups.html) + +## Example Usage + +```terraform +resource "aws_db_instance_automated_backups_replication" "example" { + source_db_instance_arn = aws_db_instance.example.arn +} +``` + +## Argument Reference + +The following arguments are supported: + +* `backup_retention_period` - (Optional) The retention period for the replicated automated backups. +* `kms_key_id` - (Optional) The AWS KMS key identifier for encryption of the replicated automated backups. +* `pre_signed_url` - (Optional) A URL that contains a Signature Version 4 signed request for the [StartDBInstanceAutomatedBackupsReplication](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_StartDBInstanceAutomatedBackupsReplication.html) action to be called in the AWS Region of the source DB instance. +* `source_db_instance_arn` - (Optional) The Amazon Resource Name (ARN) of the source DB instance for the replicated automated backups. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - DB Instance Automated Backup Replication ARN + +## Import + +`aws_db_instance_automated_backups_replication` can be imported using the DB Instance Automated Backup Replication ARN, e.g. + +``` +$ terraform import aws_db_instance_automated_backups_replication.example arn:aws:rds:eu-west-1:123456789012:auto-backup:ab-lrg8qb6qtarwcfvoto3so53igbdulp3xjs8xeym +``` From b2e546846756698132e0b05e0dc4a95e6e990865 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sat, 19 Mar 2022 00:09:26 +0100 Subject: [PATCH 02/32] db_instance_backup_replication - WIP on new resource --- internal/provider/provider.go | 39 +++++---- .../rds/instance_backup_replication.go | 86 +++++++++++++++++++ 2 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 internal/service/rds/instance_backup_replication.go diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 72cd598284d5..02fd42e096b4 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1659,25 +1659,26 @@ func Provider() *schema.Provider { "aws_ram_resource_share": ram.ResourceResourceShare(), "aws_ram_resource_share_accepter": ram.ResourceResourceShareAccepter(), - "aws_db_cluster_snapshot": rds.ResourceClusterSnapshot(), - "aws_db_event_subscription": rds.ResourceEventSubscription(), - "aws_db_instance": rds.ResourceInstance(), - "aws_db_instance_role_association": rds.ResourceInstanceRoleAssociation(), - "aws_db_option_group": rds.ResourceOptionGroup(), - "aws_db_parameter_group": rds.ResourceParameterGroup(), - "aws_db_proxy": rds.ResourceProxy(), - "aws_db_proxy_default_target_group": rds.ResourceProxyDefaultTargetGroup(), - "aws_db_proxy_endpoint": rds.ResourceProxyEndpoint(), - "aws_db_proxy_target": rds.ResourceProxyTarget(), - "aws_db_security_group": rds.ResourceSecurityGroup(), - "aws_db_snapshot": rds.ResourceSnapshot(), - "aws_db_subnet_group": rds.ResourceSubnetGroup(), - "aws_rds_cluster": rds.ResourceCluster(), - "aws_rds_cluster_endpoint": rds.ResourceClusterEndpoint(), - "aws_rds_cluster_instance": rds.ResourceClusterInstance(), - "aws_rds_cluster_parameter_group": rds.ResourceClusterParameterGroup(), - "aws_rds_cluster_role_association": rds.ResourceClusterRoleAssociation(), - "aws_rds_global_cluster": rds.ResourceGlobalCluster(), + "aws_db_cluster_snapshot": rds.ResourceClusterSnapshot(), + "aws_db_event_subscription": rds.ResourceEventSubscription(), + "aws_db_instance": rds.ResourceInstance(), + "aws_db_instance_backup_replication": rds.resourceInstanceBackupReplication(), + "aws_db_instance_role_association": rds.ResourceInstanceRoleAssociation(), + "aws_db_option_group": rds.ResourceOptionGroup(), + "aws_db_parameter_group": rds.ResourceParameterGroup(), + "aws_db_proxy": rds.ResourceProxy(), + "aws_db_proxy_default_target_group": rds.ResourceProxyDefaultTargetGroup(), + "aws_db_proxy_endpoint": rds.ResourceProxyEndpoint(), + "aws_db_proxy_target": rds.ResourceProxyTarget(), + "aws_db_security_group": rds.ResourceSecurityGroup(), + "aws_db_snapshot": rds.ResourceSnapshot(), + "aws_db_subnet_group": rds.ResourceSubnetGroup(), + "aws_rds_cluster": rds.ResourceCluster(), + "aws_rds_cluster_endpoint": rds.ResourceClusterEndpoint(), + "aws_rds_cluster_instance": rds.ResourceClusterInstance(), + "aws_rds_cluster_parameter_group": rds.ResourceClusterParameterGroup(), + "aws_rds_cluster_role_association": rds.ResourceClusterRoleAssociation(), + "aws_rds_global_cluster": rds.ResourceGlobalCluster(), "aws_redshift_cluster": redshift.ResourceCluster(), "aws_redshift_event_subscription": redshift.ResourceEventSubscription(), diff --git a/internal/service/rds/instance_backup_replication.go b/internal/service/rds/instance_backup_replication.go new file mode 100644 index 000000000000..7aa19df6e213 --- /dev/null +++ b/internal/service/rds/instance_backup_replication.go @@ -0,0 +1,86 @@ +package rds + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/rds" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func resourceInstanceBackupReplication() *schema.Resource { + return &schema.Resource{ + Create: resourceInstanceBackupReplicationCreate, + Read: resourceInstanceBackupReplicationRead, + Delete: resourceInstanceBackupReplicationDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "source_db_instance_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: verify.ValidARN, + }, + "destination_region": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "retention_period": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func resourceInstanceBackupReplicationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).RDSConn + + input := &rds.StartDBInstanceAutomatedBackupsReplicationInput{ + BackupRetentionPeriod: aws.Int64(int64(d.Get("retention_period").(int))), + DestinationRegion: aws.String(d.Get("destination_region").(string)), + SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), + } + + if v, ok := d.GetOk("kms_key_id"); ok { + input.KmsKeyId = aws.String(v.(string)) + } + + log.Printf("[DEBUG] Starting automated backup replication for: %s", *input.SourceDBInstanceArn) + + output, err := conn.StartDBInstanceAutomatedBackupsReplication(input) + + if err != nil { + return fmt.Errorf("error creating RDS instance backup replication: %s", err) + } + + d.SetId(aws.StringValue(output.DBInstanceAutomatedBackup.DBInstanceAutomatedBackupsArn)) + + return resourceInstanceBackupReplicationRead(d, meta) +} + +func resourceInstanceBackupReplicationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).RDSConn + + return nil +} + +func resourceInstanceBackupReplicationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).RDSConn + + return nil +} From 6827e797c3165c91c7c1f136614702c9f3417129 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sat, 19 Mar 2022 00:54:17 +0100 Subject: [PATCH 03/32] db_instance_backup_replication - more wip on the new resource --- internal/provider/provider.go | 2 +- .../rds/instance_backup_replication.go | 44 ++++++++++++++++++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 02fd42e096b4..2e1810bd0e3d 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1662,7 +1662,7 @@ func Provider() *schema.Provider { "aws_db_cluster_snapshot": rds.ResourceClusterSnapshot(), "aws_db_event_subscription": rds.ResourceEventSubscription(), "aws_db_instance": rds.ResourceInstance(), - "aws_db_instance_backup_replication": rds.resourceInstanceBackupReplication(), + "aws_db_instance_backup_replication": rds.ResourceInstanceBackupReplication(), "aws_db_instance_role_association": rds.ResourceInstanceRoleAssociation(), "aws_db_option_group": rds.ResourceOptionGroup(), "aws_db_parameter_group": rds.ResourceParameterGroup(), diff --git a/internal/service/rds/instance_backup_replication.go b/internal/service/rds/instance_backup_replication.go index 7aa19df6e213..c7a989c9a14c 100644 --- a/internal/service/rds/instance_backup_replication.go +++ b/internal/service/rds/instance_backup_replication.go @@ -6,12 +6,13 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/verify" ) -func resourceInstanceBackupReplication() *schema.Resource { +func ResourceInstanceBackupReplication() *schema.Resource { return &schema.Resource{ Create: resourceInstanceBackupReplicationCreate, Read: resourceInstanceBackupReplicationRead, @@ -60,7 +61,7 @@ func resourceInstanceBackupReplicationCreate(d *schema.ResourceData, meta interf input.KmsKeyId = aws.String(v.(string)) } - log.Printf("[DEBUG] Starting automated backup replication for: %s", *input.SourceDBInstanceArn) + log.Printf("[DEBUG] Starting RDS instance backup replication for: %s", *input.SourceDBInstanceArn) output, err := conn.StartDBInstanceAutomatedBackupsReplication(input) @@ -76,11 +77,50 @@ func resourceInstanceBackupReplicationCreate(d *schema.ResourceData, meta interf func resourceInstanceBackupReplicationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).RDSConn + input := &rds.DescribeDBInstanceAutomatedBackupsInput{ + DBInstanceAutomatedBackupsArn: aws.String(d.Id()), + } + + output, err := conn.DescribeDBInstanceAutomatedBackups(input) + + if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { + log.Printf("[WARN] RDS instance backup replication not found, removing from state: %s", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading RDS instance backup replication: %s", err) + } + + for _, backup := range output.DBInstanceAutomatedBackups { + if aws.StringValue(backup.DBInstanceAutomatedBackupsArn) == d.Id() { + d.Set("source_db_instance_arn", backup.DBInstanceArn) + d.Set("destination_region", backup.Region) + d.Set("retention_period", backup.BackupRetentionPeriod) + d.Set("kms_key_id", backup.KmsKeyId) + } else { + return fmt.Errorf("Unable to find RDS instance backup replication: %s", d.Id()) + } + } + return nil } func resourceInstanceBackupReplicationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).RDSConn + input := &rds.StopDBInstanceAutomatedBackupsReplicationInput{ + SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), + } + + log.Printf("[DEBUG] Deleting RDS instance backup replication for: %s", *input.SourceDBInstanceArn) + + _, err := conn.StopDBInstanceAutomatedBackupsReplication(input) + + if err != nil { + return fmt.Errorf("error deleting RDS instance backup replication: %s", err) + } + return nil } From 43e9e42bade23515c7d0cd86d2f4c532f637d751 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sat, 19 Mar 2022 22:42:46 +0100 Subject: [PATCH 04/32] db_instance_backup_replication - remove `destination_region`, as 'region' is set through either env var or provider. And give a default value for `retention_period` --- .../rds/instance_backup_replication.go | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/internal/service/rds/instance_backup_replication.go b/internal/service/rds/instance_backup_replication.go index c7a989c9a14c..e1901520e1cc 100644 --- a/internal/service/rds/instance_backup_replication.go +++ b/internal/service/rds/instance_backup_replication.go @@ -29,20 +29,18 @@ func ResourceInstanceBackupReplication() *schema.Resource { ForceNew: true, ValidateFunc: verify.ValidARN, }, - "destination_region": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: verify.ValidARN, }, "retention_period": { Type: schema.TypeInt, - Required: true, ForceNew: true, - }, - "kms_key_id": { - Type: schema.TypeString, Optional: true, - ForceNew: true, + Default: 7, }, }, } @@ -53,7 +51,6 @@ func resourceInstanceBackupReplicationCreate(d *schema.ResourceData, meta interf input := &rds.StartDBInstanceAutomatedBackupsReplicationInput{ BackupRetentionPeriod: aws.Int64(int64(d.Get("retention_period").(int))), - DestinationRegion: aws.String(d.Get("destination_region").(string)), SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), } @@ -96,9 +93,8 @@ func resourceInstanceBackupReplicationRead(d *schema.ResourceData, meta interfac for _, backup := range output.DBInstanceAutomatedBackups { if aws.StringValue(backup.DBInstanceAutomatedBackupsArn) == d.Id() { d.Set("source_db_instance_arn", backup.DBInstanceArn) - d.Set("destination_region", backup.Region) - d.Set("retention_period", backup.BackupRetentionPeriod) d.Set("kms_key_id", backup.KmsKeyId) + d.Set("retention_period", backup.BackupRetentionPeriod) } else { return fmt.Errorf("Unable to find RDS instance backup replication: %s", d.Id()) } From fca6fc051c8175f03ada8a6aa2ddf48373827dc2 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sun, 20 Mar 2022 19:30:50 +0100 Subject: [PATCH 05/32] db_instance_backup_replication - add a waiter --- internal/service/rds/consts.go | 5 +++++ internal/service/rds/find.go | 21 +++++++++++++++++++ .../rds/instance_backup_replication.go | 10 ++++++++- internal/service/rds/status.go | 16 ++++++++++++++ internal/service/rds/wait.go | 19 +++++++++++++++++ 5 files changed, 70 insertions(+), 1 deletion(-) diff --git a/internal/service/rds/consts.go b/internal/service/rds/consts.go index c31b4aa776e2..e5cc7654776f 100644 --- a/internal/service/rds/consts.go +++ b/internal/service/rds/consts.go @@ -37,6 +37,11 @@ const ( InstanceStatusStorageOptimization = "storage-optimization" ) +const ( + InstanceAutomatedBackupPending = "pending" + InstanceAutomatedBackupReplicating = "replicating" +) + const ( EventSubscriptionStatusActive = "active" EventSubscriptionStatusCreating = "creating" diff --git a/internal/service/rds/find.go b/internal/service/rds/find.go index b53c82c1048c..aeb3026e394e 100644 --- a/internal/service/rds/find.go +++ b/internal/service/rds/find.go @@ -189,3 +189,24 @@ func FindEventSubscriptionByID(conn *rds.RDS, id string) (*rds.EventSubscription return output.EventSubscriptionsList[0], nil } + +func FindDBInstanceAutomatedBackupByID(conn *rds.RDS, id string) (*rds.DBInstanceAutomatedBackup, error) { + input := &rds.DescribeDBInstanceAutomatedBackupsInput{ + DBInstanceAutomatedBackupsArn: aws.String(id), + } + + output, err := conn.DescribeDBInstanceAutomatedBackups(input) + + if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if output == nil || len(output.DBInstanceAutomatedBackups) == 0 { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.DBInstanceAutomatedBackups[0], nil +} diff --git a/internal/service/rds/instance_backup_replication.go b/internal/service/rds/instance_backup_replication.go index e1901520e1cc..576cdd761357 100644 --- a/internal/service/rds/instance_backup_replication.go +++ b/internal/service/rds/instance_backup_replication.go @@ -50,8 +50,8 @@ func resourceInstanceBackupReplicationCreate(d *schema.ResourceData, meta interf conn := meta.(*conns.AWSClient).RDSConn input := &rds.StartDBInstanceAutomatedBackupsReplicationInput{ - BackupRetentionPeriod: aws.Int64(int64(d.Get("retention_period").(int))), SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), + BackupRetentionPeriod: aws.Int64(int64(d.Get("retention_period").(int))), } if v, ok := d.GetOk("kms_key_id"); ok { @@ -68,6 +68,10 @@ func resourceInstanceBackupReplicationCreate(d *schema.ResourceData, meta interf d.SetId(aws.StringValue(output.DBInstanceAutomatedBackup.DBInstanceAutomatedBackupsArn)) + if _, err := waitDBInstanceAutomatedBackupAvailable(conn, d.Id(), d.Timeout(schema.TimeoutDefault)); err != nil { + return fmt.Errorf("error waiting for DB instance automated backup (%s) creation: %w", d.Id(), err) + } + return resourceInstanceBackupReplicationRead(d, meta) } @@ -118,5 +122,9 @@ func resourceInstanceBackupReplicationDelete(d *schema.ResourceData, meta interf return fmt.Errorf("error deleting RDS instance backup replication: %s", err) } + // if _, err := waitDBInstanceAutomatedBackupAvailable(conn, *input.SourceDBInstanceArn, d.Timeout(schema.TimeoutDefault)); err != nil { + // return fmt.Errorf("error waiting for DB Instance (%s) delete: %w", *input.SourceDBInstanceArn, err) + // } + return nil } diff --git a/internal/service/rds/status.go b/internal/service/rds/status.go index 0f393d980030..276b198c3500 100644 --- a/internal/service/rds/status.go +++ b/internal/service/rds/status.go @@ -79,3 +79,19 @@ func statusDBInstance(conn *rds.RDS, id string) resource.StateRefreshFunc { return output, aws.StringValue(output.DBInstanceStatus), nil } } + +func statusDBInstanceAutomatedBackup(conn *rds.RDS, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := FindDBInstanceAutomatedBackupByID(conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} diff --git a/internal/service/rds/wait.go b/internal/service/rds/wait.go index 6751a4d048d5..73c5f9c64a4d 100644 --- a/internal/service/rds/wait.go +++ b/internal/service/rds/wait.go @@ -199,3 +199,22 @@ func waitDBClusterInstanceDeleted(conn *rds.RDS, id string, timeout time.Duratio return nil, err } + +func waitDBInstanceAutomatedBackupAvailable(conn *rds.RDS, arn string, timeout time.Duration) (*rds.DBInstance, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + InstanceAutomatedBackupPending, + }, + Target: []string{InstanceAutomatedBackupReplicating}, + Refresh: statusDBInstanceAutomatedBackup(conn, arn), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*rds.DBInstance); ok { + return output, err + } + + return nil, err +} From 1c9d0c29b2471ca08e7c0c90d39883425aaa62b3 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Tue, 22 Mar 2022 23:37:41 +0100 Subject: [PATCH 06/32] Touch up deletion flow, wait for source database to be available --- .../rds/instance_backup_replication.go | 61 ++++++++++++++++--- internal/service/rds/wait.go | 35 +++++++++++ 2 files changed, 89 insertions(+), 7 deletions(-) diff --git a/internal/service/rds/instance_backup_replication.go b/internal/service/rds/instance_backup_replication.go index 576cdd761357..bc156ab8cbf5 100644 --- a/internal/service/rds/instance_backup_replication.go +++ b/internal/service/rds/instance_backup_replication.go @@ -12,6 +12,10 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/verify" ) +const ( + dbInstanceAutomatedBackupReplicationRetained = "retained" +) + func ResourceInstanceBackupReplication() *schema.Resource { return &schema.Resource{ Create: resourceInstanceBackupReplicationCreate, @@ -100,7 +104,7 @@ func resourceInstanceBackupReplicationRead(d *schema.ResourceData, meta interfac d.Set("kms_key_id", backup.KmsKeyId) d.Set("retention_period", backup.BackupRetentionPeriod) } else { - return fmt.Errorf("Unable to find RDS instance backup replication: %s", d.Id()) + return fmt.Errorf("unable to find RDS instance backup replication: %s", d.Id()) } } @@ -108,23 +112,66 @@ func resourceInstanceBackupReplicationRead(d *schema.ResourceData, meta interfac } func resourceInstanceBackupReplicationDelete(d *schema.ResourceData, meta interface{}) error { + var sourceDatabaseRegion string + var databaseIdentifier string + conn := meta.(*conns.AWSClient).RDSConn + describeInput := &rds.DescribeDBInstanceAutomatedBackupsInput{ + DBInstanceAutomatedBackupsArn: aws.String(d.Id()), + } + + describeOutput, err := conn.DescribeDBInstanceAutomatedBackups(describeInput) + + // Get and set the region of the source database and database identifier + for _, backup := range describeOutput.DBInstanceAutomatedBackups { + if aws.StringValue(backup.DBInstanceAutomatedBackupsArn) == d.Id() { + sourceDatabaseRegion = aws.StringValue(backup.Region) + databaseIdentifier = aws.StringValue(backup.DBInstanceIdentifier) + } else { + return fmt.Errorf("unable to find RDS instance backup replication: %s", d.Id()) + } + // Check if the automated backup is retained + if aws.StringValue(backup.Status) == dbInstanceAutomatedBackupReplicationRetained { + log.Printf("[WARN] RDS instance backup replication is retained, removing from state: %s", d.Id()) + d.SetId("") + return nil // If the automated backup is retained, it's 'deleted' + } + } + + if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { + log.Printf("[WARN] RDS instance backup replication not found, removing from state: %s", d.Id()) + d.SetId("") + return nil // The resource is already deleted or was never created + } + + if err != nil { + return fmt.Errorf("error reading RDS instance backup replication: %s", err) + } + + // Initiate a stop of the replication process input := &rds.StopDBInstanceAutomatedBackupsReplicationInput{ SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), } - log.Printf("[DEBUG] Deleting RDS instance backup replication for: %s", *input.SourceDBInstanceArn) + log.Printf("[DEBUG] Stopping RDS instance backup replication for: %s", *input.SourceDBInstanceArn) - _, err := conn.StopDBInstanceAutomatedBackupsReplication(input) + _, err = conn.StopDBInstanceAutomatedBackupsReplication(input) if err != nil { - return fmt.Errorf("error deleting RDS instance backup replication: %s", err) + return fmt.Errorf("error stopping RDS instance backup replication: %s", err) } - // if _, err := waitDBInstanceAutomatedBackupAvailable(conn, *input.SourceDBInstanceArn, d.Timeout(schema.TimeoutDefault)); err != nil { - // return fmt.Errorf("error waiting for DB Instance (%s) delete: %w", *input.SourceDBInstanceArn, err) - // } + // Create a new client to the source region + sourceDatabaseConn := conn + if sourceDatabaseRegion != meta.(*conns.AWSClient).Region { + sourceDatabaseConn = rds.New(meta.(*conns.AWSClient).Session, aws.NewConfig().WithRegion(sourceDatabaseRegion)) + } + + // Wait for the source database to be available after the replication is stopped + if _, err := waitDBInstanceAvailable(sourceDatabaseConn, databaseIdentifier, d.Timeout(schema.TimeoutDefault)); err != nil { + return fmt.Errorf("error waiting for DB Instance (%s) delete: %w", *input.SourceDBInstanceArn, err) + } return nil } diff --git a/internal/service/rds/wait.go b/internal/service/rds/wait.go index 73c5f9c64a4d..255c5aaa111a 100644 --- a/internal/service/rds/wait.go +++ b/internal/service/rds/wait.go @@ -177,6 +177,41 @@ func waitDBInstanceDeleted(conn *rds.RDS, id string, timeout time.Duration) (*rd return nil, err } +func waitDBInstanceAvailable(conn *rds.RDS, id string, timeout time.Duration) (*rds.DBInstance, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + InstanceStatusBackingUp, + InstanceStatusConfiguringEnhancedMonitoring, + InstanceStatusConfiguringLogExports, + InstanceStatusCreating, + InstanceStatusDeleting, + InstanceStatusIncompatibleParameters, + InstanceStatusIncompatibleRestore, + InstanceStatusModifying, + InstanceStatusStarting, + InstanceStatusStopping, + InstanceStatusStorageFull, + InstanceStatusStorageOptimization, + }, + Target: []string{ + InstanceStatusAvailable, + }, + Refresh: statusDBInstance(conn, id), + Timeout: timeout, + MinTimeout: 10 * time.Second, + Delay: 30 * time.Second, + ContinuousTargetOccurence: 3, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*rds.DBInstance); ok { + return output, err + } + + return nil, err +} + func waitDBClusterInstanceDeleted(conn *rds.RDS, id string, timeout time.Duration) (*rds.DBInstance, error) { stateConf := &resource.StateChangeConf{ Pending: []string{ From 23fe79446f7519bb727e0c6a0429c898278cb82f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Wed, 23 Mar 2022 00:05:06 +0100 Subject: [PATCH 07/32] Add `db_instance_backup_replication` tests --- .../rds/instance_backup_replication_test.go | 169 ++++++++++++++++++ internal/service/rds/wait.go | 4 +- 2 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 internal/service/rds/instance_backup_replication_test.go diff --git a/internal/service/rds/instance_backup_replication_test.go b/internal/service/rds/instance_backup_replication_test.go new file mode 100644 index 000000000000..c570820b8110 --- /dev/null +++ b/internal/service/rds/instance_backup_replication_test.go @@ -0,0 +1,169 @@ +package rds_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/rds" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" +) + +func TestAccRDSInstanceBackupReplication_basic(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_db_instance_backup_replication.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckInstanceRoleAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccInstanceBackupReplicationConfig(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "retention_period", "7"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRDSInstanceBackupReplication_retentionPeriod(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_db_instance_backup_replication.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckInstanceBackupReplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccInstanceBackupReplicationConfig_RetentionPeriod(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "retention_period", "30"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccInstanceBackupReplicationConfig(rName string) string { + return fmt.Sprintf(` +provider "aws" { + region = "us-east-1" +} + +provider "aws" { + region = "us-west-2" + alias = "replica" +} + +resource "aws_kms_key" "test" { + description = %[1]q +} + +resource "aws_db_instance" "test" { + allocated_storage = 10 + identifier = %[1]q + engine = "postgresql" + engine_version = "13.4" + instance_class = "db.t3.micro" + name = "mydb" + username = "masterusername" + password = "mustbeeightcharacters" + skip_final_snapshot = true +} + +resource "aws_db_instance_backup_replication" "default" { + source_db_instance_arn = aws_db_instance.test.arn + kms_key_id = aws_kms_key.test.arn + + provider = "aws.replica" +} +`, rName) +} + +func testAccInstanceBackupReplicationConfig_RetentionPeriod(rName string) string { + return fmt.Sprintf(` +provider "aws" { + region = "us-east-1" +} + +provider "aws" { + region = "us-west-2" + alias = "replica" +} + +resource "aws_kms_key" "test" { + description = %[1]q +} + +resource "aws_db_instance" "test" { + allocated_storage = 10 + identifier = %[1]q + engine = "postgresql" + engine_version = "13.4" + instance_class = "db.t3.micro" + name = "mydb" + username = "masterusername" + password = "mustbeeightcharacters" + skip_final_snapshot = true +} + +resource "aws_db_instance_backup_replication" "default" { + source_db_instance_arn = aws_db_instance.test.arn + kms_key_id = aws_kms_key.test.arn + retention_period = 30 + + provider = "aws.replica" +} +`, rName) +} + +func testAccCheckInstanceBackupReplicationDestroy(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_db_instance_backup_replication" { + continue + } + + input := &rds.DescribeDBInstanceAutomatedBackupsInput{ + DBInstanceAutomatedBackupsArn: &rs.Primary.ID, + } + + output, err := conn.DescribeDBInstanceAutomatedBackups(input) + + if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { + continue + } + + if err != nil { + return err + } + + if output == nil { + continue + } + + return fmt.Errorf("RDS instance backup replication %q still exists", rs.Primary.ID) + } + + return nil +} diff --git a/internal/service/rds/wait.go b/internal/service/rds/wait.go index 255c5aaa111a..dc3bf6b83154 100644 --- a/internal/service/rds/wait.go +++ b/internal/service/rds/wait.go @@ -240,7 +240,9 @@ func waitDBInstanceAutomatedBackupAvailable(conn *rds.RDS, arn string, timeout t Pending: []string{ InstanceAutomatedBackupPending, }, - Target: []string{InstanceAutomatedBackupReplicating}, + Target: []string{ + InstanceAutomatedBackupReplicating, + }, Refresh: statusDBInstanceAutomatedBackup(conn, arn), Timeout: timeout, } From 2c2c7f89ad6425515940f086aab774764cc81c25 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 24 Mar 2022 00:15:51 +0100 Subject: [PATCH 08/32] Add `retention_period` and KMS encrypted backup acceptance test --- .../rds/instance_backup_replication_test.go | 158 +++++++++++------- 1 file changed, 100 insertions(+), 58 deletions(-) diff --git a/internal/service/rds/instance_backup_replication_test.go b/internal/service/rds/instance_backup_replication_test.go index c570820b8110..6053ce75a502 100644 --- a/internal/service/rds/instance_backup_replication_test.go +++ b/internal/service/rds/instance_backup_replication_test.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -17,11 +18,13 @@ func TestAccRDSInstanceBackupReplication_basic(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_db_instance_backup_replication.test" + var providers []*schema.Provider + resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckInstanceRoleAssociationDestroy, + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), + ProviderFactories: acctest.FactoriesAlternate(&providers), + CheckDestroy: testAccCheckInstanceRoleAssociationDestroy, Steps: []resource.TestStep{ { Config: testAccInstanceBackupReplicationConfig(rName), @@ -42,16 +45,18 @@ func TestAccRDSInstanceBackupReplication_retentionPeriod(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_db_instance_backup_replication.test" + var providers []*schema.Provider + resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckInstanceBackupReplicationDestroy, + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), + ProviderFactories: acctest.FactoriesAlternate(&providers), + CheckDestroy: testAccCheckInstanceRoleAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccInstanceBackupReplicationConfig_RetentionPeriod(rName), + Config: testAccInstanceBackupReplicationConfig_retentionPeriod(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "retention_period", "30"), + resource.TestCheckResourceAttr(resourceName, "retention_period", "14"), ), }, { @@ -63,77 +68,114 @@ func TestAccRDSInstanceBackupReplication_retentionPeriod(t *testing.T) { }) } -func testAccInstanceBackupReplicationConfig(rName string) string { - return fmt.Sprintf(` -provider "aws" { - region = "us-east-1" -} +func TestAccRDSInstanceBackupReplication_kmsEncrypted(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_db_instance_backup_replication.test" -provider "aws" { - region = "us-west-2" - alias = "replica" -} + var providers []*schema.Provider -resource "aws_kms_key" "test" { - description = %[1]q + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), + ProviderFactories: acctest.FactoriesAlternate(&providers), + CheckDestroy: testAccCheckInstanceRoleAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccInstanceBackupReplicationConfig_kmsEncrypted(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "retention_period", "7"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) } +func testAccInstanceBackupReplicationConfig(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(2), + fmt.Sprintf(` resource "aws_db_instance" "test" { - allocated_storage = 10 - identifier = %[1]q - engine = "postgresql" - engine_version = "13.4" - instance_class = "db.t3.micro" - name = "mydb" - username = "masterusername" - password = "mustbeeightcharacters" - skip_final_snapshot = true + allocated_storage = 10 + identifier = %[1]q + engine = "postgres" + engine_version = "13.4" + instance_class = "db.t3.micro" + name = "mydb" + username = "masterusername" + password = "mustbeeightcharacters" + backup_retention_period = 7 + skip_final_snapshot = true } -resource "aws_db_instance_backup_replication" "default" { +resource "aws_db_instance_backup_replication" "test" { source_db_instance_arn = aws_db_instance.test.arn - kms_key_id = aws_kms_key.test.arn - provider = "aws.replica" + provider = "awsalternate" } -`, rName) +`, rName)) } -func testAccInstanceBackupReplicationConfig_RetentionPeriod(rName string) string { - return fmt.Sprintf(` -provider "aws" { - region = "us-east-1" +func testAccInstanceBackupReplicationConfig_retentionPeriod(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(2), + fmt.Sprintf(` +resource "aws_db_instance" "test" { + allocated_storage = 10 + identifier = %[1]q + engine = "postgres" + engine_version = "13.4" + instance_class = "db.t3.micro" + name = "mydb" + username = "masterusername" + password = "mustbeeightcharacters" + backup_retention_period = 7 + skip_final_snapshot = true } - -provider "aws" { - region = "us-west-2" - alias = "replica" + +resource "aws_db_instance_backup_replication" "test" { + source_db_instance_arn = aws_db_instance.test.arn + retention_period = 14 + + provider = "awsalternate" } - -resource "aws_kms_key" "test" { - description = %[1]q +`, rName)) } +func testAccInstanceBackupReplicationConfig_kmsEncrypted(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(2), + fmt.Sprintf(` +resource "aws_kms_key" "test" { + description = %[1]q + provider = "awsalternate" +} + resource "aws_db_instance" "test" { - allocated_storage = 10 - identifier = %[1]q - engine = "postgresql" - engine_version = "13.4" - instance_class = "db.t3.micro" - name = "mydb" - username = "masterusername" - password = "mustbeeightcharacters" - skip_final_snapshot = true + allocated_storage = 10 + identifier = %[1]q + engine = "postgres" + engine_version = "13.4" + instance_class = "db.t3.micro" + name = "mydb" + username = "masterusername" + password = "mustbeeightcharacters" + backup_retention_period = 7 + storage_encrypted = true + skip_final_snapshot = true } -resource "aws_db_instance_backup_replication" "default" { +resource "aws_db_instance_backup_replication" "test" { source_db_instance_arn = aws_db_instance.test.arn kms_key_id = aws_kms_key.test.arn - retention_period = 30 - provider = "aws.replica" + provider = "awsalternate" } -`, rName) +`, rName)) } func testAccCheckInstanceBackupReplicationDestroy(s *terraform.State) error { From a6f13f7cb8185a7d1ef28d3fdf755cef129accee Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 24 Mar 2022 21:30:47 +0100 Subject: [PATCH 09/32] Rename to `aws_db_instance_automated_backup_replication` --- internal/provider/provider.go | 40 ++++++++--------- ... instance_automated_backup_replication.go} | 38 ++++++++-------- ...ance_automated_backup_replication_test.go} | 34 +++++++------- ...ance_automated_backup_replication.markdown | 45 +++++++++++++++++++ 4 files changed, 101 insertions(+), 56 deletions(-) rename internal/service/rds/{instance_backup_replication.go => instance_automated_backup_replication.go} (72%) rename internal/service/rds/{instance_backup_replication_test.go => instance_automated_backup_replication_test.go} (80%) create mode 100644 website/docs/r/db_instance_automated_backup_replication.markdown diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 2e1810bd0e3d..45c31b36eb10 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1659,26 +1659,26 @@ func Provider() *schema.Provider { "aws_ram_resource_share": ram.ResourceResourceShare(), "aws_ram_resource_share_accepter": ram.ResourceResourceShareAccepter(), - "aws_db_cluster_snapshot": rds.ResourceClusterSnapshot(), - "aws_db_event_subscription": rds.ResourceEventSubscription(), - "aws_db_instance": rds.ResourceInstance(), - "aws_db_instance_backup_replication": rds.ResourceInstanceBackupReplication(), - "aws_db_instance_role_association": rds.ResourceInstanceRoleAssociation(), - "aws_db_option_group": rds.ResourceOptionGroup(), - "aws_db_parameter_group": rds.ResourceParameterGroup(), - "aws_db_proxy": rds.ResourceProxy(), - "aws_db_proxy_default_target_group": rds.ResourceProxyDefaultTargetGroup(), - "aws_db_proxy_endpoint": rds.ResourceProxyEndpoint(), - "aws_db_proxy_target": rds.ResourceProxyTarget(), - "aws_db_security_group": rds.ResourceSecurityGroup(), - "aws_db_snapshot": rds.ResourceSnapshot(), - "aws_db_subnet_group": rds.ResourceSubnetGroup(), - "aws_rds_cluster": rds.ResourceCluster(), - "aws_rds_cluster_endpoint": rds.ResourceClusterEndpoint(), - "aws_rds_cluster_instance": rds.ResourceClusterInstance(), - "aws_rds_cluster_parameter_group": rds.ResourceClusterParameterGroup(), - "aws_rds_cluster_role_association": rds.ResourceClusterRoleAssociation(), - "aws_rds_global_cluster": rds.ResourceGlobalCluster(), + "aws_db_cluster_snapshot": rds.ResourceClusterSnapshot(), + "aws_db_event_subscription": rds.ResourceEventSubscription(), + "aws_db_instance": rds.ResourceInstance(), + "aws_db_instance_automated_backup_replication": rds.ResourceInstanceAutomatedBackupReplication(), + "aws_db_instance_role_association": rds.ResourceInstanceRoleAssociation(), + "aws_db_option_group": rds.ResourceOptionGroup(), + "aws_db_parameter_group": rds.ResourceParameterGroup(), + "aws_db_proxy": rds.ResourceProxy(), + "aws_db_proxy_default_target_group": rds.ResourceProxyDefaultTargetGroup(), + "aws_db_proxy_endpoint": rds.ResourceProxyEndpoint(), + "aws_db_proxy_target": rds.ResourceProxyTarget(), + "aws_db_security_group": rds.ResourceSecurityGroup(), + "aws_db_snapshot": rds.ResourceSnapshot(), + "aws_db_subnet_group": rds.ResourceSubnetGroup(), + "aws_rds_cluster": rds.ResourceCluster(), + "aws_rds_cluster_endpoint": rds.ResourceClusterEndpoint(), + "aws_rds_cluster_instance": rds.ResourceClusterInstance(), + "aws_rds_cluster_parameter_group": rds.ResourceClusterParameterGroup(), + "aws_rds_cluster_role_association": rds.ResourceClusterRoleAssociation(), + "aws_rds_global_cluster": rds.ResourceGlobalCluster(), "aws_redshift_cluster": redshift.ResourceCluster(), "aws_redshift_event_subscription": redshift.ResourceEventSubscription(), diff --git a/internal/service/rds/instance_backup_replication.go b/internal/service/rds/instance_automated_backup_replication.go similarity index 72% rename from internal/service/rds/instance_backup_replication.go rename to internal/service/rds/instance_automated_backup_replication.go index bc156ab8cbf5..ca730e7d1e2a 100644 --- a/internal/service/rds/instance_backup_replication.go +++ b/internal/service/rds/instance_automated_backup_replication.go @@ -16,11 +16,11 @@ const ( dbInstanceAutomatedBackupReplicationRetained = "retained" ) -func ResourceInstanceBackupReplication() *schema.Resource { +func ResourceInstanceAutomatedBackupReplication() *schema.Resource { return &schema.Resource{ - Create: resourceInstanceBackupReplicationCreate, - Read: resourceInstanceBackupReplicationRead, - Delete: resourceInstanceBackupReplicationDelete, + Create: resourceInstanceAutomatedBackupReplicationCreate, + Read: resourceInstanceAutomatedBackupReplicationRead, + Delete: resourceInstanceAutomatedBackupReplicationDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, @@ -50,7 +50,7 @@ func ResourceInstanceBackupReplication() *schema.Resource { } } -func resourceInstanceBackupReplicationCreate(d *schema.ResourceData, meta interface{}) error { +func resourceInstanceAutomatedBackupReplicationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).RDSConn input := &rds.StartDBInstanceAutomatedBackupsReplicationInput{ @@ -62,12 +62,12 @@ func resourceInstanceBackupReplicationCreate(d *schema.ResourceData, meta interf input.KmsKeyId = aws.String(v.(string)) } - log.Printf("[DEBUG] Starting RDS instance backup replication for: %s", *input.SourceDBInstanceArn) + log.Printf("[DEBUG] Starting RDS instance automated backup replication for: %s", *input.SourceDBInstanceArn) output, err := conn.StartDBInstanceAutomatedBackupsReplication(input) if err != nil { - return fmt.Errorf("error creating RDS instance backup replication: %s", err) + return fmt.Errorf("error creating RDS instance automated backup replication: %s", err) } d.SetId(aws.StringValue(output.DBInstanceAutomatedBackup.DBInstanceAutomatedBackupsArn)) @@ -76,10 +76,10 @@ func resourceInstanceBackupReplicationCreate(d *schema.ResourceData, meta interf return fmt.Errorf("error waiting for DB instance automated backup (%s) creation: %w", d.Id(), err) } - return resourceInstanceBackupReplicationRead(d, meta) + return resourceInstanceAutomatedBackupReplicationRead(d, meta) } -func resourceInstanceBackupReplicationRead(d *schema.ResourceData, meta interface{}) error { +func resourceInstanceAutomatedBackupReplicationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).RDSConn input := &rds.DescribeDBInstanceAutomatedBackupsInput{ @@ -89,13 +89,13 @@ func resourceInstanceBackupReplicationRead(d *schema.ResourceData, meta interfac output, err := conn.DescribeDBInstanceAutomatedBackups(input) if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { - log.Printf("[WARN] RDS instance backup replication not found, removing from state: %s", d.Id()) + log.Printf("[WARN] RDS instance automated backup replication not found, removing from state: %s", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error reading RDS instance backup replication: %s", err) + return fmt.Errorf("error reading RDS instance automated backup replication: %s", err) } for _, backup := range output.DBInstanceAutomatedBackups { @@ -104,14 +104,14 @@ func resourceInstanceBackupReplicationRead(d *schema.ResourceData, meta interfac d.Set("kms_key_id", backup.KmsKeyId) d.Set("retention_period", backup.BackupRetentionPeriod) } else { - return fmt.Errorf("unable to find RDS instance backup replication: %s", d.Id()) + return fmt.Errorf("unable to find RDS instance automated backup replication: %s", d.Id()) } } return nil } -func resourceInstanceBackupReplicationDelete(d *schema.ResourceData, meta interface{}) error { +func resourceInstanceAutomatedBackupReplicationDelete(d *schema.ResourceData, meta interface{}) error { var sourceDatabaseRegion string var databaseIdentifier string @@ -129,24 +129,24 @@ func resourceInstanceBackupReplicationDelete(d *schema.ResourceData, meta interf sourceDatabaseRegion = aws.StringValue(backup.Region) databaseIdentifier = aws.StringValue(backup.DBInstanceIdentifier) } else { - return fmt.Errorf("unable to find RDS instance backup replication: %s", d.Id()) + return fmt.Errorf("unable to find RDS instance automated backup replication: %s", d.Id()) } // Check if the automated backup is retained if aws.StringValue(backup.Status) == dbInstanceAutomatedBackupReplicationRetained { - log.Printf("[WARN] RDS instance backup replication is retained, removing from state: %s", d.Id()) + log.Printf("[WARN] RDS instance automated backup replication is retained, removing from state: %s", d.Id()) d.SetId("") return nil // If the automated backup is retained, it's 'deleted' } } if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { - log.Printf("[WARN] RDS instance backup replication not found, removing from state: %s", d.Id()) + log.Printf("[WARN] RDS instance automated backup replication not found, removing from state: %s", d.Id()) d.SetId("") return nil // The resource is already deleted or was never created } if err != nil { - return fmt.Errorf("error reading RDS instance backup replication: %s", err) + return fmt.Errorf("error reading RDS instance automated backup replication: %s", err) } // Initiate a stop of the replication process @@ -154,12 +154,12 @@ func resourceInstanceBackupReplicationDelete(d *schema.ResourceData, meta interf SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), } - log.Printf("[DEBUG] Stopping RDS instance backup replication for: %s", *input.SourceDBInstanceArn) + log.Printf("[DEBUG] Stopping RDS instance automated backup replication for: %s", *input.SourceDBInstanceArn) _, err = conn.StopDBInstanceAutomatedBackupsReplication(input) if err != nil { - return fmt.Errorf("error stopping RDS instance backup replication: %s", err) + return fmt.Errorf("error stopping RDS instance automated backup replication: %s", err) } // Create a new client to the source region diff --git a/internal/service/rds/instance_backup_replication_test.go b/internal/service/rds/instance_automated_backup_replication_test.go similarity index 80% rename from internal/service/rds/instance_backup_replication_test.go rename to internal/service/rds/instance_automated_backup_replication_test.go index 6053ce75a502..b00ea07ec47d 100644 --- a/internal/service/rds/instance_backup_replication_test.go +++ b/internal/service/rds/instance_automated_backup_replication_test.go @@ -14,9 +14,9 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" ) -func TestAccRDSInstanceBackupReplication_basic(t *testing.T) { +func TestAccRDSInstanceAutomatedBackupReplication_basic(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_db_instance_backup_replication.test" + resourceName := "aws_db_instance_automated_backup_replication.test" var providers []*schema.Provider @@ -27,7 +27,7 @@ func TestAccRDSInstanceBackupReplication_basic(t *testing.T) { CheckDestroy: testAccCheckInstanceRoleAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccInstanceBackupReplicationConfig(rName), + Config: testAccInstanceAutomatedBackupReplicationConfig(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "retention_period", "7"), ), @@ -41,9 +41,9 @@ func TestAccRDSInstanceBackupReplication_basic(t *testing.T) { }) } -func TestAccRDSInstanceBackupReplication_retentionPeriod(t *testing.T) { +func TestAccRDSInstanceAutomatedBackupReplication_retentionPeriod(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_db_instance_backup_replication.test" + resourceName := "aws_db_instance_automated_backup_replication.test" var providers []*schema.Provider @@ -54,7 +54,7 @@ func TestAccRDSInstanceBackupReplication_retentionPeriod(t *testing.T) { CheckDestroy: testAccCheckInstanceRoleAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccInstanceBackupReplicationConfig_retentionPeriod(rName), + Config: testAccInstanceAutomatedBackupReplicationConfig_retentionPeriod(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "retention_period", "14"), ), @@ -68,9 +68,9 @@ func TestAccRDSInstanceBackupReplication_retentionPeriod(t *testing.T) { }) } -func TestAccRDSInstanceBackupReplication_kmsEncrypted(t *testing.T) { +func TestAccRDSInstanceAutomatedBackupReplication_kmsEncrypted(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_db_instance_backup_replication.test" + resourceName := "aws_db_instance_automated_backup_replication.test" var providers []*schema.Provider @@ -81,7 +81,7 @@ func TestAccRDSInstanceBackupReplication_kmsEncrypted(t *testing.T) { CheckDestroy: testAccCheckInstanceRoleAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccInstanceBackupReplicationConfig_kmsEncrypted(rName), + Config: testAccInstanceAutomatedBackupReplicationConfig_kmsEncrypted(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "retention_period", "7"), ), @@ -95,7 +95,7 @@ func TestAccRDSInstanceBackupReplication_kmsEncrypted(t *testing.T) { }) } -func testAccInstanceBackupReplicationConfig(rName string) string { +func testAccInstanceAutomatedBackupReplicationConfig(rName string) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(2), fmt.Sprintf(` @@ -112,7 +112,7 @@ resource "aws_db_instance" "test" { skip_final_snapshot = true } -resource "aws_db_instance_backup_replication" "test" { +resource "aws_db_instance_automated_backup_replication" "test" { source_db_instance_arn = aws_db_instance.test.arn provider = "awsalternate" @@ -120,7 +120,7 @@ resource "aws_db_instance_backup_replication" "test" { `, rName)) } -func testAccInstanceBackupReplicationConfig_retentionPeriod(rName string) string { +func testAccInstanceAutomatedBackupReplicationConfig_retentionPeriod(rName string) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(2), fmt.Sprintf(` @@ -137,7 +137,7 @@ resource "aws_db_instance" "test" { skip_final_snapshot = true } -resource "aws_db_instance_backup_replication" "test" { +resource "aws_db_instance_automated_backup_replication" "test" { source_db_instance_arn = aws_db_instance.test.arn retention_period = 14 @@ -146,7 +146,7 @@ resource "aws_db_instance_backup_replication" "test" { `, rName)) } -func testAccInstanceBackupReplicationConfig_kmsEncrypted(rName string) string { +func testAccInstanceAutomatedBackupReplicationConfig_kmsEncrypted(rName string) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(2), fmt.Sprintf(` @@ -169,7 +169,7 @@ resource "aws_db_instance" "test" { skip_final_snapshot = true } -resource "aws_db_instance_backup_replication" "test" { +resource "aws_db_instance_automated_backup_replication" "test" { source_db_instance_arn = aws_db_instance.test.arn kms_key_id = aws_kms_key.test.arn @@ -178,11 +178,11 @@ resource "aws_db_instance_backup_replication" "test" { `, rName)) } -func testAccCheckInstanceBackupReplicationDestroy(s *terraform.State) error { +func testAccCheckInstanceAutomatedBackupReplicationDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_db_instance_backup_replication" { + if rs.Type != "aws_db_instance_automated_backup_replication" { continue } diff --git a/website/docs/r/db_instance_automated_backup_replication.markdown b/website/docs/r/db_instance_automated_backup_replication.markdown new file mode 100644 index 000000000000..36fb65b46051 --- /dev/null +++ b/website/docs/r/db_instance_automated_backup_replication.markdown @@ -0,0 +1,45 @@ +--- +subcategory: "RDS" +layout: "aws" +page_title: "AWS: aws_db_instance_automated_backup_replication" +description: |- + Enables replication of automated backups to a different AWS Region. +--- + +# Resource: aws_db_instance_automated_backup_replication + +Manage cross-region replication of automated backups to a different AWS Region. Documentation for cross-region automated backup replication can be found at: + +* [Replicating automated backups to another AWS Region](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReplicateBackups.html) + +## Example Usage +```terraform +resource "aws_db_instance_automated_backup_replication" "default" { + source_db_instance_arn = "arn:aws:rds:us-west-2:123456789012:db:mydatabase" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `source_db_instance_arn` - (Optional, Forces new resource) The Amazon Resource Name (ARN) of the source DB instance for the replicated automated backups, for example, `arn:aws:rds:us-west-2:123456789012:db:mydatabase`. +* `retention_period` - (Optional, Forces new resource) The retention period for the replicated automated backups, defaults to `7`. +* `kms_key_id` - (Optional, Forces new resource) The AWS KMS key identifier for encryption of the replicated automated backups. The KMS key ID is the Amazon Resource Name (ARN) for the KMS encryption key in the destination AWS Region, for example, `arn:aws:kms:us-east-1:123456789012:key/AKIAIOSFODNN7EXAMPLE`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The Amazon Resource Name (ARN) of the replicated automated backups. +* `source_db_instance_arn` - The Amazon Resource Name (ARN) of the source DB instance for the replicated automated backups. +* `retention_period` - The retention period for the replicated automated backups. +* `kms_key_id` - The AWS KMS key identifier for encryption of the replicated automated backups. + +## Import + +RDS instance automated backup replication can be imported using the `arn`, e.g., + +``` +$ terraform import aws_db_instance_automated_backup_replication.default arn:aws:rds:us-east-1:123456789012:auto-backup:ab-faaa2mgdj1vmp4xflr7yhsrmtbtob7ltrzzz2my +``` From bbb84a44fae2b453c386f161f5c322b3099b954d Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 24 Mar 2022 21:32:10 +0100 Subject: [PATCH 10/32] terrafmt `testAccInstanceAutomatedBackupReplicationConfig_kmsEncrypted` --- .../service/rds/instance_automated_backup_replication_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/rds/instance_automated_backup_replication_test.go b/internal/service/rds/instance_automated_backup_replication_test.go index b00ea07ec47d..06fe89a2a3cb 100644 --- a/internal/service/rds/instance_automated_backup_replication_test.go +++ b/internal/service/rds/instance_automated_backup_replication_test.go @@ -151,8 +151,8 @@ func testAccInstanceAutomatedBackupReplicationConfig_kmsEncrypted(rName string) acctest.ConfigMultipleRegionProvider(2), fmt.Sprintf(` resource "aws_kms_key" "test" { - description = %[1]q - provider = "awsalternate" + description = %[1]q + provider = "awsalternate" } resource "aws_db_instance" "test" { From 411d4e70fe6b38edcb187f1ae0033a5e3bfefe7f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 24 Mar 2022 21:44:43 +0100 Subject: [PATCH 11/32] Create CHANGELOG entry --- .changelog/23759.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/23759.txt diff --git a/.changelog/23759.txt b/.changelog/23759.txt new file mode 100644 index 000000000000..69b3ba75cb89 --- /dev/null +++ b/.changelog/23759.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_db_instance_automated_backup_replication +``` From 0dc91aac0d88b97efe280ac22d40dc24c56f7feb Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 24 Mar 2022 21:59:11 +0100 Subject: [PATCH 12/32] Update db_instance_automated_backup_replication.markdown --- ...ance_automated_backup_replication.markdown | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/website/docs/r/db_instance_automated_backup_replication.markdown b/website/docs/r/db_instance_automated_backup_replication.markdown index 36fb65b46051..91eac3f5aabd 100644 --- a/website/docs/r/db_instance_automated_backup_replication.markdown +++ b/website/docs/r/db_instance_automated_backup_replication.markdown @@ -12,10 +12,60 @@ Manage cross-region replication of automated backups to a different AWS Region. * [Replicating automated backups to another AWS Region](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReplicateBackups.html) +-> **Note:** This resource has to be created in the destinaton region. + ## Example Usage ```terraform resource "aws_db_instance_automated_backup_replication" "default" { source_db_instance_arn = "arn:aws:rds:us-west-2:123456789012:db:mydatabase" + retention_period = 14 +} +``` + +## Encrypting the automated backup with KMS +```terraform +resource "aws_db_instance_automated_backup_replication" "default" { + source_db_instance_arn = "arn:aws:rds:us-west-2:123456789012:db:mydatabase" + kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012" +} +``` + +## Example including a RDS DB instance +```terraform +provider "aws" { + region = "us-east-1" +} + +provider "aws" { + region = "us-west-2" + alias = "replica" +} + +resource "aws_db_instance" "default" { + allocated_storage = 10 + identifier = "mydb" + engine = "postgres" + engine_version = "13.4" + instance_class = "db.t3.micro" + name = "mydb" + username = "masterusername" + password = "mustbeeightcharacters" + backup_retention_period = 7 + storage_encrypted = true + skip_final_snapshot = true +} + +resource "aws_kms_key" "default" { + description = "Encryption key for automated backups" + + provider = "aws.replica" +} + +resource "aws_db_instance_automated_backup_replication" "default" { + source_db_instance_arn = aws_db_instance.default.arn + kms_key_id = aws_kms_key.default.arn + + provider = "aws.replica" } ``` From ede999b71cc192a5362001e843213b51a2c04047 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 24 Mar 2022 22:05:03 +0100 Subject: [PATCH 13/32] Surround fenced code blocks with blank links and fix typo --- .../docs/r/db_instance_automated_backup_replication.markdown | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/website/docs/r/db_instance_automated_backup_replication.markdown b/website/docs/r/db_instance_automated_backup_replication.markdown index 91eac3f5aabd..d5ebd1e16571 100644 --- a/website/docs/r/db_instance_automated_backup_replication.markdown +++ b/website/docs/r/db_instance_automated_backup_replication.markdown @@ -12,9 +12,10 @@ Manage cross-region replication of automated backups to a different AWS Region. * [Replicating automated backups to another AWS Region](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReplicateBackups.html) --> **Note:** This resource has to be created in the destinaton region. +-> **Note:** This resource has to be created in the destination region. ## Example Usage + ```terraform resource "aws_db_instance_automated_backup_replication" "default" { source_db_instance_arn = "arn:aws:rds:us-west-2:123456789012:db:mydatabase" @@ -23,6 +24,7 @@ resource "aws_db_instance_automated_backup_replication" "default" { ``` ## Encrypting the automated backup with KMS + ```terraform resource "aws_db_instance_automated_backup_replication" "default" { source_db_instance_arn = "arn:aws:rds:us-west-2:123456789012:db:mydatabase" @@ -31,6 +33,7 @@ resource "aws_db_instance_automated_backup_replication" "default" { ``` ## Example including a RDS DB instance + ```terraform provider "aws" { region = "us-east-1" From b27db95e3a42816d74ecec177a16438b1d2fe49e Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 24 Mar 2022 22:08:33 +0100 Subject: [PATCH 14/32] Remove tab --- .../service/rds/instance_automated_backup_replication_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/rds/instance_automated_backup_replication_test.go b/internal/service/rds/instance_automated_backup_replication_test.go index 06fe89a2a3cb..1bce4680da98 100644 --- a/internal/service/rds/instance_automated_backup_replication_test.go +++ b/internal/service/rds/instance_automated_backup_replication_test.go @@ -154,7 +154,7 @@ resource "aws_kms_key" "test" { description = %[1]q provider = "awsalternate" } - + resource "aws_db_instance" "test" { allocated_storage = 10 identifier = %[1]q From c7d9fff784cc8e884af0c84636037a6c3e70b607 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen <58337159+bschaatsbergen@users.noreply.github.com> Date: Thu, 24 Mar 2022 22:21:43 +0100 Subject: [PATCH 15/32] Update db_instance_automated_backup_replication.markdown --- .../docs/r/db_instance_automated_backup_replication.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/db_instance_automated_backup_replication.markdown b/website/docs/r/db_instance_automated_backup_replication.markdown index d5ebd1e16571..31886c811350 100644 --- a/website/docs/r/db_instance_automated_backup_replication.markdown +++ b/website/docs/r/db_instance_automated_backup_replication.markdown @@ -14,7 +14,7 @@ Manage cross-region replication of automated backups to a different AWS Region. -> **Note:** This resource has to be created in the destination region. -## Example Usage +## Example usage ```terraform resource "aws_db_instance_automated_backup_replication" "default" { From 6b7cea212913c0652bfc0359433e1fa5d31b0196 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 24 Mar 2022 22:29:12 +0100 Subject: [PATCH 16/32] Revert "Update db_instance_automated_backup_replication.markdown" This reverts commit c7d9fff784cc8e884af0c84636037a6c3e70b607. --- .../docs/r/db_instance_automated_backup_replication.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/db_instance_automated_backup_replication.markdown b/website/docs/r/db_instance_automated_backup_replication.markdown index 31886c811350..d5ebd1e16571 100644 --- a/website/docs/r/db_instance_automated_backup_replication.markdown +++ b/website/docs/r/db_instance_automated_backup_replication.markdown @@ -14,7 +14,7 @@ Manage cross-region replication of automated backups to a different AWS Region. -> **Note:** This resource has to be created in the destination region. -## Example usage +## Example Usage ```terraform resource "aws_db_instance_automated_backup_replication" "default" { From 1506c504b73cdcdd791d0764fae790a6c970416a Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 24 Mar 2022 23:20:46 +0100 Subject: [PATCH 17/32] Move retained status check to `resourceInstanceAutomatedBackupReplicationRead` op --- .../instance_automated_backup_replication.go | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/internal/service/rds/instance_automated_backup_replication.go b/internal/service/rds/instance_automated_backup_replication.go index ca730e7d1e2a..6b8c0ddc7efe 100644 --- a/internal/service/rds/instance_automated_backup_replication.go +++ b/internal/service/rds/instance_automated_backup_replication.go @@ -100,9 +100,17 @@ func resourceInstanceAutomatedBackupReplicationRead(d *schema.ResourceData, meta for _, backup := range output.DBInstanceAutomatedBackups { if aws.StringValue(backup.DBInstanceAutomatedBackupsArn) == d.Id() { - d.Set("source_db_instance_arn", backup.DBInstanceArn) - d.Set("kms_key_id", backup.KmsKeyId) - d.Set("retention_period", backup.BackupRetentionPeriod) + // Check if the automated backup is retained + if aws.StringValue(backup.Status) == dbInstanceAutomatedBackupReplicationRetained { + log.Printf("[WARN] RDS instance automated backup replication is retained, removing from state: %s", d.Id()) + d.SetId("") + return nil // If the automated backup is retained, the replication is stopped. + } else { + d.Set("source_db_instance_arn", backup.DBInstanceArn) + d.Set("kms_key_id", backup.KmsKeyId) + d.Set("retention_period", backup.BackupRetentionPeriod) + } + } else { return fmt.Errorf("unable to find RDS instance automated backup replication: %s", d.Id()) } @@ -131,12 +139,6 @@ func resourceInstanceAutomatedBackupReplicationDelete(d *schema.ResourceData, me } else { return fmt.Errorf("unable to find RDS instance automated backup replication: %s", d.Id()) } - // Check if the automated backup is retained - if aws.StringValue(backup.Status) == dbInstanceAutomatedBackupReplicationRetained { - log.Printf("[WARN] RDS instance automated backup replication is retained, removing from state: %s", d.Id()) - d.SetId("") - return nil // If the automated backup is retained, it's 'deleted' - } } if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { From 2dc70db0f5c5865c37b1939c24aaccf70eebb2fe Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 24 Mar 2022 23:27:10 +0100 Subject: [PATCH 18/32] Remove NotFound check in delete op, this is already handled in the read --- .../service/rds/instance_automated_backup_replication.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/internal/service/rds/instance_automated_backup_replication.go b/internal/service/rds/instance_automated_backup_replication.go index 6b8c0ddc7efe..ee73d2f8ea88 100644 --- a/internal/service/rds/instance_automated_backup_replication.go +++ b/internal/service/rds/instance_automated_backup_replication.go @@ -141,12 +141,6 @@ func resourceInstanceAutomatedBackupReplicationDelete(d *schema.ResourceData, me } } - if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { - log.Printf("[WARN] RDS instance automated backup replication not found, removing from state: %s", d.Id()) - d.SetId("") - return nil // The resource is already deleted or was never created - } - if err != nil { return fmt.Errorf("error reading RDS instance automated backup replication: %s", err) } From de608b47d4894a55c28c1511c130d255a947375e Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 25 Mar 2022 00:11:06 +0100 Subject: [PATCH 19/32] Update instance_automated_backup_replication_test.go --- .../rds/instance_automated_backup_replication_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/rds/instance_automated_backup_replication_test.go b/internal/service/rds/instance_automated_backup_replication_test.go index 1bce4680da98..b157c7b3fc48 100644 --- a/internal/service/rds/instance_automated_backup_replication_test.go +++ b/internal/service/rds/instance_automated_backup_replication_test.go @@ -24,7 +24,7 @@ func TestAccRDSInstanceAutomatedBackupReplication_basic(t *testing.T) { PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), ProviderFactories: acctest.FactoriesAlternate(&providers), - CheckDestroy: testAccCheckInstanceRoleAssociationDestroy, + CheckDestroy: testAccCheckInstanceAutomatedBackupReplicationDestroy, Steps: []resource.TestStep{ { Config: testAccInstanceAutomatedBackupReplicationConfig(rName), @@ -51,7 +51,7 @@ func TestAccRDSInstanceAutomatedBackupReplication_retentionPeriod(t *testing.T) PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), ProviderFactories: acctest.FactoriesAlternate(&providers), - CheckDestroy: testAccCheckInstanceRoleAssociationDestroy, + CheckDestroy: testAccCheckInstanceAutomatedBackupReplicationDestroy, Steps: []resource.TestStep{ { Config: testAccInstanceAutomatedBackupReplicationConfig_retentionPeriod(rName), @@ -78,7 +78,7 @@ func TestAccRDSInstanceAutomatedBackupReplication_kmsEncrypted(t *testing.T) { PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), ProviderFactories: acctest.FactoriesAlternate(&providers), - CheckDestroy: testAccCheckInstanceRoleAssociationDestroy, + CheckDestroy: testAccCheckInstanceAutomatedBackupReplicationDestroy, Steps: []resource.TestStep{ { Config: testAccInstanceAutomatedBackupReplicationConfig_kmsEncrypted(rName), From c990f490bf7f9cb3ee33aae0f200e3cacd7dd2da Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 28 Mar 2022 23:47:30 +0200 Subject: [PATCH 20/32] Fix acceptance tests, iterate through CheckDestroy response --- ...tance_automated_backup_replication_test.go | 69 +++++++++++++------ 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/internal/service/rds/instance_automated_backup_replication_test.go b/internal/service/rds/instance_automated_backup_replication_test.go index b157c7b3fc48..8e5a187978da 100644 --- a/internal/service/rds/instance_automated_backup_replication_test.go +++ b/internal/service/rds/instance_automated_backup_replication_test.go @@ -4,8 +4,9 @@ import ( "fmt" "testing" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/rds" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -14,14 +15,25 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" ) +const ( + dbInstanceAutomatedBackupReplicationRetained = "retained" +) + func TestAccRDSInstanceAutomatedBackupReplication_basic(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_db_instance_automated_backup_replication.test" var providers []*schema.Provider resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckMultipleRegion(t, 2) + }, ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), ProviderFactories: acctest.FactoriesAlternate(&providers), CheckDestroy: testAccCheckInstanceAutomatedBackupReplicationDestroy, @@ -42,13 +54,20 @@ func TestAccRDSInstanceAutomatedBackupReplication_basic(t *testing.T) { } func TestAccRDSInstanceAutomatedBackupReplication_retentionPeriod(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_db_instance_automated_backup_replication.test" var providers []*schema.Provider resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckMultipleRegion(t, 2) + }, ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), ProviderFactories: acctest.FactoriesAlternate(&providers), CheckDestroy: testAccCheckInstanceAutomatedBackupReplicationDestroy, @@ -69,13 +88,20 @@ func TestAccRDSInstanceAutomatedBackupReplication_retentionPeriod(t *testing.T) } func TestAccRDSInstanceAutomatedBackupReplication_kmsEncrypted(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_db_instance_automated_backup_replication.test" var providers []*schema.Provider resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckMultipleRegion(t, 2) + }, ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), ProviderFactories: acctest.FactoriesAlternate(&providers), CheckDestroy: testAccCheckInstanceAutomatedBackupReplicationDestroy, @@ -182,29 +208,32 @@ func testAccCheckInstanceAutomatedBackupReplicationDestroy(s *terraform.State) e conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_db_instance_automated_backup_replication" { + if rs.Type != "aws_rds_cluster" { continue } - input := &rds.DescribeDBInstanceAutomatedBackupsInput{ - DBInstanceAutomatedBackupsArn: &rs.Primary.ID, + // Try to find the Group + var err error + resp, err := conn.DescribeDBInstanceAutomatedBackups( + &rds.DescribeDBInstanceAutomatedBackupsInput{ + DBInstanceAutomatedBackupsArn: aws.String(rs.Primary.ID), + }) + + if err == nil { + if len(resp.DBInstanceAutomatedBackups) != 0 && + *resp.DBInstanceAutomatedBackups[0].DBInstanceAutomatedBackupsArn == rs.Primary.ID { + return fmt.Errorf("DB Instance Automated Backup still exists, %s", rs.Primary.ID) + } } - output, err := conn.DescribeDBInstanceAutomatedBackups(input) - - if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { - continue - } - - if err != nil { - return err - } - - if output == nil { - continue + // Return nil if the cluster is already destroyed + if awsErr, ok := err.(awserr.Error); ok { + if awsErr.Code() == rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault { + return nil + } } - return fmt.Errorf("RDS instance backup replication %q still exists", rs.Primary.ID) + return err } return nil From 8ade2a2f1014a33f452acfd9848f19609cfff013 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Tue, 29 Mar 2022 09:58:55 +0200 Subject: [PATCH 21/32] Removed unused const `dbInstanceAutomatedBackupReplicationRetained` --- .../service/rds/instance_automated_backup_replication_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/service/rds/instance_automated_backup_replication_test.go b/internal/service/rds/instance_automated_backup_replication_test.go index 8e5a187978da..d37eae0ce444 100644 --- a/internal/service/rds/instance_automated_backup_replication_test.go +++ b/internal/service/rds/instance_automated_backup_replication_test.go @@ -15,10 +15,6 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" ) -const ( - dbInstanceAutomatedBackupReplicationRetained = "retained" -) - func TestAccRDSInstanceAutomatedBackupReplication_basic(t *testing.T) { if testing.Short() { t.Skip("skipping long-running test in short mode") From e4ff8dea49e2f4b4bf4e161df52968b3150dd402 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Mar 2022 08:48:59 -0400 Subject: [PATCH 22/32] r/aws_db_instance_automated_backup_replication: Alphabetize attributes. --- .../rds/instance_automated_backup_replication.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/service/rds/instance_automated_backup_replication.go b/internal/service/rds/instance_automated_backup_replication.go index ee73d2f8ea88..822d860577c1 100644 --- a/internal/service/rds/instance_automated_backup_replication.go +++ b/internal/service/rds/instance_automated_backup_replication.go @@ -27,12 +27,6 @@ func ResourceInstanceAutomatedBackupReplication() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "source_db_instance_arn": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: verify.ValidARN, - }, "kms_key_id": { Type: schema.TypeString, Optional: true, @@ -46,6 +40,12 @@ func ResourceInstanceAutomatedBackupReplication() *schema.Resource { Optional: true, Default: 7, }, + "source_db_instance_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: verify.ValidARN, + }, }, } } From d938b63664bf047993d120a660c758e38d6f3b72 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Mar 2022 08:54:26 -0400 Subject: [PATCH 23/32] r/aws_db_instance_automated_backup_replication: No need to document attributes that are arguments. --- .../docs/r/db_instance_automated_backup_replication.markdown | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/website/docs/r/db_instance_automated_backup_replication.markdown b/website/docs/r/db_instance_automated_backup_replication.markdown index d5ebd1e16571..2f7a14e69c5d 100644 --- a/website/docs/r/db_instance_automated_backup_replication.markdown +++ b/website/docs/r/db_instance_automated_backup_replication.markdown @@ -76,7 +76,7 @@ resource "aws_db_instance_automated_backup_replication" "default" { The following arguments are supported: -* `source_db_instance_arn` - (Optional, Forces new resource) The Amazon Resource Name (ARN) of the source DB instance for the replicated automated backups, for example, `arn:aws:rds:us-west-2:123456789012:db:mydatabase`. +* `source_db_instance_arn` - (Required, Forces new resource) The Amazon Resource Name (ARN) of the source DB instance for the replicated automated backups, for example, `arn:aws:rds:us-west-2:123456789012:db:mydatabase`. * `retention_period` - (Optional, Forces new resource) The retention period for the replicated automated backups, defaults to `7`. * `kms_key_id` - (Optional, Forces new resource) The AWS KMS key identifier for encryption of the replicated automated backups. The KMS key ID is the Amazon Resource Name (ARN) for the KMS encryption key in the destination AWS Region, for example, `arn:aws:kms:us-east-1:123456789012:key/AKIAIOSFODNN7EXAMPLE`. @@ -85,9 +85,6 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `id` - The Amazon Resource Name (ARN) of the replicated automated backups. -* `source_db_instance_arn` - The Amazon Resource Name (ARN) of the source DB instance for the replicated automated backups. -* `retention_period` - The retention period for the replicated automated backups. -* `kms_key_id` - The AWS KMS key identifier for encryption of the replicated automated backups. ## Import From 050331d4094a5b2877b1fea7d9aa9a975bf90872 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Mar 2022 08:59:13 -0400 Subject: [PATCH 24/32] r/aws_db_instance_automated_backup_replication: 'waitDBInstanceAutomatedBackupAvailable' returns 'rds.DBInstanceAutomatedBackup'. --- internal/service/rds/wait.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/internal/service/rds/wait.go b/internal/service/rds/wait.go index dc3bf6b83154..a87853b93129 100644 --- a/internal/service/rds/wait.go +++ b/internal/service/rds/wait.go @@ -235,21 +235,17 @@ func waitDBClusterInstanceDeleted(conn *rds.RDS, id string, timeout time.Duratio return nil, err } -func waitDBInstanceAutomatedBackupAvailable(conn *rds.RDS, arn string, timeout time.Duration) (*rds.DBInstance, error) { +func waitDBInstanceAutomatedBackupAvailable(conn *rds.RDS, arn string, timeout time.Duration) (*rds.DBInstanceAutomatedBackup, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{ - InstanceAutomatedBackupPending, - }, - Target: []string{ - InstanceAutomatedBackupReplicating, - }, + Pending: []string{InstanceAutomatedBackupPending}, + Target: []string{InstanceAutomatedBackupReplicating}, Refresh: statusDBInstanceAutomatedBackup(conn, arn), Timeout: timeout, } outputRaw, err := stateConf.WaitForState() - if output, ok := outputRaw.(*rds.DBInstance); ok { + if output, ok := outputRaw.(*rds.DBInstanceAutomatedBackup); ok { return output, err } From 7b4046f21c5a4c088ef2aa1c33af4524b4e49c1d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Mar 2022 09:12:07 -0400 Subject: [PATCH 25/32] r/aws_db_instance_automated_backup_replication: 'FindDBInstanceAutomatedBackupByID' -> 'FindDBInstanceAutomatedBackupByARN'. --- internal/service/rds/consts.go | 5 +++-- internal/service/rds/find.go | 31 ++++++++++++++++++++++++++++--- internal/service/rds/status.go | 4 ++-- internal/service/rds/wait.go | 4 ++-- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/internal/service/rds/consts.go b/internal/service/rds/consts.go index e5cc7654776f..add45745ed46 100644 --- a/internal/service/rds/consts.go +++ b/internal/service/rds/consts.go @@ -38,8 +38,9 @@ const ( ) const ( - InstanceAutomatedBackupPending = "pending" - InstanceAutomatedBackupReplicating = "replicating" + InstanceAutomatedBackupStatusPending = "pending" + InstanceAutomatedBackupStatusReplicating = "replicating" + InstanceAutomatedBackupStatusRetained = "retained" ) const ( diff --git a/internal/service/rds/find.go b/internal/service/rds/find.go index aeb3026e394e..5c3f74f08463 100644 --- a/internal/service/rds/find.go +++ b/internal/service/rds/find.go @@ -190,11 +190,36 @@ func FindEventSubscriptionByID(conn *rds.RDS, id string) (*rds.EventSubscription return output.EventSubscriptionsList[0], nil } -func FindDBInstanceAutomatedBackupByID(conn *rds.RDS, id string) (*rds.DBInstanceAutomatedBackup, error) { +func FindDBInstanceAutomatedBackupByARN(conn *rds.RDS, arn string) (*rds.DBInstanceAutomatedBackup, error) { input := &rds.DescribeDBInstanceAutomatedBackupsInput{ - DBInstanceAutomatedBackupsArn: aws.String(id), + DBInstanceAutomatedBackupsArn: aws.String(arn), } + output, err := FindDBInstanceAutomatedBackup(conn, input) + + if err != nil { + return nil, err + } + + if status := aws.StringValue(output.Status); status == InstanceAutomatedBackupStatusRetained { + // If the automated backup is retained, the replication is stopped. + return nil, &resource.NotFoundError{ + Message: status, + LastRequest: input, + } + } + + // Eventual consistency check. + if aws.StringValue(output.DBInstanceAutomatedBackupsArn) != arn { + return nil, &resource.NotFoundError{ + LastRequest: input, + } + } + + return output, nil +} + +func FindDBInstanceAutomatedBackup(conn *rds.RDS, input *rds.DescribeDBInstanceAutomatedBackupsInput) (*rds.DBInstanceAutomatedBackup, error) { output, err := conn.DescribeDBInstanceAutomatedBackups(input) if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { @@ -204,7 +229,7 @@ func FindDBInstanceAutomatedBackupByID(conn *rds.RDS, id string) (*rds.DBInstanc } } - if output == nil || len(output.DBInstanceAutomatedBackups) == 0 { + if output == nil || len(output.DBInstanceAutomatedBackups) == 0 || output.DBInstanceAutomatedBackups[0] == nil { return nil, tfresource.NewEmptyResultError(input) } diff --git a/internal/service/rds/status.go b/internal/service/rds/status.go index 276b198c3500..d9bac6f1d8cb 100644 --- a/internal/service/rds/status.go +++ b/internal/service/rds/status.go @@ -80,9 +80,9 @@ func statusDBInstance(conn *rds.RDS, id string) resource.StateRefreshFunc { } } -func statusDBInstanceAutomatedBackup(conn *rds.RDS, id string) resource.StateRefreshFunc { +func statusDBInstanceAutomatedBackup(conn *rds.RDS, arn string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := FindDBInstanceAutomatedBackupByID(conn, id) + output, err := FindDBInstanceAutomatedBackupByARN(conn, arn) if tfresource.NotFound(err) { return nil, "", nil diff --git a/internal/service/rds/wait.go b/internal/service/rds/wait.go index a87853b93129..b5c9b8c7edf1 100644 --- a/internal/service/rds/wait.go +++ b/internal/service/rds/wait.go @@ -237,8 +237,8 @@ func waitDBClusterInstanceDeleted(conn *rds.RDS, id string, timeout time.Duratio func waitDBInstanceAutomatedBackupAvailable(conn *rds.RDS, arn string, timeout time.Duration) (*rds.DBInstanceAutomatedBackup, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{InstanceAutomatedBackupPending}, - Target: []string{InstanceAutomatedBackupReplicating}, + Pending: []string{InstanceAutomatedBackupStatusPending}, + Target: []string{InstanceAutomatedBackupStatusReplicating}, Refresh: statusDBInstanceAutomatedBackup(conn, arn), Timeout: timeout, } From 392d369d4caf39e3f9e9297ab72a9903fd0b48f9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Mar 2022 10:09:59 -0400 Subject: [PATCH 26/32] r/aws_db_instance_automated_backup_replication: Use 'FindDBInstanceAutomatedBackupByARN'. --- .../instance_automated_backup_replication.go | 47 ++++--------- ...tance_automated_backup_replication_test.go | 70 +++++++++++-------- 2 files changed, 54 insertions(+), 63 deletions(-) diff --git a/internal/service/rds/instance_automated_backup_replication.go b/internal/service/rds/instance_automated_backup_replication.go index 822d860577c1..5a7255fcfd42 100644 --- a/internal/service/rds/instance_automated_backup_replication.go +++ b/internal/service/rds/instance_automated_backup_replication.go @@ -6,16 +6,12 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" ) -const ( - dbInstanceAutomatedBackupReplicationRetained = "retained" -) - func ResourceInstanceAutomatedBackupReplication() *schema.Resource { return &schema.Resource{ Create: resourceInstanceAutomatedBackupReplicationCreate, @@ -54,26 +50,25 @@ func resourceInstanceAutomatedBackupReplicationCreate(d *schema.ResourceData, me conn := meta.(*conns.AWSClient).RDSConn input := &rds.StartDBInstanceAutomatedBackupsReplicationInput{ - SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), BackupRetentionPeriod: aws.Int64(int64(d.Get("retention_period").(int))), + SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), } if v, ok := d.GetOk("kms_key_id"); ok { input.KmsKeyId = aws.String(v.(string)) } - log.Printf("[DEBUG] Starting RDS instance automated backup replication for: %s", *input.SourceDBInstanceArn) - + log.Printf("[DEBUG] Creating RDS instance automated backup replication: %s", input) output, err := conn.StartDBInstanceAutomatedBackupsReplication(input) if err != nil { - return fmt.Errorf("error creating RDS instance automated backup replication: %s", err) + return fmt.Errorf("error creating RDS instance automated backup replication: %w", err) } d.SetId(aws.StringValue(output.DBInstanceAutomatedBackup.DBInstanceAutomatedBackupsArn)) if _, err := waitDBInstanceAutomatedBackupAvailable(conn, d.Id(), d.Timeout(schema.TimeoutDefault)); err != nil { - return fmt.Errorf("error waiting for DB instance automated backup (%s) creation: %w", d.Id(), err) + return fmt.Errorf("error waiting for DB instance automated backup (%s) create: %w", d.Id(), err) } return resourceInstanceAutomatedBackupReplicationRead(d, meta) @@ -82,39 +77,21 @@ func resourceInstanceAutomatedBackupReplicationCreate(d *schema.ResourceData, me func resourceInstanceAutomatedBackupReplicationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).RDSConn - input := &rds.DescribeDBInstanceAutomatedBackupsInput{ - DBInstanceAutomatedBackupsArn: aws.String(d.Id()), - } - - output, err := conn.DescribeDBInstanceAutomatedBackups(input) + backup, err := FindDBInstanceAutomatedBackupByARN(conn, d.Id()) - if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { - log.Printf("[WARN] RDS instance automated backup replication not found, removing from state: %s", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] RDS instance automated backup replication %s not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error reading RDS instance automated backup replication: %s", err) + return fmt.Errorf("error reading RDS instance automated backup replication (%s): %w", d.Id(), err) } - for _, backup := range output.DBInstanceAutomatedBackups { - if aws.StringValue(backup.DBInstanceAutomatedBackupsArn) == d.Id() { - // Check if the automated backup is retained - if aws.StringValue(backup.Status) == dbInstanceAutomatedBackupReplicationRetained { - log.Printf("[WARN] RDS instance automated backup replication is retained, removing from state: %s", d.Id()) - d.SetId("") - return nil // If the automated backup is retained, the replication is stopped. - } else { - d.Set("source_db_instance_arn", backup.DBInstanceArn) - d.Set("kms_key_id", backup.KmsKeyId) - d.Set("retention_period", backup.BackupRetentionPeriod) - } - - } else { - return fmt.Errorf("unable to find RDS instance automated backup replication: %s", d.Id()) - } - } + d.Set("kms_key_id", backup.KmsKeyId) + d.Set("retention_period", backup.BackupRetentionPeriod) + d.Set("source_db_instance_arn", backup.DBInstanceArn) return nil } diff --git a/internal/service/rds/instance_automated_backup_replication_test.go b/internal/service/rds/instance_automated_backup_replication_test.go index d37eae0ce444..1394bbcd8363 100644 --- a/internal/service/rds/instance_automated_backup_replication_test.go +++ b/internal/service/rds/instance_automated_backup_replication_test.go @@ -4,8 +4,6 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/rds" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -13,6 +11,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfrds "github.com/hashicorp/terraform-provider-aws/internal/service/rds" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func TestAccRDSInstanceAutomatedBackupReplication_basic(t *testing.T) { @@ -37,6 +37,7 @@ func TestAccRDSInstanceAutomatedBackupReplication_basic(t *testing.T) { { Config: testAccInstanceAutomatedBackupReplicationConfig(rName), Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceAutomatedBackupReplicationExist(resourceName), resource.TestCheckResourceAttr(resourceName, "retention_period", "7"), ), }, @@ -71,6 +72,7 @@ func TestAccRDSInstanceAutomatedBackupReplication_retentionPeriod(t *testing.T) { Config: testAccInstanceAutomatedBackupReplicationConfig_retentionPeriod(rName), Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceAutomatedBackupReplicationExist(resourceName), resource.TestCheckResourceAttr(resourceName, "retention_period", "14"), ), }, @@ -105,6 +107,7 @@ func TestAccRDSInstanceAutomatedBackupReplication_kmsEncrypted(t *testing.T) { { Config: testAccInstanceAutomatedBackupReplicationConfig_kmsEncrypted(rName), Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceAutomatedBackupReplicationExist(resourceName), resource.TestCheckResourceAttr(resourceName, "retention_period", "7"), ), }, @@ -132,12 +135,12 @@ resource "aws_db_instance" "test" { password = "mustbeeightcharacters" backup_retention_period = 7 skip_final_snapshot = true + + provider = "awsalternate" } resource "aws_db_instance_automated_backup_replication" "test" { source_db_instance_arn = aws_db_instance.test.arn - - provider = "awsalternate" } `, rName)) } @@ -157,13 +160,13 @@ resource "aws_db_instance" "test" { password = "mustbeeightcharacters" backup_retention_period = 7 skip_final_snapshot = true + + provider = "awsalternate" } resource "aws_db_instance_automated_backup_replication" "test" { source_db_instance_arn = aws_db_instance.test.arn retention_period = 14 - - provider = "awsalternate" } `, rName)) } @@ -174,7 +177,6 @@ func testAccInstanceAutomatedBackupReplicationConfig_kmsEncrypted(rName string) fmt.Sprintf(` resource "aws_kms_key" "test" { description = %[1]q - provider = "awsalternate" } resource "aws_db_instance" "test" { @@ -189,47 +191,59 @@ resource "aws_db_instance" "test" { backup_retention_period = 7 storage_encrypted = true skip_final_snapshot = true + + provider = "awsalternate" } resource "aws_db_instance_automated_backup_replication" "test" { source_db_instance_arn = aws_db_instance.test.arn kms_key_id = aws_kms_key.test.arn - - provider = "awsalternate" } `, rName)) } +func testAccCheckInstanceAutomatedBackupReplicationExist(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 RDS instance automated backup replication ID is set") + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn + + _, err := tfrds.FindDBInstanceAutomatedBackupByARN(conn, rs.Primary.ID) + + if err != nil { + return err + } + + return nil + } +} + func testAccCheckInstanceAutomatedBackupReplicationDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_rds_cluster" { + if rs.Type != "aws_db_instance_automated_backup_replication" { continue } - // Try to find the Group - var err error - resp, err := conn.DescribeDBInstanceAutomatedBackups( - &rds.DescribeDBInstanceAutomatedBackupsInput{ - DBInstanceAutomatedBackupsArn: aws.String(rs.Primary.ID), - }) - - if err == nil { - if len(resp.DBInstanceAutomatedBackups) != 0 && - *resp.DBInstanceAutomatedBackups[0].DBInstanceAutomatedBackupsArn == rs.Primary.ID { - return fmt.Errorf("DB Instance Automated Backup still exists, %s", rs.Primary.ID) - } + _, err := tfrds.FindDBInstanceAutomatedBackupByARN(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue } - // Return nil if the cluster is already destroyed - if awsErr, ok := err.(awserr.Error); ok { - if awsErr.Code() == rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault { - return nil - } + if err != nil { + return err } - return err + return fmt.Errorf("RDS instance automated backup replication %s still exists", rs.Primary.ID) } return nil From b4f4967609eb78aeef3f509a05c0917b973613f9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Mar 2022 13:41:31 -0400 Subject: [PATCH 27/32] Derive source DB region from its ARN. --- internal/service/rds/find.go | 44 +++++++++++++-- .../instance_automated_backup_replication.go | 55 ++++++++----------- 2 files changed, 61 insertions(+), 38 deletions(-) diff --git a/internal/service/rds/find.go b/internal/service/rds/find.go index 5c3f74f08463..04e9d5c9b19a 100644 --- a/internal/service/rds/find.go +++ b/internal/service/rds/find.go @@ -195,7 +195,7 @@ func FindDBInstanceAutomatedBackupByARN(conn *rds.RDS, arn string) (*rds.DBInsta DBInstanceAutomatedBackupsArn: aws.String(arn), } - output, err := FindDBInstanceAutomatedBackup(conn, input) + output, err := findDBInstanceAutomatedBackup(conn, input) if err != nil { return nil, err @@ -219,8 +219,40 @@ func FindDBInstanceAutomatedBackupByARN(conn *rds.RDS, arn string) (*rds.DBInsta return output, nil } -func FindDBInstanceAutomatedBackup(conn *rds.RDS, input *rds.DescribeDBInstanceAutomatedBackupsInput) (*rds.DBInstanceAutomatedBackup, error) { - output, err := conn.DescribeDBInstanceAutomatedBackups(input) +func findDBInstanceAutomatedBackup(conn *rds.RDS, input *rds.DescribeDBInstanceAutomatedBackupsInput) (*rds.DBInstanceAutomatedBackup, error) { + output, err := findDBInstanceAutomatedBackups(conn, input) + + if err != nil { + return nil, err + } + + if len(output) == 0 || output[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if count := len(output); count > 1 { + return nil, tfresource.NewTooManyResultsError(count, input) + } + + return output[0], nil +} + +func findDBInstanceAutomatedBackups(conn *rds.RDS, input *rds.DescribeDBInstanceAutomatedBackupsInput) ([]*rds.DBInstanceAutomatedBackup, error) { + var output []*rds.DBInstanceAutomatedBackup + + err := conn.DescribeDBInstanceAutomatedBackupsPages(input, func(page *rds.DescribeDBInstanceAutomatedBackupsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.DBInstanceAutomatedBackups { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault) { return nil, &resource.NotFoundError{ @@ -229,9 +261,9 @@ func FindDBInstanceAutomatedBackup(conn *rds.RDS, input *rds.DescribeDBInstanceA } } - if output == nil || len(output.DBInstanceAutomatedBackups) == 0 || output.DBInstanceAutomatedBackups[0] == nil { - return nil, tfresource.NewEmptyResultError(input) + if err != nil { + return nil, err } - return output.DBInstanceAutomatedBackups[0], nil + return output, nil } diff --git a/internal/service/rds/instance_automated_backup_replication.go b/internal/service/rds/instance_automated_backup_replication.go index 5a7255fcfd42..4a22ebc3890b 100644 --- a/internal/service/rds/instance_automated_backup_replication.go +++ b/internal/service/rds/instance_automated_backup_replication.go @@ -5,6 +5,7 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -58,11 +59,11 @@ func resourceInstanceAutomatedBackupReplicationCreate(d *schema.ResourceData, me input.KmsKeyId = aws.String(v.(string)) } - log.Printf("[DEBUG] Creating RDS instance automated backup replication: %s", input) + log.Printf("[DEBUG] Starting RDS instance automated backup replication: %s", input) output, err := conn.StartDBInstanceAutomatedBackupsReplication(input) if err != nil { - return fmt.Errorf("error creating RDS instance automated backup replication: %w", err) + return fmt.Errorf("error starting RDS instance automated backup replication: %w", err) } d.SetId(aws.StringValue(output.DBInstanceAutomatedBackup.DBInstanceAutomatedBackupsArn)) @@ -97,53 +98,43 @@ func resourceInstanceAutomatedBackupReplicationRead(d *schema.ResourceData, meta } func resourceInstanceAutomatedBackupReplicationDelete(d *schema.ResourceData, meta interface{}) error { - var sourceDatabaseRegion string - var databaseIdentifier string - conn := meta.(*conns.AWSClient).RDSConn - describeInput := &rds.DescribeDBInstanceAutomatedBackupsInput{ - DBInstanceAutomatedBackupsArn: aws.String(d.Id()), - } - - describeOutput, err := conn.DescribeDBInstanceAutomatedBackups(describeInput) + backup, err := FindDBInstanceAutomatedBackupByARN(conn, d.Id()) - // Get and set the region of the source database and database identifier - for _, backup := range describeOutput.DBInstanceAutomatedBackups { - if aws.StringValue(backup.DBInstanceAutomatedBackupsArn) == d.Id() { - sourceDatabaseRegion = aws.StringValue(backup.Region) - databaseIdentifier = aws.StringValue(backup.DBInstanceIdentifier) - } else { - return fmt.Errorf("unable to find RDS instance automated backup replication: %s", d.Id()) - } + if tfresource.NotFound(err) { + return nil } if err != nil { - return fmt.Errorf("error reading RDS instance automated backup replication: %s", err) + return fmt.Errorf("error reading RDS instance automated backup replication (%s): %w", d.Id(), err) } - // Initiate a stop of the replication process - input := &rds.StopDBInstanceAutomatedBackupsReplicationInput{ - SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), - } + databaseID := aws.StringValue(backup.DBInstanceIdentifier) + sourceDatabaseARN, err := arn.Parse(aws.StringValue(backup.DBInstanceArn)) - log.Printf("[DEBUG] Stopping RDS instance automated backup replication for: %s", *input.SourceDBInstanceArn) + if err != nil { + return err + } - _, err = conn.StopDBInstanceAutomatedBackupsReplication(input) + log.Printf("[DEBUG] Stopping RDS instance automated backup replication: %s", d.Id()) + _, err = conn.StopDBInstanceAutomatedBackupsReplication(&rds.StopDBInstanceAutomatedBackupsReplicationInput{ + SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), + }) if err != nil { - return fmt.Errorf("error stopping RDS instance automated backup replication: %s", err) + return fmt.Errorf("error stopping RDS instance automated backup replication (%s): %w", d.Id(), err) } - // Create a new client to the source region + // Create a new client to the source region. sourceDatabaseConn := conn - if sourceDatabaseRegion != meta.(*conns.AWSClient).Region { - sourceDatabaseConn = rds.New(meta.(*conns.AWSClient).Session, aws.NewConfig().WithRegion(sourceDatabaseRegion)) + if sourceDatabaseARN.Region != meta.(*conns.AWSClient).Region { + sourceDatabaseConn = rds.New(meta.(*conns.AWSClient).Session, aws.NewConfig().WithRegion(sourceDatabaseARN.Region)) } - // Wait for the source database to be available after the replication is stopped - if _, err := waitDBInstanceAvailable(sourceDatabaseConn, databaseIdentifier, d.Timeout(schema.TimeoutDefault)); err != nil { - return fmt.Errorf("error waiting for DB Instance (%s) delete: %w", *input.SourceDBInstanceArn, err) + // Wait for the source database to be available after the replication is stopped. + if _, err := waitDBInstanceAvailable(sourceDatabaseConn, databaseID, d.Timeout(schema.TimeoutDefault)); err != nil { + return fmt.Errorf("error waiting for DB Instance (%s) to become available: %w", databaseID, err) } return nil From c6ad6a7da217312d5088a32cbde4bb32da5e9531 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Mar 2022 15:19:24 -0400 Subject: [PATCH 28/32] r/aws_db_instance_automated_backup_replication: Change the logic for waiting for deletion. Acceptance test output: % make testacc TESTS=TestAccRDSInstanceAutomatedBackupReplication_basic PKG=rds ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/rds/... -v -count 1 -parallel 20 -run='TestAccRDSInstanceAutomatedBackupReplication_basic' -timeout 180m === RUN TestAccRDSInstanceAutomatedBackupReplication_basic === PAUSE TestAccRDSInstanceAutomatedBackupReplication_basic === CONT TestAccRDSInstanceAutomatedBackupReplication_basic --- PASS: TestAccRDSInstanceAutomatedBackupReplication_basic (1340.32s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/rds 1345.529s --- .../instance_automated_backup_replication.go | 9 ++- internal/service/rds/status.go | 26 +++++++++ internal/service/rds/wait.go | 55 +++++++------------ 3 files changed, 50 insertions(+), 40 deletions(-) diff --git a/internal/service/rds/instance_automated_backup_replication.go b/internal/service/rds/instance_automated_backup_replication.go index 4a22ebc3890b..5a2a4e1d4db2 100644 --- a/internal/service/rds/instance_automated_backup_replication.go +++ b/internal/service/rds/instance_automated_backup_replication.go @@ -68,7 +68,7 @@ func resourceInstanceAutomatedBackupReplicationCreate(d *schema.ResourceData, me d.SetId(aws.StringValue(output.DBInstanceAutomatedBackup.DBInstanceAutomatedBackupsArn)) - if _, err := waitDBInstanceAutomatedBackupAvailable(conn, d.Id(), d.Timeout(schema.TimeoutDefault)); err != nil { + if _, err := waitDBInstanceAutomatedBackupCreated(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return fmt.Errorf("error waiting for DB instance automated backup (%s) create: %w", d.Id(), err) } @@ -110,7 +110,7 @@ func resourceInstanceAutomatedBackupReplicationDelete(d *schema.ResourceData, me return fmt.Errorf("error reading RDS instance automated backup replication (%s): %w", d.Id(), err) } - databaseID := aws.StringValue(backup.DBInstanceIdentifier) + dbInstanceID := aws.StringValue(backup.DBInstanceIdentifier) sourceDatabaseARN, err := arn.Parse(aws.StringValue(backup.DBInstanceArn)) if err != nil { @@ -132,9 +132,8 @@ func resourceInstanceAutomatedBackupReplicationDelete(d *schema.ResourceData, me sourceDatabaseConn = rds.New(meta.(*conns.AWSClient).Session, aws.NewConfig().WithRegion(sourceDatabaseARN.Region)) } - // Wait for the source database to be available after the replication is stopped. - if _, err := waitDBInstanceAvailable(sourceDatabaseConn, databaseID, d.Timeout(schema.TimeoutDefault)); err != nil { - return fmt.Errorf("error waiting for DB Instance (%s) to become available: %w", databaseID, err) + if _, err := waitDBInstanceAutomatedBackupDeleted(sourceDatabaseConn, dbInstanceID, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return fmt.Errorf("error waiting for DB instance automated backup (%s) delete: %w", d.Id(), err) } return nil diff --git a/internal/service/rds/status.go b/internal/service/rds/status.go index d9bac6f1d8cb..b6d3a4284bbc 100644 --- a/internal/service/rds/status.go +++ b/internal/service/rds/status.go @@ -1,6 +1,8 @@ package rds import ( + "strconv" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -95,3 +97,27 @@ func statusDBInstanceAutomatedBackup(conn *rds.RDS, arn string) resource.StateRe return output, aws.StringValue(output.Status), nil } } + +// statusDBInstanceHasAutomatedBackup returns whether or not a database instance has a specified automated backup. +// The connection must be valid for the database instance's Region. +func statusDBInstanceHasAutomatedBackup(conn *rds.RDS, dbInstanceID, dbInstanceAutomatedBackupARN string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := FindDBInstanceByID(conn, dbInstanceID) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + for _, v := range output.DBInstanceAutomatedBackupsReplications { + if aws.StringValue(v.DBInstanceAutomatedBackupsArn) == dbInstanceAutomatedBackupARN { + return output, strconv.FormatBool(true), nil + } + } + + return output, strconv.FormatBool(false), nil + } +} diff --git a/internal/service/rds/wait.go b/internal/service/rds/wait.go index b5c9b8c7edf1..57fbe89892e6 100644 --- a/internal/service/rds/wait.go +++ b/internal/service/rds/wait.go @@ -1,6 +1,7 @@ package rds import ( + "strconv" "time" "github.com/aws/aws-sdk-go/service/rds" @@ -177,30 +178,18 @@ func waitDBInstanceDeleted(conn *rds.RDS, id string, timeout time.Duration) (*rd return nil, err } -func waitDBInstanceAvailable(conn *rds.RDS, id string, timeout time.Duration) (*rds.DBInstance, error) { +func waitDBClusterInstanceDeleted(conn *rds.RDS, id string, timeout time.Duration) (*rds.DBInstance, error) { stateConf := &resource.StateChangeConf{ Pending: []string{ - InstanceStatusBackingUp, - InstanceStatusConfiguringEnhancedMonitoring, InstanceStatusConfiguringLogExports, - InstanceStatusCreating, InstanceStatusDeleting, - InstanceStatusIncompatibleParameters, - InstanceStatusIncompatibleRestore, InstanceStatusModifying, - InstanceStatusStarting, - InstanceStatusStopping, - InstanceStatusStorageFull, - InstanceStatusStorageOptimization, - }, - Target: []string{ - InstanceStatusAvailable, }, - Refresh: statusDBInstance(conn, id), - Timeout: timeout, - MinTimeout: 10 * time.Second, - Delay: 30 * time.Second, - ContinuousTargetOccurence: 3, + Target: []string{}, + Refresh: statusDBInstance(conn, id), + Timeout: timeout, + MinTimeout: 10 * time.Second, + Delay: 30 * time.Second, } outputRaw, err := stateConf.WaitForState() @@ -212,40 +201,36 @@ func waitDBInstanceAvailable(conn *rds.RDS, id string, timeout time.Duration) (* return nil, err } -func waitDBClusterInstanceDeleted(conn *rds.RDS, id string, timeout time.Duration) (*rds.DBInstance, error) { +func waitDBInstanceAutomatedBackupCreated(conn *rds.RDS, arn string, timeout time.Duration) (*rds.DBInstanceAutomatedBackup, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{ - InstanceStatusConfiguringLogExports, - InstanceStatusDeleting, - InstanceStatusModifying, - }, - Target: []string{}, - Refresh: statusDBInstance(conn, id), - Timeout: timeout, - MinTimeout: 10 * time.Second, - Delay: 30 * time.Second, + Pending: []string{InstanceAutomatedBackupStatusPending}, + Target: []string{InstanceAutomatedBackupStatusReplicating}, + Refresh: statusDBInstanceAutomatedBackup(conn, arn), + Timeout: timeout, } outputRaw, err := stateConf.WaitForState() - if output, ok := outputRaw.(*rds.DBInstance); ok { + if output, ok := outputRaw.(*rds.DBInstanceAutomatedBackup); ok { return output, err } return nil, err } -func waitDBInstanceAutomatedBackupAvailable(conn *rds.RDS, arn string, timeout time.Duration) (*rds.DBInstanceAutomatedBackup, error) { +// waitDBInstanceAutomatedBackupDeleted waits for a specified automated backup to be deleted from a database instance. +// The connection must be valid for the database instance's Region. +func waitDBInstanceAutomatedBackupDeleted(conn *rds.RDS, dbInstanceID, dbInstanceAutomatedBackupARN string, timeout time.Duration) (*rds.DBInstance, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{InstanceAutomatedBackupStatusPending}, - Target: []string{InstanceAutomatedBackupStatusReplicating}, - Refresh: statusDBInstanceAutomatedBackup(conn, arn), + Pending: []string{strconv.FormatBool(true)}, + Target: []string{strconv.FormatBool(false)}, + Refresh: statusDBInstanceHasAutomatedBackup(conn, dbInstanceID, dbInstanceAutomatedBackupARN), Timeout: timeout, } outputRaw, err := stateConf.WaitForState() - if output, ok := outputRaw.(*rds.DBInstanceAutomatedBackup); ok { + if output, ok := outputRaw.(*rds.DBInstance); ok { return output, err } From 3e533dadf2685fd50ae3c5cee62918d1e86a866c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Mar 2022 15:45:18 -0400 Subject: [PATCH 29/32] Revert "feat: add aws_db_instance_automated_backups_replication" This reverts commit 955b974a210debb0717e7810bbf8615d07927860. --- aws/internal/service/rds/finder/finder.go | 28 ---- aws/internal/service/rds/waiter/status.go | 19 --- aws/internal/service/rds/waiter/waiter.go | 46 ----- aws/provider.go | 1 - ..._instance_automated_backups_replication.go | 150 ----------------- ...ance_automated_backups_replication_test.go | 158 ------------------ ...nce_automated_backups_replication.markdown | 46 ----- 7 files changed, 448 deletions(-) delete mode 100644 aws/resource_aws_db_instance_automated_backups_replication.go delete mode 100644 aws/resource_aws_db_instance_automated_backups_replication_test.go delete mode 100644 website/docs/r/db_instance_automated_backups_replication.markdown diff --git a/aws/internal/service/rds/finder/finder.go b/aws/internal/service/rds/finder/finder.go index 434f6fd1116c..a401d39b5b22 100644 --- a/aws/internal/service/rds/finder/finder.go +++ b/aws/internal/service/rds/finder/finder.go @@ -1,8 +1,6 @@ package finder import ( - "context" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/aws-sdk-go-base/tfawserr" @@ -122,29 +120,3 @@ func DBClusterByID(conn *rds.RDS, id string) (*rds.DBCluster, error) { return dbCluster, nil } - -// DBInstanceAutomatedBackup returns matching DBInstanceAutomatedBackup -func DBInstanceAutomatedBackup(ctx context.Context, conn *rds.RDS, dbInstanceAutomatedBackupsArn string) (*rds.DBInstanceAutomatedBackup, error) { - input := &rds.DescribeDBInstanceAutomatedBackupsInput{ - DBInstanceAutomatedBackupsArn: aws.String(dbInstanceAutomatedBackupsArn), - } - - var dbInstanceAutomatedBackup *rds.DBInstanceAutomatedBackup - - err := conn.DescribeDBInstanceAutomatedBackupsPagesWithContext(ctx, input, func(page *rds.DescribeDBInstanceAutomatedBackupsOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } - - for _, backup := range page.DBInstanceAutomatedBackups { - if aws.StringValue(backup.DBInstanceAutomatedBackupsArn) == dbInstanceAutomatedBackupsArn { - dbInstanceAutomatedBackup = backup - return false - } - } - - return !lastPage - }) - - return dbInstanceAutomatedBackup, err -} diff --git a/aws/internal/service/rds/waiter/status.go b/aws/internal/service/rds/waiter/status.go index 9ae1f2f17b1a..870f1b58e8e5 100644 --- a/aws/internal/service/rds/waiter/status.go +++ b/aws/internal/service/rds/waiter/status.go @@ -1,8 +1,6 @@ package waiter import ( - "context" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -77,20 +75,3 @@ func DBClusterRoleStatus(conn *rds.RDS, dbClusterID, roleARN string) resource.St return output, aws.StringValue(output.Status), nil } } - -// DBInstanceAutomatedBackupsReplicationStatus fetches the DBInstanceAutomatedBackup and its Status -func DBInstanceAutomatedBackupsReplicationStatus(ctx context.Context, conn *rds.RDS, dbInstanceAutomatedBackupsArn string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - output, err := finder.DBInstanceAutomatedBackup(ctx, conn, dbInstanceAutomatedBackupsArn) - - if tfresource.NotFound(err) { - return nil, "", nil - } - - if err != nil { - return nil, "", err - } - - return output, aws.StringValue(output.Status), nil - } -} diff --git a/aws/internal/service/rds/waiter/waiter.go b/aws/internal/service/rds/waiter/waiter.go index db329bdfab7c..d3ad5da52d03 100644 --- a/aws/internal/service/rds/waiter/waiter.go +++ b/aws/internal/service/rds/waiter/waiter.go @@ -1,7 +1,6 @@ package waiter import ( - "context" "time" "github.com/aws/aws-sdk-go/service/rds" @@ -16,15 +15,6 @@ const ( DBClusterRoleAssociationCreatedTimeout = 5 * time.Minute DBClusterRoleAssociationDeletedTimeout = 5 * time.Minute - - // DB Instance Automated Backups Replication timeouts - DBInstanceAutomatedBackupsReplicationStartedTimeout = 30 * time.Minute - DBInstanceAutomatedBackupsReplicationDeletedTimeout = 5 * time.Minute - - // DB Instance Automated Backups Replication states - DBInstanceAutomatedBackupsPending = "pending" - DBInstanceAutomatedBackupsReplicating = "replicating" - DBInstanceAutomatedBackupsDeleting = "deleting" ) // EventSubscriptionDeleted waits for a EventSubscription to return Deleted @@ -117,39 +107,3 @@ func DBClusterRoleAssociationDeleted(conn *rds.RDS, dbClusterID, roleARN string) return nil, err } - -// DBInstanceAutomatedBackupsReplicationStarted waits for a DBInstanceAutomatedBackup to return replicating -func DBInstanceAutomatedBackupsReplicationStarted(ctx context.Context, conn *rds.RDS, dbInstanceAutomatedBackupsArn string) (*rds.DBInstanceAutomatedBackup, error) { - stateConf := &resource.StateChangeConf{ - Pending: []string{DBInstanceAutomatedBackupsPending}, - Target: []string{DBInstanceAutomatedBackupsReplicating}, - Refresh: DBInstanceAutomatedBackupsReplicationStatus(ctx, conn, dbInstanceAutomatedBackupsArn), - Timeout: DBInstanceAutomatedBackupsReplicationStartedTimeout, - } - - outputRaw, err := stateConf.WaitForState() - - if output, ok := outputRaw.(*rds.DBInstanceAutomatedBackup); ok { - return output, err - } - - return nil, err -} - -// DBInstanceAutomatedBackupsReplicationDeleted waits for a DBInstanceAutomatedBackup to return deleting -func DBInstanceAutomatedBackupsReplicationDeleted(ctx context.Context, conn *rds.RDS, dbInstanceAutomatedBackupsArn string) (*rds.DBInstanceAutomatedBackup, error) { - stateConf := &resource.StateChangeConf{ - Pending: []string{DBInstanceAutomatedBackupsReplicating}, - Target: []string{DBInstanceAutomatedBackupsDeleting}, - Refresh: DBInstanceAutomatedBackupsReplicationStatus(ctx, conn, dbInstanceAutomatedBackupsArn), - Timeout: DBInstanceAutomatedBackupsReplicationDeletedTimeout, - } - - outputRaw, err := stateConf.WaitForState() - - if output, ok := outputRaw.(*rds.DBInstanceAutomatedBackup); ok { - return output, err - } - - return nil, err -} diff --git a/aws/provider.go b/aws/provider.go index feeffb30e2b5..872662fcedc6 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -639,7 +639,6 @@ func Provider() *schema.Provider { "aws_db_cluster_snapshot": resourceAwsDbClusterSnapshot(), "aws_db_event_subscription": resourceAwsDbEventSubscription(), "aws_db_instance": resourceAwsDbInstance(), - "aws_db_instance_automated_backups_replication": resourceAwsDbInstanceAutomatedBackupsReplication(), "aws_db_instance_role_association": resourceAwsDbInstanceRoleAssociation(), "aws_db_option_group": resourceAwsDbOptionGroup(), "aws_db_parameter_group": resourceAwsDbParameterGroup(), diff --git a/aws/resource_aws_db_instance_automated_backups_replication.go b/aws/resource_aws_db_instance_automated_backups_replication.go deleted file mode 100644 index 4176e46933e5..000000000000 --- a/aws/resource_aws_db_instance_automated_backups_replication.go +++ /dev/null @@ -1,150 +0,0 @@ -package aws - -import ( - "context" - "fmt" - "log" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/rds" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds/finder" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds/waiter" -) - -func resourceAwsDbInstanceAutomatedBackupsReplication() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceAwsDbInstanceAutomatedBackupsReplicationCreate, - ReadContext: resourceAwsDbInstanceAutomatedBackupsReplicationRead, - DeleteContext: resourceAwsDbInstanceAutomatedBackupsReplicationDelete, - - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, - - Schema: map[string]*schema.Schema{ - "backup_retention_period": { - Type: schema.TypeInt, - Optional: true, - ForceNew: true, - Default: 1, - }, - "kms_key_id": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - "pre_signed_url": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - "source_db_instance_arn": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validateArn, - }, - }, - } -} - -func resourceAwsDbInstanceAutomatedBackupsReplicationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*AWSClient).rdsconn - - input := &rds.StartDBInstanceAutomatedBackupsReplicationInput{ - SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), - } - - if attr, ok := d.GetOk("backup_retention_period"); ok { - input.BackupRetentionPeriod = aws.Int64(int64(attr.(int))) - } - - if attr, ok := d.GetOk("kms_key_id"); ok { - input.KmsKeyId = aws.String(attr.(string)) - } - - if attr, ok := d.GetOk("pre_signed_url"); ok { - input.PreSignedUrl = aws.String(attr.(string)) - } - - log.Printf("[DEBUG] RDS DB Instance Start Automated Backups Replication: (%s)", input) - output, err := conn.StartDBInstanceAutomatedBackupsReplicationWithContext(ctx, input) - if err != nil { - return diag.FromErr(fmt.Errorf("unable to Start Automated Backup Replication: %s", err)) - } - - if output == nil || output.DBInstanceAutomatedBackup == nil { - return diag.FromErr(fmt.Errorf("error starting RDS DB Instance Start Automated Backups Replication: empty output")) - } - - dbInstanceAutomatedBackupsArn := aws.StringValue(output.DBInstanceAutomatedBackup.DBInstanceAutomatedBackupsArn) - d.SetId(dbInstanceAutomatedBackupsArn) - - if _, err := waiter.DBInstanceAutomatedBackupsReplicationStarted(ctx, conn, dbInstanceAutomatedBackupsArn); err != nil { - return diag.FromErr(fmt.Errorf("error waiting to RDS DB Instance Start Automated Backups Replication: %s", err)) - } - - return resourceAwsDbInstanceAutomatedBackupsReplicationRead(ctx, d, meta) -} - -func resourceAwsDbInstanceAutomatedBackupsReplicationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*AWSClient).rdsconn - - dbInstanceAutomatedBackup, err := finder.DBInstanceAutomatedBackup(ctx, conn, d.Id()) - if isAWSErr(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault, "") { - log.Printf("[WARN] RDS DB Instance Automated Backups Replication not found (%s), removing from state", d.Id()) - d.SetId("") - return nil - } - - if err != nil { - return diag.FromErr(fmt.Errorf("error describe RDS DB Instance Automated Backups Replication: %s", err)) - } - - if err := d.Set("backup_retention_period", dbInstanceAutomatedBackup.BackupRetentionPeriod); err != nil { - return diag.FromErr(fmt.Errorf("error setting backup retention period for RDS DB Instance: %s", err)) - } - if err := d.Set("kms_key_id", dbInstanceAutomatedBackup.KmsKeyId); err != nil { - return diag.FromErr(fmt.Errorf("error setting kms key id for RDS DB Instance: %s", err)) - } - if err := d.Set("source_db_instance_arn", dbInstanceAutomatedBackup.DBInstanceArn); err != nil { - return diag.FromErr(fmt.Errorf("error setting source db instance arn for RDS DB Instance: (%s)", err)) - } - - return nil -} - -func resourceAwsDbInstanceAutomatedBackupsReplicationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*AWSClient).rdsconn - - input := &rds.DeleteDBInstanceAutomatedBackupInput{ - DBInstanceAutomatedBackupsArn: aws.String(d.Id()), - } - - log.Printf("[DEBUG] Delete RDS DB Instance Automated Backups Replication: %s", d.Id()) - _, err := conn.DeleteDBInstanceAutomatedBackupWithContext(ctx, input) - - if isAWSErr(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault, "") { - return nil - } - - if isAWSErr(err, rds.ErrCodeInvalidDBInstanceAutomatedBackupStateFault, "") { - return nil - } - - if isAWSErr(err, rds.ErrCodeInvalidDBInstanceStateFault, "") { - return nil - } - - if err != nil { - return diag.FromErr(fmt.Errorf("error delete RDS DB Instance Automated Backups Replication: %s", err)) - } - - if _, err = waiter.DBInstanceAutomatedBackupsReplicationDeleted(ctx, conn, d.Id()); err != nil { - return diag.FromErr(fmt.Errorf("error waiting to delete RDS DB Instance Automated Backups Replication: %s", err)) - } - - return nil -} diff --git a/aws/resource_aws_db_instance_automated_backups_replication_test.go b/aws/resource_aws_db_instance_automated_backups_replication_test.go deleted file mode 100644 index a05950951fb4..000000000000 --- a/aws/resource_aws_db_instance_automated_backups_replication_test.go +++ /dev/null @@ -1,158 +0,0 @@ -package aws - -import ( - "context" - "fmt" - "regexp" - "testing" - - "github.com/aws/aws-sdk-go/service/rds" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds/finder" -) - -func TestAccAWSDbInstanceAutomatedBackupsReplication_basic(t *testing.T) { - var providers []*schema.Provider - var dbInstanceAutomatedBackup rds.DBInstanceAutomatedBackup - - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_db_instance_automated_backups_replication.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccMultipleRegionPreCheck(t, 2) - }, - ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), - ProviderFactories: testAccProviderFactoriesMultipleRegion(&providers, 2), - CheckDestroy: testAccCheckAWSDbInstanceAutomatedBackupsReplicationDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSDbInstanceAutomatedBackupsReplicationConfig(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSDbInstanceAutomatedBackupsReplicationExists(resourceName, &dbInstanceAutomatedBackup), - testAccCheckResourceAttrRegionalARNIgnoreRegionAndAccount(resourceName, "source_db_instance_arn", "rds", regexp.MustCompile(`db:.+`).String()), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccAWSDbInstanceAutomatedBackupsReplication_disappears(t *testing.T) { - var providers []*schema.Provider - var dbInstanceAutomatedBackup rds.DBInstanceAutomatedBackup - - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_db_instance_automated_backups_replication.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccMultipleRegionPreCheck(t, 2) - testAccAlternateAccountPreCheck(t) - }, - ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), - ProviderFactories: testAccProviderFactoriesMultipleRegion(&providers, 2), - CheckDestroy: testAccCheckAWSDbInstanceAutomatedBackupsReplicationDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSDbInstanceAutomatedBackupsReplicationConfig(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSDbInstanceAutomatedBackupsReplicationExists(resourceName, &dbInstanceAutomatedBackup), - testAccCheckResourceDisappears(testAccProvider, resourceAwsDbInstanceAutomatedBackupsReplication(), resourceName), - ), - ExpectNonEmptyPlan: false, - }, - }, - }) -} - -func testAccCheckAWSDbInstanceAutomatedBackupsReplicationExists(resourceName string, dbInstanceAutomatedBackup *rds.DBInstanceAutomatedBackup) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[resourceName] - - if !ok { - return fmt.Errorf("Resource not found: %s", resourceName) - } - - conn := testAccProvider.Meta().(*AWSClient).rdsconn - - backup, err := finder.DBInstanceAutomatedBackup(context.Background(), conn, rs.Primary.ID) - if err != nil { - return err - } - - if backup == nil { - return fmt.Errorf("RDS DB Instance Automated Backup not found (%s)", rs.Primary.ID) - } - - *dbInstanceAutomatedBackup = *backup - - return nil - } -} - -func testAccCheckAWSDbInstanceAutomatedBackupsReplicationDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).rdsconn - - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_db_instance_automated_backups_replication" { - continue - } - - backup, err := finder.DBInstanceAutomatedBackup(context.Background(), conn, rs.Primary.ID) - if isAWSErr(err, rds.ErrCodeDBInstanceAutomatedBackupNotFoundFault, "") { - continue - } - - if isAWSErr(err, rds.ErrCodeInvalidDBInstanceAutomatedBackupStateFault, "") { - continue - } - - if isAWSErr(err, rds.ErrCodeInvalidDBInstanceStateFault, "") { - return nil - } - - if err != nil { - return err - } - - if backup == nil { - continue - } - - return fmt.Errorf("RDS DB Instance Automated Backups Replication still exists %s", rs.Primary.ID) - } - - return nil -} - -func testAccAWSDbInstanceAutomatedBackupsReplicationConfig(rName string) string { - return composeConfig( - testAccMultipleRegionProviderConfig(2), fmt.Sprintf(` -resource "aws_db_instance" "test" { - allocated_storage = 10 - engine = "postgres" - identifier = %[1]q - instance_class = "db.t3.micro" - password = "avoid-plaintext-passwords" - username = "tfacctest" - skip_final_snapshot = true - delete_automated_backups = true - backup_retention_period = 1 - provider = awsalternate -} - -resource "aws_db_instance_automated_backups_replication" "test" { - source_db_instance_arn = aws_db_instance.test.arn -} -`, rName)) -} diff --git a/website/docs/r/db_instance_automated_backups_replication.markdown b/website/docs/r/db_instance_automated_backups_replication.markdown deleted file mode 100644 index 3753d57f3b8e..000000000000 --- a/website/docs/r/db_instance_automated_backups_replication.markdown +++ /dev/null @@ -1,46 +0,0 @@ ---- -subcategory: "RDS" -layout: "aws" -page_title: "AWS: aws_db_instance_automated_backups_replication" -description: |- - Manages an RDS DB Instance Automated Backups Replication. ---- - -# Resource: aws_db_instance_automated_backups_replication - -Manages an RDS DB Instance Automated Backups Replication. - -~> **NOTE:** This resource requires a second AWS provider to be defined in another region. - -* [Replicating automated backups to another AWS Region](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReplicateBackups.html) - -## Example Usage - -```terraform -resource "aws_db_instance_automated_backups_replication" "example" { - source_db_instance_arn = aws_db_instance.example.arn -} -``` - -## Argument Reference - -The following arguments are supported: - -* `backup_retention_period` - (Optional) The retention period for the replicated automated backups. -* `kms_key_id` - (Optional) The AWS KMS key identifier for encryption of the replicated automated backups. -* `pre_signed_url` - (Optional) A URL that contains a Signature Version 4 signed request for the [StartDBInstanceAutomatedBackupsReplication](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_StartDBInstanceAutomatedBackupsReplication.html) action to be called in the AWS Region of the source DB instance. -* `source_db_instance_arn` - (Optional) The Amazon Resource Name (ARN) of the source DB instance for the replicated automated backups. - -## Attributes Reference - -In addition to all arguments above, the following attributes are exported: - -* `id` - DB Instance Automated Backup Replication ARN - -## Import - -`aws_db_instance_automated_backups_replication` can be imported using the DB Instance Automated Backup Replication ARN, e.g. - -``` -$ terraform import aws_db_instance_automated_backups_replication.example arn:aws:rds:eu-west-1:123456789012:auto-backup:ab-lrg8qb6qtarwcfvoto3so53igbdulp3xjs8xeym -``` From 38de16e7d00df7cc57ffecda91ed9ae8bf43a745 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Mar 2022 16:51:57 -0400 Subject: [PATCH 30/32] r/aws_db_instance_automated_backup_replication: Add 'pre_signed_url' argument. --- .../service/rds/instance_automated_backup_replication.go | 9 +++++++++ .../r/db_instance_automated_backup_replication.markdown | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/internal/service/rds/instance_automated_backup_replication.go b/internal/service/rds/instance_automated_backup_replication.go index 5a2a4e1d4db2..ae4c47e0923f 100644 --- a/internal/service/rds/instance_automated_backup_replication.go +++ b/internal/service/rds/instance_automated_backup_replication.go @@ -31,6 +31,11 @@ func ResourceInstanceAutomatedBackupReplication() *schema.Resource { ForceNew: true, ValidateFunc: verify.ValidARN, }, + "pre_signed_url": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, "retention_period": { Type: schema.TypeInt, ForceNew: true, @@ -59,6 +64,10 @@ func resourceInstanceAutomatedBackupReplicationCreate(d *schema.ResourceData, me input.KmsKeyId = aws.String(v.(string)) } + if v, ok := d.GetOk("pre_signed_url"); ok { + input.PreSignedUrl = aws.String(v.(string)) + } + log.Printf("[DEBUG] Starting RDS instance automated backup replication: %s", input) output, err := conn.StartDBInstanceAutomatedBackupsReplication(input) diff --git a/website/docs/r/db_instance_automated_backup_replication.markdown b/website/docs/r/db_instance_automated_backup_replication.markdown index 2f7a14e69c5d..a187d142f550 100644 --- a/website/docs/r/db_instance_automated_backup_replication.markdown +++ b/website/docs/r/db_instance_automated_backup_replication.markdown @@ -76,9 +76,10 @@ resource "aws_db_instance_automated_backup_replication" "default" { The following arguments are supported: -* `source_db_instance_arn` - (Required, Forces new resource) The Amazon Resource Name (ARN) of the source DB instance for the replicated automated backups, for example, `arn:aws:rds:us-west-2:123456789012:db:mydatabase`. -* `retention_period` - (Optional, Forces new resource) The retention period for the replicated automated backups, defaults to `7`. * `kms_key_id` - (Optional, Forces new resource) The AWS KMS key identifier for encryption of the replicated automated backups. The KMS key ID is the Amazon Resource Name (ARN) for the KMS encryption key in the destination AWS Region, for example, `arn:aws:kms:us-east-1:123456789012:key/AKIAIOSFODNN7EXAMPLE`. +* `pre_signed_url` - (Optional, Forces new resource) A URL that contains a [Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) signed request for the [`StartDBInstanceAutomatedBackupsReplication`](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_StartDBInstanceAutomatedBackupsReplication.html) action to be called in the AWS Region of the source DB instance. +* `retention_period` - (Optional, Forces new resource) The retention period for the replicated automated backups, defaults to `7`. +* `source_db_instance_arn` - (Required, Forces new resource) The Amazon Resource Name (ARN) of the source DB instance for the replicated automated backups, for example, `arn:aws:rds:us-west-2:123456789012:db:mydatabase`. ## Attributes Reference From 2b33840cb9d5e07fa0ac86f58ca6a30df3d642fe Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Mar 2022 17:01:29 -0400 Subject: [PATCH 31/32] 'aws_db_instance_automated_backup_replication' -> 'aws_db_instance_automated_backups_replication'; Rename files. --- ...p_replication.go => instance_automated_backups_replication.go} | 0 ...ion_test.go => instance_automated_backups_replication_test.go} | 0 ...arkdown => db_instance_automated_backups_replication.markdown} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename internal/service/rds/{instance_automated_backup_replication.go => instance_automated_backups_replication.go} (100%) rename internal/service/rds/{instance_automated_backup_replication_test.go => instance_automated_backups_replication_test.go} (100%) rename website/docs/r/{db_instance_automated_backup_replication.markdown => db_instance_automated_backups_replication.markdown} (100%) diff --git a/internal/service/rds/instance_automated_backup_replication.go b/internal/service/rds/instance_automated_backups_replication.go similarity index 100% rename from internal/service/rds/instance_automated_backup_replication.go rename to internal/service/rds/instance_automated_backups_replication.go diff --git a/internal/service/rds/instance_automated_backup_replication_test.go b/internal/service/rds/instance_automated_backups_replication_test.go similarity index 100% rename from internal/service/rds/instance_automated_backup_replication_test.go rename to internal/service/rds/instance_automated_backups_replication_test.go diff --git a/website/docs/r/db_instance_automated_backup_replication.markdown b/website/docs/r/db_instance_automated_backups_replication.markdown similarity index 100% rename from website/docs/r/db_instance_automated_backup_replication.markdown rename to website/docs/r/db_instance_automated_backups_replication.markdown From 9ced21cfba38a2bcdf200c325308369b5c089dc3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Mar 2022 17:11:24 -0400 Subject: [PATCH 32/32] 'aws_db_instance_automated_backup_replication' -> 'aws_db_instance_automated_backups_replication'; Rename functions. --- .changelog/23759.txt | 2 +- internal/provider/provider.go | 40 ++++++------ .../instance_automated_backups_replication.go | 30 ++++----- ...ance_automated_backups_replication_test.go | 64 +++++++++---------- internal/service/rds/status.go | 4 +- internal/service/rds/wait.go | 4 +- ...nce_automated_backups_replication.markdown | 14 ++-- 7 files changed, 76 insertions(+), 82 deletions(-) diff --git a/.changelog/23759.txt b/.changelog/23759.txt index 69b3ba75cb89..32a903abdd4f 100644 --- a/.changelog/23759.txt +++ b/.changelog/23759.txt @@ -1,3 +1,3 @@ ```release-note:new-resource -aws_db_instance_automated_backup_replication +aws_db_instance_automated_backups_replication ``` diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 45c31b36eb10..62555cf3728f 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1659,26 +1659,26 @@ func Provider() *schema.Provider { "aws_ram_resource_share": ram.ResourceResourceShare(), "aws_ram_resource_share_accepter": ram.ResourceResourceShareAccepter(), - "aws_db_cluster_snapshot": rds.ResourceClusterSnapshot(), - "aws_db_event_subscription": rds.ResourceEventSubscription(), - "aws_db_instance": rds.ResourceInstance(), - "aws_db_instance_automated_backup_replication": rds.ResourceInstanceAutomatedBackupReplication(), - "aws_db_instance_role_association": rds.ResourceInstanceRoleAssociation(), - "aws_db_option_group": rds.ResourceOptionGroup(), - "aws_db_parameter_group": rds.ResourceParameterGroup(), - "aws_db_proxy": rds.ResourceProxy(), - "aws_db_proxy_default_target_group": rds.ResourceProxyDefaultTargetGroup(), - "aws_db_proxy_endpoint": rds.ResourceProxyEndpoint(), - "aws_db_proxy_target": rds.ResourceProxyTarget(), - "aws_db_security_group": rds.ResourceSecurityGroup(), - "aws_db_snapshot": rds.ResourceSnapshot(), - "aws_db_subnet_group": rds.ResourceSubnetGroup(), - "aws_rds_cluster": rds.ResourceCluster(), - "aws_rds_cluster_endpoint": rds.ResourceClusterEndpoint(), - "aws_rds_cluster_instance": rds.ResourceClusterInstance(), - "aws_rds_cluster_parameter_group": rds.ResourceClusterParameterGroup(), - "aws_rds_cluster_role_association": rds.ResourceClusterRoleAssociation(), - "aws_rds_global_cluster": rds.ResourceGlobalCluster(), + "aws_db_cluster_snapshot": rds.ResourceClusterSnapshot(), + "aws_db_event_subscription": rds.ResourceEventSubscription(), + "aws_db_instance": rds.ResourceInstance(), + "aws_db_instance_automated_backups_replication": rds.ResourceInstanceAutomatedBackupsReplication(), + "aws_db_instance_role_association": rds.ResourceInstanceRoleAssociation(), + "aws_db_option_group": rds.ResourceOptionGroup(), + "aws_db_parameter_group": rds.ResourceParameterGroup(), + "aws_db_proxy": rds.ResourceProxy(), + "aws_db_proxy_default_target_group": rds.ResourceProxyDefaultTargetGroup(), + "aws_db_proxy_endpoint": rds.ResourceProxyEndpoint(), + "aws_db_proxy_target": rds.ResourceProxyTarget(), + "aws_db_security_group": rds.ResourceSecurityGroup(), + "aws_db_snapshot": rds.ResourceSnapshot(), + "aws_db_subnet_group": rds.ResourceSubnetGroup(), + "aws_rds_cluster": rds.ResourceCluster(), + "aws_rds_cluster_endpoint": rds.ResourceClusterEndpoint(), + "aws_rds_cluster_instance": rds.ResourceClusterInstance(), + "aws_rds_cluster_parameter_group": rds.ResourceClusterParameterGroup(), + "aws_rds_cluster_role_association": rds.ResourceClusterRoleAssociation(), + "aws_rds_global_cluster": rds.ResourceGlobalCluster(), "aws_redshift_cluster": redshift.ResourceCluster(), "aws_redshift_event_subscription": redshift.ResourceEventSubscription(), diff --git a/internal/service/rds/instance_automated_backups_replication.go b/internal/service/rds/instance_automated_backups_replication.go index ae4c47e0923f..2e1840eeae4f 100644 --- a/internal/service/rds/instance_automated_backups_replication.go +++ b/internal/service/rds/instance_automated_backups_replication.go @@ -13,11 +13,11 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/verify" ) -func ResourceInstanceAutomatedBackupReplication() *schema.Resource { +func ResourceInstanceAutomatedBackupsReplication() *schema.Resource { return &schema.Resource{ - Create: resourceInstanceAutomatedBackupReplicationCreate, - Read: resourceInstanceAutomatedBackupReplicationRead, - Delete: resourceInstanceAutomatedBackupReplicationDelete, + Create: resourceInstanceAutomatedBackupsReplicationCreate, + Read: resourceInstanceAutomatedBackupsReplicationRead, + Delete: resourceInstanceAutomatedBackupsReplicationDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, @@ -52,7 +52,7 @@ func ResourceInstanceAutomatedBackupReplication() *schema.Resource { } } -func resourceInstanceAutomatedBackupReplicationCreate(d *schema.ResourceData, meta interface{}) error { +func resourceInstanceAutomatedBackupsReplicationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).RDSConn input := &rds.StartDBInstanceAutomatedBackupsReplicationInput{ @@ -68,11 +68,11 @@ func resourceInstanceAutomatedBackupReplicationCreate(d *schema.ResourceData, me input.PreSignedUrl = aws.String(v.(string)) } - log.Printf("[DEBUG] Starting RDS instance automated backup replication: %s", input) + log.Printf("[DEBUG] Starting RDS instance automated backups replication: %s", input) output, err := conn.StartDBInstanceAutomatedBackupsReplication(input) if err != nil { - return fmt.Errorf("error starting RDS instance automated backup replication: %w", err) + return fmt.Errorf("error starting RDS instance automated backups replication: %w", err) } d.SetId(aws.StringValue(output.DBInstanceAutomatedBackup.DBInstanceAutomatedBackupsArn)) @@ -81,22 +81,22 @@ func resourceInstanceAutomatedBackupReplicationCreate(d *schema.ResourceData, me return fmt.Errorf("error waiting for DB instance automated backup (%s) create: %w", d.Id(), err) } - return resourceInstanceAutomatedBackupReplicationRead(d, meta) + return resourceInstanceAutomatedBackupsReplicationRead(d, meta) } -func resourceInstanceAutomatedBackupReplicationRead(d *schema.ResourceData, meta interface{}) error { +func resourceInstanceAutomatedBackupsReplicationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).RDSConn backup, err := FindDBInstanceAutomatedBackupByARN(conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { - log.Printf("[WARN] RDS instance automated backup replication %s not found, removing from state", d.Id()) + log.Printf("[WARN] RDS instance automated backup %s not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error reading RDS instance automated backup replication (%s): %w", d.Id(), err) + return fmt.Errorf("error reading RDS instance automated backup (%s): %w", d.Id(), err) } d.Set("kms_key_id", backup.KmsKeyId) @@ -106,7 +106,7 @@ func resourceInstanceAutomatedBackupReplicationRead(d *schema.ResourceData, meta return nil } -func resourceInstanceAutomatedBackupReplicationDelete(d *schema.ResourceData, meta interface{}) error { +func resourceInstanceAutomatedBackupsReplicationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).RDSConn backup, err := FindDBInstanceAutomatedBackupByARN(conn, d.Id()) @@ -116,7 +116,7 @@ func resourceInstanceAutomatedBackupReplicationDelete(d *schema.ResourceData, me } if err != nil { - return fmt.Errorf("error reading RDS instance automated backup replication (%s): %w", d.Id(), err) + return fmt.Errorf("error reading RDS instance automated backup (%s): %w", d.Id(), err) } dbInstanceID := aws.StringValue(backup.DBInstanceIdentifier) @@ -126,13 +126,13 @@ func resourceInstanceAutomatedBackupReplicationDelete(d *schema.ResourceData, me return err } - log.Printf("[DEBUG] Stopping RDS instance automated backup replication: %s", d.Id()) + log.Printf("[DEBUG] Stopping RDS instance automated backups replication: %s", d.Id()) _, err = conn.StopDBInstanceAutomatedBackupsReplication(&rds.StopDBInstanceAutomatedBackupsReplicationInput{ SourceDBInstanceArn: aws.String(d.Get("source_db_instance_arn").(string)), }) if err != nil { - return fmt.Errorf("error stopping RDS instance automated backup replication (%s): %w", d.Id(), err) + return fmt.Errorf("error stopping RDS instance automated backups replication (%s): %w", d.Id(), err) } // Create a new client to the source region. diff --git a/internal/service/rds/instance_automated_backups_replication_test.go b/internal/service/rds/instance_automated_backups_replication_test.go index 1394bbcd8363..8672e12e2e3c 100644 --- a/internal/service/rds/instance_automated_backups_replication_test.go +++ b/internal/service/rds/instance_automated_backups_replication_test.go @@ -15,13 +15,13 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) -func TestAccRDSInstanceAutomatedBackupReplication_basic(t *testing.T) { +func TestAccRDSInstanceAutomatedBackupsReplication_basic(t *testing.T) { if testing.Short() { t.Skip("skipping long-running test in short mode") } rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_db_instance_automated_backup_replication.test" + resourceName := "aws_db_instance_automated_backups_replication.test" var providers []*schema.Provider @@ -32,12 +32,12 @@ func TestAccRDSInstanceAutomatedBackupReplication_basic(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), ProviderFactories: acctest.FactoriesAlternate(&providers), - CheckDestroy: testAccCheckInstanceAutomatedBackupReplicationDestroy, + CheckDestroy: testAccCheckInstanceAutomatedBackupsReplicationDestroy, Steps: []resource.TestStep{ { - Config: testAccInstanceAutomatedBackupReplicationConfig(rName), + Config: testAccInstanceAutomatedBackupsReplicationConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceAutomatedBackupReplicationExist(resourceName), + testAccCheckInstanceAutomatedBackupsReplicationExist(resourceName), resource.TestCheckResourceAttr(resourceName, "retention_period", "7"), ), }, @@ -50,13 +50,13 @@ func TestAccRDSInstanceAutomatedBackupReplication_basic(t *testing.T) { }) } -func TestAccRDSInstanceAutomatedBackupReplication_retentionPeriod(t *testing.T) { +func TestAccRDSInstanceAutomatedBackupsReplication_retentionPeriod(t *testing.T) { if testing.Short() { t.Skip("skipping long-running test in short mode") } rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_db_instance_automated_backup_replication.test" + resourceName := "aws_db_instance_automated_backups_replication.test" var providers []*schema.Provider @@ -67,12 +67,12 @@ func TestAccRDSInstanceAutomatedBackupReplication_retentionPeriod(t *testing.T) }, ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), ProviderFactories: acctest.FactoriesAlternate(&providers), - CheckDestroy: testAccCheckInstanceAutomatedBackupReplicationDestroy, + CheckDestroy: testAccCheckInstanceAutomatedBackupsReplicationDestroy, Steps: []resource.TestStep{ { - Config: testAccInstanceAutomatedBackupReplicationConfig_retentionPeriod(rName), + Config: testAccInstanceAutomatedBackupReplicationsRetentionPeriodConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceAutomatedBackupReplicationExist(resourceName), + testAccCheckInstanceAutomatedBackupsReplicationExist(resourceName), resource.TestCheckResourceAttr(resourceName, "retention_period", "14"), ), }, @@ -85,13 +85,13 @@ func TestAccRDSInstanceAutomatedBackupReplication_retentionPeriod(t *testing.T) }) } -func TestAccRDSInstanceAutomatedBackupReplication_kmsEncrypted(t *testing.T) { +func TestAccRDSInstanceAutomatedBackupsReplication_kmsEncrypted(t *testing.T) { if testing.Short() { t.Skip("skipping long-running test in short mode") } rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_db_instance_automated_backup_replication.test" + resourceName := "aws_db_instance_automated_backups_replication.test" var providers []*schema.Provider @@ -102,12 +102,12 @@ func TestAccRDSInstanceAutomatedBackupReplication_kmsEncrypted(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), ProviderFactories: acctest.FactoriesAlternate(&providers), - CheckDestroy: testAccCheckInstanceAutomatedBackupReplicationDestroy, + CheckDestroy: testAccCheckInstanceAutomatedBackupsReplicationDestroy, Steps: []resource.TestStep{ { - Config: testAccInstanceAutomatedBackupReplicationConfig_kmsEncrypted(rName), + Config: testAccInstanceAutomatedBackupsReplicationKMSEncryptedConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceAutomatedBackupReplicationExist(resourceName), + testAccCheckInstanceAutomatedBackupsReplicationExist(resourceName), resource.TestCheckResourceAttr(resourceName, "retention_period", "7"), ), }, @@ -120,10 +120,8 @@ func TestAccRDSInstanceAutomatedBackupReplication_kmsEncrypted(t *testing.T) { }) } -func testAccInstanceAutomatedBackupReplicationConfig(rName string) string { - return acctest.ConfigCompose( - acctest.ConfigMultipleRegionProvider(2), - fmt.Sprintf(` +func testAccInstanceAutomatedBackupsReplicationConfig(rName string) string { + return acctest.ConfigCompose(acctest.ConfigMultipleRegionProvider(2), fmt.Sprintf(` resource "aws_db_instance" "test" { allocated_storage = 10 identifier = %[1]q @@ -139,16 +137,14 @@ resource "aws_db_instance" "test" { provider = "awsalternate" } -resource "aws_db_instance_automated_backup_replication" "test" { +resource "aws_db_instance_automated_backups_replication" "test" { source_db_instance_arn = aws_db_instance.test.arn } `, rName)) } -func testAccInstanceAutomatedBackupReplicationConfig_retentionPeriod(rName string) string { - return acctest.ConfigCompose( - acctest.ConfigMultipleRegionProvider(2), - fmt.Sprintf(` +func testAccInstanceAutomatedBackupReplicationsRetentionPeriodConfig(rName string) string { + return acctest.ConfigCompose(acctest.ConfigMultipleRegionProvider(2), fmt.Sprintf(` resource "aws_db_instance" "test" { allocated_storage = 10 identifier = %[1]q @@ -164,17 +160,15 @@ resource "aws_db_instance" "test" { provider = "awsalternate" } -resource "aws_db_instance_automated_backup_replication" "test" { +resource "aws_db_instance_automated_backups_replication" "test" { source_db_instance_arn = aws_db_instance.test.arn retention_period = 14 } `, rName)) } -func testAccInstanceAutomatedBackupReplicationConfig_kmsEncrypted(rName string) string { - return acctest.ConfigCompose( - acctest.ConfigMultipleRegionProvider(2), - fmt.Sprintf(` +func testAccInstanceAutomatedBackupsReplicationKMSEncryptedConfig(rName string) string { + return acctest.ConfigCompose(acctest.ConfigMultipleRegionProvider(2), fmt.Sprintf(` resource "aws_kms_key" "test" { description = %[1]q } @@ -195,14 +189,14 @@ resource "aws_db_instance" "test" { provider = "awsalternate" } -resource "aws_db_instance_automated_backup_replication" "test" { +resource "aws_db_instance_automated_backups_replication" "test" { source_db_instance_arn = aws_db_instance.test.arn kms_key_id = aws_kms_key.test.arn } `, rName)) } -func testAccCheckInstanceAutomatedBackupReplicationExist(n string) resource.TestCheckFunc { +func testAccCheckInstanceAutomatedBackupsReplicationExist(n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -210,7 +204,7 @@ func testAccCheckInstanceAutomatedBackupReplicationExist(n string) resource.Test } if rs.Primary.ID == "" { - return fmt.Errorf("No RDS instance automated backup replication ID is set") + return fmt.Errorf("No RDS instance automated backups replication ID is set") } conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn @@ -225,11 +219,11 @@ func testAccCheckInstanceAutomatedBackupReplicationExist(n string) resource.Test } } -func testAccCheckInstanceAutomatedBackupReplicationDestroy(s *terraform.State) error { +func testAccCheckInstanceAutomatedBackupsReplicationDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_db_instance_automated_backup_replication" { + if rs.Type != "aws_db_instance_automated_backups_replication" { continue } @@ -243,7 +237,7 @@ func testAccCheckInstanceAutomatedBackupReplicationDestroy(s *terraform.State) e return err } - return fmt.Errorf("RDS instance automated backup replication %s still exists", rs.Primary.ID) + return fmt.Errorf("RDS instance automated backups replication %s still exists", rs.Primary.ID) } return nil diff --git a/internal/service/rds/status.go b/internal/service/rds/status.go index b6d3a4284bbc..3277b8a16dc0 100644 --- a/internal/service/rds/status.go +++ b/internal/service/rds/status.go @@ -100,7 +100,7 @@ func statusDBInstanceAutomatedBackup(conn *rds.RDS, arn string) resource.StateRe // statusDBInstanceHasAutomatedBackup returns whether or not a database instance has a specified automated backup. // The connection must be valid for the database instance's Region. -func statusDBInstanceHasAutomatedBackup(conn *rds.RDS, dbInstanceID, dbInstanceAutomatedBackupARN string) resource.StateRefreshFunc { +func statusDBInstanceHasAutomatedBackup(conn *rds.RDS, dbInstanceID, dbInstanceAutomatedBackupsARN string) resource.StateRefreshFunc { return func() (interface{}, string, error) { output, err := FindDBInstanceByID(conn, dbInstanceID) @@ -113,7 +113,7 @@ func statusDBInstanceHasAutomatedBackup(conn *rds.RDS, dbInstanceID, dbInstanceA } for _, v := range output.DBInstanceAutomatedBackupsReplications { - if aws.StringValue(v.DBInstanceAutomatedBackupsArn) == dbInstanceAutomatedBackupARN { + if aws.StringValue(v.DBInstanceAutomatedBackupsArn) == dbInstanceAutomatedBackupsARN { return output, strconv.FormatBool(true), nil } } diff --git a/internal/service/rds/wait.go b/internal/service/rds/wait.go index 57fbe89892e6..91f162cb6a50 100644 --- a/internal/service/rds/wait.go +++ b/internal/service/rds/wait.go @@ -220,11 +220,11 @@ func waitDBInstanceAutomatedBackupCreated(conn *rds.RDS, arn string, timeout tim // waitDBInstanceAutomatedBackupDeleted waits for a specified automated backup to be deleted from a database instance. // The connection must be valid for the database instance's Region. -func waitDBInstanceAutomatedBackupDeleted(conn *rds.RDS, dbInstanceID, dbInstanceAutomatedBackupARN string, timeout time.Duration) (*rds.DBInstance, error) { +func waitDBInstanceAutomatedBackupDeleted(conn *rds.RDS, dbInstanceID, dbInstanceAutomatedBackupsARN string, timeout time.Duration) (*rds.DBInstance, error) { stateConf := &resource.StateChangeConf{ Pending: []string{strconv.FormatBool(true)}, Target: []string{strconv.FormatBool(false)}, - Refresh: statusDBInstanceHasAutomatedBackup(conn, dbInstanceID, dbInstanceAutomatedBackupARN), + Refresh: statusDBInstanceHasAutomatedBackup(conn, dbInstanceID, dbInstanceAutomatedBackupsARN), Timeout: timeout, } diff --git a/website/docs/r/db_instance_automated_backups_replication.markdown b/website/docs/r/db_instance_automated_backups_replication.markdown index a187d142f550..f70e68c9c405 100644 --- a/website/docs/r/db_instance_automated_backups_replication.markdown +++ b/website/docs/r/db_instance_automated_backups_replication.markdown @@ -1,12 +1,12 @@ --- subcategory: "RDS" layout: "aws" -page_title: "AWS: aws_db_instance_automated_backup_replication" +page_title: "AWS: aws_db_instance_automated_backups_replication" description: |- Enables replication of automated backups to a different AWS Region. --- -# Resource: aws_db_instance_automated_backup_replication +# Resource: aws_db_instance_automated_backups_replication Manage cross-region replication of automated backups to a different AWS Region. Documentation for cross-region automated backup replication can be found at: @@ -17,7 +17,7 @@ Manage cross-region replication of automated backups to a different AWS Region. ## Example Usage ```terraform -resource "aws_db_instance_automated_backup_replication" "default" { +resource "aws_db_instance_automated_backups_replication" "default" { source_db_instance_arn = "arn:aws:rds:us-west-2:123456789012:db:mydatabase" retention_period = 14 } @@ -26,7 +26,7 @@ resource "aws_db_instance_automated_backup_replication" "default" { ## Encrypting the automated backup with KMS ```terraform -resource "aws_db_instance_automated_backup_replication" "default" { +resource "aws_db_instance_automated_backups_replication" "default" { source_db_instance_arn = "arn:aws:rds:us-west-2:123456789012:db:mydatabase" kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012" } @@ -64,7 +64,7 @@ resource "aws_kms_key" "default" { provider = "aws.replica" } -resource "aws_db_instance_automated_backup_replication" "default" { +resource "aws_db_instance_automated_backups_replication" "default" { source_db_instance_arn = aws_db_instance.default.arn kms_key_id = aws_kms_key.default.arn @@ -89,8 +89,8 @@ In addition to all arguments above, the following attributes are exported: ## Import -RDS instance automated backup replication can be imported using the `arn`, e.g., +RDS instance automated backups replication can be imported using the `arn`, e.g., ``` -$ terraform import aws_db_instance_automated_backup_replication.default arn:aws:rds:us-east-1:123456789012:auto-backup:ab-faaa2mgdj1vmp4xflr7yhsrmtbtob7ltrzzz2my +$ terraform import aws_db_instance_automated_backups_replication.default arn:aws:rds:us-east-1:123456789012:auto-backup:ab-faaa2mgdj1vmp4xflr7yhsrmtbtob7ltrzzz2my ```