Skip to content

Commit a568038

Browse files
modular-magicianNickElliotshuyama1
authored
Add support for restoring AlloyDB clusters via backup restore and PITR (#8575) (#6129)
Signed-off-by: Modular Magician <[email protected]> Co-authored-by: Nick Elliot <[email protected]> Co-authored-by: Shuya Ma <[email protected]>
1 parent 070141a commit a568038

File tree

5 files changed

+885
-2
lines changed

5 files changed

+885
-2
lines changed

.changelog/8575.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
alloydb: added `restore_backup_source` and `restore_continuous_backup_source` fields to support restore feature in `google_alloydb_cluster` resource.
3+
```

google-beta/services/alloydb/resource_alloydb_cluster.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,48 @@ If not set, defaults to 14 days.`,
296296
Description: `User-defined labels for the alloydb cluster.`,
297297
Elem: &schema.Schema{Type: schema.TypeString},
298298
},
299+
"restore_backup_source": {
300+
Type: schema.TypeList,
301+
Optional: true,
302+
ForceNew: true,
303+
Description: `The source when restoring from a backup. Conflicts with 'restore_continuous_backup_source', both can't be set together.`,
304+
MaxItems: 1,
305+
Elem: &schema.Resource{
306+
Schema: map[string]*schema.Schema{
307+
"backup_name": {
308+
Type: schema.TypeString,
309+
Required: true,
310+
ForceNew: true,
311+
Description: `The name of the backup that this cluster is restored from.`,
312+
},
313+
},
314+
},
315+
ConflictsWith: []string{"restore_continuous_backup_source"},
316+
},
317+
"restore_continuous_backup_source": {
318+
Type: schema.TypeList,
319+
Optional: true,
320+
ForceNew: true,
321+
Description: `The source when restoring via point in time recovery (PITR). Conflicts with 'restore_backup_source', both can't be set together.`,
322+
MaxItems: 1,
323+
Elem: &schema.Resource{
324+
Schema: map[string]*schema.Schema{
325+
"cluster": {
326+
Type: schema.TypeString,
327+
Required: true,
328+
ForceNew: true,
329+
Description: `The name of the source cluster that this cluster is restored from.`,
330+
},
331+
"point_in_time": {
332+
Type: schema.TypeString,
333+
Required: true,
334+
ForceNew: true,
335+
Description: `The point in time that this cluster is restored to, in RFC 3339 format.`,
336+
},
337+
},
338+
},
339+
ConflictsWith: []string{"restore_backup_source"},
340+
},
299341
"backup_source": {
300342
Type: schema.TypeList,
301343
Computed: true,
@@ -469,6 +511,18 @@ func resourceAlloydbClusterCreate(d *schema.ResourceData, meta interface{}) erro
469511
} else if v, ok := d.GetOkExists("initial_user"); !tpgresource.IsEmptyValue(reflect.ValueOf(initialUserProp)) && (ok || !reflect.DeepEqual(v, initialUserProp)) {
470512
obj["initialUser"] = initialUserProp
471513
}
514+
restoreBackupSourceProp, err := expandAlloydbClusterRestoreBackupSource(d.Get("restore_backup_source"), d, config)
515+
if err != nil {
516+
return err
517+
} else if v, ok := d.GetOkExists("restore_backup_source"); !tpgresource.IsEmptyValue(reflect.ValueOf(restoreBackupSourceProp)) && (ok || !reflect.DeepEqual(v, restoreBackupSourceProp)) {
518+
obj["restoreBackupSource"] = restoreBackupSourceProp
519+
}
520+
restoreContinuousBackupSourceProp, err := expandAlloydbClusterRestoreContinuousBackupSource(d.Get("restore_continuous_backup_source"), d, config)
521+
if err != nil {
522+
return err
523+
} else if v, ok := d.GetOkExists("restore_continuous_backup_source"); !tpgresource.IsEmptyValue(reflect.ValueOf(restoreContinuousBackupSourceProp)) && (ok || !reflect.DeepEqual(v, restoreContinuousBackupSourceProp)) {
524+
obj["restoreContinuousBackupSource"] = restoreContinuousBackupSourceProp
525+
}
472526
continuousBackupConfigProp, err := expandAlloydbClusterContinuousBackupConfig(d.Get("continuous_backup_config"), d, config)
473527
if err != nil {
474528
return err
@@ -501,6 +555,39 @@ func resourceAlloydbClusterCreate(d *schema.ResourceData, meta interface{}) erro
501555
billingProject = bp
502556
}
503557

