Skip to content

Commit

Permalink
Make root_password field in google_sql_database_instance resource…
Browse files Browse the repository at this point in the history
  • Loading branch information
ravisiddhu authored and ericayyliu committed Jul 26, 2023
1 parent 2321b78 commit e12e96f
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,6 @@ is set to true. Defaults to ZONAL.`,
"root_password": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Sensitive: true,
Description: `Initial root password. Required for MS SQL Server.`,
},
Expand Down Expand Up @@ -1524,6 +1523,67 @@ func resourceSqlDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{})
}
}

// Check if the root_password is being updated, because updating root_password is an atomic operation and can not be
// performed with other fields, we first update root password before updating the rest of the fields.
if d.HasChange("root_password") {
oldPwd, newPwd := d.GetChange("root_password")
password := newPwd.(string)
dv := d.Get("database_version").(string)
name := ""
host := ""
if strings.Contains(dv, "MYSQL") {
name = "root"
host = "%"
} else if strings.Contains(dv, "POSTGRES") {
name = "postgres"
} else if strings.Contains(dv, "SQLSERVER") {
name = "sqlserver"
if len(password) == 0 {
if err := d.Set("root_password", oldPwd.(string)); err != nil {
return fmt.Errorf("Error re-setting root_password: %s", err)
}
return fmt.Errorf("Error, root password cannot be empty for SQL Server instance.")
}
}else {
if err := d.Set("root_password", oldPwd.(string)); err != nil {
return fmt.Errorf("Error re-setting root_password: %s", err)
}
return fmt.Errorf("Error, invalid database version")
}
instance := d.Get("name").(string)

user := &sqladmin.User{
Name: name,
Instance: instance,
Password: password,
}

mutexKV.Lock(instanceMutexKey(project, instance))
defer mutexKV.Unlock(instanceMutexKey(project, instance))
var op *sqladmin.Operation
updateFunc := func() error {
op, err = config.NewSqlAdminClient(userAgent).Users.Update(project, instance, user).Host(host).Name(name).Do()
return err
}
err = retryTimeDuration(updateFunc, d.Timeout(schema.TimeoutUpdate))

if err != nil {
if err := d.Set("root_password", oldPwd.(string)); err != nil {
return fmt.Errorf("Error re-setting root_password: %s", err)
}
return fmt.Errorf("Error, failed to update root_password : %s", err)
}

err = sqlAdminOperationWaitTime(config, op, project, "Insert User", userAgent, d.Timeout(schema.TimeoutUpdate))

if err != nil {
if err := d.Set("root_password", oldPwd.(string)); err != nil {
return fmt.Errorf("Error re-setting root_password: %s", err)
}
return fmt.Errorf("Error, failed to update root_password : %s", err)
}
}

// Check if the maintenance version is being updated, because patching maintenance version is an atomic operation and can not be
// performed with other fields, we first patch maintenance version before updating the rest of the fields.
if d.HasChange("maintenance_version") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1472,6 +1472,48 @@ func TestAccSqlDatabaseInstance_updateReadReplicaWithBinaryLogEnabled(t *testing
})
}

func TestAccSqlDatabaseInstance_rootPasswordShouldBeUpdatable(t *testing.T) {
t.Parallel()

databaseName := "tf-test-" + randString(t, 10)
rootPwd := "rootPassword-1-" + randString(t, 10)
newRootPwd := "rootPassword-2-" + randString(t, 10)
databaseVersion := "SQLSERVER_2017_STANDARD"

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t),
Steps: []resource.TestStep{
resource.TestStep{
Config: testGoogleSqlDatabaseInstance_updateRootPassword(databaseName, databaseVersion, rootPwd),
},
resource.TestStep{
ResourceName: "google_sql_database_instance.main",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"deletion_protection", "root_password"},
},
resource.TestStep{
Config: testGoogleSqlDatabaseInstance_updateRootPassword(databaseName, databaseVersion, newRootPwd),
},
resource.TestStep{
ResourceName: "google_sql_database_instance.main",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"deletion_protection", "root_password"},
},
resource.TestStep{
Config: testGoogleSqlDatabaseInstance_updateRootPassword(databaseName, databaseVersion, ""),
ExpectError: regexp.MustCompile(
`Error, root password cannot be empty for SQL Server instance.`),
},
},
})
}



func testAccSqlDatabaseInstance_sqlMysqlInstancePvpExample(context map[string]interface{}) string {
return Nprintf(`
resource "google_sql_database_instance" "mysql_pvp_instance_name" {
Expand Down Expand Up @@ -2900,4 +2942,18 @@ resource "google_sql_database_instance" "replica" {
}
}
}`, instance, instance)
}

func testGoogleSqlDatabaseInstance_updateRootPassword(instance, databaseVersion, rootPassword string) string {
return fmt.Sprintf(`
resource "google_sql_database_instance" "main" {
name = "%s"
database_version = "%s"
region = "us-central1"
deletion_protection = false
root_password = "%s"
settings {
tier = "db-custom-2-13312"
}
}`, instance, databaseVersion, rootPassword)
}
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ includes an up-to-date reference of supported versions.
* `replica_configuration` - (Optional) The configuration for replication. The
configuration is detailed below. Valid only for MySQL instances.

* `root_password` - (Optional) Initial root password. Required for MS SQL Server.
* `root_password` - (Optional) Initial root password. Can be updated. Required for MS SQL Server.

* `encryption_key_name` - (Optional)
The full path to the encryption key used for the CMEK disk encryption. Setting
Expand Down

0 comments on commit e12e96f

Please sign in to comment.