diff --git a/.changelog/3954.txt b/.changelog/3954.txt new file mode 100644 index 00000000000..ab7dbfc20ca --- /dev/null +++ b/.changelog/3954.txt @@ -0,0 +1,6 @@ +```release-note:note +Added `deletion_protection` to `google_sql_database_instance`, which defaults to true. SQL instances can no longer be destroyed without setting `deletion_protection = false`. +``` +```release-note:enhancement +sql: added a check to `google_sql_database_instance` to catch failures early by seeing if Service Networking Connections already exists for the private network of the instance. +``` diff --git a/google/resource_sql_database_instance.go b/google/resource_sql_database_instance.go index 2cfdd49cfe9..7de4f004131 100644 --- a/google/resource_sql_database_instance.go +++ b/google/resource_sql_database_instance.go @@ -101,7 +101,12 @@ func resourceSqlDatabaseInstance() *schema.Resource { ForceNew: true, Description: `The region the instance will sit in. Note, Cloud SQL is not available in all regions - choose from one of the options listed here. A valid region must be provided to use this resource. If a region is not provided in the resource definition, the provider region will be used instead, but this will be an apply-time error for instances if the provider region is not supported with Cloud SQL. If you choose not to provide the region argument for this resource, make sure you understand this.`, }, - + "deletion_protection": { + Type: schema.TypeBool, + Default: true, + Optional: true, + Description: `Used to block Terraform from deleting a SQL Instance.`, + }, "settings": { Type: schema.TypeList, Required: true, @@ -646,6 +651,27 @@ func resourceSqlDatabaseInstanceCreate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Error setting name: %s", err) } + // Before we create the instance, check if at least 1 service connection exists for private SQL Instances. + network := d.Get("settings.0.ip_configuration.0.private_network").(string) + if network != "" { + // Borrow some of the functions from resource_service_networking_connection.go + serviceNetworkingNetworkName, err := retrieveServiceNetworkingNetworkName(d, config, network, userAgent) + if err != nil { + return err + } + config.clientServiceNetworking.UserAgent = userAgent + response, err := config.clientServiceNetworking.Services.Connections.List("services/servicenetworking.googleapis.com"). + Network(serviceNetworkingNetworkName).Do() + if err != nil { + // It is possible that the identity creating the SQL Instance might not have permissions to call servicenetworking.services.connections.list + log.Printf("[WARNING] Failed to list Service Networking of the project. Skipping Service Networking check.") + } else { + if len(response.Connections) < 1 { + return fmt.Errorf("Error, failed to create instance because the network doesn't have at least 1 private services connection. Please see https://cloud.google.com/sql/docs/mysql/private-ip#network_requirements for how to create this connection.") + } + } + } + instance := &sqladmin.DatabaseInstance{ Name: name, Region: region, @@ -1024,6 +1050,12 @@ func resourceSqlDatabaseInstanceDelete(d *schema.ResourceData, meta interface{}) return err } + // Check if deletion protection is enabled. + + if d.Get("deletion_protection").(bool) { + return fmt.Errorf("Error, failed to delete instance because deletion_protection is set to true. Set it to false to proceed with instance deletion") + } + // Lock on the master_instance_name just in case deleting a replica causes // operations on the master. if v, ok := d.GetOk("master_instance_name"); ok { @@ -1058,6 +1090,10 @@ func resourceSqlDatabaseInstanceImport(d *schema.ResourceData, meta interface{}) return nil, err } + if err := d.Set("deletion_protection", true); err != nil { + return nil, fmt.Errorf("Error setting deletion_protection: %s", err) + } + // Replace import id for the resource id id, err := replaceVars(d, config, "projects/{{project}}/instances/{{name}}") if err != nil { diff --git a/google/resource_sql_database_instance_test.go b/google/resource_sql_database_instance_test.go index 417fc26c9fb..629facc00cc 100644 --- a/google/resource_sql_database_instance_test.go +++ b/google/resource_sql_database_instance_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "regexp" "strings" "testing" "time" @@ -26,6 +27,7 @@ var ignoredReplicaConfigurationFields = []string{ "replica_configuration.0.ssl_cipher", "replica_configuration.0.username", "replica_configuration.0.verify_server_certificate", + "deletion_protection", } func init() { @@ -165,9 +167,10 @@ func TestAccSqlDatabaseInstance_basicInferredName(t *testing.T) { Config: testGoogleSqlDatabaseInstance_basic2, }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -189,9 +192,10 @@ func TestAccSqlDatabaseInstance_basicSecondGen(t *testing.T) { Check: testAccCheckGoogleSqlDatabaseRootUserDoesNotExist(t, databaseName), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -216,7 +220,7 @@ func TestAccSqlDatabaseInstance_basicMSSQL(t *testing.T) { ResourceName: "google_sql_database_instance.instance", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"root_password"}, + ImportStateVerifyIgnore: []string{"root_password", "deletion_protection"}, }, }, }) @@ -240,9 +244,10 @@ func TestAccSqlDatabaseInstance_dontDeleteDefaultUserOnReplica(t *testing.T) { Config: testGoogleSqlDatabaseInstanceConfig_withoutReplica(databaseName), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { PreConfig: func() { @@ -285,9 +290,63 @@ func TestAccSqlDatabaseInstance_settings_basic(t *testing.T) { testGoogleSqlDatabaseInstance_settings, databaseName), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, + }, + }, + }) +} + +func TestAccSqlDatabaseInstance_settings_deletionProtection(t *testing.T) { + t.Parallel() + + databaseName := "tf-test-" + randString(t, 10) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf( + testGoogleSqlDatabaseInstance_settings_deletionProtection, databaseName, "true"), + }, + { + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, + }, + { + Config: fmt.Sprintf( + testGoogleSqlDatabaseInstance_settings_deletionProtection, databaseName, "true"), + Destroy: true, + ExpectError: regexp.MustCompile("Error, failed to delete instance because deletion_protection is set to true. Set it to false to proceed with instance deletion"), + }, + { + Config: fmt.Sprintf( + testGoogleSqlDatabaseInstance_settings_deletionProtection, databaseName, "false"), + }, + }, + }) +} + +func TestAccSqlDatabaseInstance_settings_checkServiceNetworking(t *testing.T) { + t.Parallel() + + databaseName := "tf-test-" + randString(t, 10) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf( + testGoogleSqlDatabaseInstance_settings_checkServiceNetworking, databaseName, databaseName), + ExpectError: regexp.MustCompile("Error, failed to create instance because the network doesn't have at least 1 private services connection. Please see https://cloud.google.com/sql/docs/mysql/private-ip#network_requirements for how to create this connection."), }, }, }) @@ -308,9 +367,10 @@ func TestAccSqlDatabaseInstance_replica(t *testing.T) { testGoogleSqlDatabaseInstance_replica, databaseID, databaseID, databaseID), }, { - ResourceName: "google_sql_database_instance.instance_master", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance_master", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { ResourceName: "google_sql_database_instance.replica1", @@ -344,14 +404,16 @@ func TestAccSqlDatabaseInstance_slave(t *testing.T) { testGoogleSqlDatabaseInstance_slave, masterID, slaveID), }, { - ResourceName: "google_sql_database_instance.instance_master", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance_master", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { - ResourceName: "google_sql_database_instance.instance_slave", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance_slave", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -372,9 +434,10 @@ func TestAccSqlDatabaseInstance_highAvailability(t *testing.T) { testGoogleSqlDatabaseInstance_highAvailability, instanceID), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -395,9 +458,10 @@ func TestAccSqlDatabaseInstance_diskspecs(t *testing.T) { testGoogleSqlDatabaseInstance_diskspecs, masterID), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -418,9 +482,10 @@ func TestAccSqlDatabaseInstance_maintenance(t *testing.T) { testGoogleSqlDatabaseInstance_maintenance, masterID), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -441,18 +506,20 @@ func TestAccSqlDatabaseInstance_settings_upgrade(t *testing.T) { testGoogleSqlDatabaseInstance_basic3, databaseName), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { Config: fmt.Sprintf( testGoogleSqlDatabaseInstance_settings, databaseName), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -473,18 +540,20 @@ func TestAccSqlDatabaseInstance_settingsDowngrade(t *testing.T) { testGoogleSqlDatabaseInstance_settings, databaseName), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { Config: fmt.Sprintf( testGoogleSqlDatabaseInstance_basic3, databaseName), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -506,27 +575,30 @@ func TestAccSqlDatabaseInstance_authNets(t *testing.T) { testGoogleSqlDatabaseInstance_authNets_step1, databaseID), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { Config: fmt.Sprintf( testGoogleSqlDatabaseInstance_authNets_step2, databaseID), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { Config: fmt.Sprintf( testGoogleSqlDatabaseInstance_authNets_step1, databaseID), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -549,9 +621,10 @@ func TestAccSqlDatabaseInstance_multipleOperations(t *testing.T) { testGoogleSqlDatabaseInstance_multipleOperations, databaseID, instanceID, userID), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -573,18 +646,20 @@ func TestAccSqlDatabaseInstance_basic_with_user_labels(t *testing.T) { Check: testAccCheckGoogleSqlDatabaseRootUserDoesNotExist(t, databaseName), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { Config: fmt.Sprintf( testGoogleSqlDatabaseInstance_basic_with_user_labels_update, databaseName), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -643,17 +718,19 @@ func TestAccSqlDatabaseInstance_PointInTimeRecoveryEnabled(t *testing.T) { Config: testGoogleSqlDatabaseInstance_PointInTimeRecoveryEnabled(masterID, true), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { Config: testGoogleSqlDatabaseInstance_PointInTimeRecoveryEnabled(masterID, false), }, { - ResourceName: "google_sql_database_instance.instance", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -662,6 +739,7 @@ func TestAccSqlDatabaseInstance_PointInTimeRecoveryEnabled(t *testing.T) { var testGoogleSqlDatabaseInstance_basic2 = ` resource "google_sql_database_instance" "instance" { region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" } @@ -672,6 +750,7 @@ var testGoogleSqlDatabaseInstance_basic3 = ` resource "google_sql_database_instance" "instance" { name = "%s" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" } @@ -683,6 +762,7 @@ resource "google_sql_database_instance" "instance" { name = "%s" database_version = "SQLSERVER_2017_STANDARD" root_password = "%s" + deletion_protection = false settings { tier = "db-custom-1-3840" } @@ -695,6 +775,7 @@ resource "google_sql_database_instance" "instance" { name = "%s" region = "us-central1" database_version = "MYSQL_5_7" + deletion_protection = false settings { tier = "db-n1-standard-1" @@ -715,6 +796,7 @@ resource "google_sql_database_instance" "instance" { name = "%s" region = "us-central1" database_version = "MYSQL_5_7" + deletion_protection = false settings { tier = "db-n1-standard-1" @@ -732,6 +814,7 @@ resource "google_sql_database_instance" "instance-failover" { region = "us-central1" database_version = "MYSQL_5_7" master_instance_name = google_sql_database_instance.instance.name + deletion_protection = false replica_configuration { failover_target = "true" @@ -748,6 +831,7 @@ var testGoogleSqlDatabaseInstance_settings = ` resource "google_sql_database_instance" "instance" { name = "%s" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" location_preference { @@ -772,12 +856,61 @@ resource "google_sql_database_instance" "instance" { } } ` +var testGoogleSqlDatabaseInstance_settings_deletionProtection = ` +resource "google_sql_database_instance" "instance" { + name = "%s" + region = "us-central1" + deletion_protection = %s + settings { + tier = "db-f1-micro" + location_preference { + zone = "us-central1-f" + } + + ip_configuration { + ipv4_enabled = "true" + authorized_networks { + value = "108.12.12.12" + name = "misc" + expiration_time = "2037-11-15T16:19:00.094Z" + } + } + + backup_configuration { + enabled = "true" + start_time = "19:19" + } + + activation_policy = "ALWAYS" + } +} +` + +var testGoogleSqlDatabaseInstance_settings_checkServiceNetworking = ` +resource "google_compute_network" "servicenet" { + name = "%s" +} + +resource "google_sql_database_instance" "instance" { + name = "%s" + region = "us-central1" + deletion_protection = false + settings { + tier = "db-f1-micro" + ip_configuration { + ipv4_enabled = "false" + private_network = google_compute_network.servicenet.self_link + } + } +} +` var testGoogleSqlDatabaseInstance_replica = ` resource "google_sql_database_instance" "instance_master" { name = "tf-lw-%d" database_version = "MYSQL_5_6" region = "us-central1" + deletion_protection = false settings { tier = "db-n1-standard-1" @@ -794,6 +927,7 @@ resource "google_sql_database_instance" "replica1" { name = "tf-lw-%d-1" database_version = "MYSQL_5_6" region = "us-central1" + deletion_protection = false settings { tier = "db-n1-standard-1" @@ -815,6 +949,7 @@ resource "google_sql_database_instance" "replica2" { name = "tf-lw-%d-2" database_version = "MYSQL_5_6" region = "us-central1" + deletion_protection = false settings { tier = "db-n1-standard-1" @@ -837,6 +972,7 @@ var testGoogleSqlDatabaseInstance_slave = ` resource "google_sql_database_instance" "instance_master" { name = "tf-lw-%d" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" @@ -851,6 +987,7 @@ resource "google_sql_database_instance" "instance_master" { resource "google_sql_database_instance" "instance_slave" { name = "tf-lw-%d" region = "us-central1" + deletion_protection = false master_instance_name = google_sql_database_instance.instance_master.name @@ -865,6 +1002,7 @@ resource "google_sql_database_instance" "instance" { name = "tf-lw-%d" region = "us-central1" database_version = "POSTGRES_9_6" + deletion_protection = false settings { tier = "db-f1-micro" @@ -883,6 +1021,7 @@ var testGoogleSqlDatabaseInstance_diskspecs = ` resource "google_sql_database_instance" "instance" { name = "tf-lw-%d" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" @@ -897,6 +1036,7 @@ var testGoogleSqlDatabaseInstance_maintenance = ` resource "google_sql_database_instance" "instance" { name = "tf-lw-%d" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" @@ -914,6 +1054,7 @@ var testGoogleSqlDatabaseInstance_authNets_step1 = ` resource "google_sql_database_instance" "instance" { name = "tf-lw-%d" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" @@ -932,6 +1073,7 @@ var testGoogleSqlDatabaseInstance_authNets_step2 = ` resource "google_sql_database_instance" "instance" { name = "tf-lw-%d" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" @@ -946,6 +1088,7 @@ var testGoogleSqlDatabaseInstance_multipleOperations = ` resource "google_sql_database_instance" "instance" { name = "tf-test-%s" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" } @@ -968,6 +1111,7 @@ var testGoogleSqlDatabaseInstance_basic_with_user_labels = ` resource "google_sql_database_instance" "instance" { name = "%s" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" user_labels = { @@ -981,6 +1125,7 @@ var testGoogleSqlDatabaseInstance_basic_with_user_labels_update = ` resource "google_sql_database_instance" "instance" { name = "%s" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" user_labels = { @@ -996,6 +1141,7 @@ resource "google_sql_database_instance" "instance" { name = "tf-test-%d" region = "us-central1" database_version = "POSTGRES_9_6" + deletion_protection = false settings { tier = "db-f1-micro" backup_configuration { diff --git a/google/resource_sql_database_test.go b/google/resource_sql_database_test.go index 055527f384d..68eeec9303c 100644 --- a/google/resource_sql_database_test.go +++ b/google/resource_sql_database_test.go @@ -50,16 +50,18 @@ func TestAccSqlDatabase_basic(t *testing.T) { ImportStateVerify: true, }, { - ResourceName: resourceName, - ImportStateId: fmt.Sprintf("%s/%s/%s", getTestProjectFromEnv(), instanceName, dbName), - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportStateId: fmt.Sprintf("%s/%s/%s", getTestProjectFromEnv(), instanceName, dbName), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { - ResourceName: resourceName, - ImportStateId: fmt.Sprintf("projects/%s/instances/%s/databases/%s", getTestProjectFromEnv(), instanceName, dbName), - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportStateId: fmt.Sprintf("projects/%s/instances/%s/databases/%s", getTestProjectFromEnv(), instanceName, dbName), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, }, }, }) @@ -183,6 +185,7 @@ var testGoogleSqlDatabase_basic = ` resource "google_sql_database_instance" "instance" { name = "%s" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" } @@ -197,6 +200,7 @@ var testGoogleSqlDatabase_latin1 = ` resource "google_sql_database_instance" "instance" { name = "%s" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" } diff --git a/google/resource_sql_ssl_cert_test.go b/google/resource_sql_ssl_cert_test.go index e9871afb823..cfc370ccbb2 100644 --- a/google/resource_sql_ssl_cert_test.go +++ b/google/resource_sql_ssl_cert_test.go @@ -100,6 +100,7 @@ func testGoogleSqlClientCert_mysql(instance string) string { resource "google_sql_database_instance" "instance" { name = "%s" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" } @@ -123,7 +124,7 @@ func testGoogleSqlClientCert_postgres(instance string) string { name = "%s" region = "us-central1" database_version = "POSTGRES_9_6" - + deletion_protection = false settings { tier = "db-f1-micro" } diff --git a/google/resource_sql_user_test.go b/google/resource_sql_user_test.go index fbf335bb4f1..641f3048fe4 100644 --- a/google/resource_sql_user_test.go +++ b/google/resource_sql_user_test.go @@ -138,6 +138,7 @@ func testGoogleSqlUser_mysql(instance, password string) string { resource "google_sql_database_instance" "instance" { name = "%s" region = "us-central1" + deletion_protection = false settings { tier = "db-f1-micro" } @@ -165,6 +166,7 @@ resource "google_sql_database_instance" "instance" { name = "%s" region = "us-central1" database_version = "POSTGRES_9_6" + deletion_protection = false settings { tier = "db-f1-micro" diff --git a/website/docs/r/sql_database_instance.html.markdown b/website/docs/r/sql_database_instance.html.markdown index 739f37e4253..d6435f11af3 100644 --- a/website/docs/r/sql_database_instance.html.markdown +++ b/website/docs/r/sql_database_instance.html.markdown @@ -39,6 +39,10 @@ default 'root'@'%' user with no password. This user will be deleted by Terraform instance creation. You should use `google_sql_user` to define a custom user with a restricted host and strong password. +-> **Note**: On newer versions of the provider, you must explicitly set `deletion_protection=false` +(and run `terraform apply` to write the field to state) in order to destroy an instance. +It is recommended to not set this field (or set it to true) until you're ready to destroy the instance and its databases. + ## Example Usage ### SQL Second Generation Instance @@ -226,6 +230,9 @@ includes an up-to-date reference of supported versions. That service account needs the `Cloud KMS > Cloud KMS CryptoKey Encrypter/Decrypter` role on your key - please see [this step](https://cloud.google.com/sql/docs/mysql/configure-cmek#grantkey). +* `deletion_protection` - (Optional, Default: `true` ) Whether or not to allow Terraform to destroy the instance. Unless this field is set to false +in Terraform state, a `terraform destroy` or `terraform apply` command that deletes the instance will fail. + The required `settings` block supports: * `tier` - (Required) The machine type to use. See [tiers](https://cloud.google.com/sql/docs/admin-api/v1beta4/tiers)