From db2ad4f1e12e7e45b41f5250e764567f7725df15 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Fri, 23 Oct 2020 17:21:21 +0100 Subject: [PATCH 01/16] Adds new resource 'aws-db-snapshot-copy' Update tf code in 'aws-db-snapshot-copy' test Fix Terraform linting --- .../rds/resource_aws_db_snapshot_copy.go | 191 +++++++++++++++ .../rds/resource_aws_db_snapshot_copy_test.go | 229 ++++++++++++++++++ 2 files changed, 420 insertions(+) create mode 100644 internal/service/rds/resource_aws_db_snapshot_copy.go create mode 100644 internal/service/rds/resource_aws_db_snapshot_copy_test.go diff --git a/internal/service/rds/resource_aws_db_snapshot_copy.go b/internal/service/rds/resource_aws_db_snapshot_copy.go new file mode 100644 index 00000000000..a644dc71bd7 --- /dev/null +++ b/internal/service/rds/resource_aws_db_snapshot_copy.go @@ -0,0 +1,191 @@ +package rds + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/rds" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func resourceAwsDbSnapshotCopy() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsDbSnapshotCopyCreate, + Read: resourceAwsDbSnapshotCopyRead, + Delete: resourceAwsDbSnapshotCopyDelete, + + Schema: map[string]*schema.Schema{ + "copy_tags": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + }, + "destination_region": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "presigned_url": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "option_group_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "source_db_snapshot_identifier": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "source_region": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "tags": { + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + }, + "target_db_snapshot_identifier": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceAwsDbSnapshotCopyCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).rdsconn + tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().RdsTags() + + request := &rds.CopyDBSnapshotInput{ + SourceRegion: aws.String(d.Get("source_region").(string)), + SourceDBSnapshotIdentifier: aws.String(d.Get("source_db_snapshot_identifier").(string)), + TargetDBSnapshotIdentifier: aws.String(d.Get("target_db_snapshot_identifier").(string)), + Tags: tags, + } + if v, ok := d.GetOk("copy_tags"); ok { + request.CopyTags = aws.Bool(v.(bool)) + } + if v, ok := d.GetOk("kms_key_id"); ok { + request.KmsKeyId = aws.String(v.(string)) + } + if v, ok := d.GetOk("option_group_name"); ok { + request.OptionGroupName = aws.String(v.(string)) + } + if v, ok := d.GetOk("destination_region"); ok { + request.DestinationRegion = aws.String(v.(string)) + } + if v, ok := d.GetOk("presigned_url"); ok { + request.PreSignedUrl = aws.String(v.(string)) + } + + res, err := conn.CopyDBSnapshot(request) + if err != nil { + return err + } + + d.SetId(*res.DBSnapshot.DBSnapshotIdentifier) + + err = resourceAwsDbSnapshotCopyWaitForAvailable(d.Id(), conn) + if err != nil { + return err + } + + return resourceAwsDbSnapshotCopyRead(d, meta) +} + +func resourceAwsDbSnapshotCopyRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).rdsconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + req := &rds.DescribeDBSnapshotsInput{ + DBSnapshotIdentifier: aws.String(d.Id()), + } + res, err := conn.DescribeDBSnapshots(req) + if isAWSErr(err, "InvalidDBSnapshot.NotFound", "") { + log.Printf("Snapshot %q Not found - removing from state", d.Id()) + d.SetId("") + return nil + } + + snapshot := res.DBSnapshots[0] + + arn := aws.StringValue(snapshot.DBSnapshotArn) + d.Set("engine", snapshot.Engine) + d.Set("engine_version", snapshot.EngineVersion) + d.Set("encrypted", snapshot.Encrypted) + d.Set("snapshot_create_type", snapshot.SnapshotCreateTime) + d.Set("snapshot_identifier", snapshot.DBSnapshotIdentifier) + d.Set("kms_key_id", snapshot.KmsKeyId) + d.Set("storage_type", snapshot.StorageType) + + tags, err := keyvaluetags.RdsListTags(conn, arn) + + if err != nil { + return fmt.Errorf("error listing tags for RDS DB Snapshot (%s): %s", arn, err) + } + + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} + +func resourceAwsDbSnapshotCopyDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).rdsconn + input := &rds.DeleteDBSnapshotInput{ + DBSnapshotIdentifier: aws.String(d.Id()), + } + err := resource.Retry(5*time.Minute, func() *resource.RetryError { + _, err := conn.DeleteDBSnapshot(input) + if err == nil { + return nil + } + + if isAWSErr(err, "SnapshotInUse", "") { + return resource.RetryableError(fmt.Errorf("RDS SnapshotInUse - trying again while it detaches")) + } + + if isAWSErr(err, "InvalidSnapshot.NotFound", "") { + return nil + } + + return resource.NonRetryableError(err) + }) + if isResourceTimeoutError(err) { + _, err = conn.DeleteDBSnapshot(input) + if isAWSErr(err, "InvalidDBSnapshot.NotFound", "") { + return nil + } + } + if err != nil { + return fmt.Errorf("Error deleting RDS snapshot copy: %s", err) + } + return nil +} + +func resourceAwsDbSnapshotCopyWaitForAvailable(id string, conn *rds.RDS) error { + log.Printf("Waiting for Snapshot %s to become available...", id) + + req := &rds.DescribeDBSnapshotsInput{ + DBSnapshotIdentifier: aws.String(id), + } + err := conn.WaitUntilDBSnapshotAvailable(req) + return err +} diff --git a/internal/service/rds/resource_aws_db_snapshot_copy_test.go b/internal/service/rds/resource_aws_db_snapshot_copy_test.go new file mode 100644 index 00000000000..96cd21741a6 --- /dev/null +++ b/internal/service/rds/resource_aws_db_snapshot_copy_test.go @@ -0,0 +1,229 @@ +package rds + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/rds" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccAWSRdsSnapshotCopy_basic(t *testing.T) { + var v rds.DBSnapshot + rInt := acctest.RandInt() + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRdsDbSnapshotCopyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsRdsDbSnapshotCopyConfig(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckRdsDbSnapshotCopyExists("aws_db_snapshot_copy.test", &v), + ), + }, + }, + }) +} + +func TestAccAWSRdsDbSnapshotCopy_withRegions(t *testing.T) { + var v rds.DBSnapshot + rInt := acctest.RandInt() + var providers []*schema.Provider + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckRdsDbSnapshotCopyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsRdsDbSnapshotCopyConfigWithRegions(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckRdsDbSnapshotCopyExistsWithProviders("aws_db_snapshot_copy.test", &v, &providers), + ), + }, + }, + }) + +} + +func TestAccAWSRdsDbSnapshotCopy_disappears(t *testing.T) { + var v rds.DBSnapshot + rInt := acctest.RandInt() + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRdsDbSnapshotCopyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsRdsDbSnapshotCopyConfig(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckRdsDbSnapshotCopyExists("aws_db_snapshot_copy.test", &v), + testAccCheckRdsDbSnapshotCopyDisappears(&v), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckRdsDbSnapshotCopyDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).rdsconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_rds_db_snapshot_copy" { + continue + } + + resp, err := conn.DescribeDBSnapshots(&rds.DescribeDBSnapshotsInput{ + DBSnapshotIdentifier: aws.String(rs.Primary.ID), + }) + + if isAWSErr(err, "InvalidSnapshot.NotFound", "") { + continue + } + + if err == nil { + for _, snapshot := range resp.DBSnapshots { + if aws.StringValue(snapshot.DBSnapshotIdentifier) == rs.Primary.ID { + return fmt.Errorf("RDS Snapshot still exists") + } + } + } + + return err + } + + return nil +} + +func testAccCheckRdsDbSnapshotCopyDisappears(snapshot *rds.DBSnapshot) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).rdsconn + + _, err := conn.DeleteDBSnapshot(&rds.DeleteDBSnapshotInput{ + DBSnapshotIdentifier: snapshot.DBSnapshotIdentifier, + }) + + return err + } +} + +func testAccCheckRdsDbSnapshotCopyExists(n string, v *rds.DBSnapshot) resource.TestCheckFunc { + providers := []*schema.Provider{testAccProvider} + return testAccCheckRdsDbSnapshotCopyExistsWithProviders(n, v, &providers) +} + +func testAccCheckRdsDbSnapshotCopyExistsWithProviders(n string, v *rds.DBSnapshot, providers *[]*schema.Provider) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + for _, provider := range *providers { + // Ignore if Meta is empty, this can happen for validation providers + if provider.Meta() == nil { + continue + } + + conn := provider.Meta().(*AWSClient).rdsconn + + request := &rds.DescribeDBSnapshotsInput{ + DBSnapshotIdentifier: aws.String(rs.Primary.ID), + } + + response, err := conn.DescribeDBSnapshots(request) + if err == nil { + if response.DBSnapshots != nil && len(response.DBSnapshots) > 0 { + *v = *response.DBSnapshots[0] + return nil + } + } + } + return fmt.Errorf("Error finding RDS Snapshot %s", rs.Primary.ID) + } +} + +func testAccAwsRdsDbSnapshotCopyConfig(rInt int) string { + return fmt.Sprintf(`resource "aws_db_instance" "bar" { + allocated_storage = 10 + engine = "MySQL" + engine_version = "5.6.35" + instance_class = "db.t2.micro" + name = "baz" + password = "barbarbarbar" + username = "foo" + + maintenance_window = "Fri:09:00-Fri:09:30" + + backup_retention_period = 0 + + parameter_group_name = "default.mysql5.6" + + skip_final_snapshot = true +} + +resource "aws_db_snapshot" "test" { + db_instance_identifier = aws_db_instance.bar.id + db_snapshot_identifier = "testsnapshot%d" +} + +resource "aws_db_snapshot_copy" "test" { + source_db_snapshot_identifier = aws_db_snapshot.test.db_snapshot_arn + target_db_snapshot_identifier = "testsnapshot%d" + source_region = "us-west-2" +}`, rInt, rInt) +} + +func testAccAwsRdsDbSnapshotCopyConfigWithRegions(rInt int) string { + return fmt.Sprintf(`provider "aws" { + region = "us-west-2" + alias = "uswest2" +} + +provider "aws" { + region = "us-west-1" + alias = "uswest1" +} + +resource "aws_db_instance" "bar" { + provider = "aws.uswest2" + allocated_storage = 10 + engine = "MySQL" + engine_version = "5.6.35" + instance_class = "db.t2.micro" + name = "baz" + password = "barbarbarbar" + username = "foo" + + maintenance_window = "Fri:09:00-Fri:09:30" + + backup_retention_period = 0 + + parameter_group_name = "default.mysql5.6" + + skip_final_snapshot = true +} + +resource "aws_db_snapshot" "test" { + provider = "aws.uswest2" + db_instance_identifier = aws_db_instance.bar.id + db_snapshot_identifier = "testsnapshot%d" +} + +resource "aws_db_snapshot_copy" "test" { + provider = "aws.uswest1" + source_db_snapshot_identifier = aws_db_snapshot.test.db_snapshot_arn + target_db_snapshot_identifier = "testsnapshot%d" + source_region = "us-west-2" +}`, rInt, rInt) +} From e5c2730123fe9447870b8c29f47af3c7b71cd897 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 12 May 2022 14:55:54 -0500 Subject: [PATCH 02/16] r/aws_db_snapshot_copy: rename files --- .../rds/{resource_aws_db_snapshot_copy.go => snapshot_copy.go} | 0 ...esource_aws_db_snapshot_copy_test.go => snapshot_copy_test.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename internal/service/rds/{resource_aws_db_snapshot_copy.go => snapshot_copy.go} (100%) rename internal/service/rds/{resource_aws_db_snapshot_copy_test.go => snapshot_copy_test.go} (100%) diff --git a/internal/service/rds/resource_aws_db_snapshot_copy.go b/internal/service/rds/snapshot_copy.go similarity index 100% rename from internal/service/rds/resource_aws_db_snapshot_copy.go rename to internal/service/rds/snapshot_copy.go diff --git a/internal/service/rds/resource_aws_db_snapshot_copy_test.go b/internal/service/rds/snapshot_copy_test.go similarity index 100% rename from internal/service/rds/resource_aws_db_snapshot_copy_test.go rename to internal/service/rds/snapshot_copy_test.go From 0671799de9a5c77d298081a719112d8a801ef345 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 13 May 2022 14:24:12 -0500 Subject: [PATCH 03/16] r/aws_db_snapshot_copy: update CRUD functions --- internal/provider/provider.go | 1 + internal/service/rds/snapshot_copy.go | 207 +++++++++++++++++--------- 2 files changed, 137 insertions(+), 71 deletions(-) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 033b465d1fc..4752c850b8f 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1747,6 +1747,7 @@ func Provider() *schema.Provider { "aws_db_proxy_target": rds.ResourceProxyTarget(), "aws_db_security_group": rds.ResourceSecurityGroup(), "aws_db_snapshot": rds.ResourceSnapshot(), + "aws_db_snapshot_copy": rds.ResourceSnapshotCopy(), "aws_db_subnet_group": rds.ResourceSubnetGroup(), "aws_rds_cluster": rds.ResourceCluster(), "aws_rds_cluster_activity_stream": rds.ResourceClusterActivityStream(), diff --git a/internal/service/rds/snapshot_copy.go b/internal/service/rds/snapshot_copy.go index a644dc71bd7..d3d904e2a80 100644 --- a/internal/service/rds/snapshot_copy.go +++ b/internal/service/rds/snapshot_copy.go @@ -1,22 +1,37 @@ package rds import ( - "fmt" + "context" "log" + "regexp" "time" "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/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/internal/verify" ) -func resourceAwsDbSnapshotCopy() *schema.Resource { +func ResourceSnapshotCopy() *schema.Resource { return &schema.Resource{ - Create: resourceAwsDbSnapshotCopyCreate, - Read: resourceAwsDbSnapshotCopyRead, - Delete: resourceAwsDbSnapshotCopyDelete, + CreateWithoutTimeout: resourceSnapshotCopyCreate, + ReadWithoutTimeout: resourceSnapshotCopyRead, + UpdateWithoutTimeout: resourceSnapshotCopyUpdate, + DeleteWithoutTimeout: resourceSnapshotCopyDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + }, Schema: map[string]*schema.Schema{ "copy_tags": { @@ -24,6 +39,10 @@ func resourceAwsDbSnapshotCopy() *schema.Resource { Optional: true, ForceNew: true, }, + "db_snapshot_arn": { + Type: schema.TypeString, + Computed: true, + }, "destination_region": { Type: schema.TypeString, Optional: true, @@ -34,12 +53,12 @@ func resourceAwsDbSnapshotCopy() *schema.Resource { Optional: true, ForceNew: true, }, - "presigned_url": { + "option_group_name": { Type: schema.TypeString, Optional: true, ForceNew: true, }, - "option_group_name": { + "presigned_url": { Type: schema.TypeString, Optional: true, ForceNew: true, @@ -51,11 +70,12 @@ func resourceAwsDbSnapshotCopy() *schema.Resource { }, "source_region": { Type: schema.TypeString, - Required: true, - ForceNew: true, + Computed: true, }, - "tags": { - Type: schema.TypeMap, + "tags": tftags.TagsSchema(), + "tags_all": tftags.TagsSchemaComputed(), + "target_custom_availability_zone": { + Type: schema.TypeString, Optional: true, ForceNew: true, }, @@ -63,69 +83,80 @@ func resourceAwsDbSnapshotCopy() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 255), + validation.All(validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9][\w-]+`), "must contain only alphanumeric, and hyphen (-) characters")), + ), }, }, + + CustomizeDiff: verify.SetTagsDiff, } } -func resourceAwsDbSnapshotCopyCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).rdsconn - tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().RdsTags() +func resourceSnapshotCopyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).RDSConn + defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) - request := &rds.CopyDBSnapshotInput{ + in := &rds.CopyDBSnapshotInput{ SourceRegion: aws.String(d.Get("source_region").(string)), SourceDBSnapshotIdentifier: aws.String(d.Get("source_db_snapshot_identifier").(string)), TargetDBSnapshotIdentifier: aws.String(d.Get("target_db_snapshot_identifier").(string)), - Tags: tags, + Tags: Tags(tags.IgnoreAWS()), } + if v, ok := d.GetOk("copy_tags"); ok { - request.CopyTags = aws.Bool(v.(bool)) + in.CopyTags = aws.Bool(v.(bool)) } if v, ok := d.GetOk("kms_key_id"); ok { - request.KmsKeyId = aws.String(v.(string)) + in.KmsKeyId = aws.String(v.(string)) } if v, ok := d.GetOk("option_group_name"); ok { - request.OptionGroupName = aws.String(v.(string)) + in.OptionGroupName = aws.String(v.(string)) } if v, ok := d.GetOk("destination_region"); ok { - request.DestinationRegion = aws.String(v.(string)) + in.DestinationRegion = aws.String(v.(string)) } if v, ok := d.GetOk("presigned_url"); ok { - request.PreSignedUrl = aws.String(v.(string)) + in.PreSignedUrl = aws.String(v.(string)) } - res, err := conn.CopyDBSnapshot(request) + out, err := conn.CopyDBSnapshotWithContext(ctx, in) if err != nil { - return err + return diag.Errorf("error creating DB Snapshot Copy %s", err) } - d.SetId(*res.DBSnapshot.DBSnapshotIdentifier) + d.SetId(aws.StringValue(out.DBSnapshot.DBSnapshotIdentifier)) - err = resourceAwsDbSnapshotCopyWaitForAvailable(d.Id(), conn) + err = waitDBSnapshotCopyAvailable(ctx, d, conn) if err != nil { - return err + return diag.FromErr(err) } - return resourceAwsDbSnapshotCopyRead(d, meta) + return resourceSnapshotCopyRead(ctx, d, meta) } -func resourceAwsDbSnapshotCopyRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).rdsconn - ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig +func resourceSnapshotCopyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).RDSConn + defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - req := &rds.DescribeDBSnapshotsInput{ - DBSnapshotIdentifier: aws.String(d.Id()), - } - res, err := conn.DescribeDBSnapshots(req) - if isAWSErr(err, "InvalidDBSnapshot.NotFound", "") { - log.Printf("Snapshot %q Not found - removing from state", d.Id()) + snapshot, err := FindDBSnapshot(ctx, conn, d.Id()) + + if tfresource.NotFound(err) { + log.Printf("[WARN] RDS DB Snapshot (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - snapshot := res.DBSnapshots[0] + if err != nil { + return diag.Errorf("error describing RDS DB snapshot (%s): %s", d.Id(), err) + } arn := aws.StringValue(snapshot.DBSnapshotArn) + + d.Set("db_snapshot_arn", snapshot.DBSnapshotArn) d.Set("engine", snapshot.Engine) d.Set("engine_version", snapshot.EngineVersion) d.Set("encrypted", snapshot.Encrypted) @@ -134,58 +165,92 @@ func resourceAwsDbSnapshotCopyRead(d *schema.ResourceData, meta interface{}) err d.Set("kms_key_id", snapshot.KmsKeyId) d.Set("storage_type", snapshot.StorageType) - tags, err := keyvaluetags.RdsListTags(conn, arn) + tags, err := ListTags(conn, arn) if err != nil { - return fmt.Errorf("error listing tags for RDS DB Snapshot (%s): %s", arn, err) + return diag.Errorf("error listing tags for RDS DB Snapshot (%s): %s", arn, err) } - if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %s", err) + tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) + + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return diag.Errorf("error setting tags: %s", err) } return nil } -func resourceAwsDbSnapshotCopyDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).rdsconn - input := &rds.DeleteDBSnapshotInput{ - DBSnapshotIdentifier: aws.String(d.Id()), - } - err := resource.Retry(5*time.Minute, func() *resource.RetryError { - _, err := conn.DeleteDBSnapshot(input) - if err == nil { - return nil - } +func resourceSnapshotCopyUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).RDSConn - if isAWSErr(err, "SnapshotInUse", "") { - return resource.RetryableError(fmt.Errorf("RDS SnapshotInUse - trying again while it detaches")) - } + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") - if isAWSErr(err, "InvalidSnapshot.NotFound", "") { - return nil + if err := UpdateTags(conn, d.Get("db_snapshot_arn").(string), o, n); err != nil { + return diag.Errorf("error updating RDS DB Snapshot (%s) tags: %s", d.Get("db_snapshot_arn").(string), err) } + } - return resource.NonRetryableError(err) - }) - if isResourceTimeoutError(err) { - _, err = conn.DeleteDBSnapshot(input) - if isAWSErr(err, "InvalidDBSnapshot.NotFound", "") { - return nil - } + return resourceSnapshotCopyRead(ctx, d, meta) +} + +func resourceSnapshotCopyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).RDSConn + + log.Printf("[INFO] Deleting RDS DB Snapshot %s", d.Id()) + + in := &rds.DeleteDBSnapshotInput{ + DBSnapshotIdentifier: aws.String(d.Id()), + } + + _, err := conn.DeleteDBSnapshotWithContext(ctx, in) + if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBSnapshotNotFoundFault) { + return nil } + if err != nil { - return fmt.Errorf("Error deleting RDS snapshot copy: %s", err) + return diag.Errorf("error deleting RDS DB Snapshot (%s): %s", d.Id(), err) } + return nil } -func resourceAwsDbSnapshotCopyWaitForAvailable(id string, conn *rds.RDS) error { - log.Printf("Waiting for Snapshot %s to become available...", id) - - req := &rds.DescribeDBSnapshotsInput{ +func FindDBSnapshot(ctx context.Context, conn *rds.RDS, id string) (*rds.DBSnapshot, error) { + in := &rds.DescribeDBSnapshotsInput{ DBSnapshotIdentifier: aws.String(id), } - err := conn.WaitUntilDBSnapshotAvailable(req) - return err + out, err := conn.DescribeDBSnapshots(in) + + if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBSnapshotNotFoundFault) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: in, + } + } + + if out == nil || len(out.DBSnapshots) == 0 || out.DBSnapshots[0] == nil { + return nil, tfresource.NewEmptyResultError(in) + } + + return out.DBSnapshots[0], nil +} +func waitDBSnapshotCopyAvailable(ctx context.Context, d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Waiting for Snapshot %s to become available...", d.Id()) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"creating"}, + Target: []string{"available"}, + Refresh: resourceSnapshotStateRefreshFunc(d, meta), + Timeout: d.Timeout(schema.TimeoutCreate), + MinTimeout: 10 * time.Second, + Delay: 30 * time.Second, // Wait 30 secs before starting + } + + // Wait, catching any errors + _, err := stateConf.WaitForStateContext(ctx) + if err != nil { + return err + } + + return nil } From a50cf0cbf3494a92d79a4475405efaee6614a03f Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 13 May 2022 15:08:17 -0500 Subject: [PATCH 04/16] r/aws_db_snapshot_copy: update tests --- internal/service/rds/snapshot_copy.go | 1 + internal/service/rds/snapshot_copy_test.go | 283 ++++++++++----------- 2 files changed, 133 insertions(+), 151 deletions(-) diff --git a/internal/service/rds/snapshot_copy.go b/internal/service/rds/snapshot_copy.go index d3d904e2a80..169e240c991 100644 --- a/internal/service/rds/snapshot_copy.go +++ b/internal/service/rds/snapshot_copy.go @@ -162,6 +162,7 @@ func resourceSnapshotCopyRead(ctx context.Context, d *schema.ResourceData, meta d.Set("encrypted", snapshot.Encrypted) d.Set("snapshot_create_type", snapshot.SnapshotCreateTime) d.Set("snapshot_identifier", snapshot.DBSnapshotIdentifier) + d.Set("source_region", snapshot.SourceRegion) d.Set("kms_key_id", snapshot.KmsKeyId) d.Set("storage_type", snapshot.StorageType) diff --git a/internal/service/rds/snapshot_copy_test.go b/internal/service/rds/snapshot_copy_test.go index 96cd21741a6..316aed62ea2 100644 --- a/internal/service/rds/snapshot_copy_test.go +++ b/internal/service/rds/snapshot_copy_test.go @@ -1,69 +1,69 @@ -package rds +package rds_test import ( + "context" "fmt" + "log" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + 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" + tfrds "github.com/hashicorp/terraform-provider-aws/internal/service/rds" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) -func TestAccAWSRdsSnapshotCopy_basic(t *testing.T) { - var v rds.DBSnapshot - rInt := acctest.RandInt() - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckRdsDbSnapshotCopyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAwsRdsDbSnapshotCopyConfig(rInt), - Check: resource.ComposeTestCheckFunc( - testAccCheckRdsDbSnapshotCopyExists("aws_db_snapshot_copy.test", &v), - ), - }, - }, - }) -} +func TestAccSnapshotCopy_basic(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } -func TestAccAWSRdsDbSnapshotCopy_withRegions(t *testing.T) { var v rds.DBSnapshot - rInt := acctest.RandInt() - var providers []*schema.Provider + resourceName := "aws_db_snapshot_copy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactories(&providers), - CheckDestroy: testAccCheckRdsDbSnapshotCopyDestroy, + PreCheck: func() { acctest.PreCheck(t) }, + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckSnapshotCopyDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsRdsDbSnapshotCopyConfigWithRegions(rInt), + Config: testAccSnapshotCopyConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckRdsDbSnapshotCopyExistsWithProviders("aws_db_snapshot_copy.test", &v, &providers), + testAccCheckRdsDbSnapshotCopyExists(resourceName, &v), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) - } func TestAccAWSRdsDbSnapshotCopy_disappears(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + var v rds.DBSnapshot - rInt := acctest.RandInt() + resourceName := "aws_db_snapshot_copy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckRdsDbSnapshotCopyDestroy, + PreCheck: func() { acctest.PreCheck(t) }, + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckSnapshotCopyDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsRdsDbSnapshotCopyConfig(rInt), + Config: testAccSnapshotCopyConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckRdsDbSnapshotCopyExists("aws_db_snapshot_copy.test", &v), - testAccCheckRdsDbSnapshotCopyDisappears(&v), + testAccCheckRdsDbSnapshotCopyExists(resourceName, &v), + acctest.CheckResourceDisappears(acctest.Provider, tfrds.ResourceSnapshotCopy(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -71,54 +71,34 @@ func TestAccAWSRdsDbSnapshotCopy_disappears(t *testing.T) { }) } -func testAccCheckRdsDbSnapshotCopyDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).rdsconn +func testAccCheckSnapshotCopyDestroy(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn for _, rs := range s.RootModule().Resources { if rs.Type != "aws_rds_db_snapshot_copy" { continue } - resp, err := conn.DescribeDBSnapshots(&rds.DescribeDBSnapshotsInput{ - DBSnapshotIdentifier: aws.String(rs.Primary.ID), - }) + log.Printf("[DEBUG] Checking if RDS DB Snapshot %s exists", rs.Primary.ID) - if isAWSErr(err, "InvalidSnapshot.NotFound", "") { - continue - } + _, err := tfrds.FindDBSnapshot(context.Background(), conn, rs.Primary.ID) if err == nil { - for _, snapshot := range resp.DBSnapshots { - if aws.StringValue(snapshot.DBSnapshotIdentifier) == rs.Primary.ID { - return fmt.Errorf("RDS Snapshot still exists") - } - } + return fmt.Errorf("the RDS DB Snapshot %s still exists. Failing", rs.Primary.ID) } - return err - } - - return nil -} - -func testAccCheckRdsDbSnapshotCopyDisappears(snapshot *rds.DBSnapshot) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).rdsconn - - _, err := conn.DeleteDBSnapshot(&rds.DeleteDBSnapshotInput{ - DBSnapshotIdentifier: snapshot.DBSnapshotIdentifier, - }) + // verify error is what we want + if tfresource.NotFound(err) { + return nil + } return err } -} -func testAccCheckRdsDbSnapshotCopyExists(n string, v *rds.DBSnapshot) resource.TestCheckFunc { - providers := []*schema.Provider{testAccProvider} - return testAccCheckRdsDbSnapshotCopyExistsWithProviders(n, v, &providers) + return nil } -func testAccCheckRdsDbSnapshotCopyExistsWithProviders(n string, v *rds.DBSnapshot, providers *[]*schema.Provider) resource.TestCheckFunc { +func testAccCheckRdsDbSnapshotCopyExists(n string, ci *rds.DBSnapshot) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -126,104 +106,105 @@ func testAccCheckRdsDbSnapshotCopyExistsWithProviders(n string, v *rds.DBSnapsho } if rs.Primary.ID == "" { - return fmt.Errorf("No ID is set") - } - - for _, provider := range *providers { - // Ignore if Meta is empty, this can happen for validation providers - if provider.Meta() == nil { - continue - } - - conn := provider.Meta().(*AWSClient).rdsconn - - request := &rds.DescribeDBSnapshotsInput{ - DBSnapshotIdentifier: aws.String(rs.Primary.ID), - } - - response, err := conn.DescribeDBSnapshots(request) - if err == nil { - if response.DBSnapshots != nil && len(response.DBSnapshots) > 0 { - *v = *response.DBSnapshots[0] - return nil - } - } + return fmt.Errorf("no RDS DB Snapshot ID is set") } - return fmt.Errorf("Error finding RDS Snapshot %s", rs.Primary.ID) - } -} - -func testAccAwsRdsDbSnapshotCopyConfig(rInt int) string { - return fmt.Sprintf(`resource "aws_db_instance" "bar" { - allocated_storage = 10 - engine = "MySQL" - engine_version = "5.6.35" - instance_class = "db.t2.micro" - name = "baz" - password = "barbarbarbar" - username = "foo" - - maintenance_window = "Fri:09:00-Fri:09:30" - - backup_retention_period = 0 - parameter_group_name = "default.mysql5.6" + conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn - skip_final_snapshot = true -} + out, err := tfrds.FindDBSnapshot(context.Background(), conn, rs.Primary.ID) + if err != nil { + return err + } -resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.bar.id - db_snapshot_identifier = "testsnapshot%d" -} + ci = out -resource "aws_db_snapshot_copy" "test" { - source_db_snapshot_identifier = aws_db_snapshot.test.db_snapshot_arn - target_db_snapshot_identifier = "testsnapshot%d" - source_region = "us-west-2" -}`, rInt, rInt) + return nil + } } -func testAccAwsRdsDbSnapshotCopyConfigWithRegions(rInt int) string { - return fmt.Sprintf(`provider "aws" { - region = "us-west-2" - alias = "uswest2" +func testAccSnapshotCopyBaseConfig(rName string) string { + return fmt.Sprintf(` +data "aws_rds_engine_version" "default" { + engine = "mysql" } -provider "aws" { - region = "us-west-1" - alias = "uswest1" +data "aws_rds_orderable_db_instance" "test" { + engine = data.aws_rds_engine_version.default.engine + engine_version = data.aws_rds_engine_version.default.version + preferred_instance_classes = ["db.t3.small", "db.t2.small", "db.t2.medium"] } -resource "aws_db_instance" "bar" { - provider = "aws.uswest2" - allocated_storage = 10 - engine = "MySQL" - engine_version = "5.6.35" - instance_class = "db.t2.micro" - name = "baz" - password = "barbarbarbar" - username = "foo" - - maintenance_window = "Fri:09:00-Fri:09:30" - - backup_retention_period = 0 - - parameter_group_name = "default.mysql5.6" - - skip_final_snapshot = true +resource "aws_db_instance" "test" { + allocated_storage = 10 + engine = data.aws_rds_engine_version.default.engine + engine_version = data.aws_rds_engine_version.default.version + instance_class = data.aws_rds_orderable_db_instance.test.instance_class + name = "baz" + identifier = %[1]q + password = "barbarbarbar" + username = "foo" + maintenance_window = "Fri:09:00-Fri:09:30" + backup_retention_period = 0 + parameter_group_name = "default.${data.aws_rds_engine_version.default.parameter_group_family}" + skip_final_snapshot = true } resource "aws_db_snapshot" "test" { - provider = "aws.uswest2" - db_instance_identifier = aws_db_instance.bar.id - db_snapshot_identifier = "testsnapshot%d" + db_instance_identifier = aws_db_instance.test.id + db_snapshot_identifier = "%[1]s-source" +}`, rName) } +func testAccSnapshotCopyConfig(rName string) string { + return acctest.ConfigCompose( + testAccSnapshotCopyBaseConfig(rName), + fmt.Sprintf(` resource "aws_db_snapshot_copy" "test" { - provider = "aws.uswest1" - source_db_snapshot_identifier = aws_db_snapshot.test.db_snapshot_arn - target_db_snapshot_identifier = "testsnapshot%d" - source_region = "us-west-2" -}`, rInt, rInt) + source_db_snapshot_identifier = aws_db_snapshot.test.db_snapshot_arn + target_db_snapshot_identifier = "%[1]s-target" +}`, rName)) } + +//func testAccAwsRdsDbSnapshotCopyConfigWithRegions(rInt int) string { +// return fmt.Sprintf(`provider "aws" { +// region = "us-west-2" +// alias = "uswest2" +//} +// +//provider "aws" { +// region = "us-west-1" +// alias = "uswest1" +//} +// +//resource "aws_db_instance" "bar" { +// provider = "aws.uswest2" +// allocated_storage = 10 +// engine = "MySQL" +// engine_version = "5.6.35" +// instance_class = "db.t2.micro" +// name = "baz" +// password = "barbarbarbar" +// username = "foo" +// +// maintenance_window = "Fri:09:00-Fri:09:30" +// +// backup_retention_period = 0 +// +// parameter_group_name = "default.mysql5.6" +// +// skip_final_snapshot = true +//} +// +//resource "aws_db_snapshot" "test" { +// provider = "aws.uswest2" +// db_instance_identifier = aws_db_instance.bar.id +// db_snapshot_identifier = "testsnapshot%d" +//} +// +//resource "aws_db_snapshot_copy" "test" { +// provider = "aws.uswest1" +// source_db_snapshot_identifier = aws_db_snapshot.test.db_snapshot_arn +// target_db_snapshot_identifier = "testsnapshot%d" +// source_region = "us-west-2" +//}`, rInt, rInt) +//} From f098fafc804283b28de3cb66f0caa286d0c2bd39 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 13 May 2022 17:30:38 -0500 Subject: [PATCH 05/16] r/aws_db_snapshot_copy: set additional attributes --- internal/provider/provider.go | 2 +- internal/service/rds/snapshot_copy.go | 38 +++++++++++++++++----- internal/service/rds/snapshot_copy_test.go | 26 +++++++-------- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 4752c850b8f..842f0d897b0 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1747,7 +1747,6 @@ func Provider() *schema.Provider { "aws_db_proxy_target": rds.ResourceProxyTarget(), "aws_db_security_group": rds.ResourceSecurityGroup(), "aws_db_snapshot": rds.ResourceSnapshot(), - "aws_db_snapshot_copy": rds.ResourceSnapshotCopy(), "aws_db_subnet_group": rds.ResourceSubnetGroup(), "aws_rds_cluster": rds.ResourceCluster(), "aws_rds_cluster_activity_stream": rds.ResourceClusterActivityStream(), @@ -1755,6 +1754,7 @@ func Provider() *schema.Provider { "aws_rds_cluster_instance": rds.ResourceClusterInstance(), "aws_rds_cluster_parameter_group": rds.ResourceClusterParameterGroup(), "aws_rds_cluster_role_association": rds.ResourceClusterRoleAssociation(), + "aws_rds_db_snapshot_copy": rds.ResourceSnapshotCopy(), "aws_rds_global_cluster": rds.ResourceGlobalCluster(), "aws_redshift_cluster": redshift.ResourceCluster(), diff --git a/internal/service/rds/snapshot_copy.go b/internal/service/rds/snapshot_copy.go index 169e240c991..de9c3984aa9 100644 --- a/internal/service/rds/snapshot_copy.go +++ b/internal/service/rds/snapshot_copy.go @@ -48,6 +48,18 @@ func ResourceSnapshotCopy() *schema.Resource { Optional: true, ForceNew: true, }, + "encrypted": { + Type: schema.TypeBool, + Computed: true, + }, + "engine": { + Type: schema.TypeString, + Computed: true, + }, + "engine_version": { + Type: schema.TypeString, + Computed: true, + }, "kms_key_id": { Type: schema.TypeString, Optional: true, @@ -72,6 +84,10 @@ func ResourceSnapshotCopy() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "storage_type": { + Type: schema.TypeString, + Computed: true, + }, "tags": tftags.TagsSchema(), "tags_all": tftags.TagsSchemaComputed(), "target_custom_availability_zone": { @@ -100,7 +116,6 @@ func resourceSnapshotCopyCreate(ctx context.Context, d *schema.ResourceData, met tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) in := &rds.CopyDBSnapshotInput{ - SourceRegion: aws.String(d.Get("source_region").(string)), SourceDBSnapshotIdentifier: aws.String(d.Get("source_db_snapshot_identifier").(string)), TargetDBSnapshotIdentifier: aws.String(d.Get("target_db_snapshot_identifier").(string)), Tags: Tags(tags.IgnoreAWS()), @@ -129,7 +144,7 @@ func resourceSnapshotCopyCreate(ctx context.Context, d *schema.ResourceData, met d.SetId(aws.StringValue(out.DBSnapshot.DBSnapshotIdentifier)) - err = waitDBSnapshotCopyAvailable(ctx, d, conn) + err = waitSnapshotCopyAvailable(ctx, d, meta) if err != nil { return diag.FromErr(err) } @@ -142,7 +157,7 @@ func resourceSnapshotCopyRead(ctx context.Context, d *schema.ResourceData, meta defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - snapshot, err := FindDBSnapshot(ctx, conn, d.Id()) + snapshot, err := FindSnapshot(ctx, conn, d.Id()) if tfresource.NotFound(err) { log.Printf("[WARN] RDS DB Snapshot (%s) not found, removing from state", d.Id()) @@ -157,14 +172,14 @@ func resourceSnapshotCopyRead(ctx context.Context, d *schema.ResourceData, meta arn := aws.StringValue(snapshot.DBSnapshotArn) d.Set("db_snapshot_arn", snapshot.DBSnapshotArn) + d.Set("encrypted", snapshot.Encrypted) d.Set("engine", snapshot.Engine) d.Set("engine_version", snapshot.EngineVersion) - d.Set("encrypted", snapshot.Encrypted) - d.Set("snapshot_create_type", snapshot.SnapshotCreateTime) - d.Set("snapshot_identifier", snapshot.DBSnapshotIdentifier) d.Set("source_region", snapshot.SourceRegion) d.Set("kms_key_id", snapshot.KmsKeyId) + d.Set("source_db_snapshot_identifier", snapshot.SourceDBSnapshotIdentifier) d.Set("storage_type", snapshot.StorageType) + d.Set("target_db_snapshot_identifier", snapshot.DBSnapshotIdentifier) tags, err := ListTags(conn, arn) @@ -174,10 +189,15 @@ func resourceSnapshotCopyRead(ctx context.Context, d *schema.ResourceData, meta tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) + //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { return diag.Errorf("error setting tags: %s", err) } + if err := d.Set("tags_all", tags.Map()); err != nil { + return diag.Errorf("error setting tags_all: %s", err) + } + return nil } @@ -216,11 +236,11 @@ func resourceSnapshotCopyDelete(ctx context.Context, d *schema.ResourceData, met return nil } -func FindDBSnapshot(ctx context.Context, conn *rds.RDS, id string) (*rds.DBSnapshot, error) { +func FindSnapshot(ctx context.Context, conn *rds.RDS, id string) (*rds.DBSnapshot, error) { in := &rds.DescribeDBSnapshotsInput{ DBSnapshotIdentifier: aws.String(id), } - out, err := conn.DescribeDBSnapshots(in) + out, err := conn.DescribeDBSnapshotsWithContext(ctx, in) if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBSnapshotNotFoundFault) { return nil, &resource.NotFoundError{ @@ -235,7 +255,7 @@ func FindDBSnapshot(ctx context.Context, conn *rds.RDS, id string) (*rds.DBSnaps return out.DBSnapshots[0], nil } -func waitDBSnapshotCopyAvailable(ctx context.Context, d *schema.ResourceData, meta interface{}) error { +func waitSnapshotCopyAvailable(ctx context.Context, d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Waiting for Snapshot %s to become available...", d.Id()) stateConf := &resource.StateChangeConf{ diff --git a/internal/service/rds/snapshot_copy_test.go b/internal/service/rds/snapshot_copy_test.go index 316aed62ea2..acb9283f89e 100644 --- a/internal/service/rds/snapshot_copy_test.go +++ b/internal/service/rds/snapshot_copy_test.go @@ -22,18 +22,19 @@ func TestAccSnapshotCopy_basic(t *testing.T) { } var v rds.DBSnapshot - resourceName := "aws_db_snapshot_copy.test" + resourceName := "aws_rds_db_snapshot_copy.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), ProviderFactories: acctest.ProviderFactories, CheckDestroy: testAccCheckSnapshotCopyDestroy, Steps: []resource.TestStep{ { Config: testAccSnapshotCopyConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckRdsDbSnapshotCopyExists(resourceName, &v), + testAccCheckSnapshotCopyExists(resourceName, &v), ), }, { @@ -45,24 +46,25 @@ func TestAccSnapshotCopy_basic(t *testing.T) { }) } -func TestAccAWSRdsDbSnapshotCopy_disappears(t *testing.T) { +func TestAccSnapshotCopy_disappears(t *testing.T) { if testing.Short() { t.Skip("skipping long-running test in short mode") } var v rds.DBSnapshot - resourceName := "aws_db_snapshot_copy.test" + resourceName := "aws_rds_db_snapshot_copy.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), ProviderFactories: acctest.ProviderFactories, CheckDestroy: testAccCheckSnapshotCopyDestroy, Steps: []resource.TestStep{ { Config: testAccSnapshotCopyConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckRdsDbSnapshotCopyExists(resourceName, &v), + testAccCheckSnapshotCopyExists(resourceName, &v), acctest.CheckResourceDisappears(acctest.Provider, tfrds.ResourceSnapshotCopy(), resourceName), ), ExpectNonEmptyPlan: true, @@ -81,15 +83,11 @@ func testAccCheckSnapshotCopyDestroy(s *terraform.State) error { log.Printf("[DEBUG] Checking if RDS DB Snapshot %s exists", rs.Primary.ID) - _, err := tfrds.FindDBSnapshot(context.Background(), conn, rs.Primary.ID) - - if err == nil { - return fmt.Errorf("the RDS DB Snapshot %s still exists. Failing", rs.Primary.ID) - } + _, err := tfrds.FindSnapshot(context.Background(), conn, rs.Primary.ID) // verify error is what we want if tfresource.NotFound(err) { - return nil + continue } return err @@ -98,7 +96,7 @@ func testAccCheckSnapshotCopyDestroy(s *terraform.State) error { return nil } -func testAccCheckRdsDbSnapshotCopyExists(n string, ci *rds.DBSnapshot) resource.TestCheckFunc { +func testAccCheckSnapshotCopyExists(n string, ci *rds.DBSnapshot) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -111,7 +109,7 @@ func testAccCheckRdsDbSnapshotCopyExists(n string, ci *rds.DBSnapshot) resource. conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn - out, err := tfrds.FindDBSnapshot(context.Background(), conn, rs.Primary.ID) + out, err := tfrds.FindSnapshot(context.Background(), conn, rs.Primary.ID) if err != nil { return err } @@ -159,7 +157,7 @@ func testAccSnapshotCopyConfig(rName string) string { return acctest.ConfigCompose( testAccSnapshotCopyBaseConfig(rName), fmt.Sprintf(` -resource "aws_db_snapshot_copy" "test" { +resource "aws_rds_db_snapshot_copy" "test" { source_db_snapshot_identifier = aws_db_snapshot.test.db_snapshot_arn target_db_snapshot_identifier = "%[1]s-target" }`, rName)) From 43dfa79b9ab8892a2d6f841a44b9ad75bcb233a4 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 13 May 2022 17:42:16 -0500 Subject: [PATCH 06/16] r/aws_db_snapshot_copy: docs --- .../docs/r/rds_db_snapshot_copy.html.markdown | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 website/docs/r/rds_db_snapshot_copy.html.markdown diff --git a/website/docs/r/rds_db_snapshot_copy.html.markdown b/website/docs/r/rds_db_snapshot_copy.html.markdown new file mode 100644 index 00000000000..7c6cf1c3398 --- /dev/null +++ b/website/docs/r/rds_db_snapshot_copy.html.markdown @@ -0,0 +1,82 @@ +--- +subcategory: "RDS (Relational Database)" +layout: "aws" +page_title: "AWS: aws_rds_db_snapshot" +description: |- +Manages an RDS database instance snapshot copy. +--- + +# Resource: aws_db_snapshot + +Manages an RDS database instance snapshot copy. For managing RDS database cluster snapshots, see the [`aws_db_cluster_snapshot` resource](/docs/providers/aws/r/db_cluster_snapshot.html). + +## Example Usage + +```terraform +resource "aws_db_instance" "example" { + allocated_storage = 10 + engine = "mysql" + engine_version = "5.6.21" + instance_class = "db.t2.micro" + name = "baz" + password = "barbarbarbar" + username = "foo" + + maintenance_window = "Fri:09:00-Fri:09:30" + backup_retention_period = 0 + parameter_group_name = "default.mysql5.6" +} + +resource "aws_db_snapshot" "example" { + db_instance_identifier = aws_db_instance.example.id + db_snapshot_identifier = "%[1]s-source" +} + +resource "aws_rds_db_snapshot_copy" "example" { + source_db_snapshot_identifier = aws_db_snapshot.example.db_snapshot_arn + target_db_snapshot_identifier = "testsnapshot1234" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `source_db_snapshot_identifier` - (Required) Snapshot identifier of the source snapshot. +* `target_db_snapshot_identifier` - (Required) The Identifier for the snapshot. +* `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. + + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `allocated_storage` - Specifies the allocated storage size in gigabytes (GB). +* `availability_zone` - Specifies the name of the Availability Zone the DB instance was located in at the time of the DB snapshot. +* `db_snapshot_arn` - The Amazon Resource Name (ARN) for the DB snapshot. +* `encrypted` - Specifies whether the DB snapshot is encrypted. +* `engine` - Specifies the name of the database engine. +* `engine_version` - Specifies the version of the database engine. +* `iops` - Specifies the Provisioned IOPS (I/O operations per second) value of the DB instance at the time of the snapshot. +* `kms_key_id` - The ARN for the KMS encryption key. +* `license_model` - License model information for the restored DB instance. +* `option_group_name` - Provides the option group name for the DB snapshot. +* `source_db_snapshot_identifier` - The DB snapshot Arn that the DB snapshot was copied from. It only has value in case of cross customer or cross region copy. +* `source_region` - The region that the DB snapshot was created in or copied from. +* `storage_type` - Specifies the storage type associated with DB snapshot. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block). +* `vpc_id` - Provides the VPC ID associated with the DB snapshot. + +## Timeouts + +`aws_rds_db_snapshot_copy` provides the following [Timeouts](https://www.terraform.io/docs/configuration/blocks/resources/syntax.html#operation-timeouts) configuration options: + +- `create` - (Default `20 minutes`) Length of time to wait for the snapshot to become available + +## Import + +`aws_rds_db_snapshot_copy` can be imported by using the snapshot identifier, e.g., + +``` +$ terraform import aws_rds_db_snapshot_copy.example my-snapshot +``` From 06d995fbea8b0323547b2e47345fea5723a155dc Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 13 May 2022 17:59:13 -0500 Subject: [PATCH 07/16] r/aws_db_snapshot_copy: update exported attributes --- internal/service/rds/snapshot_copy.go | 8 +++++++- website/docs/r/rds_db_snapshot_copy.html.markdown | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/internal/service/rds/snapshot_copy.go b/internal/service/rds/snapshot_copy.go index de9c3984aa9..02945b732fd 100644 --- a/internal/service/rds/snapshot_copy.go +++ b/internal/service/rds/snapshot_copy.go @@ -171,15 +171,21 @@ func resourceSnapshotCopyRead(ctx context.Context, d *schema.ResourceData, meta arn := aws.StringValue(snapshot.DBSnapshotArn) + d.Set("allocated_storage", snapshot.AllocatedStorage) + d.Set("availability_zone", snapshot.AvailabilityZone) d.Set("db_snapshot_arn", snapshot.DBSnapshotArn) d.Set("encrypted", snapshot.Encrypted) d.Set("engine", snapshot.Engine) d.Set("engine_version", snapshot.EngineVersion) - d.Set("source_region", snapshot.SourceRegion) + d.Set("iops", snapshot.Iops) d.Set("kms_key_id", snapshot.KmsKeyId) + d.Set("license_model", snapshot.LicenseModel) + d.Set("option_group_name", snapshot.OptionGroupName) d.Set("source_db_snapshot_identifier", snapshot.SourceDBSnapshotIdentifier) + d.Set("source_region", snapshot.SourceRegion) d.Set("storage_type", snapshot.StorageType) d.Set("target_db_snapshot_identifier", snapshot.DBSnapshotIdentifier) + d.Set("vpc_id", snapshot.VpcId) tags, err := ListTags(conn, arn) diff --git a/website/docs/r/rds_db_snapshot_copy.html.markdown b/website/docs/r/rds_db_snapshot_copy.html.markdown index 7c6cf1c3398..7f6ac2ad3cc 100644 --- a/website/docs/r/rds_db_snapshot_copy.html.markdown +++ b/website/docs/r/rds_db_snapshot_copy.html.markdown @@ -42,7 +42,13 @@ resource "aws_rds_db_snapshot_copy" "example" { The following arguments are supported: +* `copy_tags` - (Optional) Whether to copy existing tags. Defaults to `false`. +* `destination_region` - (Optional) The Destination region to place snapshot copy. +* `kms_key_id` - (Optional) KMS key ID. +* `option_group_name`- (Optional) The name of an option group to associate with the copy of the snapshot. +* `presigned_url` - (Optional) he URL that contains a Signature Version 4 signed request. * `source_db_snapshot_identifier` - (Required) Snapshot identifier of the source snapshot. +* `target_custom_availability_zone` - (Optional) The external custom Availability Zone. * `target_db_snapshot_identifier` - (Required) The Identifier for the snapshot. * `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. @@ -51,6 +57,7 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: +* `id` - Snapshot Identifier. * `allocated_storage` - Specifies the allocated storage size in gigabytes (GB). * `availability_zone` - Specifies the name of the Availability Zone the DB instance was located in at the time of the DB snapshot. * `db_snapshot_arn` - The Amazon Resource Name (ARN) for the DB snapshot. From e2fb346a2dee3de68c7ceba54d0f460bced7735d Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 13 May 2022 19:44:20 -0500 Subject: [PATCH 08/16] r/aws_db_snapshot_copy: docs --- internal/service/rds/snapshot_copy_test.go | 44 ------------------- .../docs/r/rds_db_snapshot_copy.html.markdown | 2 +- 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/internal/service/rds/snapshot_copy_test.go b/internal/service/rds/snapshot_copy_test.go index acb9283f89e..182d445d2ca 100644 --- a/internal/service/rds/snapshot_copy_test.go +++ b/internal/service/rds/snapshot_copy_test.go @@ -162,47 +162,3 @@ resource "aws_rds_db_snapshot_copy" "test" { target_db_snapshot_identifier = "%[1]s-target" }`, rName)) } - -//func testAccAwsRdsDbSnapshotCopyConfigWithRegions(rInt int) string { -// return fmt.Sprintf(`provider "aws" { -// region = "us-west-2" -// alias = "uswest2" -//} -// -//provider "aws" { -// region = "us-west-1" -// alias = "uswest1" -//} -// -//resource "aws_db_instance" "bar" { -// provider = "aws.uswest2" -// allocated_storage = 10 -// engine = "MySQL" -// engine_version = "5.6.35" -// instance_class = "db.t2.micro" -// name = "baz" -// password = "barbarbarbar" -// username = "foo" -// -// maintenance_window = "Fri:09:00-Fri:09:30" -// -// backup_retention_period = 0 -// -// parameter_group_name = "default.mysql5.6" -// -// skip_final_snapshot = true -//} -// -//resource "aws_db_snapshot" "test" { -// provider = "aws.uswest2" -// db_instance_identifier = aws_db_instance.bar.id -// db_snapshot_identifier = "testsnapshot%d" -//} -// -//resource "aws_db_snapshot_copy" "test" { -// provider = "aws.uswest1" -// source_db_snapshot_identifier = aws_db_snapshot.test.db_snapshot_arn -// target_db_snapshot_identifier = "testsnapshot%d" -// source_region = "us-west-2" -//}`, rInt, rInt) -//} diff --git a/website/docs/r/rds_db_snapshot_copy.html.markdown b/website/docs/r/rds_db_snapshot_copy.html.markdown index 7f6ac2ad3cc..c19e95bfcfc 100644 --- a/website/docs/r/rds_db_snapshot_copy.html.markdown +++ b/website/docs/r/rds_db_snapshot_copy.html.markdown @@ -3,7 +3,7 @@ subcategory: "RDS (Relational Database)" layout: "aws" page_title: "AWS: aws_rds_db_snapshot" description: |- -Manages an RDS database instance snapshot copy. + Manages an RDS database instance snapshot copy. --- # Resource: aws_db_snapshot From b9d5a0459071147c5860d52aad4d661249be1d7f Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 13 May 2022 19:57:57 -0500 Subject: [PATCH 09/16] r/aws_db_snapshot_copy: fix docs --- website/docs/r/rds_db_snapshot_copy.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/rds_db_snapshot_copy.html.markdown b/website/docs/r/rds_db_snapshot_copy.html.markdown index c19e95bfcfc..a379cb5a44c 100644 --- a/website/docs/r/rds_db_snapshot_copy.html.markdown +++ b/website/docs/r/rds_db_snapshot_copy.html.markdown @@ -6,7 +6,7 @@ description: |- Manages an RDS database instance snapshot copy. --- -# Resource: aws_db_snapshot +# Resource: aws_rds_db_snapshot_copy Manages an RDS database instance snapshot copy. For managing RDS database cluster snapshots, see the [`aws_db_cluster_snapshot` resource](/docs/providers/aws/r/db_cluster_snapshot.html). From 03d893fd7cbde823013fb0e9b59d563fb0183183 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 13 May 2022 20:15:20 -0500 Subject: [PATCH 10/16] r/aws_db_snapshot_copy: fix validation function --- internal/service/rds/snapshot_copy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/rds/snapshot_copy.go b/internal/service/rds/snapshot_copy.go index 02945b732fd..5b994ccc42a 100644 --- a/internal/service/rds/snapshot_copy.go +++ b/internal/service/rds/snapshot_copy.go @@ -101,7 +101,7 @@ func ResourceSnapshotCopy() *schema.Resource { ForceNew: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 255), - validation.All(validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9][\w-]+`), "must contain only alphanumeric, and hyphen (-) characters")), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9][\w-]+`), "must contain only alphanumeric, and hyphen (-) characters"), ), }, }, From 510d4fff6ea2f1234c5f6ce65f7ed55716200228 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Mon, 16 May 2022 14:04:32 -0500 Subject: [PATCH 11/16] r/aws_db_snapshot_copy: update tests and attributes --- internal/provider/provider.go | 2 +- internal/service/rds/snapshot_copy.go | 31 +++++++ internal/service/rds/snapshot_copy_test.go | 86 ++++++++++++++++++- ...arkdown => db_snapshot_copy.html.markdown} | 10 +-- 4 files changed, 119 insertions(+), 10 deletions(-) rename website/docs/r/{rds_db_snapshot_copy.html.markdown => db_snapshot_copy.html.markdown} (93%) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 842f0d897b0..4752c850b8f 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1747,6 +1747,7 @@ func Provider() *schema.Provider { "aws_db_proxy_target": rds.ResourceProxyTarget(), "aws_db_security_group": rds.ResourceSecurityGroup(), "aws_db_snapshot": rds.ResourceSnapshot(), + "aws_db_snapshot_copy": rds.ResourceSnapshotCopy(), "aws_db_subnet_group": rds.ResourceSubnetGroup(), "aws_rds_cluster": rds.ResourceCluster(), "aws_rds_cluster_activity_stream": rds.ResourceClusterActivityStream(), @@ -1754,7 +1755,6 @@ func Provider() *schema.Provider { "aws_rds_cluster_instance": rds.ResourceClusterInstance(), "aws_rds_cluster_parameter_group": rds.ResourceClusterParameterGroup(), "aws_rds_cluster_role_association": rds.ResourceClusterRoleAssociation(), - "aws_rds_db_snapshot_copy": rds.ResourceSnapshotCopy(), "aws_rds_global_cluster": rds.ResourceGlobalCluster(), "aws_redshift_cluster": redshift.ResourceCluster(), diff --git a/internal/service/rds/snapshot_copy.go b/internal/service/rds/snapshot_copy.go index 5b994ccc42a..1f7971ef4a1 100644 --- a/internal/service/rds/snapshot_copy.go +++ b/internal/service/rds/snapshot_copy.go @@ -34,6 +34,14 @@ func ResourceSnapshotCopy() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "allocated_storage": { + Type: schema.TypeInt, + Computed: true, + }, + "availability_zone": { + Type: schema.TypeString, + Computed: true, + }, "copy_tags": { Type: schema.TypeBool, Optional: true, @@ -60,16 +68,29 @@ func ResourceSnapshotCopy() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "iops": { + Type: schema.TypeInt, + Computed: true, + }, "kms_key_id": { Type: schema.TypeString, Optional: true, ForceNew: true, }, + "license_model": { + Type: schema.TypeString, + Computed: true, + }, "option_group_name": { Type: schema.TypeString, Optional: true, + Computed: true, ForceNew: true, }, + "port": { + Type: schema.TypeInt, + Computed: true, + }, "presigned_url": { Type: schema.TypeString, Optional: true, @@ -84,6 +105,10 @@ func ResourceSnapshotCopy() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "snapshot_type": { + Type: schema.TypeString, + Computed: true, + }, "storage_type": { Type: schema.TypeString, Computed: true, @@ -104,6 +129,10 @@ func ResourceSnapshotCopy() *schema.Resource { validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9][\w-]+`), "must contain only alphanumeric, and hyphen (-) characters"), ), }, + "vpc_id": { + Type: schema.TypeString, + Computed: true, + }, }, CustomizeDiff: verify.SetTagsDiff, @@ -181,6 +210,8 @@ func resourceSnapshotCopyRead(ctx context.Context, d *schema.ResourceData, meta d.Set("kms_key_id", snapshot.KmsKeyId) d.Set("license_model", snapshot.LicenseModel) d.Set("option_group_name", snapshot.OptionGroupName) + d.Set("port", snapshot.Port) + d.Set("snapshot_type", snapshot.SnapshotType) d.Set("source_db_snapshot_identifier", snapshot.SourceDBSnapshotIdentifier) d.Set("source_region", snapshot.SourceRegion) d.Set("storage_type", snapshot.StorageType) diff --git a/internal/service/rds/snapshot_copy_test.go b/internal/service/rds/snapshot_copy_test.go index 182d445d2ca..d0c9b831d3f 100644 --- a/internal/service/rds/snapshot_copy_test.go +++ b/internal/service/rds/snapshot_copy_test.go @@ -22,7 +22,7 @@ func TestAccSnapshotCopy_basic(t *testing.T) { } var v rds.DBSnapshot - resourceName := "aws_rds_db_snapshot_copy.test" + resourceName := "aws_db_snapshot_copy.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ @@ -46,13 +46,62 @@ func TestAccSnapshotCopy_basic(t *testing.T) { }) } +func TestAccSnapshotCopy_tags(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var v rds.DBSnapshot + resourceName := "aws_db_snapshot_copy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckSnapshotCopyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccSnapshotCopyTagsConfig1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDbSnapshotExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccSnapshotCopyTagsConfig2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDbSnapshotExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccSnapshotCopyTagsConfig1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDbSnapshotExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + func TestAccSnapshotCopy_disappears(t *testing.T) { if testing.Short() { t.Skip("skipping long-running test in short mode") } var v rds.DBSnapshot - resourceName := "aws_rds_db_snapshot_copy.test" + resourceName := "aws_db_snapshot_copy.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ @@ -77,7 +126,7 @@ func testAccCheckSnapshotCopyDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_rds_db_snapshot_copy" { + if rs.Type != "aws_db_snapshot_copy" { continue } @@ -157,8 +206,37 @@ func testAccSnapshotCopyConfig(rName string) string { return acctest.ConfigCompose( testAccSnapshotCopyBaseConfig(rName), fmt.Sprintf(` -resource "aws_rds_db_snapshot_copy" "test" { +resource "aws_db_snapshot_copy" "test" { source_db_snapshot_identifier = aws_db_snapshot.test.db_snapshot_arn target_db_snapshot_identifier = "%[1]s-target" }`, rName)) } + +func testAccSnapshotCopyTagsConfig1(rName, tagKey, tagValue string) string { + return acctest.ConfigCompose( + testAccSnapshotCopyBaseConfig(rName), + fmt.Sprintf(` +resource "aws_db_snapshot_copy" "test" { + source_db_snapshot_identifier = aws_db_snapshot.test.db_snapshot_arn + target_db_snapshot_identifier = "%[1]s-target" + + tags = { + %[2]s = %[3]q + } +}`, rName, tagKey, tagValue)) +} + +func testAccSnapshotCopyTagsConfig2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return acctest.ConfigCompose( + testAccSnapshotCopyBaseConfig(rName), + fmt.Sprintf(` +resource "aws_db_snapshot_copy" "test" { + source_db_snapshot_identifier = aws_db_snapshot.test.db_snapshot_arn + target_db_snapshot_identifier = "%[1]s-target" + + tags = { + %[2]s = %[3]q + %[4]s = %[5]q + } +}`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) +} diff --git a/website/docs/r/rds_db_snapshot_copy.html.markdown b/website/docs/r/db_snapshot_copy.html.markdown similarity index 93% rename from website/docs/r/rds_db_snapshot_copy.html.markdown rename to website/docs/r/db_snapshot_copy.html.markdown index a379cb5a44c..39577ca95cd 100644 --- a/website/docs/r/rds_db_snapshot_copy.html.markdown +++ b/website/docs/r/db_snapshot_copy.html.markdown @@ -1,12 +1,12 @@ --- subcategory: "RDS (Relational Database)" layout: "aws" -page_title: "AWS: aws_rds_db_snapshot" +page_title: "AWS: aws_db_snapshot_copy" description: |- Manages an RDS database instance snapshot copy. --- -# Resource: aws_rds_db_snapshot_copy +# Resource: aws_db_snapshot_copy Manages an RDS database instance snapshot copy. For managing RDS database cluster snapshots, see the [`aws_db_cluster_snapshot` resource](/docs/providers/aws/r/db_cluster_snapshot.html). @@ -32,7 +32,7 @@ resource "aws_db_snapshot" "example" { db_snapshot_identifier = "%[1]s-source" } -resource "aws_rds_db_snapshot_copy" "example" { +resource "aws_db_snapshot_copy" "example" { source_db_snapshot_identifier = aws_db_snapshot.example.db_snapshot_arn target_db_snapshot_identifier = "testsnapshot1234" } @@ -82,8 +82,8 @@ In addition to all arguments above, the following attributes are exported: ## Import -`aws_rds_db_snapshot_copy` can be imported by using the snapshot identifier, e.g., +`aws_db_snapshot_copy` can be imported by using the snapshot identifier, e.g., ``` -$ terraform import aws_rds_db_snapshot_copy.example my-snapshot +$ terraform import aws_db_snapshot_copy.example my-snapshot ``` From 17e30ad167f12e8609e2c731f171ad1cbb0f8912 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Mon, 16 May 2022 14:08:09 -0500 Subject: [PATCH 12/16] r/aws_db_snapshot_copy: update error message --- internal/service/rds/snapshot_copy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/rds/snapshot_copy.go b/internal/service/rds/snapshot_copy.go index 1f7971ef4a1..40b7a5fea27 100644 --- a/internal/service/rds/snapshot_copy.go +++ b/internal/service/rds/snapshot_copy.go @@ -168,7 +168,7 @@ func resourceSnapshotCopyCreate(ctx context.Context, d *schema.ResourceData, met out, err := conn.CopyDBSnapshotWithContext(ctx, in) if err != nil { - return diag.Errorf("error creating DB Snapshot Copy %s", err) + return diag.Errorf("error creating RDS DB Snapshot Copy %s", err) } d.SetId(aws.StringValue(out.DBSnapshot.DBSnapshotIdentifier)) From 929e9b41d9970cde1510c2736f235730a3fa8b46 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Mon, 16 May 2022 14:17:39 -0500 Subject: [PATCH 13/16] r/aws_db_snapshot_copy: tests --- internal/service/rds/snapshot_copy_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/rds/snapshot_copy_test.go b/internal/service/rds/snapshot_copy_test.go index d0c9b831d3f..3ede7e98ac3 100644 --- a/internal/service/rds/snapshot_copy_test.go +++ b/internal/service/rds/snapshot_copy_test.go @@ -221,7 +221,7 @@ resource "aws_db_snapshot_copy" "test" { target_db_snapshot_identifier = "%[1]s-target" tags = { - %[2]s = %[3]q + %[2]q = %[3]q } }`, rName, tagKey, tagValue)) } @@ -235,8 +235,8 @@ resource "aws_db_snapshot_copy" "test" { target_db_snapshot_identifier = "%[1]s-target" tags = { - %[2]s = %[3]q - %[4]s = %[5]q + %[2]q = %[3]q + %[4]q = %[5]q } }`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) } From 70dbfe720ed668147006086b3e8e66c58ac74598 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Mon, 16 May 2022 14:19:19 -0500 Subject: [PATCH 14/16] update CHANGELOG for #9886 --- .changelog/9886.txtt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/9886.txtt diff --git a/.changelog/9886.txtt b/.changelog/9886.txtt new file mode 100644 index 00000000000..cdbd156e1d2 --- /dev/null +++ b/.changelog/9886.txtt @@ -0,0 +1,3 @@ +```release-note:new-resource + aws_db_snapshot_copy + ``` \ No newline at end of file From 569922f54165766442a90780a13f7b92f21f391b Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Mon, 16 May 2022 14:36:51 -0500 Subject: [PATCH 15/16] r/aws_db_snapshot_copy: testfmt --- internal/service/rds/snapshot_copy_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/rds/snapshot_copy_test.go b/internal/service/rds/snapshot_copy_test.go index 3ede7e98ac3..f09b61147c1 100644 --- a/internal/service/rds/snapshot_copy_test.go +++ b/internal/service/rds/snapshot_copy_test.go @@ -236,7 +236,7 @@ resource "aws_db_snapshot_copy" "test" { tags = { %[2]q = %[3]q - %[4]q = %[5]q + %[4]q = %[5]q } }`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) } From 0ce93b199ede04e8a918dad060227fdaafdb0b00 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Mon, 16 May 2022 15:50:13 -0500 Subject: [PATCH 16/16] r/aws_db_snapshot_copy: docs --- .changelog/{9886.txtt => 9886.txt} | 0 website/docs/r/db_snapshot_copy.html.markdown | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename .changelog/{9886.txtt => 9886.txt} (100%) diff --git a/.changelog/9886.txtt b/.changelog/9886.txt similarity index 100% rename from .changelog/9886.txtt rename to .changelog/9886.txt diff --git a/website/docs/r/db_snapshot_copy.html.markdown b/website/docs/r/db_snapshot_copy.html.markdown index 39577ca95cd..142042ed773 100644 --- a/website/docs/r/db_snapshot_copy.html.markdown +++ b/website/docs/r/db_snapshot_copy.html.markdown @@ -29,12 +29,12 @@ resource "aws_db_instance" "example" { resource "aws_db_snapshot" "example" { db_instance_identifier = aws_db_instance.example.id - db_snapshot_identifier = "%[1]s-source" + db_snapshot_identifier = "testsnapshot1234" } resource "aws_db_snapshot_copy" "example" { source_db_snapshot_identifier = aws_db_snapshot.example.db_snapshot_arn - target_db_snapshot_identifier = "testsnapshot1234" + target_db_snapshot_identifier = "testsnapshot1234-copy" } ``` @@ -76,7 +76,7 @@ In addition to all arguments above, the following attributes are exported: ## Timeouts -`aws_rds_db_snapshot_copy` provides the following [Timeouts](https://www.terraform.io/docs/configuration/blocks/resources/syntax.html#operation-timeouts) configuration options: +`aws_db_snapshot_copy` provides the following [Timeouts](https://www.terraform.io/docs/configuration/blocks/resources/syntax.html#operation-timeouts) configuration options: - `create` - (Default `20 minutes`) Length of time to wait for the snapshot to become available