diff --git a/.changelog/6374.txt b/.changelog/6374.txt new file mode 100644 index 00000000000..bb5381a350a --- /dev/null +++ b/.changelog/6374.txt @@ -0,0 +1,4 @@ +```release-note:enhancement +sql: added support for major version upgrade to `google_sql_database_instance ` resource + +``` diff --git a/google/resource_sql_database_instance.go b/google/resource_sql_database_instance.go index 2a2008f64b3..a1871d917ba 100644 --- a/google/resource_sql_database_instance.go +++ b/google/resource_sql_database_instance.go @@ -518,7 +518,6 @@ is set to true.`, "database_version": { Type: schema.TypeString, Required: true, - ForceNew: true, Description: `The MySQL, PostgreSQL or SQL Server (beta) version to use. Supported values include MYSQL_5_6, MYSQL_5_7, MYSQL_8_0, POSTGRES_9_6, POSTGRES_10, POSTGRES_11, POSTGRES_12, POSTGRES_13, POSTGRES_14, SQLSERVER_2017_STANDARD, SQLSERVER_2017_ENTERPRISE, SQLSERVER_2017_EXPRESS, SQLSERVER_2017_WEB. Database Version Policies includes an up-to-date reference of supported versions.`, }, @@ -1357,11 +1356,39 @@ func resourceSqlDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{}) return err } - // Update only updates the settings, so they are all we need to set. - instance := &sqladmin.DatabaseInstance{ - Settings: expandSqlDatabaseInstanceSettings(d.Get("settings").([]interface{})), + desiredSetting := d.Get("settings") + var op *sqladmin.Operation + var instance *sqladmin.DatabaseInstance + // Check if the database version is being updated, because patching database version is an atomic operation and can not be + // performed with other fields, we first patch database version before updating the rest of the fields. + if v, ok := d.GetOk("database_version"); ok { + instance = &sqladmin.DatabaseInstance{DatabaseVersion: v.(string)} + err = retryTimeDuration(func() (rerr error) { + op, rerr = config.NewSqlAdminClient(userAgent).Instances.Patch(project, d.Get("name").(string), instance).Do() + return rerr + }, d.Timeout(schema.TimeoutUpdate), isSqlOperationInProgressError) + if err != nil { + return fmt.Errorf("Error, failed to patch instance settings for %s: %s", instance.Name, err) + } + err = sqlAdminOperationWaitTime(config, op, project, "Patch Instance", userAgent, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + err = resourceSqlDatabaseInstanceRead(d, meta) + if err != nil { + return err + } } + s := d.Get("settings") + instance = &sqladmin.DatabaseInstance{ + Settings: expandSqlDatabaseInstanceSettings(desiredSetting.([]interface{})), + } + _settings := s.([]interface{})[0].(map[string]interface{}) + // Instance.Patch operation on completion updates the settings proto version by +8. As terraform does not know this it tries + // to make an update call with the proto version before patch and fails. To resolve this issue we update the setting version + // before making the update call. + instance.Settings.SettingsVersion = int64(_settings["version"].(int)) // Collation cannot be included in the update request instance.Settings.Collation = "" @@ -1372,7 +1399,6 @@ func resourceSqlDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{}) defer mutexKV.Unlock(instanceMutexKey(project, v.(string))) } - var op *sqladmin.Operation err = retryTimeDuration(func() (rerr error) { op, rerr = config.NewSqlAdminClient(userAgent).Instances.Update(project, d.Get("name").(string), instance).Do() return rerr diff --git a/google/resource_sql_database_instance_test.go b/google/resource_sql_database_instance_test.go index 11f3f364adf..540031bc25d 100644 --- a/google/resource_sql_database_instance_test.go +++ b/google/resource_sql_database_instance_test.go @@ -1195,6 +1195,36 @@ func TestAccSqlDatabaseInstance_SqlServerAuditConfig(t *testing.T) { }) } +func TestAccSqlDatabaseInstance_mysqlMajorVersionUpgrade(t *testing.T) { + t.Parallel() + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testGoogleSqlDatabaseInstance_basic2, + }, + { + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"root_password", "deletion_protection"}, + }, + { + Config: testGoogleSqlDatabaseInstance_basic2_update, + }, + { + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"root_password", "deletion_protection"}, + }, + }, + }) +} + func TestAccSqlDatabaseInstance_sqlMysqlInstancePvpExample(t *testing.T) { t.Parallel() @@ -1253,6 +1283,17 @@ resource "google_sql_database_instance" "instance" { } ` +var testGoogleSqlDatabaseInstance_basic2_update = ` +resource "google_sql_database_instance" "instance" { + region = "us-central1" + database_version = "MYSQL_8_0" + deletion_protection = false + settings { + tier = "db-f1-micro" + } +} +` + var testGoogleSqlDatabaseInstance_basic3 = ` resource "google_sql_database_instance" "instance" { name = "%s"