From 1975db0b9489befb2f2cd56e7b227b2612ed1a4f Mon Sep 17 00:00:00 2001 From: Andrew Starr-Bochicchio Date: Fri, 21 Apr 2023 10:36:37 -0400 Subject: [PATCH] databases: Add support for resizing replicas. (#977) --- .../database/resource_database_replica.go | 33 +++++++++- .../resource_database_replica_test.go | 61 +++++++++++++++++++ docs/resources/database_replica.md | 2 +- 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/digitalocean/database/resource_database_replica.go b/digitalocean/database/resource_database_replica.go index 290260057..88e249e3c 100644 --- a/digitalocean/database/resource_database_replica.go +++ b/digitalocean/database/resource_database_replica.go @@ -22,6 +22,7 @@ func ResourceDigitalOceanDatabaseReplica() *schema.Resource { return &schema.Resource{ CreateContext: resourceDigitalOceanDatabaseReplicaCreate, ReadContext: resourceDigitalOceanDatabaseReplicaRead, + UpdateContext: resourceDigitalOceanDatabaseReplicaUpdate, DeleteContext: resourceDigitalOceanDatabaseReplicaDelete, Importer: &schema.ResourceImporter{ State: resourceDigitalOceanDatabaseReplicaImport, @@ -58,7 +59,6 @@ func ResourceDigitalOceanDatabaseReplica() *schema.Resource { "size": { Type: schema.TypeString, Optional: true, - ForceNew: true, }, "private_network_uuid": { @@ -217,6 +217,37 @@ func resourceDigitalOceanDatabaseReplicaRead(ctx context.Context, d *schema.Reso return nil } +func resourceDigitalOceanDatabaseReplicaUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*config.CombinedConfig).GodoClient() + clusterID := d.Get("cluster_id").(string) + replicaID := d.Get("uuid").(string) + replicaName := d.Get("name").(string) + + if d.HasChanges("size") { + opts := &godo.DatabaseResizeRequest{ + SizeSlug: d.Get("size").(string), + NumNodes: 1, // Read-only replicas only support a single node configuration. + } + + resp, err := client.Databases.Resize(context.Background(), replicaID, opts) + if err != nil { + if resp != nil && resp.StatusCode == 404 { + d.SetId("") + return nil + } + + return diag.Errorf("Error resizing database replica: %s", err) + } + + _, err = waitForDatabaseReplica(client, clusterID, "online", replicaName) + if err != nil { + return diag.Errorf("Error resizing database replica: %s", err) + } + } + + return resourceDigitalOceanDatabaseReplicaRead(ctx, d, meta) +} + func resourceDigitalOceanDatabaseReplicaImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { if strings.Contains(d.Id(), ",") { s := strings.Split(d.Id(), ",") diff --git a/digitalocean/database/resource_database_replica_test.go b/digitalocean/database/resource_database_replica_test.go index 5e2dff28a..7cff31160 100644 --- a/digitalocean/database/resource_database_replica_test.go +++ b/digitalocean/database/resource_database_replica_test.go @@ -105,6 +105,58 @@ func TestAccDigitalOceanDatabaseReplica_WithVPC(t *testing.T) { }) } +func TestAccDigitalOceanDatabaseReplica_Resize(t *testing.T) { + var databaseReplica godo.DatabaseReplica + var database godo.Database + + databaseName := acceptance.RandomTestName() + databaseReplicaName := acceptance.RandomTestName() + + databaseConfig := fmt.Sprintf(testAccCheckDigitalOceanDatabaseClusterConfigBasic, databaseName) + replicaConfig := fmt.Sprintf(testAccCheckDigitalOceanDatabaseReplicaConfigBasic, databaseReplicaName) + resizedConfig := fmt.Sprintf(testAccCheckDigitalOceanDatabaseReplicaConfigResized, databaseReplicaName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t) }, + ProviderFactories: acceptance.TestAccProviderFactories, + CheckDestroy: testAccCheckDigitalOceanDatabaseReplicaDestroy, + Steps: []resource.TestStep{ + { + Config: databaseConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckDigitalOceanDatabaseClusterExists("digitalocean_database_cluster.foobar", &database), + ), + }, + { + Config: databaseConfig + replicaConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckDigitalOceanDatabaseReplicaExists("digitalocean_database_replica.read-01", &databaseReplica), + testAccCheckDigitalOceanDatabaseReplicaAttributes(&databaseReplica, databaseReplicaName), + resource.TestCheckResourceAttr( + "digitalocean_database_replica.read-01", "size", "db-s-1vcpu-2gb"), + resource.TestCheckResourceAttr( + "digitalocean_database_replica.read-01", "name", databaseReplicaName), + resource.TestCheckResourceAttrSet( + "digitalocean_database_replica.read-01", "uuid"), + ), + }, + { + Config: databaseConfig + resizedConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckDigitalOceanDatabaseReplicaExists("digitalocean_database_replica.read-01", &databaseReplica), + testAccCheckDigitalOceanDatabaseReplicaAttributes(&databaseReplica, databaseReplicaName), + resource.TestCheckResourceAttr( + "digitalocean_database_replica.read-01", "size", "db-s-2vcpu-4gb"), + resource.TestCheckResourceAttr( + "digitalocean_database_replica.read-01", "name", databaseReplicaName), + resource.TestCheckResourceAttrSet( + "digitalocean_database_replica.read-01", "uuid"), + ), + }, + }, + }) +} + func testAccCheckDigitalOceanDatabaseReplicaDestroy(s *terraform.State) error { client := acceptance.TestAccProvider.Meta().(*config.CombinedConfig).GodoClient() @@ -182,6 +234,15 @@ resource "digitalocean_database_replica" "read-01" { tags = ["staging"] }` +const testAccCheckDigitalOceanDatabaseReplicaConfigResized = ` +resource "digitalocean_database_replica" "read-01" { + cluster_id = digitalocean_database_cluster.foobar.id + name = "%s" + region = "nyc3" + size = "db-s-2vcpu-4gb" + tags = ["staging"] +}` + const testAccCheckDigitalOceanDatabaseReplicaConfigWithVPC = ` diff --git a/docs/resources/database_replica.md b/docs/resources/database_replica.md index 0b8bf8e00..94c30a7f7 100644 --- a/docs/resources/database_replica.md +++ b/docs/resources/database_replica.md @@ -47,7 +47,7 @@ The following arguments are supported: * `cluster_id` - (Required) The ID of the original source database cluster. * `name` - (Required) The name for the database replica. -* `size` - (Required) Database Droplet size associated with the replica (ex. `db-s-1vcpu-1gb`). +* `size` - (Required) Database Droplet size associated with the replica (ex. `db-s-1vcpu-1gb`). Note that when resizing an existing replica, its size can only be increased. Decreasing its size is not supported. * `region` - (Required) DigitalOcean region where the replica will reside. * `tags` - (Optional) A list of tag names to be applied to the database replica. * `private_network_uuid` - (Optional) The ID of the VPC where the database replica will be located.