From 1e28c5488fae2a450abd2f1fa539b70fb7db99ae Mon Sep 17 00:00:00 2001 From: Shubham Sahu Date: Mon, 9 Oct 2023 13:14:19 -0700 Subject: [PATCH] Add support for secondary instance --- mmv1/products/alloydb/Cluster.yaml | 9 +++ mmv1/products/alloydb/Instance.yaml | 21 +++++- .../alloydb_secondary_instance_basic.tf.erb | 69 +++++++++++++++++++ .../pre_create/alloydb_instance.go.erb | 18 +++++ .../pre_delete/alloydb_cluster.go.erb | 4 ++ .../pre_delete/alloydb_instance.go.erb | 18 +++++ .../pre_update/alloydb_instance.go.erb | 6 ++ 7 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 mmv1/templates/terraform/examples/alloydb_secondary_instance_basic.tf.erb create mode 100644 mmv1/templates/terraform/pre_create/alloydb_instance.go.erb create mode 100644 mmv1/templates/terraform/pre_delete/alloydb_cluster.go.erb create mode 100644 mmv1/templates/terraform/pre_delete/alloydb_instance.go.erb create mode 100644 mmv1/templates/terraform/pre_update/alloydb_instance.go.erb diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 4d4c00fb18f5..0a4627570f09 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -87,6 +87,7 @@ examples: alloydb_secondary_cluster_name: 'alloydb-secondary-cluster' 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 pre_update: templates/terraform/pre_update/alloydb_cluster.go.erb parameters: - !ruby/object:Api::Type::String @@ -479,3 +480,11 @@ 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 forecefully. Deleting a cluster forcefully, deletes the cluster and all its associated instances within the cluster.' + values: + - :DEFAULT + - :FORCE + default_value: :DEFAULT diff --git a/mmv1/products/alloydb/Instance.yaml b/mmv1/products/alloydb/Instance.yaml index e17e9286b905..f7a9b8a2b99c 100644 --- a/mmv1/products/alloydb/Instance.yaml +++ b/mmv1/products/alloydb/Instance.yaml @@ -49,6 +49,9 @@ 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_update: templates/terraform/pre_update/alloydb_instance.go.erb + pre_delete: templates/terraform/pre_delete/alloydb_instance.go.erb examples: - !ruby/object:Provider::Terraform::Examples name: 'alloydb_instance_basic' @@ -60,6 +63,18 @@ examples: ignore_read_extra: - 'reconciling' - 'update_time' + - !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' parameters: - !ruby/object:Api::Type::ResourceRef name: 'cluster' @@ -153,10 +168,14 @@ 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} 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..7ef2f57694a7 --- /dev/null +++ b/mmv1/templates/terraform/examples/alloydb_secondary_instance_basic.tf.erb @@ -0,0 +1,69 @@ +resource "google_alloydb_cluster" "primary" { + cluster_id = "<%= ctx[:vars]['alloydb_primary_cluster_name'] %>" + location = "us-central1" + network = google_compute_network.default.id + cluster_type = "PRIMARY" +} + +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/pre_create/alloydb_instance.go.erb b/mmv1/templates/terraform/pre_create/alloydb_instance.go.erb new file mode 100644 index 000000000000..c2da6148711b --- /dev/null +++ b/mmv1/templates/terraform/pre_create/alloydb_instance.go.erb @@ -0,0 +1,18 @@ +// Read the config and call createsecondary api if instance_type is SECONDARY + +var instanceType interface{} +var cluster interface{} + +if val, ok := obj["instanceType"]; ok { + instanceType = val +} + +cluster = d.Get("cluster") + +if instanceType == "SECONDARY" { + if cluster != nil { + url = strings.Replace(url, "instances?instanceId", "instances:createsecondary?instanceId", 1) + } else { + return fmt.Errorf("Ill defined cluster name when creating secondary instance.") + } +} 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/templates/terraform/pre_update/alloydb_instance.go.erb b/mmv1/templates/terraform/pre_update/alloydb_instance.go.erb new file mode 100644 index 000000000000..07d40bfbf4ef --- /dev/null +++ b/mmv1/templates/terraform/pre_update/alloydb_instance.go.erb @@ -0,0 +1,6 @@ +// Avoid modifying instance type. No use case for this +// Secondary instances can not be created in primary cluster and vice versa. +// Default change is destroy before create, so modifcation from primary <-> secondary will only delete the instance with failure to create the instance. +if d.HasChange("instance_type") { + return fmt.Errorf("Can not change instance type after creation.") +}