Skip to content

Commit aad9ff6

Browse files
committed
feat: add test
1 parent 3294ebb commit aad9ff6

20 files changed

+11245
-2327
lines changed

docs/resources/rdb_snapshot.md

Whitespace-only changes.

internal/provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ func Provider(config *Config) plugin.ProviderFunc {
204204
"scaleway_rdb_privilege": rdb.ResourcePrivilege(),
205205
"scaleway_rdb_read_replica": rdb.ResourceReadReplica(),
206206
"scaleway_rdb_user": rdb.ResourceUser(),
207+
"scaleway_rdb_snapshot": rdb.ResourceSnapshot(),
207208
"scaleway_redis_cluster": redis.ResourceCluster(),
208209
"scaleway_registry_namespace": registry.ResourceNamespace(),
209210
"scaleway_sdb_sql_database": sdb.ResourceDatabase(),

internal/services/rdb/instance.go

Lines changed: 107 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,23 @@ func ResourceInstance() *schema.Resource {
5454
},
5555
"engine": {
5656
Type: schema.TypeString,
57-
Required: true,
57+
Optional: true,
58+
Computed: true,
5859
ForceNew: true,
5960
Description: "Database's engine version id",
6061
DiffSuppressFunc: dsf.IgnoreCase,
62+
ConflictsWith: []string{
63+
"snapshot_id",
64+
},
65+
},
66+
"snapshot_id": {
67+
Type: schema.TypeString,
68+
Optional: true,
69+
ForceNew: true,
70+
Description: "ID of an existing snapshot to create a new instance from. This allows restoring a database instance to the state captured in the specified snapshot. Conflicts with the `engine` attribute.",
71+
ConflictsWith: []string{
72+
"engine",
73+
},
6174
},
6275
"is_ha_cluster": {
6376
Type: schema.TypeBool,
@@ -323,66 +336,110 @@ func ResourceRdbInstanceCreate(ctx context.Context, d *schema.ResourceData, m in
323336
if err != nil {
324337
return diag.FromErr(err)
325338
}
339+
id := ""
326340

327-
createReq := &rdb.CreateInstanceRequest{
328-
Region: region,
329-
ProjectID: types.ExpandStringPtr(d.Get("project_id")),
330-
Name: types.ExpandOrGenerateString(d.Get("name"), "rdb"),
331-
NodeType: d.Get("node_type").(string),
332-
Engine: d.Get("engine").(string),
333-
IsHaCluster: d.Get("is_ha_cluster").(bool),
334-
DisableBackup: d.Get("disable_backup").(bool),
335-
UserName: d.Get("user_name").(string),
336-
Password: d.Get("password").(string),
337-
VolumeType: rdb.VolumeType(d.Get("volume_type").(string)),
338-
Encryption: &rdb.EncryptionAtRest{
339-
Enabled: d.Get("encryption_at_rest").(bool),
340-
},
341-
}
341+
if regionalSnapshotID, ok := d.GetOk("snapshot_id"); ok {
342+
haCluster := d.Get("is_ha_cluster").(bool)
343+
nodeType := d.Get("node_type").(string)
344+
_, snapshotID, err := regional.ParseID(regionalSnapshotID.(string))
345+
if err != nil {
346+
return diag.FromErr(err)
347+
}
348+
createReqFromSnapshot := &rdb.CreateInstanceFromSnapshotRequest{
349+
SnapshotID: snapshotID,
350+
Region: region,
351+
InstanceName: types.ExpandOrGenerateString(d.Get("name"), "rdb"),
352+
IsHaCluster: &haCluster,
353+
NodeType: &nodeType,
354+
}
355+
res, err := rdbAPI.CreateInstanceFromSnapshot(createReqFromSnapshot, scw.WithContext(ctx))
356+
if err != nil {
357+
return diag.FromErr(err)
358+
}
359+
_, err = waitForRDBInstance(ctx, rdbAPI, region, res.ID, d.Timeout(schema.TimeoutCreate))
360+
if err != nil {
361+
return diag.FromErr(err)
362+
}
342363

343-
if initSettings, ok := d.GetOk("init_settings"); ok {
344-
createReq.InitSettings = expandInstanceSettings(initSettings)
345-
}
364+
rawTag, tagExist := d.GetOk("tags")
365+
if tagExist {
366+
updateReq := &rdb.UpdateInstanceRequest{
367+
Region: region,
368+
InstanceID: res.ID,
369+
}
370+
tags := types.ExpandStrings(rawTag)
371+
updateReq.Tags = &tags
372+
_, err = rdbAPI.UpdateInstance(updateReq, scw.WithContext(ctx))
373+
if err != nil {
374+
return diag.FromErr(err)
375+
}
376+
}
377+
d.SetId(regional.NewIDString(region, res.ID))
378+
id = res.ID
346379

347-
rawTag, tagExist := d.GetOk("tags")
348-
if tagExist {
349-
createReq.Tags = types.ExpandStrings(rawTag)
350-
}
380+
} else {
351381

352-
// Init Endpoints
353-
if pn, pnExist := d.GetOk("private_network"); pnExist {
354-
ipamConfig, staticConfig := getIPConfigCreate(d, "ip_net")
355-
var diags diag.Diagnostics
356-
createReq.InitEndpoints, diags = expandPrivateNetwork(pn, pnExist, ipamConfig, staticConfig)
357-
if diags.HasError() {
358-
return diags
382+
createReq := &rdb.CreateInstanceRequest{
383+
Region: region,
384+
ProjectID: types.ExpandStringPtr(d.Get("project_id")),
385+
Name: types.ExpandOrGenerateString(d.Get("name"), "rdb"),
386+
NodeType: d.Get("node_type").(string),
387+
Engine: d.Get("engine").(string),
388+
IsHaCluster: d.Get("is_ha_cluster").(bool),
389+
DisableBackup: d.Get("disable_backup").(bool),
390+
UserName: d.Get("user_name").(string),
391+
Password: d.Get("password").(string),
392+
VolumeType: rdb.VolumeType(d.Get("volume_type").(string)),
393+
Encryption: &rdb.EncryptionAtRest{
394+
Enabled: d.Get("encryption_at_rest").(bool),
395+
},
359396
}
360-
for _, warning := range diags {
361-
tflog.Warn(ctx, warning.Detail)
397+
398+
if initSettings, ok := d.GetOk("init_settings"); ok {
399+
createReq.InitSettings = expandInstanceSettings(initSettings)
362400
}
363-
}
364-
if _, lbExists := d.GetOk("load_balancer"); lbExists {
365-
createReq.InitEndpoints = append(createReq.InitEndpoints, expandLoadBalancer())
366-
}
367401

368-
if size, ok := d.GetOk("volume_size_in_gb"); ok {
369-
if createReq.VolumeType == rdb.VolumeTypeLssd {
370-
return diag.FromErr(fmt.Errorf("volume_size_in_gb should not be used with volume_type %s", rdb.VolumeTypeLssd.String()))
402+
rawTag, tagExist := d.GetOk("tags")
403+
if tagExist {
404+
createReq.Tags = types.ExpandStrings(rawTag)
371405
}
372-
createReq.VolumeSize = scw.Size(uint64(size.(int)) * uint64(scw.GB))
373-
}
374406

375-
res, err := rdbAPI.CreateInstance(createReq, scw.WithContext(ctx))
376-
if err != nil {
377-
return diag.FromErr(err)
378-
}
407+
// Init Endpoints
408+
if pn, pnExist := d.GetOk("private_network"); pnExist {
409+
ipamConfig, staticConfig := getIPConfigCreate(d, "ip_net")
410+
var diags diag.Diagnostics
411+
createReq.InitEndpoints, diags = expandPrivateNetwork(pn, pnExist, ipamConfig, staticConfig)
412+
if diags.HasError() {
413+
return diags
414+
}
415+
for _, warning := range diags {
416+
tflog.Warn(ctx, warning.Detail)
417+
}
418+
}
419+
if _, lbExists := d.GetOk("load_balancer"); lbExists {
420+
createReq.InitEndpoints = append(createReq.InitEndpoints, expandLoadBalancer())
421+
}
422+
423+
if size, ok := d.GetOk("volume_size_in_gb"); ok {
424+
if createReq.VolumeType == rdb.VolumeTypeLssd {
425+
return diag.FromErr(fmt.Errorf("volume_size_in_gb should not be used with volume_type %s", rdb.VolumeTypeLssd.String()))
426+
}
427+
createReq.VolumeSize = scw.Size(uint64(size.(int)) * uint64(scw.GB))
428+
}
429+
430+
res, err := rdbAPI.CreateInstance(createReq, scw.WithContext(ctx))
431+
if err != nil {
432+
return diag.FromErr(err)
433+
}
379434

380-
d.SetId(regional.NewIDString(region, res.ID))
435+
d.SetId(regional.NewIDString(region, res.ID))
436+
id = res.ID
437+
}
381438

382439
mustUpdate := false
383440
updateReq := &rdb.UpdateInstanceRequest{
384441
Region: region,
385-
InstanceID: res.ID,
442+
InstanceID: id,
386443
}
387444
// Configure Schedule Backup
388445
// BackupScheduleFrequency and BackupScheduleRetention can only configure after instance creation
@@ -403,9 +460,8 @@ func ResourceRdbInstanceCreate(ctx context.Context, d *schema.ResourceData, m in
403460
updateReq.LogsPolicy = expandInstanceLogsPolicy(policyRaw)
404461
mustUpdate = true
405462
}
406-
407463
if mustUpdate {
408-
_, err = waitForRDBInstance(ctx, rdbAPI, region, res.ID, d.Timeout(schema.TimeoutCreate))
464+
_, err = waitForRDBInstance(ctx, rdbAPI, region, id, d.Timeout(schema.TimeoutCreate))
409465
if err != nil {
410466
return diag.FromErr(err)
411467
}
@@ -416,12 +472,12 @@ func ResourceRdbInstanceCreate(ctx context.Context, d *schema.ResourceData, m in
416472
}
417473
// Configure Instance settings
418474
if settings, ok := d.GetOk("settings"); ok {
419-
res, err = waitForRDBInstance(ctx, rdbAPI, region, res.ID, d.Timeout(schema.TimeoutCreate))
475+
res, err := waitForRDBInstance(ctx, rdbAPI, region, id, d.Timeout(schema.TimeoutCreate))
420476
if err != nil {
421477
return diag.FromErr(err)
422478
}
423479

424-
_, err := rdbAPI.SetInstanceSettings(&rdb.SetInstanceSettingsRequest{
480+
_, err = rdbAPI.SetInstanceSettings(&rdb.SetInstanceSettingsRequest{
425481
InstanceID: res.ID,
426482
Region: region,
427483
Settings: expandInstanceSettings(settings),
@@ -430,7 +486,6 @@ func ResourceRdbInstanceCreate(ctx context.Context, d *schema.ResourceData, m in
430486
return diag.FromErr(err)
431487
}
432488
}
433-
434489
return ResourceRdbInstanceRead(ctx, d, m)
435490
}
436491

internal/services/rdb/instance_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,6 +1383,103 @@ func TestAccInstance_UpdateEncryptionAtRest(t *testing.T) {
13831383
})
13841384
}
13851385

1386+
func TestAccRdbInstance_CompleteWorkflow(t *testing.T) {
1387+
tt := acctest.NewTestTools(t)
1388+
defer tt.Cleanup()
1389+
1390+
latestEngineVersion := rdbchecks.GetLatestEngineVersion(tt, postgreSQLEngineName)
1391+
1392+
resource.ParallelTest(t, resource.TestCase{
1393+
PreCheck: func() { acctest.PreCheck(t) },
1394+
ProviderFactories: tt.ProviderFactories,
1395+
CheckDestroy: IsSnapshotDestroyed(tt),
1396+
Steps: []resource.TestStep{
1397+
// Step 1: Create an instance and a snapshot
1398+
{
1399+
Config: fmt.Sprintf(`
1400+
resource "scaleway_rdb_instance" "main" {
1401+
name = "test-rdb-instance"
1402+
node_type = "db-dev-s"
1403+
engine = %q
1404+
is_ha_cluster = false
1405+
disable_backup = true
1406+
user_name = "my_initial_user"
1407+
password = "thiZ_is_v&ry_s3cret"
1408+
tags = ["terraform-test", "scaleway_rdb_instance"]
1409+
volume_type = "bssd"
1410+
volume_size_in_gb = 10
1411+
}
1412+
1413+
resource "scaleway_rdb_snapshot" "test" {
1414+
name = "test-snapshot"
1415+
instance_id = scaleway_rdb_instance.main.id
1416+
depends_on = [scaleway_rdb_instance.main]
1417+
}
1418+
1419+
resource "scaleway_rdb_instance" "from_snapshot" {
1420+
name = "test-instance-from-snapshot"
1421+
node_type = "db-dev-s"
1422+
is_ha_cluster = false
1423+
disable_backup = true
1424+
snapshot_id = scaleway_rdb_snapshot.test.id
1425+
volume_type = "bssd"
1426+
tags = ["terraform-test", "restored_instance"]
1427+
depends_on = [scaleway_rdb_snapshot.test]
1428+
}
1429+
`, latestEngineVersion),
1430+
Check: resource.ComposeTestCheckFunc(
1431+
resource.TestCheckResourceAttr("scaleway_rdb_instance.from_snapshot", "name", "test-instance-from-snapshot"),
1432+
resource.TestCheckResourceAttr("scaleway_rdb_instance.from_snapshot", "user_name", "my_initial_user"),
1433+
resource.TestCheckResourceAttr("scaleway_rdb_instance.from_snapshot", "tags.0", "terraform-test"),
1434+
resource.TestCheckResourceAttr("scaleway_rdb_instance.from_snapshot", "tags.1", "restored_instance"),
1435+
),
1436+
},
1437+
// Step 2: Update the instance created from the snapshot
1438+
{
1439+
Config: fmt.Sprintf(`
1440+
resource "scaleway_rdb_instance" "main" {
1441+
name = "test-rdb-instance"
1442+
node_type = "db-dev-s"
1443+
engine = %q
1444+
is_ha_cluster = false
1445+
disable_backup = true
1446+
user_name = "my_initial_user"
1447+
password = "thiZ_is_v&ry_s3cret"
1448+
tags = ["terraform-test", "scaleway_rdb_instance"]
1449+
volume_type = "bssd"
1450+
volume_size_in_gb = 10
1451+
}
1452+
1453+
resource "scaleway_rdb_snapshot" "test" {
1454+
name = "test-snapshot"
1455+
instance_id = scaleway_rdb_instance.main.id
1456+
depends_on = [scaleway_rdb_instance.main]
1457+
}
1458+
1459+
resource "scaleway_rdb_instance" "from_snapshot" {
1460+
name = "test-instance-from-snapshot-updated"
1461+
node_type = "db-dev-s"
1462+
is_ha_cluster = false
1463+
disable_backup = true
1464+
snapshot_id = scaleway_rdb_snapshot.test.id
1465+
volume_type = "bssd"
1466+
user_name = "updated_user"
1467+
password = "thiZ_is_v&ry_s3cret2"
1468+
tags = ["terraform-test", "updated_instance"]
1469+
depends_on = [scaleway_rdb_snapshot.test]
1470+
}
1471+
`, latestEngineVersion),
1472+
Check: resource.ComposeTestCheckFunc(
1473+
resource.TestCheckResourceAttr("scaleway_rdb_instance.from_snapshot", "name", "test-instance-from-snapshot-updated"),
1474+
resource.TestCheckResourceAttr("scaleway_rdb_instance.from_snapshot", "user_name", "updated_user"),
1475+
resource.TestCheckResourceAttr("scaleway_rdb_instance.from_snapshot", "tags.0", "terraform-test"),
1476+
resource.TestCheckResourceAttr("scaleway_rdb_instance.from_snapshot", "tags.1", "updated_instance"),
1477+
),
1478+
},
1479+
},
1480+
})
1481+
}
1482+
13861483
func isInstancePresent(tt *acctest.TestTools, n string) resource.TestCheckFunc {
13871484
return func(s *terraform.State) error {
13881485
rs, ok := s.RootModule().Resources[n]

0 commit comments

Comments
 (0)