Skip to content

Commit ee4d5e0

Browse files
authored
Increase robustness of disk_autoresize in sql_database_instance (#14952)
1 parent 83e9a95 commit ee4d5e0

File tree

2 files changed

+254
-3
lines changed

2 files changed

+254
-3
lines changed

mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.tmpl

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

20-
"github.com/hashicorp/terraform-provider-google/google/services/compute"
2120
"github.com/hashicorp/terraform-provider-google/google/services/servicenetworking"
2221
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
2322
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
@@ -127,6 +126,41 @@ var (
127126
}
128127
)
129128

129+
func diskSizeCutomizeDiff(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error {
130+
key := "settings.0.disk_size"
131+
132+
old, new := d.GetChange(key)
133+
// It's okay to remove size entirely.
134+
if old == nil || new == nil {
135+
return nil
136+
}
137+
autoResizeI, exists := d.GetOkExists("settings.0.disk_autoresize")
138+
autoResize := !exists || autoResizeI.(bool)
139+
140+
if old.(int) <= new.(int) {
141+
// If a resize up, always allow it - keep the diff.
142+
return nil
143+
}
144+
145+
if autoResize {
146+
// Allow having disk size larger in the state than in config if auto resize is enabled.
147+
// Delete the diff.
148+
err := d.Clear(key)
149+
if err != nil {
150+
return err
151+
}
152+
return nil
153+
}
154+
155+
// If we are here, we are trying to shrink the disk with auto resize disabled and no ignore changes on disk size.
156+
// This will force a new resource.
157+
if err := d.ForceNew(key); err != nil {
158+
return err
159+
}
160+
161+
return nil
162+
}
163+
130164
func ResourceSqlDatabaseInstance() *schema.Resource {
131165
return &schema.Resource{
132166
Create: resourceSqlDatabaseInstanceCreate,
@@ -145,7 +179,7 @@ func ResourceSqlDatabaseInstance() *schema.Resource {
145179

146180
CustomizeDiff: customdiff.All(
147181
tpgresource.DefaultProviderProject,
148-
customdiff.ForceNewIfChange("settings.0.disk_size", compute.IsDiskShrinkage),
182+
diskSizeCutomizeDiff,
149183
customdiff.ForceNewIf("master_instance_name", func(_ context.Context, d *schema.ResourceDiff, meta interface{}) bool {
150184
// If we set master but this is not the new master of a switchover, require replacement and warn user.
151185
return !isSwitchoverFromOldPrimarySide(d)
@@ -2269,10 +2303,27 @@ func resourceSqlDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{})
22692303
}
22702304
}
22712305

2272-
s := d.Get("settings")
22732306
instance = &sqladmin.DatabaseInstance{
22742307
Settings: expandSqlDatabaseInstanceSettings(desiredSetting.([]interface{}), databaseVersion),
22752308
}
2309+
2310+
// If there is no change detected in disk size, no need to try and update the disk size, send 0 always
2311+
instance.Settings.DataDiskSizeGb = 0
2312+
if d.HasChange("settings.0.disk_size") {
2313+
autoResize := true
2314+
_, autoResizeI := d.GetChange("settings.0.disk_autoresize")
2315+
if autoResizeI != nil {
2316+
autoResize = autoResizeI.(bool)
2317+
}
2318+
oldDiskSizeI, newDiskSizeI := d.GetChange("settings.0.disk_size")
2319+
if !autoResize || newDiskSizeI.(int) > oldDiskSizeI.(int) {
2320+
// If auto resize is not enabled - set the disk size as requested, even if it's a decrease - let it fail.
2321+
// Otherwise, allow increasing even if auto resize is enabled.
2322+
instance.Settings.DataDiskSizeGb = int64(newDiskSizeI.(int))
2323+
}
2324+
}
2325+
2326+
s := d.Get("settings")
22762327
_settings := s.([]interface{})[0].(map[string]interface{})
22772328
// Instance.Patch operation on completion updates the settings proto version by +8. As terraform does not know this it tries
22782329
// to make an update call with the proto version before patch and fails. To resolve this issue we update the setting version

mmv1/third_party/terraform/services/sql/resource_sql_database_instance_test.go.tmpl

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3531,6 +3531,107 @@ func TestAccSqlDatabaseInstance_useCustomerManagedServerCa(t *testing.T) {
35313531
})
35323532
}
35333533

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

0 commit comments

Comments
 (0)