diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 8299d85f662f..cf597bad4d43 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -62,6 +62,24 @@ examples: primary_resource_id: 'full' vars: alloydb_cluster_name: 'alloydb-cluster-full' + - !ruby/object:Provider::Terraform::Examples + name: 'alloydb_cluster_restore' + primary_resource_id: 'source' + skip_test: true + vars: + alloydb_cluster_name: 'alloydb-source-cluster' + alloydb_backup_restored_cluster_name: 'alloydb-backup-restored' + alloydb_pitr_restored_cluster_name: 'alloydb-pitr-restored' + alloydb_backup_id: 'alloydb-backup' + alloydb_instance_name: 'alloydb-instance' + network_name: 'alloydb-network' + test_vars_overrides: + network_name: 'acctest.BootstrapSharedTestNetwork(t, "alloydb-instance-basic")' + ignore_read_extra: + - 'reconciling' + - 'update_time' +custom_code: !ruby/object:Provider::Terraform::CustomCode + pre_create: templates/terraform/pre_create/alloydb_restore_cluster.go.erb parameters: - !ruby/object:Api::Type::String name: 'clusterId' @@ -193,6 +211,42 @@ properties: The initial password for the user. required: true sensitive: true + - !ruby/object:Api::Type::NestedObject + name: 'restoreBackupSource' + ignore_read: true + immutable: true + conflicts: + - restore_continuous_backup_source + description: | + The source when restoring from a backup. Conflicts with 'restore_continuous_backup_source', both can't be set together. + properties: + - !ruby/object:Api::Type::String + name: 'backupName' + required: true + immutable: true + description: | + The name of the backup that this cluster is restored from. + - !ruby/object:Api::Type::NestedObject + name: 'restoreContinuousBackupSource' + ignore_read: true + immutable: true + conflicts: + - restore_backup_source + description: | + The source when restoring via point in time recovery (PITR). Conflicts with 'restore_backup_source', both can't be set together. + properties: + - !ruby/object:Api::Type::String + name: 'cluster' + required: true + immutable: true + description: | + The name of the source cluster that this cluster is restored from. + - !ruby/object:Api::Type::String + name: 'pointInTime' + required: true + immutable: true + description: | + The point in time that this cluster is restored to, in RFC 3339 format. - !ruby/object:Api::Type::NestedObject name: 'continuousBackupConfig' default_from_api: true diff --git a/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb b/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb new file mode 100644 index 000000000000..5b60c638c793 --- /dev/null +++ b/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb @@ -0,0 +1,69 @@ +resource "google_alloydb_cluster" "<%= ctx[:primary_resource_id] %>" { + cluster_id = "<%= ctx[:vars]['alloydb_cluster_name'] %>" + location = "us-central1" + network = data.google_compute_network.default.id + + initial_user { + password = "<%= ctx[:vars]['alloydb_cluster_name'] %>" + } +} + +resource "google_alloydb_instance" "<%= ctx[:primary_resource_id] %>" { + cluster = google_alloydb_cluster.<%= ctx[:primary_resource_id] %>.name + instance_id = "<%= ctx[:vars]['alloydb_instance_name'] %>" + instance_type = "PRIMARY" + + machine_config { + cpu_count = 2 + } + + depends_on = [google_service_networking_connection.vpc_connection] +} + +resource "google_alloydb_backup" "<%= ctx[:primary_resource_id] %>" { + backup_id = "<%= ctx[:vars]['alloydb_backup_id'] %>" + location = "us-central1" + cluster_name = google_alloydb_cluster.<%= ctx[:primary_resource_id] %>.name + + depends_on = [google_alloydb_instance.<%= ctx[:primary_resource_id] %>] +} + +resource "google_alloydb_cluster" "restored_from_backup" { + cluster_id = "<%= ctx[:vars]['alloydb_backup_restored_cluster_name'] %>" + location = "us-central1" + network = data.google_compute_network.default.id + restore_backup_source { + backup_name = google_alloydb_backup.<%= ctx[:primary_resource_id] %>.name + } +} + +resource "google_alloydb_cluster" "restored_via_pitr" { + cluster_id = "<%= ctx[:vars]['alloydb_pitr_restored_cluster_name'] %>" + location = "us-central1" + network = data.google_compute_network.default.id + + restore_continuous_backup_source { + cluster = google_alloydb_cluster.<%= ctx[:primary_resource_id] %>.name + point_in_time = "2023-08-03T19:19:00.094Z" + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "<%= ctx[:vars]['network_name'] %>" +} + +resource "google_compute_global_address" "private_ip_alloc" { + name = "<%= ctx[:vars]['alloydb_cluster_name'] %>" + address_type = "INTERNAL" + purpose = "VPC_PEERING" + prefix_length = 16 + network = data.google_compute_network.default.id +} + +resource "google_service_networking_connection" "vpc_connection" { + network = data.google_compute_network.default.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name] +} diff --git a/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb b/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb new file mode 100644 index 000000000000..1cce1c5bf5b9 --- /dev/null +++ b/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb @@ -0,0 +1,33 @@ +// Read the restore variables from obj and remove them, since they do not map to anything in the cluster +var backupSource interface{} +var continuousBackupSource interface{} +if val, ok := obj["restoreBackupSource"]; ok { + backupSource = val + delete(obj, "restoreBackupSource") +} +if val, ok := obj["restoreContinuousBackupSource"]; ok { + continuousBackupSource = val + delete(obj, "restoreContinuousBackupSource") +} + +restoreClusterRequestBody := make(map[string]interface{}) +if backupSource != nil { + // If restoring from a backup, set the backupSource + restoreClusterRequestBody["backup_source"] = backupSource +} else if continuousBackupSource != nil { + // Otherwise if restoring via PITR, set the continuousBackupSource + restoreClusterRequestBody["continuous_backup_source"] = continuousBackupSource +} + +if backupSource != nil || continuousBackupSource != nil { + // Use restore API if this is a restore instead of a create cluster call + url = strings.Replace(url, "clusters?clusterId", "clusters:restore?clusterId", 1) + + // Copy obj which contains the cluster into a cluster map + cluster := make(map[string]interface{}) + for k,v := range obj { + cluster[k] = v + } + restoreClusterRequestBody["cluster"] = cluster + obj = restoreClusterRequestBody +} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/alloydb/resource_alloydb_cluster_restore_test.go b/mmv1/third_party/terraform/services/alloydb/resource_alloydb_cluster_restore_test.go new file mode 100644 index 000000000000..d6def69f6832 --- /dev/null +++ b/mmv1/third_party/terraform/services/alloydb/resource_alloydb_cluster_restore_test.go @@ -0,0 +1,634 @@ +package alloydb_test + +import ( + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +/* + * Restore tests are kept separate from other cluster tests because they require an instance and a backup to exist + */ + +// Restore tests depend on instances and backups being taken, which can take up to 10 minutes. Since the instance doesn't change in between tests, +// we condense everything into individual test cases. +func TestAccAlloydbCluster_restore(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "network_name": acctest.BootstrapSharedTestNetwork(t, "alloydbinstance-restore"), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbClusterAndInstanceAndBackup(context), + }, + { + ResourceName: "google_alloydb_cluster.source", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + // Invalid input check - cannot pass in both sources + Config: testAccAlloydbClusterAndInstanceAndBackup_OnlyOneSourceAllowed(context), + ExpectError: regexp.MustCompile("\"restore_continuous_backup_source\": conflicts with restore_backup_source"), + }, + { + // Invalid input check - both source cluster and point in time are required + Config: testAccAlloydbClusterAndInstanceAndBackup_SourceClusterAndPointInTimeRequired(context), + ExpectError: regexp.MustCompile("The argument \"point_in_time\" is required, but no definition was found."), + }, + { + // Validate backup restore succeeds + Config: testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackup(context), + }, + { + ResourceName: "google_alloydb_cluster.restored_from_backup", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "restore_backup_source"}, + }, + { + // Validate PITR succeeds + Config: testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackupAndRestoredFromPointInTime(context), + }, + { + ResourceName: "google_alloydb_cluster.restored_from_point_in_time", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "restore_continuous_backup_source"}, + }, + { + // Make sure updates work without recreating the clusters + Config: testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackupAndRestoredFromPointInTime_AllowedUpdate(context), + }, + { + Config: testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackupAndRestoredFromPointInTime_NotAllowedUpdate(context), + ExpectError: regexp.MustCompile("the plan calls for this resource to be\ndestroyed"), + }, + { + Config: testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackupAndRestoredFromPointInTime_AllowDestroy(context), + }, + }, + }) +} + +func testAccAlloydbClusterAndInstanceAndBackup(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "source" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "source" { + cluster = google_alloydb_cluster.source.name + instance_id = "tf-test-alloydb-instance%{random_suffix}" + instance_type = "PRIMARY" + + depends_on = [google_service_networking_connection.vpc_connection] +} + +resource "google_alloydb_backup" "default" { + location = "us-central1" + backup_id = "tf-test-alloydb-backup%{random_suffix}" + cluster_name = google_alloydb_cluster.source.name + + depends_on = [google_alloydb_instance.source] +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_compute_global_address" "private_ip_alloc" { + name = "tf-test-alloydb-cluster%{random_suffix}" + address_type = "INTERNAL" + purpose = "VPC_PEERING" + prefix_length = 16 + network = data.google_compute_network.default.id +} + +resource "google_service_networking_connection" "vpc_connection" { + network = data.google_compute_network.default.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name] +} +`, context) +} + +// Cannot restore if multiple sources are present +func testAccAlloydbClusterAndInstanceAndBackup_OnlyOneSourceAllowed(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "source" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "source" { + cluster = google_alloydb_cluster.source.name + instance_id = "tf-test-alloydb-instance%{random_suffix}" + instance_type = "PRIMARY" + + depends_on = [google_service_networking_connection.vpc_connection] +} + +resource "google_alloydb_backup" "default" { + location = "us-central1" + backup_id = "tf-test-alloydb-backup%{random_suffix}" + cluster_name = google_alloydb_cluster.source.name + + depends_on = [google_alloydb_instance.source] +} + +resource "google_alloydb_cluster" "restored" { + cluster_id = "tf-test-alloydb-backup-restored-cluster-%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id + restore_backup_source { + backup_name = google_alloydb_backup.default.name + } + restore_continuous_backup_source { + cluster = google_alloydb_cluster.source.name + point_in_time = google_alloydb_backup.default.update_time + } + + lifecycle { + prevent_destroy = true + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_compute_global_address" "private_ip_alloc" { + name = "tf-test-alloydb-cluster%{random_suffix}" + address_type = "INTERNAL" + purpose = "VPC_PEERING" + prefix_length = 16 + network = data.google_compute_network.default.id +} + +resource "google_service_networking_connection" "vpc_connection" { + network = data.google_compute_network.default.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name] +} +`, context) +} + +// Cannot restore if multiple sources are present +func testAccAlloydbClusterAndInstanceAndBackup_SourceClusterAndPointInTimeRequired(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "source" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "source" { + cluster = google_alloydb_cluster.source.name + instance_id = "tf-test-alloydb-instance%{random_suffix}" + instance_type = "PRIMARY" + + depends_on = [google_service_networking_connection.vpc_connection] +} + +resource "google_alloydb_backup" "default" { + location = "us-central1" + backup_id = "tf-test-alloydb-backup%{random_suffix}" + cluster_name = google_alloydb_cluster.source.name + + depends_on = [google_alloydb_instance.source] +} + +resource "google_alloydb_cluster" "restored" { + cluster_id = "tf-test-alloydb-backup-restored-cluster-%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id + + restore_continuous_backup_source { + cluster = google_alloydb_cluster.source.name + } + + lifecycle { + prevent_destroy = true + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_compute_global_address" "private_ip_alloc" { + name = "tf-test-alloydb-cluster%{random_suffix}" + address_type = "INTERNAL" + purpose = "VPC_PEERING" + prefix_length = 16 + network = data.google_compute_network.default.id +} + +resource "google_service_networking_connection" "vpc_connection" { + network = data.google_compute_network.default.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name] +} +`, context) +} + +func testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackup(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "source" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "source" { + cluster = google_alloydb_cluster.source.name + instance_id = "tf-test-alloydb-instance%{random_suffix}" + instance_type = "PRIMARY" + + depends_on = [google_service_networking_connection.vpc_connection] +} + +resource "google_alloydb_backup" "default" { + location = "us-central1" + backup_id = "tf-test-alloydb-backup%{random_suffix}" + cluster_name = google_alloydb_cluster.source.name + + depends_on = [google_alloydb_instance.source] +} + +resource "google_alloydb_cluster" "restored_from_backup" { + cluster_id = "tf-test-alloydb-backup-restored-cluster-%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id + restore_backup_source { + backup_name = google_alloydb_backup.default.name + } + + lifecycle { + prevent_destroy = true + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_compute_global_address" "private_ip_alloc" { + name = "tf-test-alloydb-cluster%{random_suffix}" + address_type = "INTERNAL" + purpose = "VPC_PEERING" + prefix_length = 16 + network = data.google_compute_network.default.id +} + +resource "google_service_networking_connection" "vpc_connection" { + network = data.google_compute_network.default.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name] +} +`, context) +} + +// The source cluster, instance, and backup should all exist prior to this being invoked. Otherwise the PITR restore will not succeed +// due to the time being too early. +func testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackupAndRestoredFromPointInTime(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "source" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "source" { + cluster = google_alloydb_cluster.source.name + instance_id = "tf-test-alloydb-instance%{random_suffix}" + instance_type = "PRIMARY" + + depends_on = [google_service_networking_connection.vpc_connection] +} + +resource "google_alloydb_backup" "default" { + location = "us-central1" + backup_id = "tf-test-alloydb-backup%{random_suffix}" + cluster_name = google_alloydb_cluster.source.name + + depends_on = [google_alloydb_instance.source] +} + +resource "google_alloydb_cluster" "restored_from_backup" { + cluster_id = "tf-test-alloydb-backup-restored-cluster-%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id + restore_backup_source { + backup_name = google_alloydb_backup.default.name + } + + lifecycle { + prevent_destroy = true + } +} + +resource "google_alloydb_cluster" "restored_from_point_in_time" { + cluster_id = "tf-test-alloydb-pitr-restored-cluster-%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id + restore_continuous_backup_source { + cluster = google_alloydb_cluster.source.name + point_in_time = google_alloydb_backup.default.update_time + } + + lifecycle { + prevent_destroy = true + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_compute_global_address" "private_ip_alloc" { + name = "tf-test-alloydb-cluster%{random_suffix}" + address_type = "INTERNAL" + purpose = "VPC_PEERING" + prefix_length = 16 + network = data.google_compute_network.default.id +} + +resource "google_service_networking_connection" "vpc_connection" { + network = data.google_compute_network.default.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name] +} +`, context) +} + +// This updates the PITR and backup restored clusters by adding a continuous backup configuration. This can be done in place +// and does not require re-creating the cluster from scratch. +func testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackupAndRestoredFromPointInTime_AllowedUpdate(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "source" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "source" { + cluster = google_alloydb_cluster.source.name + instance_id = "tf-test-alloydb-instance%{random_suffix}" + instance_type = "PRIMARY" + + depends_on = [google_service_networking_connection.vpc_connection] +} + +resource "google_alloydb_backup" "default" { + location = "us-central1" + backup_id = "tf-test-alloydb-backup%{random_suffix}" + cluster_name = google_alloydb_cluster.source.name + + depends_on = [google_alloydb_instance.source] +} + +resource "google_alloydb_cluster" "restored_from_backup" { + cluster_id = "tf-test-alloydb-backup-restored-cluster-%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id + restore_backup_source { + backup_name = google_alloydb_backup.default.name + } + + continuous_backup_config { + enabled = true + recovery_window_days = 20 + } + + lifecycle { + prevent_destroy = true + } +} + +resource "google_alloydb_cluster" "restored_from_point_in_time" { + cluster_id = "tf-test-alloydb-pitr-restored-cluster-%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id + restore_continuous_backup_source { + cluster = google_alloydb_cluster.source.name + point_in_time = google_alloydb_backup.default.update_time + } + + continuous_backup_config { + enabled = true + recovery_window_days = 20 + } + + lifecycle { + prevent_destroy = true + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_compute_global_address" "private_ip_alloc" { + name = "tf-test-alloydb-cluster%{random_suffix}" + address_type = "INTERNAL" + purpose = "VPC_PEERING" + prefix_length = 16 + network = data.google_compute_network.default.id +} + +resource "google_service_networking_connection" "vpc_connection" { + network = data.google_compute_network.default.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name] +} +`, context) +} + +// Updating the source cluster, point in time, or source backup are not allowed. This type of operation would +// require deleting and recreating the cluster +func testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackupAndRestoredFromPointInTime_NotAllowedUpdate(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "source" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "source" { + cluster = google_alloydb_cluster.source.name + instance_id = "tf-test-alloydb-instance%{random_suffix}" + instance_type = "PRIMARY" + + depends_on = [google_service_networking_connection.vpc_connection] +} + +resource "google_alloydb_backup" "default" { + location = "us-central1" + backup_id = "tf-test-alloydb-backup%{random_suffix}" + cluster_name = google_alloydb_cluster.source.name + + depends_on = [google_alloydb_instance.source] +} + +resource "google_alloydb_backup" "default2" { + location = "us-central1" + backup_id = "tf-test-alloydb-backup2-%{random_suffix}" + cluster_name = google_alloydb_cluster.source.name + + depends_on = [google_alloydb_instance.source] +} + +resource "google_alloydb_cluster" "restored_from_backup" { + cluster_id = "tf-test-alloydb-backup-restored-cluster-%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id + restore_backup_source { + backup_name = google_alloydb_backup.default2.name + } + + continuous_backup_config { + enabled = true + recovery_window_days = 20 + } + + lifecycle { + prevent_destroy = true + } + + depends_on = [google_alloydb_backup.default2] +} + +resource "google_alloydb_cluster" "restored_from_point_in_time" { + cluster_id = "tf-test-alloydb-pitr-restored-cluster-%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id + restore_continuous_backup_source { + cluster = google_alloydb_cluster.restored_from_backup.name + point_in_time = google_alloydb_backup.default.update_time + } + + continuous_backup_config { + enabled = true + recovery_window_days = 20 + } + + lifecycle { + prevent_destroy = true + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_compute_global_address" "private_ip_alloc" { + name = "tf-test-alloydb-cluster%{random_suffix}" + address_type = "INTERNAL" + purpose = "VPC_PEERING" + prefix_length = 16 + network = data.google_compute_network.default.id +} + +resource "google_service_networking_connection" "vpc_connection" { + network = data.google_compute_network.default.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name] +} +`, context) +} + +// The source cluster, instance, and backup should all exist prior to this being invoked. Otherwise the PITR restore will not succeed +// due to the time being too early. +func testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackupAndRestoredFromPointInTime_AllowDestroy(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "source" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "source" { + cluster = google_alloydb_cluster.source.name + instance_id = "tf-test-alloydb-instance%{random_suffix}" + instance_type = "PRIMARY" + + depends_on = [google_service_networking_connection.vpc_connection] +} + +resource "google_alloydb_backup" "default" { + location = "us-central1" + backup_id = "tf-test-alloydb-backup%{random_suffix}" + cluster_name = google_alloydb_cluster.source.name + + depends_on = [google_alloydb_instance.source] +} + +resource "google_alloydb_cluster" "restored_from_backup" { + cluster_id = "tf-test-alloydb-backup-restored-cluster-%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id + restore_backup_source { + backup_name = google_alloydb_backup.default.name + } +} + +resource "google_alloydb_cluster" "restored_from_point_in_time" { + cluster_id = "tf-test-alloydb-pitr-restored-cluster-%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id + restore_continuous_backup_source { + cluster = google_alloydb_cluster.source.name + point_in_time = google_alloydb_backup.default.update_time + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_compute_global_address" "private_ip_alloc" { + name = "tf-test-alloydb-cluster%{random_suffix}" + address_type = "INTERNAL" + purpose = "VPC_PEERING" + prefix_length = 16 + network = data.google_compute_network.default.id +} + +resource "google_service_networking_connection" "vpc_connection" { + network = data.google_compute_network.default.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name] +} +`, context) +}