Skip to content

Commit ad22c3d

Browse files
Merge pull request #646 from RedisLabs/feat/OPCR-18-upgrade-path-pro-database
OPCR-18 upgrade path pro database
2 parents ce4955b + 5f49c2b commit ad22c3d

10 files changed

+222
-26
lines changed

.github/workflows/terraform_provider_pr.yml

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,29 +114,28 @@ jobs:
114114
- run: EXECUTE_TESTS=true make testacc TESTARGS='-run="TestAccResourceRedisCloudActiveActiveDatabase_CRUDI"'
115115

116116

117-
go_test_smoke_essentials_db:
118-
name: go test smoke essentials db
117+
go_test_smoke_essentials_sub:
118+
name: go test smoke essentials sub
119119
needs: [go_build]
120120
runs-on: ubuntu-latest
121121
steps:
122122
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
123123
- uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
124124
with:
125125
go-version-file: go.mod
126-
- run: EXECUTE_TESTS=true make testacc TESTARGS='-run="TestAccResourceRedisCloudEssentialsDatabase_CRUDI"'
126+
- run: EXECUTE_TESTS=true make testacc TESTARGS='-run="TestAccResourceRedisCloudEssentialsSubscription"'
127127

128128

129-
go_test_smoke_essentials_sub:
130-
name: go test smoke essentials sub
131-
needs: [go_build]
129+
go_test_smoke_essentials_db:
130+
name: go test smoke essentials db
131+
needs: go_test_smoke_essentials_sub
132132
runs-on: ubuntu-latest
133133
steps:
134134
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
135135
- uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
136136
with:
137137
go-version-file: go.mod
138-
- run: EXECUTE_TESTS=true make testacc TESTARGS='-run="TestAccResourceRedisCloudEssentialsSubscription"'
139-
138+
- run: EXECUTE_TESTS=true make testacc TESTARGS='-run="TestAccResourceRedisCloudEssentialsDatabase_CRUDI"'
140139

141140
go_test_smoke_pro_db:
142141
name: go test smoke pro db
@@ -161,6 +160,18 @@ jobs:
161160
go-version-file: go.mod
162161
- run: EXECUTE_TESTS=true make testacc TESTARGS='-run="TestAccResourceRedisCloud(PrivateServiceConnect_CRUDI|AclRule_CRUDI)"'
163162

163+
go_test_pro_db_upgrade:
164+
name: go test smoke pro db upgrade
165+
needs: [ go_build ]
166+
runs-on: ubuntu-latest
167+
steps:
168+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
169+
- uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
170+
with:
171+
go-version-file: go.mod
172+
- run: EXECUTE_TESTS=true make testacc TESTARGS='-run="TestAccResourceRedisCloudProDatabase_Upgrade"'
173+
174+
164175
tfproviderlint:
165176
name: tfproviderlint
166177
needs: [go_build]

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/RedisLabs/terraform-provider-rediscloud
33
go 1.22.4
44

