Skip to content

Commit f758b7d

Browse files
Increase robustness of disk_autoresize in sql_database_instance (#14952) (#10739)
[upstream:ee4d5e099cfc134fa160da375c3a18b6a941b886] Signed-off-by: Modular Magician <[email protected]>
1 parent 0bd12f0 commit f758b7d

File tree

3 files changed

+257
-3
lines changed

3 files changed

+257
-3
lines changed

.changelog/14952.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
sql: Increase robustness of disk_autoresize in sql_database_instance
3+
```

google-beta/services/sql/resource_sql_database_instance.go

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import (
3333
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
3434
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
3535

36-
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/compute"
3736
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/servicenetworking"
3837
"github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource"
3938
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
@@ -143,6 +142,41 @@ var (
143142
}
144143
)
145144

145+
func diskSizeCutomizeDiff(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error {
146+
key := "settings.0.disk_size"
147+
148+
old, new := d.GetChange(key)
149+
// It's okay to remove size entirely.
150+
if old == nil || new == nil {
151+
return nil
152+
}
153+
autoResizeI, exists := d.GetOkExists("settings.0.disk_autoresize")
154+
autoResize := !exists || autoResizeI.(bool)
155+
156+
if old.(int) <= new.(int) {
157+
// If a resize up, always allow it - keep the diff.
158+
return nil
159+
}
160+
161+
if autoResize {
162+
// Allow having disk size larger in the state than in config if auto resize is enabled.
163+
// Delete the diff.
164+
err := d.Clear(key)
165+
if err != nil {
166+
return err
167+
}
168+
return nil
169+
}
170+
171+
// If we are here, we are trying to shrink the disk with auto resize disabled and no ignore changes on disk size.
172+
// This will force a new resource.
173+
if err := d.ForceNew(key); err != nil {
174+
return err
175+
}
176+
177+
return nil
178+
}
179+
146180
func ResourceSqlDatabaseInstance() *schema.Resource {
147181
return &schema.Resource{
148182
Create: resourceSqlDatabaseInstanceCreate,
@@ -161,7 +195,7 @@ func ResourceSqlDatabaseInstance() *schema.Resource {
161195

162196
CustomizeDiff: customdiff.All(
163197
tpgresource.DefaultProviderProject,
164-
customdiff.ForceNewIfChange("settings.0.disk_size", compute.IsDiskShrinkage),
198+
diskSizeCutomizeDiff,
165199
customdiff.ForceNewIf("master_instance_name", func(_ context.Context, d *schema.ResourceDiff, meta interface{}) bool {
166200
// If we set master but this is not the new master of a switchover, require replacement and warn user.
167201
return !isSwitchoverFromOldPrimarySide(d)
@@ -2278,10 +2312,27 @@ func resourceSqlDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{})
22782312
}
22792313
}
22802314

2281-
s := d.Get("settings")
22822315
instance = &sqladmin.DatabaseInstance{
22832316
Settings: expandSqlDatabaseInstanceSettings(desiredSetting.([]interface{}), databaseVersion),
22842317
}
2318+
2319+
// If there is no change detected in disk size, no need to try and update the disk size, send 0 always
2320+
instance.Settings.DataDiskSizeGb = 0
2321+
if d.HasChange("settings.0.disk_size") {
2322+
autoResize := true
2323+
_, autoResizeI := d.GetChange("settings.0.disk_autoresize")
2324+
if autoResizeI != nil {
2325+
autoResize = autoResizeI.(bool)
2326+
}
2327+
oldDiskSizeI, newDiskSizeI := d.GetChange("settings.0.disk_size")
2328+
if !autoResize || newDiskSizeI.(int) > oldDiskSizeI.(int) {
2329+
// If auto resize is not enabled - set the disk size as requested, even if it's a decrease - let it fail.
2330+
// Otherwise, allow increasing even if auto resize is enabled.
2331+
instance.Settings.DataDiskSizeGb = int64(newDiskSizeI.(int))
2332+
}
2333+
}
2334+
2335+
s := d.Get("settings")
22852336
_settings := s.([]interface{})[0].(map[string]interface{})
22862337
// Instance.Patch operation on completion updates the settings proto version by +8. As terraform does not know this it tries
22872338
// to make an update call with the proto version before patch and fails. To resolve this issue we update the setting version

google-beta/services/sql/resource_sql_database_instance_test.go

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3539,6 +3539,107 @@ func TestAccSqlDatabaseInstance_useCustomerManagedServerCa(t *testing.T) {
35393539
})
35403540
}
35413541

3542+
func TestAccSqlDatabaseInstance_DiskSizeAutoResizeWithoutDiskSize(t *testing.T) {
3543+
t.Parallel()
3544+
3545+
project := envvar.GetTestProjectFromEnv()
3546+
databaseName := "tf-test-" + acctest.RandString(t, 10)
3547+
3548+
trueVar := true
3549+
falseVar := false
3550+
3551+
acctest.VcrTest(t, resource.TestCase{
3552+
PreCheck: func() { acctest.AccTestPreCheck(t) },
3553+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
3554+
CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t),
3555+
Steps: []resource.TestStep{
3556+
{
3557+
// Create DB with disk size 10gb (minimal) - no disk size specified in configuration, auto resize enabled
3558+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 0, 100, nil, false, false),
3559+
// Add additional 2gb outside of TF to simulate increase in disk size
3560+
Check: testGoogleSqlDatabaseInstanceResizeDisk(t, databaseName, 2),
3561+
},
3562+
{
3563+
// Disk size is now 12gb - requested (original value) 10gb, configuration is empty - should not trigger resize, no errors.
3564+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 0, 101, nil, false, false),
3565+
Check: testGoogleSqlDatabaseInstanceCheckDiskSize(t, databaseName, 12),
3566+
},
3567+
{
3568+
// Disk size is now 12gb - requested (original value) 10gb, configuration is empty - should not trigger resize, no errors.
3569+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 0, 101, &trueVar, false, false),
3570+
Check: testGoogleSqlDatabaseInstanceCheckDiskSize(t, databaseName, 12),
3571+
},
3572+
{
3573+
// Disk size is now 12gb - requested (original value) 10gb, configuration is empty - disable auto resize - should not error.
3574+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 0, 101, &falseVar, false, false),
3575+
Check: testGoogleSqlDatabaseInstanceCheckDiskSize(t, databaseName, 12),
3576+
},
3577+
{
3578+
// Disk size is now 12gb - requested (original value) 10gb, configuration is empty - disable auto resize, but enable deletion protection should not error.
3579+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 0, 101, &falseVar, true, false),
3580+
Check: testGoogleSqlDatabaseInstanceCheckDiskSize(t, databaseName, 12),
3581+
},
3582+
{
3583+
// Allow destroy
3584+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 0, 101, &falseVar, true, true),
3585+
},
3586+
},
3587+
})
3588+
}
3589+
3590+
func TestAccSqlDatabaseInstance_DiskSizeAutoResizeWithDiskSize(t *testing.T) {
3591+
t.Parallel()
3592+
3593+
project := envvar.GetTestProjectFromEnv()
3594+
databaseName := "tf-test-" + acctest.RandString(t, 10)
3595+
3596+
trueVar := true
3597+
falseVar := false
3598+
3599+
acctest.VcrTest(t, resource.TestCase{
3600+
PreCheck: func() { acctest.AccTestPreCheck(t) },
3601+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
3602+
CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t),
3603+
Steps: []resource.TestStep{
3604+
{
3605+
// Create DB with disk size 12gb with auto resize enabled
3606+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 12, 100, nil, false, false),
3607+
// Add additional 2gb outside of TF to simulate increase in disk size
3608+
Check: testGoogleSqlDatabaseInstanceResizeDisk(t, databaseName, 2),
3609+
},
3610+
{
3611+
// Disk size is now 14gb - requested (original value) 12gb and auto resize enable - should not trigger resize, no errors.
3612+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 12, 101, nil, false, false),
3613+
Check: testGoogleSqlDatabaseInstanceCheckDiskSize(t, databaseName, 14),
3614+
},
3615+
{
3616+
// Disk size is now 14gb - requested 13gb in configuration, still less - should not trigger resize, no errors.
3617+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 13, 102, &trueVar, false, false),
3618+
Check: testGoogleSqlDatabaseInstanceCheckDiskSize(t, databaseName, 14),
3619+
},
3620+
{
3621+
// Disk size is now 14gb - requested 15gb in configuration, that's an additional increase should trigger resize to 15gb.
3622+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 15, 103, nil, false, false),
3623+
Check: testGoogleSqlDatabaseInstanceCheckDiskSize(t, databaseName, 15),
3624+
},
3625+
{
3626+
// Disk size is now 15gb - requested 14gb, but disabled auto resize - should error because it can't be deleted for replacement.
3627+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 14, 104, &falseVar, false, false),
3628+
ExpectError: regexp.MustCompile("Instance cannot be destroyed"),
3629+
},
3630+
{
3631+
// Disk size is now 15gb - requested 14gb, but ignore changes is set - so should ignore the configuration change.
3632+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 14, 105, &falseVar, true, false),
3633+
Check: testGoogleSqlDatabaseInstanceCheckDiskSize(t, databaseName, 15),
3634+
},
3635+
{
3636+
// Allow destroy
3637+
Config: testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, databaseName, 14, 105, &falseVar, true, true),
3638+
},
3639+
},
3640+
})
3641+
}
3642+
35423643
func testGoogleSqlDatabaseInstance_setCustomSubjectAlternateName(context map[string]interface{}) string {
35433644
return acctest.Nprintf(`
35443645
data "google_project" "project" {
@@ -7186,3 +7287,102 @@ resource "google_sql_database_instance" "instance" {
71867287
}
71877288
`, instance, databaseVersion, deletionProtection, activationPolicy)
71887289
}
7290+
7291+
func testGoogleSqlDatabaseInstance_diskSizeAutoResize(project, dbName string, diskSize, maxConnections int, autoResize *bool, ignoreChanges, allowDestroy bool) string {
7292+
diskSizeStmt := ""
7293+
if diskSize != 0 {
7294+
diskSizeStmt = fmt.Sprintf("disk_size = %d", diskSize)
7295+
}
7296+
autoResizeStmt := ""
7297+
if autoResize != nil {
7298+
if *autoResize {
7299+
autoResizeStmt = "disk_autoresize = true"
7300+
} else {
7301+
autoResizeStmt = "disk_autoresize = false"
7302+
}
7303+
}
7304+
ignoreChangesStmt := ""
7305+
if ignoreChanges {
7306+
ignoreChangesStmt = "settings[0].disk_size"
7307+
}
7308+
7309+
preventDestroyStmt := "prevent_destroy = true"
7310+
if allowDestroy {
7311+
preventDestroyStmt = ""
7312+
}
7313+
7314+
return fmt.Sprintf(`
7315+
data "google_project" "project" {
7316+
project_id = "%s"
7317+
}
7318+
7319+
resource "google_sql_database_instance" "instance" {
7320+
name = "%s"
7321+
region = "us-central1"
7322+
database_version = "POSTGRES_15"
7323+
deletion_protection = false
7324+
settings {
7325+
tier = "db-f1-micro"
7326+
%s
7327+
%s
7328+
database_flags {
7329+
name = "max_connections"
7330+
value = "%d"
7331+
}
7332+
}
7333+
lifecycle {
7334+
ignore_changes = [%s]
7335+
%s
7336+
}
7337+
}
7338+
`, project, dbName, diskSizeStmt, autoResizeStmt, maxConnections, ignoreChangesStmt, preventDestroyStmt)
7339+
}
7340+
7341+
func testGoogleSqlDatabaseInstanceResizeDisk(t *testing.T, instance string, addGb int64) resource.TestCheckFunc {
7342+
return func(s *terraform.State) error {
7343+
config := acctest.GoogleProviderConfig(t)
7344+
7345+
sqlAdminClient := config.NewSqlAdminClient(config.UserAgent)
7346+
7347+
inst, err := sqlAdminClient.Instances.Get(config.Project, instance).Do()
7348+
if err != nil {
7349+
return fmt.Errorf("Could not get database instance %q: %s", instance, err)
7350+
}
7351+
7352+
operation, err := sqlAdminClient.Instances.Patch(config.Project, instance, &sqladmin.DatabaseInstance{
7353+
Settings: &sqladmin.Settings{
7354+
SettingsVersion: inst.Settings.SettingsVersion,
7355+
DataDiskSizeGb: inst.Settings.DataDiskSizeGb + addGb,
7356+
},
7357+
}).Do()
7358+
if err != nil {
7359+
return fmt.Errorf("Could not update database instance %q: %s", instance, err)
7360+
}
7361+
7362+
// Wait for the operation to complete
7363+
if err := sql.SqlAdminOperationWaitTime(config, operation, config.Project, "Waiting for disk resize", config.UserAgent, 10*time.Minute); err != nil {
7364+
return fmt.Errorf("Could not wait for operation to complete: %s", err)
7365+
}
7366+
7367+
return nil
7368+
}
7369+
}
7370+
7371+
func testGoogleSqlDatabaseInstanceCheckDiskSize(t *testing.T, instance string, size int64) resource.TestCheckFunc {
7372+
return func(s *terraform.State) error {
7373+
config := acctest.GoogleProviderConfig(t)
7374+
7375+
sqlAdminClient := config.NewSqlAdminClient(config.UserAgent)
7376+
7377+
inst, err := sqlAdminClient.Instances.Get(config.Project, instance).Do()
7378+
if err != nil {
7379+
return fmt.Errorf("Could not get database instance %q: %s", instance, err)
7380+
}
7381+
7382+
if inst.Settings.DataDiskSizeGb != size {
7383+
return fmt.Errorf("Expected disk size %d, got %d", size, inst.Settings.DataDiskSizeGb)
7384+
}
7385+
7386+
return nil
7387+
}
7388+
}

0 commit comments

Comments
 (0)