Skip to content

Commit 87e6807

Browse files
committed
feat: ensure both old and new RDB instances reach stable states during engine upgrade
1 parent 924440e commit 87e6807

File tree

5 files changed

+2740
-360
lines changed

5 files changed

+2740
-360
lines changed

internal/services/rdb/instance.go

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -968,15 +968,6 @@ func ResourceRdbInstanceUpdate(ctx context.Context, d *schema.ResourceData, m an
968968
return diag.FromErr(fmt.Errorf("engine version %s is not available for upgrade from %s. Available versions: %v",
969969
newEngineStr, oldEngine.(string), availableVersions))
970970
}
971-
972-
// MajorUpgradeWorkflow performs a blue/green deployment:
973-
// 1. Creates a snapshot of the current instance
974-
// 2. Creates a new instance with the target engine version
975-
// 3. Restores data from the snapshot
976-
// 4. Migrates endpoints (WithEndpoints=true) to the new instance
977-
// 5. Returns the new instance with a different ID
978-
// Note: Scaleway manages the lifecycle of the source instance. It remains available
979-
// for potential rollback and is eventually cleaned up by Scaleway's infrastructure.
980971
upgradeInstanceRequests = append(upgradeInstanceRequests,
981972
rdb.UpgradeInstanceRequest{
982973
Region: region,
@@ -988,7 +979,6 @@ func ResourceRdbInstanceUpdate(ctx context.Context, d *schema.ResourceData, m an
988979
})
989980
}
990981

991-
// Carry out the upgrades
992982
for i := range upgradeInstanceRequests {
993983
_, err = waitForRDBInstance(ctx, rdbAPI, region, ID, d.Timeout(schema.TimeoutUpdate))
994984
if err != nil && !httperrors.Is404(err) {
@@ -1002,13 +992,41 @@ func ResourceRdbInstanceUpdate(ctx context.Context, d *schema.ResourceData, m an
1002992

1003993
if upgradeInstanceRequests[i].MajorUpgradeWorkflow != nil && upgradedInstance.ID != ID {
1004994
tflog.Info(ctx, fmt.Sprintf("Engine upgrade created new instance, updating ID from %s to %s", ID, upgradedInstance.ID))
995+
oldInstanceID := ID
1005996
ID = upgradedInstance.ID
1006997
d.SetId(regional.NewIDString(region, ID))
1007-
}
1008998

1009-
_, err = waitForRDBInstance(ctx, rdbAPI, region, ID, d.Timeout(schema.TimeoutUpdate))
1010-
if err != nil && !httperrors.Is404(err) {
1011-
return diag.FromErr(err)
999+
_, err = waitForRDBInstance(ctx, rdbAPI, region, ID, d.Timeout(schema.TimeoutUpdate))
1000+
if err != nil && !httperrors.Is404(err) {
1001+
return diag.FromErr(err)
1002+
}
1003+
1004+
_, err = waitForRDBInstance(ctx, rdbAPI, region, oldInstanceID, d.Timeout(schema.TimeoutUpdate))
1005+
if err != nil && !httperrors.Is404(err) {
1006+
tflog.Warn(ctx, fmt.Sprintf("Old instance %s not ready for deletion: %v", oldInstanceID, err))
1007+
} else {
1008+
_, err = rdbAPI.DeleteInstance(&rdb.DeleteInstanceRequest{
1009+
Region: region,
1010+
InstanceID: oldInstanceID,
1011+
}, scw.WithContext(ctx))
1012+
if err != nil && !httperrors.Is404(err) {
1013+
tflog.Warn(ctx, fmt.Sprintf("Failed to delete old instance %s: %v", oldInstanceID, err))
1014+
} else {
1015+
_, err = rdbAPI.WaitForInstance(&rdb.WaitForInstanceRequest{
1016+
Region: region,
1017+
InstanceID: oldInstanceID,
1018+
Timeout: scw.TimeDurationPtr(d.Timeout(schema.TimeoutUpdate)),
1019+
}, scw.WithContext(ctx))
1020+
if err != nil && !httperrors.Is404(err) {
1021+
tflog.Warn(ctx, fmt.Sprintf("Error waiting for old instance %s deletion: %v", oldInstanceID, err))
1022+
}
1023+
}
1024+
}
1025+
} else {
1026+
_, err = waitForRDBInstance(ctx, rdbAPI, region, ID, d.Timeout(schema.TimeoutUpdate))
1027+
if err != nil && !httperrors.Is404(err) {
1028+
return diag.FromErr(err)
1029+
}
10121030
}
10131031
}
10141032

internal/services/rdb/instance_test.go

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,29 +1544,6 @@ func TestAccInstance_EndpointErrorHandling(t *testing.T) {
15441544
})
15451545
}
15461546

1547-
func isInstancePresent(tt *acctest.TestTools, n string) resource.TestCheckFunc {
1548-
return func(s *terraform.State) error {
1549-
rs, ok := s.RootModule().Resources[n]
1550-
if !ok {
1551-
return fmt.Errorf("resource not found: %s", n)
1552-
}
1553-
1554-
rdbAPI, region, ID, err := rdb.NewAPIWithRegionAndID(tt.Meta, rs.Primary.ID)
1555-
if err != nil {
1556-
return err
1557-
}
1558-
1559-
_, err = rdbAPI.GetInstance(&rdbSDK.GetInstanceRequest{
1560-
InstanceID: ID,
1561-
Region: region,
1562-
})
1563-
if err != nil {
1564-
return err
1565-
}
1566-
1567-
return nil
1568-
}
1569-
}
15701547
func TestAccInstance_EngineUpgrade(t *testing.T) {
15711548
tt := acctest.NewTestTools(t)
15721549
defer tt.Cleanup()
@@ -1731,3 +1708,26 @@ func TestAccInstance_EngineUpgrade(t *testing.T) {
17311708
})
17321709
}
17331710

1711+
func isInstancePresent(tt *acctest.TestTools, n string) resource.TestCheckFunc {
1712+
return func(s *terraform.State) error {
1713+
rs, ok := s.RootModule().Resources[n]
1714+
if !ok {
1715+
return fmt.Errorf("resource not found: %s", n)
1716+
}
1717+
1718+
rdbAPI, region, ID, err := rdb.NewAPIWithRegionAndID(tt.Meta, rs.Primary.ID)
1719+
if err != nil {
1720+
return err
1721+
}
1722+
1723+
_, err = rdbAPI.GetInstance(&rdbSDK.GetInstanceRequest{
1724+
InstanceID: ID,
1725+
Region: region,
1726+
})
1727+
if err != nil {
1728+
return err
1729+
}
1730+
1731+
return nil
1732+
}
1733+
}

internal/services/rdb/testdata/instance-engine-upgrade-invalid-version.cassette.yaml

Lines changed: 1083 additions & 0 deletions
Large diffs are not rendered by default.

internal/services/rdb/testdata/instance-engine-upgrade.cassette.yaml

Lines changed: 764 additions & 323 deletions
Large diffs are not rendered by default.

internal/services/rdb/testdata/instance-upgradable-versions-read.cassette.yaml

Lines changed: 838 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)