55
require (
6-
github.com/RedisLabs/rediscloud-go-api v0.32.0
6+
github.com/RedisLabs/rediscloud-go-api v0.33.1
77
github.com/bflad/tfproviderlint v0.31.0
88
github.com/hashicorp/go-cty v1.5.0
99
github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc
44
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
55
github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
66
github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
7-
github.com/RedisLabs/rediscloud-go-api v0.32.0 h1:gjOt+8nyMR8MZ5spCz6BXDDdOZrzf7NJJUw4lz8OCGE=
8-
github.com/RedisLabs/rediscloud-go-api v0.32.0/go.mod h1:3/oVb71rv2OstFRYEc65QCIbfwnJTgZeQhtPCcdHook=
7+
github.com/RedisLabs/rediscloud-go-api v0.33.1 h1:sOCGvkvgY4jnH/mMQcA6XO8p1YQ2HfFvtbiblkA1Z/c=
8+
github.com/RedisLabs/rediscloud-go-api v0.33.1/go.mod h1:3/oVb71rv2OstFRYEc65QCIbfwnJTgZeQhtPCcdHook=
99
github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
1010
github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
1111
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=

provider/rediscloud_essentials_subscription_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func TestAccResourceRedisCloudEssentialsSubscription_Free_CRUDI(t *testing.T) {
2626
const resourceName = "rediscloud_essentials_subscription.example"
2727
const datasourceName = "data.rediscloud_essentials_subscription.example"
2828

29-
resource.ParallelTest(t, resource.TestCase{
29+
resource.Test(t, resource.TestCase{
3030
PreCheck: func() { testAccPreCheck(t) },
3131
ProviderFactories: providerFactories,
3232
CheckDestroy: testAccCheckEssentialsSubscriptionDestroy,
@@ -91,7 +91,7 @@ func TestAccResourceRedisCloudEssentialsSubscription_Paid_CreditCard_CRUDI(t *te
9191
const resourceName = "rediscloud_essentials_subscription.example"
9292
const datasourceName = "data.rediscloud_essentials_subscription.example"
9393

94-
resource.ParallelTest(t, resource.TestCase{
94+
resource.Test(t, resource.TestCase{
9595
PreCheck: func() { testAccPreCheck(t) },
9696
ProviderFactories: providerFactories,
9797
CheckDestroy: testAccCheckEssentialsSubscriptionDestroy,
@@ -157,7 +157,7 @@ func TestAccResourceRedisCloudEssentialsSubscription_Paid_NoPaymentType_CRUDI(t
157157
const resourceName = "rediscloud_essentials_subscription.example"
158158
const datasourceName = "data.rediscloud_essentials_subscription.example"
159159

160-
resource.ParallelTest(t, resource.TestCase{
160+
resource.Test(t, resource.TestCase{
161161
PreCheck: func() { testAccPreCheck(t) },
162162
ProviderFactories: providerFactories,
163163
CheckDestroy: testAccCheckEssentialsSubscriptionDestroy,
@@ -228,7 +228,7 @@ func TestAccResourceRedisCloudEssentialsSubscription_Paid_Marketplace_CRUDI(t *t
228228
const resourceName = "rediscloud_essentials_subscription.example"
229229
const datasourceName = "data.rediscloud_essentials_subscription.example"
230230

231-
resource.ParallelTest(t, resource.TestCase{
231+
resource.Test(t, resource.TestCase{
232232
PreCheck: func() { testAccPreCheck(t) },
233233
ProviderFactories: providerFactories,
234234
CheckDestroy: testAccCheckEssentialsSubscriptionDestroy,

provider/resource_rediscloud_essentials_database_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestAccResourceRedisCloudEssentialsDatabase_CRUDI(t *testing.T) {
1919
const resourceName = "rediscloud_essentials_database.example"
2020
const datasourceName = "data.rediscloud_essentials_database.example"
2121

22-
resource.ParallelTest(t, resource.TestCase{
22+
resource.Test(t, resource.TestCase{
2323
PreCheck: func() { testAccPreCheck(t) },
2424
ProviderFactories: providerFactories,
2525
CheckDestroy: testAccCheckEssentialsSubscriptionDestroy,
@@ -276,7 +276,7 @@ func TestAccResourceRedisCloudEssentialsDatabase_DisableDefaultUser(t *testing.T
276276
const resourceName = "rediscloud_essentials_database.example"
277277
const datasourceName = "data.rediscloud_essentials_database.example"
278278

279-
resource.ParallelTest(t, resource.TestCase{
279+
resource.Test(t, resource.TestCase{
280280
PreCheck: func() { testAccPreCheck(t) },
281281
ProviderFactories: providerFactories,
282282
CheckDestroy: testAccCheckEssentialsSubscriptionDestroy,

provider/resource_rediscloud_pro_database.go

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"github.com/RedisLabs/terraform-provider-rediscloud/provider/utils"
7+
"log"
78
"regexp"
89
"strconv"
910
"strings"
@@ -240,6 +241,7 @@ func resourceRedisCloudProDatabase() *schema.Resource {
240241
Description: "Defines the Redis database version. If omitted, the Redis version will be set to the default version",
241242
Type: schema.TypeString,
242243
Optional: true,
244+
Computed: true,
243245
},
244246
"modules": {
245247
Description: "Modules to be provisioned in the database",
@@ -538,6 +540,10 @@ func resourceRedisCloudProDatabaseRead(ctx context.Context, d *schema.ResourceDa
538540
return diag.FromErr(err)
539541
}
540542

543+
if err := d.Set("redis_version", redis.StringValue(db.RedisVersion)); err != nil {
544+
return diag.FromErr(err)
545+
}
546+
541547
if err := d.Set("modules", flattenModules(db.Modules)); err != nil {
542548
return diag.FromErr(err)
543549
}
@@ -683,19 +689,20 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource
683689
}
684690

685691
update := databases.UpdateDatabase{
686-
Name: redis.String(d.Get("name").(string)),
687-
SupportOSSClusterAPI: redis.Bool(d.Get("support_oss_cluster_api").(bool)),
688-
Replication: redis.Bool(d.Get("replication").(bool)),
692+
Name: utils.GetString(d, "name"),
693+
SupportOSSClusterAPI: utils.GetBool(d, "support_oss_cluster_api"),
694+
Replication: utils.GetBool(d, "replication"),
689695
ThroughputMeasurement: &databases.UpdateThroughputMeasurement{
690-
By: redis.String(d.Get("throughput_measurement_by").(string)),
691-
Value: redis.Int(d.Get("throughput_measurement_value").(int)),
696+
By: utils.GetString(d, "throughput_measurement_by"),
697+
Value: utils.GetInt(d, "throughput_measurement_value"),
692698
},
693-
DataPersistence: redis.String(d.Get("data_persistence").(string)),
694-
DataEvictionPolicy: redis.String(d.Get("data_eviction").(string)),
699+
700+
DataPersistence: utils.GetString(d, "data_persistence"),
701+
DataEvictionPolicy: utils.GetString(d, "data_eviction"),
695702
SourceIP: setToStringSlice(d.Get("source_ips").(*schema.Set)),
696703
Alerts: &alerts,
697704
RemoteBackup: buildBackupPlan(d.Get("remote_backup").([]interface{}), d.Get("periodic_backup_path")),
698-
EnableDefaultUser: redis.Bool(d.Get("enable_default_user").(bool)),
705+
EnableDefaultUser: utils.GetBool(d, "enable_default_user"),
699706
}
700707

701708
// One of the following fields must be set, validation is handled in the schema (ExactlyOneOf)
@@ -779,6 +786,25 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource
779786
return diag.FromErr(err)
780787
}
781788

789+
// if redis_version has changed, then upgrade first
790+
if d.HasChange("redis_version") {
791+
// if we have just created the database, it will detect an upgrade unnecessarily
792+
originalVersion, newVersion := d.GetChange("redis_version")
793+
794+
// if either version is blank, it could attempt to upgrade unnecessarily.
795+
// only upgrade when a known version goes to another known version
796+
if originalVersion.(string) != "" && newVersion.(string) != "" {
797+
if diags, unlocked := upgradeRedisVersion(ctx, api, subId, dbId, newVersion.(string)); diags != nil {
798+
if !unlocked {
799+
subscriptionMutex.Unlock(subId)
800+
}
801+
return diags
802+
}
803+
}
804+
}
805+
806+
// Confirm db + sub active status
807+
782808
if err := api.client.Database.Update(ctx, subId, dbId, update); err != nil {
783809
subscriptionMutex.Unlock(subId)
784810
return diag.FromErr(err)
@@ -803,6 +829,29 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource
803829
return resourceRedisCloudProDatabaseRead(ctx, d, meta)
804830
}
805831

832+
func upgradeRedisVersion(ctx context.Context, api *apiClient, subId int, dbId int, newVersion string) (diag.Diagnostics, bool) {
833+
log.Printf("[INFO] Requesting Redis version change to %s...", newVersion)
834+
835+
upgrade := databases.UpgradeRedisVersion{
836+
TargetRedisVersion: redis.String(newVersion),
837+
}
838+
839+
if err := api.client.Database.UpgradeRedisVersion(ctx, subId, dbId, upgrade); err != nil {
840+
subscriptionMutex.Unlock(subId)
841+
return diag.Errorf("failed to change Redis version to %s: %v", newVersion, err), true
842+
}
843+
844+
log.Printf("[INFO] Redis version change request to %s accepted by API", newVersion)
845+
846+
// wait for upgrade
847+
if err := waitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil {
848+
subscriptionMutex.Unlock(subId)
849+
return diag.FromErr(err), true
850+
}
851+
852+
return nil, false
853+
}
854+
806855
func buildBackupPlan(data interface{}, periodicBackupPath interface{}) *databases.DatabaseBackupConfig {
807856
var d map[string]interface{}
808857

provider/resource_rediscloud_pro_database_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
1515
)
1616

17-
// Checks CRUDI (CREATE,READ,UPDATE,IMPORT) operations on the database resource.
17+
// Checks CRUDI (CREATE, READ, UPDATE, IMPORT) operations on the database resource.
1818
func TestAccResourceRedisCloudProDatabase_CRUDI(t *testing.T) {
1919

2020
testAccRequiresEnvVar(t, "EXECUTE_TESTS")
@@ -58,6 +58,7 @@ func TestAccResourceRedisCloudProDatabase_CRUDI(t *testing.T) {
5858
resource.TestCheckResourceAttr(resourceName, "modules.#", "1"),
5959
resource.TestCheckResourceAttr(resourceName, "modules.0.name", "RedisBloom"),
6060
resource.TestCheckResourceAttr(resourceName, "enable_default_user", "true"),
61+
resource.TestCheckResourceAttr(resourceName, "redis_version", "7.2"),
6162

6263
resource.TestCheckResourceAttr(resourceName, "tags.market", "emea"),
6364
resource.TestCheckResourceAttr(resourceName, "tags.material", "cardboard"),
@@ -125,6 +126,7 @@ func TestAccResourceRedisCloudProDatabase_CRUDI(t *testing.T) {
125126
resource.TestCheckResourceAttr(resourceName, "modules.#", "1"),
126127
resource.TestCheckResourceAttr(resourceName, "modules.0.name", "RedisBloom"),
127128
resource.TestCheckResourceAttr(resourceName, "enable_default_user", "true"),
129+
resource.TestCheckResourceAttr(resourceName, "redis_version", "7.2"),
128130
),
129131
},
130132
// Test that alerts are deleted
@@ -376,6 +378,7 @@ resource "rediscloud_subscription_database" "example" {
376378
client_ssl_certificate = ""
377379
periodic_backup_path = ""
378380
enable_default_user = true
381+
redis_version = 7.2
379382
380383
alert {
381384
name = "dataset-size"
@@ -467,6 +470,7 @@ resource "rediscloud_subscription_database" "example" {
467470
replication = true
468471
average_item_size_in_bytes = 0
469472
enable_default_user = true
473+
redis_version = 7.2
470474
471475
alert {
472476
name = "dataset-size"
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package provider
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
10+
)
11+
12+
func TestAccResourceRedisCloudProDatabase_Upgrade(t *testing.T) {
13+
14+
testAccRequiresEnvVar(t, "EXECUTE_TESTS")
15+
16+
const resourceName = "rediscloud_subscription_database.example"
17+
18+
resource.ParallelTest(t, resource.TestCase{
19+
PreCheck: func() { testAccPreCheck(t); testAccAwsPreExistingCloudAccountPreCheck(t) },
20+
ProviderFactories: providerFactories,
21+
CheckDestroy: testAccCheckProSubscriptionDestroy,
22+
Steps: []resource.TestStep{
23+
// Test database and replica database creation
24+
{
25+
Config: getRedisCloudUpgradeConfig(t, "7.2"),
26+
Check: resource.ComposeAggregateTestCheckFunc(
27+
resource.TestCheckResourceAttr(resourceName, "name", "example"),
28+
resource.TestCheckResourceAttr(resourceName, "protocol", "redis"),
29+
resource.TestCheckResourceAttr(resourceName, "redis_version", "7.2"),
30+
),
31+
},
32+
// Test database is updated successfully
33+
{
34+
Config: getRedisCloudUpgradeConfig(t, "7.4"),
35+
Check: resource.ComposeAggregateTestCheckFunc(
36+
resource.TestCheckResourceAttr(resourceName, "name", "example"),
37+
resource.TestCheckResourceAttr(resourceName, "protocol", "redis"),
38+
resource.TestCheckResourceAttr(resourceName, "redis_version", "7.4"),
39+
),
40+
},
41+
},
42+
})
43+
}
44+
45+
func getRedisCloudUpgradeConfig(t *testing.T, redisVersion string) string {
46+
testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME")
47+
name := acctest.RandomWithPrefix(testResourcePrefix)
48+
49+
content, err := os.ReadFile("./testdata/testAccResourceRedisCloudProDatabaseUpgrade.tf")
50+
if err != nil {
51+
t.Fatalf("failed to read file: %v", err)
52+
}
53+
54+
return fmt.Sprintf(string(content), testCloudAccountName, name, redisVersion)
55+
}

provider/resource_rediscloud_pro_subscription.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,7 @@ func waitForDatabaseToBeActive(ctx context.Context, subId, id int, api *apiClien
12241224
databases.StatusProxyPolicyChangePending,
12251225
databases.StatusProxyPolicyChangeDraft,
12261226
databases.StatusDynamicEndpointsCreationPending,
1227+
databases.StatusActiveUpgradePending,
12271228
},
12281229
Target: []string{databases.StatusActive},
12291230
Timeout: safetyTimeout,

0 commit comments

Comments
 (0)