diff --git a/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.tmpl b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.tmpl index 669b7679f688..e13928114357 100644 --- a/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.tmpl +++ b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.tmpl @@ -1429,6 +1429,11 @@ API (for read pools, effective_availability_type may differ from availability_ty Optional: true, Description: `The name of the target instance to restore to.`, }, + "region": { + Type: schema.TypeString, + Optional: true, + Description: `The region of the target instance to restore to.`, + }, }, }, }, @@ -3417,6 +3422,7 @@ func expandPointInTimeRestoreContext(configured []interface{}) *sqladmin.PointIn Datasource: _pitrc["datasource"].(string), AllocatedIpRange: _pitrc["allocated_ip_range"].(string), TargetInstance: _pitrc["target_instance"].(string), + Region: _pitrc["region"].(string), } } diff --git a/mmv1/third_party/terraform/services/sql/resource_sql_database_instance_test.go.tmpl b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance_test.go.tmpl index 7216a92e7635..d4e49a687fb9 100644 --- a/mmv1/third_party/terraform/services/sql/resource_sql_database_instance_test.go.tmpl +++ b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance_test.go.tmpl @@ -1694,6 +1694,44 @@ func TestAccSqlDatabaseInstance_pointInTimeRestore(t *testing.T) { }) } +func TestAccSqlDatabaseInstance_pointInTimeRestoreInMultiRegion(t *testing.T) { + // Skipped due to randomness + acctest.SkipIfVcr(t) + t.Parallel() + + backupVaultID := "bv-test-mr" + location := "us" + project := envvar.GetTestProjectFromEnv() + backupVault := acctest.BootstrapBackupDRVault(t, backupVaultID, location) + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "project": project, + "backup_vault_id": backupVaultID, + "backup_vault": backupVault, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccSqlDatabaseInstance_pointInTimeRestoreContextMultiRegion(context), + }, + { + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection", "point_in_time_restore_context"}, + }, + }, + }) +} + func TestAccSqlDatabaseInstance_pointInTimeRestoreWithSettings(t *testing.T) { // Skipped due to randomness acctest.SkipIfVcr(t) @@ -8076,6 +8114,117 @@ data "google_sql_backup_run" "backup" { `, context) } +func testAccSqlDatabaseInstance_pointInTimeRestoreContextMultiRegion(context map[string]interface{}) string { + return acctest.Nprintf(` + +// Create a backup plan +resource "google_backup_dr_backup_plan" "plan" { + location = "us-central1" + backup_plan_id = "tf-test-bp-test-%{random_suffix}" + resource_type = "sqladmin.googleapis.com/Instance" + backup_vault = "%{backup_vault}" + log_retention_days = 2 + + backup_rules { + rule_id = "rule-1" + backup_retention_days = 7 + + standard_schedule { + recurrence_type = "DAILY" + hourly_frequency = 6 + time_zone = "UTC" + + backup_window { + start_hour_of_day = 0 + end_hour_of_day = 23 + } + } + } +} + +// Create source SQL instance to backup +resource "google_sql_database_instance" "source" { + name = "tf-test-source-%{random_suffix}" + database_version = "MYSQL_8_0_41" + region = "us-central1" + project = "%{project}" + settings { + tier = "db-f1-micro" + backup_configuration { + enabled = true + } + } + lifecycle { + ignore_changes = [ + settings[0].backup_configuration[0].enabled, + ] + } + deletion_protection = false +} + +// Associate backup plan with SQL instance +resource "google_backup_dr_backup_plan_association" "association" { + location = "us-central1" + backup_plan_association_id = "tf-test-bpa-test-%{random_suffix}" + resource = "projects/${google_sql_database_instance.source.project}/instances/${google_sql_database_instance.source.name}" + resource_type = "sqladmin.googleapis.com/Instance" + backup_plan = google_backup_dr_backup_plan.plan.name +} + +// Wait for the first backup to be created +resource "time_sleep" "wait_10_mins" { + depends_on = [google_backup_dr_backup_plan_association.association] + + create_duration = "600s" +} + +data "google_backup_dr_backup" "sql_backups" { + project = "%{project}" + location = "us" + backup_vault_id = "%{backup_vault_id}" + data_source_id = element(split("/", google_backup_dr_backup_plan_association.association.data_source), length(split("/", google_backup_dr_backup_plan_association.association.data_source)) - 1) + + depends_on = [time_sleep.wait_10_mins] +} + +// for a point in time restore operation to succeed, the source instance must be in active state and have logs +resource "google_sql_database" "database" { + name = "tf-test-db-%{random_suffix}" + instance = google_sql_database_instance.source.name + project = "%{project}" + depends_on = [data.google_backup_dr_backup.sql_backups] +} + +// Wait for the ten minutes (RPO is 5 minutes) +resource "time_sleep" "wait_for_binlog" { + depends_on = [google_sql_database.database] + + create_duration = "600s" +} + +resource "google_sql_database_instance" "instance" { + name = "tf-test-%{random_suffix}" + database_version = "MYSQL_8_0_41" + region = "us-central1" + + point_in_time_restore_context { + datasource = google_backup_dr_backup_plan_association.association.data_source + target_instance = "%{project}:tf-test-%{random_suffix}" + point_in_time = timestamp() + region = "us-central1" + } + + lifecycle { + ignore_changes = [point_in_time_restore_context[0].point_in_time] + } + + depends_on = [time_sleep.wait_for_binlog] + + deletion_protection = false +} +`, context) +} + func testAccSqlDatabaseInstance_pointInTimeRestoreContext(context map[string]interface{}) string { return acctest.Nprintf(` // Create service account diff --git a/mmv1/third_party/terraform/website/docs/r/sql_database_instance.html.markdown b/mmv1/third_party/terraform/website/docs/r/sql_database_instance.html.markdown index 4a93aa24519d..23d144a232e4 100644 --- a/mmv1/third_party/terraform/website/docs/r/sql_database_instance.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/sql_database_instance.html.markdown @@ -310,6 +310,29 @@ resource "google_sql_database_instance" "instance" { } ``` +### Cloud SQL Instance created using point_in_time_restore using multiregion datasource +~> **NOTE:** Replace `backupdr_datasource` with the full datasource path, `time_stamp` should be in the format of `YYYY-MM-DDTHH:MM:SSZ` and `region` with the target instance region. + +```hcl +resource "google_sql_database_instance" "instance" { + name = "main-instance" + database_version = "MYSQL_8_0" + settings { + tier = "db-f1-micro" + backup_configuration { + enabled = true + binary_log_enabled = true + } + } + point_in_time_restore_context { + datasource = "backupdr_datasource" + target_instance = "target_instance_name" + point_in_time = "time_stamp" + region = "region" + } +} +``` + ## Argument Reference The following arguments are supported: @@ -689,6 +712,8 @@ The optional `point_in_time_restore_context` block supports: * `target_instance` - The name of the target instance. +* `region` - The region of the target instance where the datasource will be restored. For example: "us-central1". + * `private_network` - (Optional) The resource link for the VPC network from which the Cloud SQL instance is accessible for private IP. For example, "/projects/myProject/global/networks/default". * `preferred_zone` - (Optional) Point-in-time recovery of an instance to the specified zone. If no zone is specified, then clone to the same primary zone as the source instance.