Skip to content

Commit 7055c4d

Browse files
Adding automated backup config to Redis (#13401) (#22117)
[upstream:3ba9ffacd77872416e7a528289c4137fb09f40a4] Signed-off-by: Modular Magician <[email protected]>
1 parent 49617a1 commit 7055c4d

File tree

5 files changed

+341
-0
lines changed

5 files changed

+341
-0
lines changed

.changelog/13401.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
redis: added `automated_backup_config` field to `google_redis_cluster`
3+
```

google/services/redis/resource_redis_cluster.go

+230
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,50 @@ projects/{projectId}/locations/{locationId}/clusters/{clusterId}`,
8080
Description: `Optional. The authorization mode of the Redis cluster. If not provided, auth feature is disabled for the cluster. Default value: "AUTH_MODE_DISABLED" Possible values: ["AUTH_MODE_UNSPECIFIED", "AUTH_MODE_IAM_AUTH", "AUTH_MODE_DISABLED"]`,
8181
Default: "AUTH_MODE_DISABLED",
8282
},
83+
"automated_backup_config": {
84+
Type: schema.TypeList,
85+
Optional: true,
86+
Description: `The automated backup config for a instance.`,
87+
MaxItems: 1,
88+
Elem: &schema.Resource{
89+
Schema: map[string]*schema.Schema{
90+
"fixed_frequency_schedule": {
91+
Type: schema.TypeList,
92+
Required: true,
93+
Description: `Trigger automated backups at a fixed frequency.`,
94+
MaxItems: 1,
95+
Elem: &schema.Resource{
96+
Schema: map[string]*schema.Schema{
97+
"start_time": {
98+
Type: schema.TypeList,
99+
Required: true,
100+
Description: `The start time of every automated backup in UTC.
101+
It must be set to the start of an hour. This field is required.`,
102+
MaxItems: 1,
103+
Elem: &schema.Resource{
104+
Schema: map[string]*schema.Schema{
105+
"hours": {
106+
Type: schema.TypeInt,
107+
Required: true,
108+
Description: `Hours of a day in 24 hour format. Must be greater than or equal to 0 and typically must be less than or equal to 23.
109+
An API may choose to allow the value "24:00:00" for scenarios like business closing time.`,
110+
},
111+
},
112+
},
113+
},
114+
},
115+
},
116+
},
117+
"retention": {
118+
Type: schema.TypeString,
119+
Required: true,
120+
Description: `How long to keep automated backups before the backups are deleted.
121+
The value should be between 1 day and 365 days. If not specified, the default value is 35 days.
122+
A duration in seconds with up to nine fractional digits, ending with 's'. Example: "3.5s".`,
123+
},
124+
},
125+
},
126+
},
83127
"cross_cluster_replication_config": {
84128
Type: schema.TypeList,
85129
Computed: true,
@@ -656,6 +700,12 @@ func resourceRedisClusterCreate(d *schema.ResourceData, meta interface{}) error
656700
}
657701

658702
obj := make(map[string]interface{})
703+
automatedBackupConfigProp, err := expandRedisClusterAutomatedBackupConfig(d.Get("automated_backup_config"), d, config)
704+
if err != nil {
705+
return err
706+
} else if v, ok := d.GetOkExists("automated_backup_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(automatedBackupConfigProp)) && (ok || !reflect.DeepEqual(v, automatedBackupConfigProp)) {
707+
obj["automatedBackupConfig"] = automatedBackupConfigProp
708+
}
659709
authorizationModeProp, err := expandRedisClusterAuthorizationMode(d.Get("authorization_mode"), d, config)
660710
if err != nil {
661711
return err
@@ -735,6 +785,11 @@ func resourceRedisClusterCreate(d *schema.ResourceData, meta interface{}) error
735785
obj["kmsKey"] = kmsKeyProp
736786
}
737787

