diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 618ac5f3dcc9..be178c4292bf 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -99,6 +99,7 @@ examples: skip_docs: true custom_code: !ruby/object:Provider::Terraform::CustomCode pre_create: templates/terraform/pre_create/alloydb_cluster.go.erb + pre_delete: templates/terraform/pre_delete/alloydb_cluster.go.erb parameters: - !ruby/object:Api::Type::String name: 'clusterId' @@ -492,3 +493,14 @@ properties: description: | Name of the primary cluster must be in the format 'projects/{project}/locations/{location}/clusters/{cluster_id}' +virtual_fields: + - !ruby/object:Api::Type::Enum + name: 'deletion_policy' + description: | + Policy to determine if the cluster should be deleted forcefully. + Deleting a cluster forcefully, deletes the cluster and all its associated instances within the cluster. + Deleting a Secondary cluster with a secondary instance REQUIRES setting deletion_policy = "FORCE" otherwise an error is returned. This is needed as there is no support to delete just the secondary instance, and the only way to delete secondary instance is to delete the associated secondary cluster forcefully which also deletes the secondary instance. + values: + - :DEFAULT + - :FORCE + default_value: :DEFAULT diff --git a/mmv1/products/alloydb/Instance.yaml b/mmv1/products/alloydb/Instance.yaml index cc8b23b35a27..9f71e922bb9e 100644 --- a/mmv1/products/alloydb/Instance.yaml +++ b/mmv1/products/alloydb/Instance.yaml @@ -13,6 +13,11 @@ --- !ruby/object:Api::Resource name: 'Instance' +docs: !ruby/object:Provider::Terraform::Docs + warning: | + Deleting an instance with instanceType = SECONDARY does not delete the secondary instance, and abandons it instead. + Use deletion_policy = "FORCE" in the associated secondary cluster and delete the cluster forcefully to delete the secondary cluster as well its associated secondary instance. + Users can undo the delete secondary instance action by importing the deleted secondary instance by calling terraform import. self_link: '{{cluster}}/instances/{{instance_id}}' base_url: '{{cluster}}/instances?instanceId={{instance_id}}' update_verb: :PATCH @@ -28,9 +33,9 @@ async: !ruby/object:Api::OpAsync base_url: '{{op_id}}' wait_ms: 1000 timeouts: !ruby/object:Api::Timeouts - insert_minutes: 40 - update_minutes: 40 - delete_minutes: 40 + insert_minutes: 120 + update_minutes: 120 + delete_minutes: 120 result: !ruby/object:Api::OpAsync::Result path: 'response' status: !ruby/object:Api::OpAsync::Status @@ -49,6 +54,8 @@ skip_sweeper: true autogen_async: true custom_code: !ruby/object:Provider::Terraform::CustomCode custom_import: templates/terraform/custom_import/alloydb_instance.go.erb + pre_create: templates/terraform/pre_create/alloydb_instance.go.erb + pre_delete: templates/terraform/pre_delete/alloydb_instance.go.erb examples: - !ruby/object:Provider::Terraform::Examples name: 'alloydb_instance_basic' @@ -61,6 +68,19 @@ examples: - 'reconciling' - 'update_time' skip_test: true + - !ruby/object:Provider::Terraform::Examples + name: 'alloydb_secondary_instance_basic' + primary_resource_id: 'secondary' + vars: + alloydb_primary_cluster_name: 'alloydb-primary-cluster' + alloydb_primary_instance_name: 'alloydb-primary-instance' + alloydb_secondary_cluster_name: 'alloydb-secondary-cluster' + alloydb_secondary_instance_name: 'alloydb-secondary-instance' + network_name: 'alloydb-secondary-network' + ignore_read_extra: + - 'reconciling' + - 'update_time' + skip_test: true - !ruby/object:Provider::Terraform::Examples name: 'alloydb_instance_basic_test' primary_resource_id: 'default' @@ -74,6 +94,21 @@ examples: - 'reconciling' - 'update_time' skip_docs: true + - !ruby/object:Provider::Terraform::Examples + name: 'alloydb_secondary_instance_basic_test' + primary_resource_id: 'secondary' + vars: + alloydb_primary_cluster_name: 'alloydb-primary-cluster' + alloydb_primary_instance_name: 'alloydb-primary-instance' + alloydb_secondary_cluster_name: 'alloydb-secondary-cluster' + alloydb_secondary_instance_name: 'alloydb-secondary-instance' + network_name: 'alloydb-secondary-network' + test_vars_overrides: + network_name: 'acctest.BootstrapSharedServiceNetworkingConnection(t, "alloydbinstance-network-config-1")' + ignore_read_extra: + - 'reconciling' + - 'update_time' + skip_docs: true parameters: - !ruby/object:Api::Type::ResourceRef name: 'cluster' @@ -167,10 +202,17 @@ properties: required: true immutable: true description: | - The type of the instance. If the instance type is READ_POOL, provide the associated PRIMARY instance in the `depends_on` meta-data attribute. + The type of the instance. + If the instance type is READ_POOL, provide the associated PRIMARY/SECONDARY instance in the `depends_on` meta-data attribute. + If the instance type is SECONDARY, point to the cluster_type of the associated secondary cluster instead of mentioning SECONDARY. + Example: {instance_type = google_alloydb_cluster..cluster_type} instead of {instance_type = SECONDARY} + If the instance type is SECONDARY, the terraform delete instance operation does not delete the secondary instance but abandons it instead. + Use deletion_policy = "FORCE" in the associated secondary cluster and delete the cluster forcefully to delete the secondary cluster as well its associated secondary instance. + Users can undo the delete secondary instance action by importing the deleted secondary instance by calling terraform import. values: - :PRIMARY - :READ_POOL + - :SECONDARY - !ruby/object:Api::Type::String name: 'ipAddress' output: true diff --git a/mmv1/templates/terraform/examples/alloydb_secondary_instance_basic.tf.erb b/mmv1/templates/terraform/examples/alloydb_secondary_instance_basic.tf.erb new file mode 100644 index 000000000000..8043621b3cfd --- /dev/null +++ b/mmv1/templates/terraform/examples/alloydb_secondary_instance_basic.tf.erb @@ -0,0 +1,68 @@ +resource "google_alloydb_cluster" "primary" { + cluster_id = "<%= ctx[:vars]['alloydb_primary_cluster_name'] %>" + location = "us-central1" + network = google_compute_network.default.id +} + +resource "google_alloydb_instance" "primary" { + cluster = google_alloydb_cluster.primary.name + instance_id = "<%= ctx[:vars]['alloydb_primary_instance_name'] %>" + instance_type = "PRIMARY" + + machine_config { + cpu_count = 2 + } + + depends_on = [google_service_networking_connection.vpc_connection] +} + +resource "google_alloydb_cluster" "secondary" { + cluster_id = "<%= ctx[:vars]['alloydb_secondary_cluster_name'] %>" + location = "us-east1" + network = google_compute_network.default.id + cluster_type = "SECONDARY" + + continuous_backup_config { + enabled = false + } + + secondary_config { + primary_cluster_name = google_alloydb_cluster.primary.name + } + + deletion_policy = "FORCE" + + depends_on = [google_alloydb_instance.primary] +} + +resource "google_alloydb_instance" "<%= ctx[:primary_resource_id] %>" { + cluster = google_alloydb_cluster.secondary.name + instance_id = "<%= ctx[:vars]['alloydb_secondary_instance_name'] %>" + instance_type = google_alloydb_cluster.secondary.cluster_type + + machine_config { + cpu_count = 2 + } + + depends_on = [google_service_networking_connection.vpc_connection] +} + +data "google_project" "project" {} + +resource "google_compute_network" "default" { + name = "<%= ctx[:vars]['network_name'] %>" +} + +resource "google_compute_global_address" "private_ip_alloc" { + name = "<%= ctx[:vars]['alloydb_secondary_instance_name'] %>" + address_type = "INTERNAL" + purpose = "VPC_PEERING" + prefix_length = 16 + network = google_compute_network.default.id +} + +resource "google_service_networking_connection" "vpc_connection" { + network = 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/examples/alloydb_secondary_instance_basic_test.tf.erb b/mmv1/templates/terraform/examples/alloydb_secondary_instance_basic_test.tf.erb new file mode 100644 index 000000000000..c6cfdce0f8d4 --- /dev/null +++ b/mmv1/templates/terraform/examples/alloydb_secondary_instance_basic_test.tf.erb @@ -0,0 +1,50 @@ +resource "google_alloydb_cluster" "primary" { + cluster_id = "<%= ctx[:vars]['alloydb_primary_cluster_name'] %>" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "primary" { + cluster = google_alloydb_cluster.primary.name + instance_id = "<%= ctx[:vars]['alloydb_primary_instance_name'] %>" + instance_type = "PRIMARY" + + machine_config { + cpu_count = 2 + } +} + +resource "google_alloydb_cluster" "secondary" { + cluster_id = "<%= ctx[:vars]['alloydb_secondary_cluster_name'] %>" + location = "us-east1" + network = data.google_compute_network.default.id + cluster_type = "SECONDARY" + + continuous_backup_config { + enabled = false + } + + secondary_config { + primary_cluster_name = google_alloydb_cluster.primary.name + } + + deletion_policy = "FORCE" + + depends_on = [google_alloydb_instance.primary] +} + +resource "google_alloydb_instance" "<%= ctx[:primary_resource_id] %>" { + cluster = google_alloydb_cluster.secondary.name + instance_id = "<%= ctx[:vars]['alloydb_secondary_instance_name'] %>" + instance_type = google_alloydb_cluster.secondary.cluster_type + + machine_config { + cpu_count = 2 + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "<%= ctx[:vars]['network_name'] %>" +} \ No newline at end of file diff --git a/mmv1/templates/terraform/pre_create/alloydb_instance.go.erb b/mmv1/templates/terraform/pre_create/alloydb_instance.go.erb new file mode 100644 index 000000000000..ba3d97920cd4 --- /dev/null +++ b/mmv1/templates/terraform/pre_create/alloydb_instance.go.erb @@ -0,0 +1,5 @@ +// Read the config and call createsecondary api if instance_type is SECONDARY + +if instanceType := d.Get("instance_type"); instanceType == "SECONDARY" { + url = strings.Replace(url, "instances?instanceId", "instances:createsecondary?instanceId", 1) +} diff --git a/mmv1/templates/terraform/pre_delete/alloydb_cluster.go.erb b/mmv1/templates/terraform/pre_delete/alloydb_cluster.go.erb new file mode 100644 index 000000000000..743d7e857912 --- /dev/null +++ b/mmv1/templates/terraform/pre_delete/alloydb_cluster.go.erb @@ -0,0 +1,4 @@ +// Forcefully delete the secondary cluster and the dependent instances because deletion of secondary instance is not supported. +if deletionPolicy := d.Get("deletion_policy"); deletionPolicy == "FORCE" { + url = url + "?force=true" +} \ No newline at end of file diff --git a/mmv1/templates/terraform/pre_delete/alloydb_instance.go.erb b/mmv1/templates/terraform/pre_delete/alloydb_instance.go.erb new file mode 100644 index 000000000000..68d0ca605bc4 --- /dev/null +++ b/mmv1/templates/terraform/pre_delete/alloydb_instance.go.erb @@ -0,0 +1,18 @@ +// Read the config and avoid calling the delete API if the instance_type is SECONDARY and instead return nil +// Returning nil is equivalent of returning a success message to the users +// This is done because deletion of secondary instance is not supported +// Instead users should be deleting the secondary cluster which will forcefully delete the associated secondary instance +// A warning message prompts the user to delete the associated secondary cluster. +// Users can always undo the delete secondary instance action by importing the deleted secondary instance by calling terraform import + +var instanceType interface{} +instanceTypeProp, err := expandAlloydbInstanceInstanceType(d.Get("instance_type"), d, config) +if err != nil { + return err +} else if v, ok := d.GetOkExists("instance_type"); !tpgresource.IsEmptyValue(reflect.ValueOf(instanceTypeProp)) && (ok || !reflect.DeepEqual(v, instanceTypeProp)) { + instanceType = instanceTypeProp +} +if instanceType != nil && instanceType == "SECONDARY" { + log.Printf("[WARNING] This operation didn't delete the Secondary Instance %q. Please delete the associated Secondary Cluster as well to delete the entire cluster and the secondary instance.\n", d.Id()) + return nil +} diff --git a/mmv1/third_party/terraform/services/alloydb/resource_alloydb_secondary_instance_test.go b/mmv1/third_party/terraform/services/alloydb/resource_alloydb_secondary_instance_test.go new file mode 100644 index 000000000000..6cb158429e11 --- /dev/null +++ b/mmv1/third_party/terraform/services/alloydb/resource_alloydb_secondary_instance_test.go @@ -0,0 +1,627 @@ +package alloydb_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +// This test passes if secondary instance's machine config can be updated +func TestAccAlloydbInstance_secondaryInstanceUpdateMachineConfig(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "alloydbinstance-network-config-1"), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbInstance_secondaryInstanceInitial(context), + }, + { + ResourceName: "google_alloydb_instance.secondary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time", "labels", "terraform_labels"}, + }, + { + Config: testAccAlloydbInstance_secondaryInstanceUpdateMachineConfig(context), + }, + { + ResourceName: "google_alloydb_instance.secondary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccAlloydbInstance_secondaryInstanceInitial(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "primary" { + cluster_id = "tf-test-alloydb-primary-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "primary" { + cluster = google_alloydb_cluster.primary.name + instance_id = "tf-test-alloydb-primary-instance%{random_suffix}" + instance_type = "PRIMARY" + + machine_config { + cpu_count = 2 + } +} + +resource "google_alloydb_cluster" "secondary" { + cluster_id = "tf-test-alloydb-secondary-cluster%{random_suffix}" + location = "us-east1" + network = data.google_compute_network.default.id + cluster_type = "SECONDARY" + + continuous_backup_config { + enabled = false + } + + secondary_config { + primary_cluster_name = google_alloydb_cluster.primary.name + } + + deletion_policy = "FORCE" + + depends_on = [google_alloydb_instance.primary] +} + +resource "google_alloydb_instance" "secondary" { + cluster = google_alloydb_cluster.secondary.name + instance_id = "tf-test-alloydb-secondary-instance%{random_suffix}" + instance_type = google_alloydb_cluster.secondary.cluster_type + + machine_config { + cpu_count = 2 + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} +`, context) +} + +func testAccAlloydbInstance_secondaryInstanceUpdateMachineConfig(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "primary" { + cluster_id = "tf-test-alloydb-primary-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "primary" { + cluster = google_alloydb_cluster.primary.name + instance_id = "tf-test-alloydb-primary-instance%{random_suffix}" + instance_type = "PRIMARY" + + machine_config { + cpu_count = 2 + } +} + +resource "google_alloydb_cluster" "secondary" { + cluster_id = "tf-test-alloydb-secondary-cluster%{random_suffix}" + location = "us-east1" + network = data.google_compute_network.default.id + cluster_type = "SECONDARY" + + continuous_backup_config { + enabled = false + } + + secondary_config { + primary_cluster_name = google_alloydb_cluster.primary.name + } + + deletion_policy = "FORCE" + + depends_on = [google_alloydb_instance.primary] +} + +resource "google_alloydb_instance" "secondary" { + cluster = google_alloydb_cluster.secondary.name + instance_id = "tf-test-alloydb-secondary-instance%{random_suffix}" + instance_type = google_alloydb_cluster.secondary.cluster_type + + machine_config { + cpu_count = 4 + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} +`, context) +} + +// This test passes if we are able to create a secondary instance with an associated read-pool instance +func TestAccAlloydbInstance_secondaryInstanceWithReadPoolInstance(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "alloydbinstance-network-config-1"), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbInstance_secondaryInstanceWithReadPoolInstance(context), + }, + { + ResourceName: "google_alloydb_instance.secondary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccAlloydbInstance_secondaryInstanceWithReadPoolInstance(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "primary" { + cluster_id = "tf-test-alloydb-primary-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "primary" { + cluster = google_alloydb_cluster.primary.name + instance_id = "tf-test-alloydb-primary-instance%{random_suffix}" + instance_type = "PRIMARY" + + machine_config { + cpu_count = 2 + } +} + +resource "google_alloydb_cluster" "secondary" { + cluster_id = "tf-test-alloydb-secondary-cluster%{random_suffix}" + location = "us-west1" + network = data.google_compute_network.default.id + cluster_type = "SECONDARY" + + continuous_backup_config { + enabled = false + } + + secondary_config { + primary_cluster_name = google_alloydb_cluster.primary.name + } + + deletion_policy = "FORCE" + + depends_on = [google_alloydb_instance.primary] +} + +resource "google_alloydb_instance" "secondary" { + cluster = google_alloydb_cluster.secondary.name + instance_id = "tf-test-alloydb-secondary-instance%{random_suffix}" + instance_type = google_alloydb_cluster.secondary.cluster_type + + machine_config { + cpu_count = 2 + } +} + +resource "google_alloydb_instance" "read_pool" { + cluster = google_alloydb_cluster.secondary.name + instance_id = "tf-test-alloydb-read-instance%{random_suffix}-read" + instance_type = "READ_POOL" + read_pool_config { + node_count = 4 + } + depends_on = [google_alloydb_instance.secondary] +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} +`, context) +} + +// This test passes if we are able to create a secondary instance by specifying network_config.network and network_config.allocated_ip_range +func TestAccAlloydbCluster_secondaryInstanceWithNetworkConfigAndAllocatedIPRange(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "alloydbinstance-network-config-1"), + "address_name": acctest.BootstrapSharedTestGlobalAddress(t, "alloydbinstance-network-config-1"), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbCluster_secondaryInstanceWithNetworkConfigAndAllocatedIPRange(context), + }, + { + ResourceName: "google_alloydb_instance.secondary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccAlloydbCluster_secondaryInstanceWithNetworkConfigAndAllocatedIPRange(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "primary" { + cluster_id = "tf-test-alloydb-primary-cluster%{random_suffix}" + location = "us-central1" + network_config { + network = data.google_compute_network.default.id + allocated_ip_range = data.google_compute_global_address.private_ip_alloc.name + } +} + +resource "google_alloydb_instance" "primary" { + cluster = google_alloydb_cluster.primary.name + instance_id = "tf-test-alloydb-primary-instance%{random_suffix}" + instance_type = "PRIMARY" + + machine_config { + cpu_count = 2 + } +} + +resource "google_alloydb_cluster" "secondary" { + cluster_id = "tf-test-alloydb-secondary-cluster%{random_suffix}" + location = "us-west1" + network_config { + network = data.google_compute_network.default.id + allocated_ip_range = data.google_compute_global_address.private_ip_alloc.name + } + cluster_type = "SECONDARY" + + continuous_backup_config { + enabled = false + } + + secondary_config { + primary_cluster_name = google_alloydb_cluster.primary.name + } + + deletion_policy = "FORCE" + + depends_on = [google_alloydb_instance.primary] +} + +resource "google_alloydb_instance" "secondary" { + cluster = google_alloydb_cluster.secondary.name + instance_id = "tf-test-alloydb-secondary-instance%{random_suffix}" + instance_type = google_alloydb_cluster.secondary.cluster_type + + machine_config { + cpu_count = 2 + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + +data "google_compute_global_address" "private_ip_alloc" { + name = "%{address_name}" +} +`, context) +} + +// This test passes if secondary instance's database flag config can be updated +func TestAccAlloydbInstance_secondaryInstanceUpdateDatabaseFlag(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "alloydbinstance-network-config-1"), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbInstance_secondaryInstanceInitial(context), + }, + { + ResourceName: "google_alloydb_instance.secondary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time", "labels", "terraform_labels"}, + }, + { + Config: testAccAlloydbInstance_secondaryInstanceUpdateDatabaseFlag(context), + }, + { + ResourceName: "google_alloydb_instance.secondary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccAlloydbInstance_secondaryInstanceUpdateDatabaseFlag(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "primary" { + cluster_id = "tf-test-alloydb-primary-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "primary" { + cluster = google_alloydb_cluster.primary.name + instance_id = "tf-test-alloydb-primary-instance%{random_suffix}" + instance_type = "PRIMARY" + + machine_config { + cpu_count = 2 + } +} + +resource "google_alloydb_cluster" "secondary" { + cluster_id = "tf-test-alloydb-secondary-cluster%{random_suffix}" + location = "us-east1" + network = data.google_compute_network.default.id + cluster_type = "SECONDARY" + + continuous_backup_config { + enabled = false + } + + secondary_config { + primary_cluster_name = google_alloydb_cluster.primary.name + } + + deletion_policy = "FORCE" + + depends_on = [google_alloydb_instance.primary] +} + +resource "google_alloydb_instance" "secondary" { + cluster = google_alloydb_cluster.secondary.name + instance_id = "tf-test-alloydb-secondary-instance%{random_suffix}" + instance_type = google_alloydb_cluster.secondary.cluster_type + + machine_config { + cpu_count = 2 + } + + database_flags = { + "alloydb.enable_auto_explain" = "true" + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} +`, context) +} + +// This test passes if secondary instance's query insight config can be updated +func TestAccAlloydbInstance_secondaryInstanceUpdateQueryInsightConfig(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "alloydbinstance-network-config-1"), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbInstance_secondaryInstanceInitial(context), + }, + { + ResourceName: "google_alloydb_instance.secondary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time", "labels", "terraform_labels"}, + }, + { + Config: testAccAlloydbInstance_secondaryInstanceUpdateQueryInsightConfig(context), + }, + { + ResourceName: "google_alloydb_instance.secondary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccAlloydbInstance_secondaryInstanceUpdateQueryInsightConfig(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "primary" { + cluster_id = "tf-test-alloydb-primary-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "primary" { + cluster = google_alloydb_cluster.primary.name + instance_id = "tf-test-alloydb-primary-instance%{random_suffix}" + instance_type = "PRIMARY" + + machine_config { + cpu_count = 2 + } +} + +resource "google_alloydb_cluster" "secondary" { + cluster_id = "tf-test-alloydb-secondary-cluster%{random_suffix}" + location = "us-east1" + network = data.google_compute_network.default.id + cluster_type = "SECONDARY" + + continuous_backup_config { + enabled = false + } + + secondary_config { + primary_cluster_name = google_alloydb_cluster.primary.name + } + + deletion_policy = "FORCE" + + depends_on = [google_alloydb_instance.primary] +} + +resource "google_alloydb_instance" "secondary" { + cluster = google_alloydb_cluster.secondary.name + instance_id = "tf-test-alloydb-secondary-instance%{random_suffix}" + instance_type = google_alloydb_cluster.secondary.cluster_type + + machine_config { + cpu_count = 2 + } + + query_insights_config { + query_plans_per_minute = 10 + query_string_length = 2048 + record_application_tags = true + record_client_address = true + } +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} +`, context) +} + +// This test passes if we are able to create a secondary instance with maximum fields +func TestAccAlloydbInstance_secondaryInstanceMaximumFields(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "alloydbinstance-network-config-1"), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbInstance_secondaryInstanceMaximumFields(context), + }, + { + ResourceName: "google_alloydb_instance.secondary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccAlloydbInstance_secondaryInstanceMaximumFields(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "primary" { + cluster_id = "tf-test-alloydb-primary-cluster%{random_suffix}" + location = "us-central1" + network = data.google_compute_network.default.id +} + +resource "google_alloydb_instance" "primary" { + cluster = google_alloydb_cluster.primary.name + instance_id = "tf-test-alloydb-primary-instance%{random_suffix}" + instance_type = "PRIMARY" + + machine_config { + cpu_count = 2 + } +} + +resource "google_alloydb_cluster" "secondary" { + cluster_id = "tf-test-alloydb-secondary-cluster%{random_suffix}" + location = "us-west1" + network = data.google_compute_network.default.id + cluster_type = "SECONDARY" + + continuous_backup_config { + enabled = false + } + + secondary_config { + primary_cluster_name = google_alloydb_cluster.primary.name + } + + deletion_policy = "FORCE" + + depends_on = [google_alloydb_instance.primary] +} + +resource "google_alloydb_instance" "secondary" { + cluster = google_alloydb_cluster.secondary.name + instance_id = "tf-test-alloydb-secondary-instance%{random_suffix}" + instance_type = google_alloydb_cluster.secondary.cluster_type + + machine_config { + cpu_count = 2 + } + + labels = { + test_label = "test-alloydb-label" + } + + query_insights_config { + query_plans_per_minute = 10 + query_string_length = 2048 + record_application_tags = true + record_client_address = true + } + + availability_type = "REGIONAL" +} + +data "google_project" "project" {} + +data "google_compute_network" "default" { + name = "%{network_name}" +} +`, context) +}