diff --git a/google/resource_sql_database_instance.go b/google/resource_sql_database_instance.go index 433894ce..154ded99 100644 --- a/google/resource_sql_database_instance.go +++ b/google/resource_sql_database_instance.go @@ -617,20 +617,23 @@ func resourceSqlDatabaseInstanceCreate(d *schema.ResourceData, meta interface{}) return err } - // If a root user exists with a wildcard ('%') hostname, delete it. - users, err := config.clientSqlAdmin.Users.List(project, instance.Name).Do() - if err != nil { - return fmt.Errorf("Error, attempting to list users associated with instance %s: %s", instance.Name, err) - } - for _, u := range users.Items { - if u.Name == "root" && u.Host == "%" { - op, err = config.clientSqlAdmin.Users.Delete(project, instance.Name, u.Host, u.Name).Do() - if err != nil { - return fmt.Errorf("Error, failed to delete default 'root'@'*' user, but the database was created successfully: %s", err) - } - err = sqladminOperationWait(config, op, "Delete default root User") - if err != nil { - return err + // If a default root user was created with a wildcard ('%') hostname, delete it. Note that if the resource is a + // replica, then any users are inherited from the master instance and should be left alone. + if !sqlResourceIsReplica(d) { + users, err := config.clientSqlAdmin.Users.List(project, instance.Name).Do() + if err != nil { + return fmt.Errorf("Error, attempting to list users associated with instance %s: %s", instance.Name, err) + } + for _, u := range users.Items { + if u.Name == "root" && u.Host == "%" { + op, err = config.clientSqlAdmin.Users.Delete(project, instance.Name, u.Host, u.Name).Do() + if err != nil { + return fmt.Errorf("Error, failed to delete default 'root'@'*' user, but the database was created successfully: %s", err) + } + err = sqladminOperationWait(config, op, "Delete default root User") + if err != nil { + return err + } } } } @@ -1104,3 +1107,10 @@ func flattenIpAddresses(ipAddresses []*sqladmin.IpMapping) []map[string]interfac func instanceMutexKey(project, instance_name string) string { return fmt.Sprintf("google-sql-database-instance-%s-%s", project, instance_name) } + +// sqlResourceIsReplica returns true if the provided schema.ResourceData represents a replica SQL instance, and false +// otherwise. +func sqlResourceIsReplica(d *schema.ResourceData) bool { + _, ok := d.GetOk("master_instance_name") + return ok +} diff --git a/google/resource_sql_database_instance_test.go b/google/resource_sql_database_instance_test.go index 133f6c0d..314c62fe 100644 --- a/google/resource_sql_database_instance_test.go +++ b/google/resource_sql_database_instance_test.go @@ -188,6 +188,54 @@ func TestAccGoogleSqlDatabaseInstance_basic3(t *testing.T) { }, }) } + +func TestAccGoogleSqlDatabaseInstance_dontDeleteDefaultUserOnReplica(t *testing.T) { + var instance sqladmin.DatabaseInstance + databaseName := "sql-instance-test-" + acctest.RandString(10) + failoverName := "sql-instance-test-failover-" + acctest.RandString(10) + // 1. Create an instance. + // 2. Add a root@'%' user. + // 3. Create a replica and assert it succeeds (it'll fail if we try to delete the root user thinking it's a + // default user) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccGoogleSqlDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testGoogleSqlDatabaseInstanceConfig_withoutReplica(databaseName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGoogleSqlDatabaseInstanceExists( + "google_sql_database_instance.instance", &instance), + testAccCheckGoogleSqlDatabaseInstanceEquals( + "google_sql_database_instance.instance", &instance), + ), + }, resource.TestStep{ + PreConfig: func() { + // Add a root user + config := testAccProvider.Meta().(*Config) + user := sqladmin.User{ + Name: "root", + Host: "%", + Password: acctest.RandString(26), + } + op, err := config.clientSqlAdmin.Users.Insert(config.Project, databaseName, &user).Do() + if err != nil { + t.Errorf("Error while inserting root@%% user: %s", err) + return + } + err = sqladminOperationWait(config, op, "Waiting for user to insert") + if err != nil { + t.Errorf("Error while waiting for user insert operation to complete: %s", err.Error()) + } + // User was created, now create replica + }, + Config: testGoogleSqlDatabaseInstanceConfig_withReplica(databaseName, failoverName), + }, + }, + }) +} + func TestAccGoogleSqlDatabaseInstance_settings_basic(t *testing.T) { var instance sqladmin.DatabaseInstance databaseID := acctest.RandInt() @@ -650,6 +698,59 @@ resource "google_sql_database_instance" "instance" { } ` +func testGoogleSqlDatabaseInstanceConfig_withoutReplica(instanceName string) string { + return fmt.Sprintf(`resource "google_sql_database_instance" "instance" { + name = "%s" + region = "us-central1" + database_version = "MYSQL_5_7" + + settings { + tier = "db-n1-standard-1" + + backup_configuration { + binary_log_enabled = "true" + enabled = "true" + start_time = "18:00" + } + } +}`, instanceName) +} + +func testGoogleSqlDatabaseInstanceConfig_withReplica(instanceName, failoverName string) string { + return fmt.Sprintf(` +resource "google_sql_database_instance" "instance" { + name = "%s" + region = "us-central1" + database_version = "MYSQL_5_7" + + settings { + tier = "db-n1-standard-1" + + backup_configuration { + binary_log_enabled = "true" + enabled = "true" + start_time = "18:00" + } + } +} + +resource "google_sql_database_instance" "instance-failover" { + name = "%s" + region = "us-central1" + database_version = "MYSQL_5_7" + master_instance_name = "${google_sql_database_instance.instance.name}" + + replica_configuration { + failover_target = "true" + } + + settings { + tier = "db-n1-standard-1" + } +} +`, instanceName, failoverName) +} + var testGoogleSqlDatabaseInstance_settings = ` resource "google_sql_database_instance" "instance" { name = "tf-lw-%d"