788+
obj, err = resourceRedisClusterEncoder(d, meta, obj)
789+
if err != nil {
790+
return err
791+
}
792+
738793
url, err := tpgresource.ReplaceVars(d, config, "{{RedisBasePath}}projects/{{project}}/locations/{{region}}/clusters?clusterId={{name}}")
739794
if err != nil {
740795
return err
@@ -850,6 +905,9 @@ func resourceRedisClusterRead(d *schema.ResourceData, meta interface{}) error {
850905
if err := d.Set("uid", flattenRedisClusterUid(res["uid"], d, config)); err != nil {
851906
return fmt.Errorf("Error reading Cluster: %s", err)
852907
}
908+
if err := d.Set("automated_backup_config", flattenRedisClusterAutomatedBackupConfig(res["automatedBackupConfig"], d, config)); err != nil {
909+
return fmt.Errorf("Error reading Cluster: %s", err)
910+
}
853911
if err := d.Set("authorization_mode", flattenRedisClusterAuthorizationMode(res["authorizationMode"], d, config)); err != nil {
854912
return fmt.Errorf("Error reading Cluster: %s", err)
855913
}
@@ -927,6 +985,12 @@ func resourceRedisClusterUpdate(d *schema.ResourceData, meta interface{}) error
927985
billingProject = project
928986

929987
obj := make(map[string]interface{})
988+
automatedBackupConfigProp, err := expandRedisClusterAutomatedBackupConfig(d.Get("automated_backup_config"), d, config)
989+
if err != nil {
990+
return err
991+
} else if v, ok := d.GetOkExists("automated_backup_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, automatedBackupConfigProp)) {
992+
obj["automatedBackupConfig"] = automatedBackupConfigProp
993+
}
930994
nodeTypeProp, err := expandRedisClusterNodeType(d.Get("node_type"), d, config)
931995
if err != nil {
932996
return err
@@ -988,6 +1052,11 @@ func resourceRedisClusterUpdate(d *schema.ResourceData, meta interface{}) error
9881052
obj["kmsKey"] = kmsKeyProp
9891053
}
9901054

1055+
obj, err = resourceRedisClusterEncoder(d, meta, obj)
1056+
if err != nil {
1057+
return err
1058+
}
1059+
9911060
url, err := tpgresource.ReplaceVars(d, config, "{{RedisBasePath}}projects/{{project}}/locations/{{region}}/clusters/{{name}}")
9921061
if err != nil {
9931062
return err
@@ -997,6 +1066,10 @@ func resourceRedisClusterUpdate(d *schema.ResourceData, meta interface{}) error
9971066
headers := make(http.Header)
9981067
updateMask := []string{}
9991068

1069+
if d.HasChange("automated_backup_config") {
1070+
updateMask = append(updateMask, "automatedBackupConfig")
1071+
}
1072+
10001073
if d.HasChange("node_type") {
10011074
updateMask = append(updateMask, "nodeType")
10021075
}
@@ -1168,6 +1241,72 @@ func flattenRedisClusterUid(v interface{}, d *schema.ResourceData, config *trans
11681241
return v
11691242
}
11701243

1244+
func flattenRedisClusterAutomatedBackupConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1245+
if v == nil {
1246+
return nil
1247+
}
1248+
original := v.(map[string]interface{})
1249+
if len(original) == 0 {
1250+
return nil
1251+
}
1252+
// if automated_backup_config is not defined
1253+
if original["automatedBackupMode"] == "DISABLED" {
1254+
return nil
1255+
}
1256+
transformed := make(map[string]interface{})
1257+
transformed["fixed_frequency_schedule"] =
1258+
flattenRedisClusterAutomatedBackupConfigFixedFrequencySchedule(original["fixedFrequencySchedule"], d, config)
1259+
transformed["retention"] =
1260+
flattenRedisClusterAutomatedBackupConfigRetention(original["retention"], d, config)
1261+
return []interface{}{transformed}
1262+
}
1263+
func flattenRedisClusterAutomatedBackupConfigFixedFrequencySchedule(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1264+
if v == nil {
1265+
return nil
1266+
}
1267+
original := v.(map[string]interface{})
1268+
if len(original) == 0 {
1269+
return nil
1270+
}
1271+
transformed := make(map[string]interface{})
1272+
transformed["start_time"] =
1273+
flattenRedisClusterAutomatedBackupConfigFixedFrequencyScheduleStartTime(original["startTime"], d, config)
1274+
return []interface{}{transformed}
1275+
}
1276+
func flattenRedisClusterAutomatedBackupConfigFixedFrequencyScheduleStartTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1277+
if v == nil {
1278+
return nil
1279+
}
1280+
original := v.(map[string]interface{})
1281+
if len(original) == 0 {
1282+
return nil
1283+
}
1284+
transformed := make(map[string]interface{})
1285+
transformed["hours"] =
1286+
flattenRedisClusterAutomatedBackupConfigFixedFrequencyScheduleStartTimeHours(original["hours"], d, config)
1287+
return []interface{}{transformed}
1288+
}
1289+
func flattenRedisClusterAutomatedBackupConfigFixedFrequencyScheduleStartTimeHours(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1290+
// Handles the string fixed64 format
1291+
if strVal, ok := v.(string); ok {
1292+
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
1293+
return intVal
1294+
}
1295+
}
1296+
1297+
// number values are represented as float64
1298+
if floatVal, ok := v.(float64); ok {
1299+
intVal := int(floatVal)
1300+
return intVal
1301+
}
1302+
1303+
return v // let terraform core handle it otherwise
1304+
}
1305+
1306+
func flattenRedisClusterAutomatedBackupConfigRetention(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1307+
return v
1308+
}
1309+
11711310
func flattenRedisClusterAuthorizationMode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
11721311
return v
11731312
}
@@ -1830,6 +1969,85 @@ func flattenRedisClusterKmsKey(v interface{}, d *schema.ResourceData, config *tr
18301969
return v
18311970
}
18321971

