Skip to content

Commit

Permalink
Merge pull request hashicorp#38540 from aristosvo/f-aws_rds_cluster-c…
Browse files Browse the repository at this point in the history
…luster_restore_via_resourceid

r/aws_rds_cluster: allow restore via cluster_resource_id to restore deleted clusters
  • Loading branch information
ewbankkit authored Jul 29, 2024
2 parents 9d23db3 + a8122cc commit 892d747
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 199 deletions.
7 changes: 7 additions & 0 deletions .changelog/38540.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_rds_cluster: Add `restore_to_point_in_time.source_cluster_resource_id` argument
```

```release-note:enhancement
resource/aws_rds_cluster: Mark `restore_to_point_in_time.source_cluster_identifier` as Optional
```
60 changes: 41 additions & 19 deletions internal/service/rds/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,11 +387,14 @@ func resourceCluster() *schema.Resource {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"restore_to_time": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: verify.ValidUTCTimestamp,
ConflictsWith: []string{"restore_to_point_in_time.0.use_latest_restorable_time"},
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: verify.ValidUTCTimestamp,
ExactlyOneOf: []string{
"restore_to_point_in_time.0.restore_to_time",
"restore_to_point_in_time.0.use_latest_restorable_time",
},
},
"restore_type": {
Type: schema.TypeString,
Expand All @@ -401,18 +404,34 @@ func resourceCluster() *schema.Resource {
},
"source_cluster_identifier": {
Type: schema.TypeString,
Required: true,
Optional: true,
ForceNew: true,
ValidateFunc: validation.Any(
verify.ValidARN,
validIdentifier,
),
ExactlyOneOf: []string{
"restore_to_point_in_time.0.source_cluster_identifier",
"restore_to_point_in_time.0.source_cluster_resource_id",
},
},
"source_cluster_resource_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ExactlyOneOf: []string{
"restore_to_point_in_time.0.source_cluster_identifier",
"restore_to_point_in_time.0.source_cluster_resource_id",
},
},
"use_latest_restorable_time": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
ConflictsWith: []string{"restore_to_point_in_time.0.restore_to_time"},
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
ExactlyOneOf: []string{
"restore_to_point_in_time.0.restore_to_time",
"restore_to_point_in_time.0.use_latest_restorable_time",
},
},
},
},
Expand Down Expand Up @@ -872,24 +891,27 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int
} else if v, ok := d.GetOk("restore_to_point_in_time"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil {
tfMap := v.([]interface{})[0].(map[string]interface{})
input := &rds.RestoreDBClusterToPointInTimeInput{
CopyTagsToSnapshot: aws.Bool(d.Get("copy_tags_to_snapshot").(bool)),
DBClusterIdentifier: aws.String(identifier),
DeletionProtection: aws.Bool(d.Get(names.AttrDeletionProtection).(bool)),
SourceDBClusterIdentifier: aws.String(tfMap["source_cluster_identifier"].(string)),
Tags: getTagsIn(ctx),
CopyTagsToSnapshot: aws.Bool(d.Get("copy_tags_to_snapshot").(bool)),
DBClusterIdentifier: aws.String(identifier),
DeletionProtection: aws.Bool(d.Get(names.AttrDeletionProtection).(bool)),
Tags: getTagsIn(ctx),
}

if v, ok := tfMap["restore_to_time"].(string); ok && v != "" {
v, _ := time.Parse(time.RFC3339, v)
input.RestoreToTime = aws.Time(v)
}

if v, ok := tfMap["use_latest_restorable_time"].(bool); ok && v {
input.UseLatestRestorableTime = aws.Bool(v)
if v, ok := tfMap["source_cluster_identifier"].(string); ok && v != "" {
input.SourceDBClusterIdentifier = aws.String(v)
}

if v, ok := tfMap["source_cluster_resource_id"].(string); ok && v != "" {
input.SourceDbClusterResourceId = aws.String(v)
}

if input.RestoreToTime == nil && input.UseLatestRestorableTime == nil {
return sdkdiag.AppendErrorf(diags, `Either "restore_to_time" or "use_latest_restorable_time" must be set`)
if v, ok := tfMap["use_latest_restorable_time"].(bool); ok && v {
input.UseLatestRestorableTime = aws.Bool(v)
}

if v, ok := d.GetOk("backtrack_window"); ok {
Expand Down
45 changes: 45 additions & 0 deletions internal/service/rds/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,35 @@ func TestAccRDSCluster_pointInTimeRestore(t *testing.T) {
})
}

func TestAccRDSCluster_pointInTimeRestoreViaResourceID(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
t.Skip("skipping long-running test in short mode")
}

var sourceDBCluster, dbCluster rds.DBCluster
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
sourceResourceName := "aws_rds_cluster.test"
resourceName := "aws_rds_cluster.restore"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.RDSServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckClusterDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccClusterConfig_pointInTimeRestoreSourceViaResourceID(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckClusterExists(ctx, sourceResourceName, &sourceDBCluster),
testAccCheckClusterExists(ctx, resourceName, &dbCluster),
resource.TestCheckResourceAttrPair(resourceName, names.AttrEngine, sourceResourceName, names.AttrEngine),
),
},
},
})
}

func TestAccRDSCluster_PointInTimeRestore_enabledCloudWatchLogsExports(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
Expand Down Expand Up @@ -3443,6 +3472,22 @@ resource "aws_rds_cluster" "restore" {
`, rName))
}

func testAccClusterConfig_pointInTimeRestoreSourceViaResourceID(rName string) string {
return acctest.ConfigCompose(testAccClusterConfig_baseForPITR(rName), fmt.Sprintf(`
resource "aws_rds_cluster" "restore" {
cluster_identifier = "%[1]s-restore"
skip_final_snapshot = true
engine = aws_rds_cluster.test.engine
restore_to_point_in_time {
source_cluster_resource_id = aws_rds_cluster.test.cluster_resource_id
restore_type = "full-copy"
use_latest_restorable_time = true
}
}
`, rName))
}

func testAccClusterConfig_pointInTimeRestoreSource_enabledCloudWatchLogsExports(rName, enabledCloudwatchLogExports string) string {
return acctest.ConfigCompose(testAccClusterConfig_baseForPITR(rName), fmt.Sprintf(`
resource "aws_rds_cluster" "restore" {
Expand Down
Loading

0 comments on commit 892d747

Please sign in to comment.