558+
// Read the restore variables from obj and remove them, since they do not map to anything in the cluster
559+
var backupSource interface{}
560+
var continuousBackupSource interface{}
561+
if val, ok := obj["restoreBackupSource"]; ok {
562+
backupSource = val
563+
delete(obj, "restoreBackupSource")
564+
}
565+
if val, ok := obj["restoreContinuousBackupSource"]; ok {
566+
continuousBackupSource = val
567+
delete(obj, "restoreContinuousBackupSource")
568+
}
569+
570+
restoreClusterRequestBody := make(map[string]interface{})
571+
if backupSource != nil {
572+
// If restoring from a backup, set the backupSource
573+
restoreClusterRequestBody["backup_source"] = backupSource
574+
} else if continuousBackupSource != nil {
575+
// Otherwise if restoring via PITR, set the continuousBackupSource
576+
restoreClusterRequestBody["continuous_backup_source"] = continuousBackupSource
577+
}
578+
579+
if backupSource != nil || continuousBackupSource != nil {
580+
// Use restore API if this is a restore instead of a create cluster call
581+
url = strings.Replace(url, "clusters?clusterId", "clusters:restore?clusterId", 1)
582+
583+
// Copy obj which contains the cluster into a cluster map
584+
cluster := make(map[string]interface{})
585+
for k, v := range obj {
586+
cluster[k] = v
587+
}
588+
restoreClusterRequestBody["cluster"] = cluster
589+
obj = restoreClusterRequestBody
590+
}
504591
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
505592
Config: config,
506593
Method: "POST",
@@ -1337,6 +1424,63 @@ func expandAlloydbClusterInitialUserPassword(v interface{}, d tpgresource.Terraf
13371424
return v, nil
13381425
}
13391426

1427+
func expandAlloydbClusterRestoreBackupSource(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1428+
l := v.([]interface{})
1429+
if len(l) == 0 || l[0] == nil {
1430+
return nil, nil
1431+
}
1432+
raw := l[0]
1433+
original := raw.(map[string]interface{})
1434+
transformed := make(map[string]interface{})
1435+
1436+
transformedBackupName, err := expandAlloydbClusterRestoreBackupSourceBackupName(original["backup_name"], d, config)
1437+
if err != nil {
1438+
return nil, err
1439+
} else if val := reflect.ValueOf(transformedBackupName); val.IsValid() && !tpgresource.IsEmptyValue(val) {
1440+
transformed["backupName"] = transformedBackupName
1441+
}
1442+
1443+
return transformed, nil
1444+
}
1445+
1446+
func expandAlloydbClusterRestoreBackupSourceBackupName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1447+
return v, nil
1448+
}
1449+
1450+
func expandAlloydbClusterRestoreContinuousBackupSource(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1451+
l := v.([]interface{})
1452+
if len(l) == 0 || l[0] == nil {
1453+
return nil, nil
1454+
}
1455+
raw := l[0]
1456+
original := raw.(map[string]interface{})
1457+
transformed := make(map[string]interface{})
1458+
1459+
transformedCluster, err := expandAlloydbClusterRestoreContinuousBackupSourceCluster(original["cluster"], d, config)
1460+
if err != nil {
1461+
return nil, err
1462+
} else if val := reflect.ValueOf(transformedCluster); val.IsValid() && !tpgresource.IsEmptyValue(val) {
1463+
transformed["cluster"] = transformedCluster
1464+
}
1465+
1466+
transformedPointInTime, err := expandAlloydbClusterRestoreContinuousBackupSourcePointInTime(original["point_in_time"], d, config)
1467+
if err != nil {
1468+
return nil, err
1469+
} else if val := reflect.ValueOf(transformedPointInTime); val.IsValid() && !tpgresource.IsEmptyValue(val) {
1470+
transformed["pointInTime"] = transformedPointInTime
1471+
}
1472+
1473+
return transformed, nil
1474+
}
1475+
1476+
func expandAlloydbClusterRestoreContinuousBackupSourceCluster(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1477+
return v, nil
1478+
}
1479+
1480+
func expandAlloydbClusterRestoreContinuousBackupSourcePointInTime(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1481+
return v, nil
1482+
}
1483+
13401484
func expandAlloydbClusterContinuousBackupConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
13411485
l := v.([]interface{})
13421486
if len(l) == 0 || l[0] == nil {

google-beta/services/alloydb/resource_alloydb_cluster_generated_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func TestAccAlloydbCluster_alloydbClusterBasicExample(t *testing.T) {
4949
ResourceName: "google_alloydb_cluster.default",
5050
ImportState: true,
5151
ImportStateVerify: true,
52-
ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"},
52+
ImportStateVerifyIgnore: []string{"initial_user", "restore_backup_source", "restore_continuous_backup_source", "cluster_id", "location"},
5353
},
5454
},
5555
})
@@ -90,7 +90,7 @@ func TestAccAlloydbCluster_alloydbClusterFullExample(t *testing.T) {
9090
ResourceName: "google_alloydb_cluster.full",
9191
ImportState: true,
9292
ImportStateVerify: true,
93-
ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"},
93+
ImportStateVerifyIgnore: []string{"initial_user", "restore_backup_source", "restore_continuous_backup_source", "cluster_id", "location"},
9494
},
9595
},
9696
})

0 commit comments

Comments
 (0)