1972+
func expandRedisClusterAutomatedBackupConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1973+
l := v.([]interface{})
1974+
if len(l) == 0 || l[0] == nil {
1975+
return nil, nil
1976+
}
1977+
raw := l[0]
1978+
original := raw.(map[string]interface{})
1979+
// The automated_backup_config block is not specified, so automatedBackupMode should be DISABLED
1980+
transformed := make(map[string]interface{})
1981+
if len(d.Get("automated_backup_config").([]interface{})) < 1 {
1982+
transformed["automatedBackupMode"] = "DISABLED"
1983+
return transformed, nil
1984+
}
1985+
1986+
// The automated_backup_config block is specified, so automatedBackupMode should be ENALBED
1987+
transformed["automatedBackupMode"] = "ENABLED"
1988+
transformedFixedFrequencySchedule, err := expandRedisClusterAutomatedBackupConfigFixedFrequencySchedule(original["fixed_frequency_schedule"], d, config)
1989+
if err != nil {
1990+
return nil, err
1991+
} else if val := reflect.ValueOf(transformedFixedFrequencySchedule); val.IsValid() && !tpgresource.IsEmptyValue(val) {
1992+
transformed["fixedFrequencySchedule"] = transformedFixedFrequencySchedule
1993+
}
1994+
1995+
transformedRetention, err := expandRedisClusterAutomatedBackupConfigRetention(original["retention"], d, config)
1996+
if err != nil {
1997+
return nil, err
1998+
} else if val := reflect.ValueOf(transformedRetention); val.IsValid() && !tpgresource.IsEmptyValue(val) {
1999+
transformed["retention"] = transformedRetention
2000+
}
2001+
2002+
return transformed, nil
2003+
}
2004+
2005+
func expandRedisClusterAutomatedBackupConfigFixedFrequencySchedule(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
2006+
l := v.([]interface{})
2007+
if len(l) == 0 || l[0] == nil {
2008+
return nil, nil
2009+
}
2010+
raw := l[0]
2011+
original := raw.(map[string]interface{})
2012+
transformed := make(map[string]interface{})
2013+
2014+
transformedStartTime, err := expandRedisClusterAutomatedBackupConfigFixedFrequencyScheduleStartTime(original["start_time"], d, config)
2015+
if err != nil {
2016+
return nil, err
2017+
} else if val := reflect.ValueOf(transformedStartTime); val.IsValid() && !tpgresource.IsEmptyValue(val) {
2018+
transformed["startTime"] = transformedStartTime
2019+
}
2020+
2021+
return transformed, nil
2022+
}
2023+
2024+
func expandRedisClusterAutomatedBackupConfigFixedFrequencyScheduleStartTime(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
2025+
l := v.([]interface{})
2026+
if len(l) == 0 || l[0] == nil {
2027+
return nil, nil
2028+
}
2029+
raw := l[0]
2030+
original := raw.(map[string]interface{})
2031+
transformed := make(map[string]interface{})
2032+
2033+
transformedHours, err := expandRedisClusterAutomatedBackupConfigFixedFrequencyScheduleStartTimeHours(original["hours"], d, config)
2034+
if err != nil {
2035+
return nil, err
2036+
} else if val := reflect.ValueOf(transformedHours); val.IsValid() && !tpgresource.IsEmptyValue(val) {
2037+
transformed["hours"] = transformedHours
2038+
}
2039+
2040+
return transformed, nil
2041+
}
2042+
2043+
func expandRedisClusterAutomatedBackupConfigFixedFrequencyScheduleStartTimeHours(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
2044+
return v, nil
2045+
}
2046+
2047+
func expandRedisClusterAutomatedBackupConfigRetention(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
2048+
return v, nil
2049+
}
2050+
18332051
func expandRedisClusterAuthorizationMode(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
18342052
return v, nil
18352053
}
@@ -2391,3 +2609,15 @@ func expandRedisClusterCrossClusterReplicationConfigUpdateTime(v interface{}, d
23912609
func expandRedisClusterKmsKey(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
23922610
return v, nil
23932611
}
2612+
2613+
func resourceRedisClusterEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
2614+
2615+
// if the automated_backup_config is not defined, automatedBackupMode needs to be passed and set to DISABLED in the expand
2616+
if obj["automatedBackupConfig"] == nil {
2617+
config := meta.(*transport_tpg.Config)
2618+
automatedBackupConfigProp, _ := expandRedisClusterAutomatedBackupConfig(d.Get("automated_backup_config"), d, config)
2619+
obj["automatedBackupConfig"] = automatedBackupConfigProp
2620+
}
2621+
2622+
return obj, nil
2623+
}

google/services/redis/resource_redis_cluster_generated_meta.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ api_version: 'v1'
66
api_resource_type_kind: 'Cluster'
77
fields:
88
- field: 'authorization_mode'
9+
- field: 'automated_backup_config.fixed_frequency_schedule.start_time.hours'
10+
- field: 'automated_backup_config.retention'
911
- field: 'create_time'
1012
- field: 'cross_cluster_replication_config.cluster_role'
1113
- field: 'cross_cluster_replication_config.membership.primary_cluster.cluster'
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,74 @@
11
// Copyright (c) HashiCorp, Inc.
22
// SPDX-License-Identifier: MPL-2.0
33
package redis_test
4+
5+
import (
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
9+
"github.com/hashicorp/terraform-provider-google/google/acctest"
10+
)
11+
12+
func TestAccRedisCluster_automatedBackupConfig(t *testing.T) {
13+
t.Parallel()
14+
15+
context := map[string]interface{}{
16+
"random_suffix": acctest.RandString(t, 10),
17+
}
18+
19+
acctest.VcrTest(t, resource.TestCase{
20+
PreCheck: func() { acctest.AccTestPreCheck(t) },
21+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
22+
CheckDestroy: testAccCheckRedisClusterDestroyProducer(t),
23+
Steps: []resource.TestStep{
24+
{
25+
Config: testAccRedisCluster_automatedBackupConfig(context),
26+
},
27+
{
28+
ResourceName: "google_redis_cluster.cluster_abc",
29+
ImportState: true,
30+
ImportStateVerify: true,
31+
},
32+
{
33+
Config: testAccRedisCluster_automatedBackupConfigWithout(context),
34+
},
35+
{
36+
ResourceName: "google_redis_cluster.cluster_abc",
37+
ImportState: true,
38+
ImportStateVerify: true,
39+
},
40+
},
41+
})
42+
}
43+
44+
func testAccRedisCluster_automatedBackupConfig(context map[string]interface{}) string {
45+
return acctest.Nprintf(`
46+
resource "google_redis_cluster" "cluster_abc" {
47+
name = "tf-test-redis-abc-%{random_suffix}"
48+
shard_count = 1
49+
region = "us-central1"
50+
deletion_protection_enabled = false
51+
automated_backup_config {
52+
retention = "259200s"
53+
fixed_frequency_schedule {
54+
start_time {
55+
hours = 20
56+
}
57+
}
58+
}
59+
60+
}
61+
`, context)
62+
}
63+
64+
func testAccRedisCluster_automatedBackupConfigWithout(context map[string]interface{}) string {
65+
return acctest.Nprintf(`
66+
resource "google_redis_cluster" "cluster_abc" {
67+
name = "tf-test-redis-abc-%{random_suffix}"
68+
shard_count = 1
69+
region = "us-central1"
70+
deletion_protection_enabled = false
71+
72+
}
73+
`, context)
74+
}

0 commit comments

Comments
 (0)