From a70591191504e9b8c0c6edeb616f42eac5a3ec1d Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Tue, 11 Jul 2023 16:42:54 -0400 Subject: [PATCH 01/28] Properly handle ABP midnight (hours = 0) --- mmv1/products/alloydb/Cluster.yaml | 1 + ...d_backup_policy_start_times_flatten.go.erb | 108 ++++++++++++++++++ .../tests/resource_alloydb_cluster_test.go | 44 ++++++- 3 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 mmv1/templates/terraform/custom_flatten/alloydb_cluster_input_automated_backup_policy_start_times_flatten.go.erb diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 7fe42bae16bb..60525b1a6af1 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -212,6 +212,7 @@ properties: - !ruby/object:Api::Type::Array name: 'startTimes' required: true + custom_flatten: 'templates/terraform/custom_flatten/alloydb_cluster_input_automated_backup_policy_start_times_flatten.go.erb' description: | The times during the day to start a backup. At least one start time must be provided. The start times are assumed to be in UTC and to be an exact hour (e.g., 04:00:00). item_type: !ruby/object:Api::Type::NestedObject diff --git a/mmv1/templates/terraform/custom_flatten/alloydb_cluster_input_automated_backup_policy_start_times_flatten.go.erb b/mmv1/templates/terraform/custom_flatten/alloydb_cluster_input_automated_backup_policy_start_times_flatten.go.erb new file mode 100644 index 000000000000..18b6ac48ed49 --- /dev/null +++ b/mmv1/templates/terraform/custom_flatten/alloydb_cluster_input_automated_backup_policy_start_times_flatten.go.erb @@ -0,0 +1,108 @@ +<%# The license inside this block applies to this file. + # Copyright 2023 Google Inc. + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. +-%> +func flatten<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // If no start times exist, that means we take backups at midnight. This is represented as 0's all around. + return append(transformed, map[string]interface{}{ + "hours": 0, + "minutes": 0, + "seconds": 0, + "nanos": 0, + }) + } + transformed = append(transformed, map[string]interface{}{ + "hours": flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesHours(original["hours"], d, config), + "minutes": flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesMinutes(original["minutes"], d, config), + "seconds": flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesSeconds(original["seconds"], d, config), + "nanos": flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesNanos(original["nanos"], d, config), + }) + } + return transformed +} + +func flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesHours(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesMinutes(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesSeconds(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesNanos(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} \ No newline at end of file diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go index b25d19f7e3d0..cd882e5046e4 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go @@ -77,6 +77,7 @@ func TestAccAlloydbCluster_addAutomatedBackupPolicyAndInitialUser(t *testing.T) context := map[string]interface{}{ "random_suffix": acctest.RandString(t, 10), + "hour": 23, } acctest.VcrTest(t, resource.TestCase{ @@ -117,6 +118,7 @@ func TestAccAlloydbCluster_deleteAutomatedBackupPolicyAndInitialUser(t *testing. context := map[string]interface{}{ "random_suffix": acctest.RandString(t, 10), + "hour": 23, } acctest.VcrTest(t, resource.TestCase{ @@ -149,6 +151,46 @@ func TestAccAlloydbCluster_deleteAutomatedBackupPolicyAndInitialUser(t *testing. }) } +// Test if automatedBackupPolicy properly handles a startTime of 0 (aka midnight). Calling terraform plan +// after creating the cluster should not bring anything up. +func TestAccAlloydbCluster_AutomatedBackupPolicyHandlesMidnight(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "hour": 0, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbCluster_withoutInitialUserAndAutomatedBackupPolicy(context), + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_withInitialUserAndAutomatedBackupPolicy(context), + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), + }, + }, + }) +} + func testAccAlloydbCluster_withInitialUserAndAutomatedBackupPolicy(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_alloydb_cluster" "default" { @@ -170,7 +212,7 @@ resource "google_alloydb_cluster" "default" { days_of_week = ["MONDAY"] start_times { - hours = 23 + hours = %{hour} minutes = 0 seconds = 0 nanos = 0 From 145121ae725182667d174962ede765c6e448cec5 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Thu, 13 Jul 2023 12:03:16 -0400 Subject: [PATCH 02/28] Add ExpectNonEmptyPlan to test --- .../terraform/tests/resource_alloydb_cluster_test.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go index cd882e5046e4..0b74787aa07b 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go @@ -167,16 +167,8 @@ func TestAccAlloydbCluster_AutomatedBackupPolicyHandlesMidnight(t *testing.T) { CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccAlloydbCluster_withoutInitialUserAndAutomatedBackupPolicy(context), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, - }, - { - Config: testAccAlloydbCluster_withInitialUserAndAutomatedBackupPolicy(context), + Config: testAccAlloydbCluster_withInitialUserAndAutomatedBackupPolicy(context), + ExpectNonEmptyPlan: false, }, { ResourceName: "google_alloydb_cluster.default", From 01bdf49a356914227df4b7efd3865fc3f280f0f8 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Fri, 14 Jul 2023 14:57:02 -0400 Subject: [PATCH 03/28] Add continuous backup config to alloydb cluster --- mmv1/products/alloydb/Cluster.yaml | 75 +++++++++++++++- .../examples/alloydb_cluster_full.tf.erb | 5 ++ .../tests/resource_alloydb_cluster_test.go | 85 +++++++++++++++++++ 3 files changed, 162 insertions(+), 3 deletions(-) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 60525b1a6af1..bf7b4111dd42 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -119,6 +119,48 @@ properties: description: | Output only. Cloud KMS key versions that are being used to protect the database or the backup. output: true + - !ruby/object:Api::Type::NestedObject + name: 'continuousBackupInfo' + description: | + ContinuousBackupInfo describes the continuous backup properties of a cluster. + output: true + properties: + - !ruby/object:Api::Type::String + name: enabledTime + description: | + When ContinuousBackup was most recently enabled. Set to null if ContinuousBackup is not enabled. + output: true + - !ruby/object:Api::Type::Array + name: schedule + item_type: Api::Type::String + description: | + Days of the week on which a continuous backup is taken. Output only field. Ignored if passed into the request. + output: true + - !ruby/object:Api::Type::String + name: earliestRestorableTime + description: | + The earliest restorable time that can be restored to. Output only field. + output: true + - !ruby/object:Api::Type::NestedObject + name: 'encryptionInfo' + description: | + Output only. The encryption information for the WALs and backups required for ContinuousBackup. + output: true + properties: + - !ruby/object:Api::Type::Enum + name: 'encryptionType' + description: 'Output only. Type of encryption.' + values: + - :TYPE_UNSPECIFIED + - :GOOGLE_DEFAULT_ENCRYPTION + - :CUSTOMER_MANAGED_ENCRYPTION + output: true + - !ruby/object:Api::Type::Array + name: kmsKeyVersions + item_type: Api::Type::String + description: | + Output only. Cloud KMS key versions that are being used to protect the database or the backup. + output: true - !ruby/object:Api::Type::String name: 'network' required: true @@ -154,11 +196,38 @@ properties: required: true sensitive: true - !ruby/object:Api::Type::NestedObject - name: 'automatedBackupPolicy' + name: 'continuousBackupConfig' description: | - The automated backup policy for this cluster. + The continuous backup config for this cluster. - If no policy is provided then the default policy will be used. The default policy takes one backup a day, has a backup window of 1 hour, and retains backups for 14 days. + If no policy is provided then the default policy will be used. The default policy takes one backup a day and retains backups for 14 days. + default_from_api: true + properties: + - !ruby/object:Api::Type::Boolean + name: enabled + description: | + Whether continuous backup recovery is enabled. If not set, defaults to true. + default_from_api: true + - !ruby/object:Api::Type::Integer + name: recoveryWindowDays + description: | + The numbers of days that are eligible to restore from using PITR. To support the entire recovery window, backups and logs are retained for one day more than the recovery window. + + If not set, defaults to 14 days. + default_from_api: true + - !ruby/object:Api::Type::NestedObject + name: 'encryptionConfig' + description: | + EncryptionConfig describes the encryption config of a cluster or a backup that is encrypted with a CMEK (customer-managed encryption key). + properties: + - !ruby/object:Api::Type::String + name: 'kmsKeyName' + description: | + The fully-qualified resource name of the KMS key. Each Cloud KMS key is regionalized and has the following format: projects/[PROJECT]/locations/[REGION]/keyRings/[RING]/cryptoKeys/[KEY_NAME]. + - !ruby/object:Api::Type::NestedObject + name: 'automatedBackupPolicy' + description: | + The automated backup policy for this cluster. AutomatedBackupPolicy is disabled by default. default_from_api: true properties: - !ruby/object:Api::Type::String diff --git a/mmv1/templates/terraform/examples/alloydb_cluster_full.tf.erb b/mmv1/templates/terraform/examples/alloydb_cluster_full.tf.erb index f9821307710e..48dbae4c4ba7 100644 --- a/mmv1/templates/terraform/examples/alloydb_cluster_full.tf.erb +++ b/mmv1/templates/terraform/examples/alloydb_cluster_full.tf.erb @@ -8,6 +8,11 @@ resource "google_alloydb_cluster" "<%= ctx[:primary_resource_id] %>" { password = "<%= ctx[:vars]['alloydb_cluster_name'] %>" } + continuous_backup_config { + enabled = true + recovery_window_days = 14 + } + automated_backup_policy { location = "us-central1" backup_window = "1800s" diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go index 0b74787aa07b..aebdd0ee9f5a 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go @@ -738,3 +738,88 @@ resource "google_kms_crypto_key_iam_binding" "crypto_key2" { } `, context) } + +// Even with continuous backups not explicitly called out, it defaults to being enabled with 14d retention. +// This test ensures that if you were to explicitly add the default continuous backup configuration and call +// terraform plan, no changes would be found. +func TestAccAlloydbCluster_continuousBackupConfigEnabledByDefault(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_defaultContinuousBackupConfig(context), + ExpectNonEmptyPlan: false, + }, + }, + }) +} + +// This test ensures that if you start with a terraform configuration were to explicitly add the default continuous backup configuration and call +// terraform plan, no changes would be found. +func TestAccAlloydbCluster_removeDefaultContinuousBackupConfigNoChanges(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbCluster_defaultContinuousBackupConfig(context), + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), + ExpectNonEmptyPlan: false, + }, + }, + }) +} + +func testAccAlloydbCluster_defaultContinuousBackupConfig(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "default" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" + + continuous_backup_config { + enabled = true + recovery_window_days = 14 + } +} + +data "google_project" "project" { +} + +resource "google_compute_network" "default" { + name = "tf-test-alloydb-cluster%{random_suffix}" +} +`, context) +} From a0a2a6844f009cce3449000f86ea3dc881091f24 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Tue, 18 Jul 2023 13:16:31 -0400 Subject: [PATCH 04/28] add more unit tests --- .../tests/resource_alloydb_cluster_test.go | 351 +++++++++++++++++- 1 file changed, 340 insertions(+), 11 deletions(-) diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go index aebdd0ee9f5a..c2ea9aadefb5 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go @@ -742,11 +742,13 @@ resource "google_kms_crypto_key_iam_binding" "crypto_key2" { // Even with continuous backups not explicitly called out, it defaults to being enabled with 14d retention. // This test ensures that if you were to explicitly add the default continuous backup configuration and call // terraform plan, no changes would be found. -func TestAccAlloydbCluster_continuousBackupConfigEnabledByDefault(t *testing.T) { +func TestAccAlloydbCluster_continuousBackup_enabledByDefault(t *testing.T) { t.Parallel() context := map[string]interface{}{ - "random_suffix": acctest.RandString(t, 10), + "random_suffix": acctest.RandString(t, 10), + "enabled": true, + "recovery_window_days": 14, } acctest.VcrTest(t, resource.TestCase{ @@ -764,20 +766,31 @@ func TestAccAlloydbCluster_continuousBackupConfigEnabledByDefault(t *testing.T) ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, }, { - Config: testAccAlloydbCluster_defaultContinuousBackupConfig(context), + Config: testAccAlloydbCluster_continuousBackupConfig(context), ExpectNonEmptyPlan: false, }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), + }, }, }) } -// This test ensures that if you start with a terraform configuration were to explicitly add the default continuous backup configuration and call -// terraform plan, no changes would be found. -func TestAccAlloydbCluster_removeDefaultContinuousBackupConfigNoChanges(t *testing.T) { +// This test ensures that if you start with a terraform configuration where continuous backups are explicitly set to the default configuration +// and then remove continuous backups and call terraform pan, no changes would be found. +func TestAccAlloydbCluster_continuousBackup_noChangeIfRemoved(t *testing.T) { t.Parallel() context := map[string]interface{}{ - "random_suffix": acctest.RandString(t, 10), + "random_suffix": acctest.RandString(t, 10), + "enabled": true, + "recovery_window_days": 14, } acctest.VcrTest(t, resource.TestCase{ @@ -786,7 +799,7 @@ func TestAccAlloydbCluster_removeDefaultContinuousBackupConfigNoChanges(t *testi CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccAlloydbCluster_defaultContinuousBackupConfig(context), + Config: testAccAlloydbCluster_continuousBackupConfig(context), }, { ResourceName: "google_alloydb_cluster.default", @@ -802,7 +815,109 @@ func TestAccAlloydbCluster_removeDefaultContinuousBackupConfigNoChanges(t *testi }) } -func testAccAlloydbCluster_defaultContinuousBackupConfig(context map[string]interface{}) string { +// Ensures changes to the continuous backup config properly applies +func TestAccAlloydbCluster_continuousBackup_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "enabled": true, + "recovery_window_days": 15, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context), + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_continuousBackupConfig(context), + ExpectNonEmptyPlan: true, + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), + }, + }, + }) +} + +// Ensures basic example enabled by default and disabling applies +func TestAccAlloydbCluster_continuousBackup_disable(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "enabled": false, + "recovery_window_days": 14, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context), + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_continuousBackupConfig(context), + ExpectNonEmptyPlan: false, + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), + }, + }, + }) +} + +func testAccAlloydbCluster_withoutContinuousBackupConfig(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "default" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" + lifecycle { + prevent_destroy = true + } +} + +data "google_project" "project" { +} + +resource "google_compute_network" "default" { + name = "tf-test-alloydb-cluster%{random_suffix}" +} +`, context) +} + +func testAccAlloydbCluster_continuousBackupConfig(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_alloydb_cluster" "default" { cluster_id = "tf-test-alloydb-cluster%{random_suffix}" @@ -810,8 +925,11 @@ resource "google_alloydb_cluster" "default" { network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" continuous_backup_config { - enabled = true - recovery_window_days = 14 + enabled = %{enabled} + recovery_window_days = %{recovery_window_days} + } + lifecycle { + prevent_destroy = true } } @@ -823,3 +941,214 @@ resource "google_compute_network" "default" { } `, context) } + +func TestAccAlloydbCluster_continuousBackup_CMEKIsUpdatable(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "key_name": "tf-test-key-" + acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbCluster_usingCMEKInClusterAndContinuousBackup(context), + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_updateCMEKInContinuousBackup(context), + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_continuousBackupUsingCMEKAllowDeletion(context), + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cluster_id", "location"}, + }, + }, + }) +} + +func testAccAlloydbCluster_usingCMEKInClusterAndContinuousBackup(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "default" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" + encryption_config { + kms_key_name = google_kms_crypto_key.key.id + } + continuous_backup_config { + enabled = true + recovery_window_days = 20 + encryption_config { + kms_key_name = google_kms_crypto_key.key.id + } + } + lifecycle { + prevent_destroy = true + } + depends_on = [google_kms_crypto_key_iam_binding.crypto_key] +} + +resource "google_compute_network" "default" { + name = "tf-test-alloydb-cluster%{random_suffix}" +} + +data "google_project" "project" {} + +resource "google_kms_key_ring" "keyring" { + name = "%{key_name}" + location = "us-central1" +} + +resource "google_kms_crypto_key" "key" { + name = "%{key_name}" + key_ring = google_kms_key_ring.keyring.id +} + +resource "google_kms_crypto_key_iam_binding" "crypto_key" { + crypto_key_id = google_kms_crypto_key.key.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + members = [ + "serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com", + ] +} +`, context) +} + +func testAccAlloydbCluster_updateCMEKInContinuousBackup(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "default" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" + encryption_config { + kms_key_name = google_kms_crypto_key.key.id + } + continuous_backup_config { + enabled = true + recovery_window_days = 20 + encryption_config { + kms_key_name = google_kms_crypto_key.key2.id + } + } + lifecycle { + prevent_destroy = true + } + depends_on = [google_kms_crypto_key_iam_binding.crypto_key] +} + +resource "google_compute_network" "default" { + name = "tf-test-alloydb-cluster%{random_suffix}" +} + +data "google_project" "project" {} + +resource "google_kms_key_ring" "keyring" { + name = "%{key_name}" + location = "us-central1" +} + +resource "google_kms_crypto_key" "key" { + name = "%{key_name}" + key_ring = google_kms_key_ring.keyring.id +} + +resource "google_kms_crypto_key" "key2" { + name = "%{key_name}-2" + key_ring = google_kms_key_ring.keyring.id +} + +resource "google_kms_crypto_key_iam_binding" "crypto_key" { + crypto_key_id = google_kms_crypto_key.key.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + members = [ + "serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com", + ] +} + +resource "google_kms_crypto_key_iam_binding" "crypto_key2" { + crypto_key_id = google_kms_crypto_key.key2.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + members = [ + "serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com", + ] +} +`, context) +} + +func testAccAlloydbCluster_continuousBackupUsingCMEKAllowDeletion(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_alloydb_cluster" "default" { + cluster_id = "tf-test-alloydb-cluster%{random_suffix}" + location = "us-central1" + network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" + encryption_config { + kms_key_name = google_kms_crypto_key.key.id + } + continuous_backup_config { + enabled = true + recovery_window_days = 20 + encryption_config { + kms_key_name = google_kms_crypto_key.key2.id + } + } + depends_on = [google_kms_crypto_key_iam_binding.crypto_key] +} + +resource "google_compute_network" "default" { + name = "tf-test-alloydb-cluster%{random_suffix}" +} + +data "google_project" "project" {} + +resource "google_kms_key_ring" "keyring" { + name = "%{key_name}" + location = "us-central1" +} + +resource "google_kms_crypto_key" "key" { + name = "%{key_name}" + key_ring = google_kms_key_ring.keyring.id +} + +resource "google_kms_crypto_key" "key2" { + name = "%{key_name}-2" + key_ring = google_kms_key_ring.keyring.id +} + +resource "google_kms_crypto_key_iam_binding" "crypto_key" { + crypto_key_id = google_kms_crypto_key.key.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + members = [ + "serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com", + ] +} + +resource "google_kms_crypto_key_iam_binding" "crypto_key2" { + crypto_key_id = google_kms_crypto_key.key2.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + members = [ + "serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com", + ] +} +`, context) +} From e886c869c73c858c0323c50089a8e97bc3c52d22 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Thu, 20 Jul 2023 12:15:00 -0400 Subject: [PATCH 05/28] Adding more tests --- mmv1/products/alloydb/Cluster.yaml | 6 +- .../tests/resource_alloydb_cluster_test.go | 95 +++++++++++++++---- 2 files changed, 80 insertions(+), 21 deletions(-) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index bf7b4111dd42..a1acb3ac5ad7 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -197,24 +197,24 @@ properties: sensitive: true - !ruby/object:Api::Type::NestedObject name: 'continuousBackupConfig' + default_from_api: true description: | The continuous backup config for this cluster. If no policy is provided then the default policy will be used. The default policy takes one backup a day and retains backups for 14 days. - default_from_api: true properties: - !ruby/object:Api::Type::Boolean name: enabled + send_empty_value: true description: | Whether continuous backup recovery is enabled. If not set, defaults to true. - default_from_api: true - !ruby/object:Api::Type::Integer name: recoveryWindowDays + default_from_api: true description: | The numbers of days that are eligible to restore from using PITR. To support the entire recovery window, backups and logs are retained for one day more than the recovery window. If not set, defaults to 14 days. - default_from_api: true - !ruby/object:Api::Type::NestedObject name: 'encryptionConfig' description: | diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go index c2ea9aadefb5..f3360d58a882 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go @@ -167,8 +167,7 @@ func TestAccAlloydbCluster_AutomatedBackupPolicyHandlesMidnight(t *testing.T) { CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccAlloydbCluster_withInitialUserAndAutomatedBackupPolicy(context), - ExpectNonEmptyPlan: false, + Config: testAccAlloydbCluster_withInitialUserAndAutomatedBackupPolicy(context), }, { ResourceName: "google_alloydb_cluster.default", @@ -739,12 +738,44 @@ resource "google_kms_crypto_key_iam_binding" "crypto_key2" { `, context) } -// Even with continuous backups not explicitly called out, it defaults to being enabled with 14d retention. -// This test ensures that if you were to explicitly add the default continuous backup configuration and call -// terraform plan, no changes would be found. +// Validates continuous backups defaults to being enabled with 14d retention, even if not explicitly configured. func TestAccAlloydbCluster_continuousBackup_enabledByDefault(t *testing.T) { t.Parallel() + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), + ), + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), + }, + }, + }) +} + +// Continuous backups defaults to being enabled with 14d retention. If the same configuration is set explicitly, terraform plan +// should return no changes. +func TestAccAlloydbCluster_continuousBackup_update_noChangeIfDefaultsSet(t *testing.T) { + t.Parallel() + context := map[string]interface{}{ "random_suffix": acctest.RandString(t, 10), "enabled": true, @@ -757,7 +788,11 @@ func TestAccAlloydbCluster_continuousBackup_enabledByDefault(t *testing.T) { CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), + Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), + ), }, { ResourceName: "google_alloydb_cluster.default", @@ -766,8 +801,11 @@ func TestAccAlloydbCluster_continuousBackup_enabledByDefault(t *testing.T) { ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, }, { - Config: testAccAlloydbCluster_continuousBackupConfig(context), - ExpectNonEmptyPlan: false, + Config: testAccAlloydbCluster_continuousBackupConfig(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), + ), }, { ResourceName: "google_alloydb_cluster.default", @@ -783,7 +821,7 @@ func TestAccAlloydbCluster_continuousBackup_enabledByDefault(t *testing.T) { } // This test ensures that if you start with a terraform configuration where continuous backups are explicitly set to the default configuration -// and then remove continuous backups and call terraform pan, no changes would be found. +// and then remove continuous backups and call terraform plan, no changes would be found. func TestAccAlloydbCluster_continuousBackup_noChangeIfRemoved(t *testing.T) { t.Parallel() @@ -800,6 +838,10 @@ func TestAccAlloydbCluster_continuousBackup_noChangeIfRemoved(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAlloydbCluster_continuousBackupConfig(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), + ), }, { ResourceName: "google_alloydb_cluster.default", @@ -808,15 +850,18 @@ func TestAccAlloydbCluster_continuousBackup_noChangeIfRemoved(t *testing.T) { ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, }, { - Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), - ExpectNonEmptyPlan: false, + Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), + ), }, }, }) } // Ensures changes to the continuous backup config properly applies -func TestAccAlloydbCluster_continuousBackup_update(t *testing.T) { +func TestAccAlloydbCluster_continuousBackup_updateRecoveryWindowDays(t *testing.T) { t.Parallel() context := map[string]interface{}{ @@ -832,6 +877,10 @@ func TestAccAlloydbCluster_continuousBackup_update(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), + ), }, { ResourceName: "google_alloydb_cluster.default", @@ -840,8 +889,11 @@ func TestAccAlloydbCluster_continuousBackup_update(t *testing.T) { ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, }, { - Config: testAccAlloydbCluster_continuousBackupConfig(context), - ExpectNonEmptyPlan: true, + Config: testAccAlloydbCluster_continuousBackupConfig(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "15"), + ), }, { ResourceName: "google_alloydb_cluster.default", @@ -856,8 +908,8 @@ func TestAccAlloydbCluster_continuousBackup_update(t *testing.T) { }) } -// Ensures basic example enabled by default and disabling applies -func TestAccAlloydbCluster_continuousBackup_disable(t *testing.T) { +// Disabling continuous backups works correctly +func TestAccAlloydbCluster_continuousBackup_updateDisable(t *testing.T) { t.Parallel() context := map[string]interface{}{ @@ -873,6 +925,10 @@ func TestAccAlloydbCluster_continuousBackup_disable(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), + ), }, { ResourceName: "google_alloydb_cluster.default", @@ -881,8 +937,11 @@ func TestAccAlloydbCluster_continuousBackup_disable(t *testing.T) { ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, }, { - Config: testAccAlloydbCluster_continuousBackupConfig(context), - ExpectNonEmptyPlan: false, + Config: testAccAlloydbCluster_continuousBackupConfig(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "false"), + resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), + ), }, { ResourceName: "google_alloydb_cluster.default", From 22dcd5ca00aaf1ce33832117fd04bf4e7618144d Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Thu, 20 Jul 2023 12:45:13 -0400 Subject: [PATCH 06/28] Fix cluster.yaml lint --- mmv1/products/alloydb/Cluster.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index adbc0fe72c5d..98b11f699da3 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -214,8 +214,8 @@ properties: name: recoveryWindowDays default_from_api: true description: | - The numbers of days that are eligible to restore from using PITR. To support the entire recovery window, backups and logs are retained for one day more than the recovery window. - + The numbers of days that are eligible to restore from using PITR. To support the entire recovery window, backups and logs are retained for one day more than the recovery window. + If not set, defaults to 14 days. - !ruby/object:Api::Type::NestedObject name: 'encryptionConfig' From 6910f0fdc35c44852752920acdbb85449e889940 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Mon, 31 Jul 2023 16:47:17 -0400 Subject: [PATCH 07/28] Add default value and update cmek test --- mmv1/products/alloydb/Cluster.yaml | 1 + .../terraform/tests/resource_alloydb_cluster_test.go | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 98b11f699da3..dd99ab9d86cd 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -208,6 +208,7 @@ properties: - !ruby/object:Api::Type::Boolean name: enabled send_empty_value: true + default_value: true description: | Whether continuous backup recovery is enabled. If not set, defaults to true. - !ruby/object:Api::Type::Integer diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go index f3360d58a882..9f2d0ee89f8d 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go @@ -1,6 +1,7 @@ package google import ( + "strings" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -1004,9 +1005,14 @@ resource "google_compute_network" "default" { func TestAccAlloydbCluster_continuousBackup_CMEKIsUpdatable(t *testing.T) { t.Parallel() + kms := acctest.BootstrapKMSKey(t) + // Name in the KMS client is in the format projects//locations//keyRings//cryptoKeys/ + keyParts := strings.Split(kms.CryptoKey.Name, "/") + keyID := keyParts[len(keyParts)-1] + context := map[string]interface{}{ "random_suffix": acctest.RandString(t, 10), - "key_name": "tf-test-key-" + acctest.RandString(t, 10), + "key_name": keyID, } acctest.VcrTest(t, resource.TestCase{ From 9c2350cb14ba1ccd7e415e02962c47707f63961c Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Mon, 31 Jul 2023 18:01:06 -0400 Subject: [PATCH 08/28] Update test to use kms key bootstrapping util --- .../tests/resource_alloydb_cluster_test.go | 144 +++--------------- 1 file changed, 18 insertions(+), 126 deletions(-) diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go index 9f2d0ee89f8d..4e00b80bc178 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go @@ -1,7 +1,6 @@ package google import ( - "strings" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -1005,14 +1004,19 @@ resource "google_compute_network" "default" { func TestAccAlloydbCluster_continuousBackup_CMEKIsUpdatable(t *testing.T) { t.Parallel() - kms := acctest.BootstrapKMSKey(t) - // Name in the KMS client is in the format projects//locations//keyRings//cryptoKeys/ - keyParts := strings.Split(kms.CryptoKey.Name, "/") - keyID := keyParts[len(keyParts)-1] - + suffix := acctest.RandString(t, 10) + kms := acctest.BootstrapKMSKeyInLocation(t, "us-central1") context := map[string]interface{}{ - "random_suffix": acctest.RandString(t, 10), - "key_name": keyID, + "random_suffix": suffix, + "key_ring": kms.KeyRing.Name, + "key_name": kms.CryptoKey.Name, + } + + kms2 := acctest.BootstrapKMSKeyInLocation(t, "us-central1") + context2 := map[string]interface{}{ + "random_suffix": suffix, + "key_ring": kms2.KeyRing.Name, + "key_name": kms2.CryptoKey.Name, } acctest.VcrTest(t, resource.TestCase{ @@ -1030,7 +1034,7 @@ func TestAccAlloydbCluster_continuousBackup_CMEKIsUpdatable(t *testing.T) { ImportStateVerifyIgnore: []string{"cluster_id", "location"}, }, { - Config: testAccAlloydbCluster_updateCMEKInContinuousBackup(context), + Config: testAccAlloydbCluster_usingCMEKInClusterAndContinuousBackup(context2), }, { ResourceName: "google_alloydb_cluster.default", @@ -1039,7 +1043,7 @@ func TestAccAlloydbCluster_continuousBackup_CMEKIsUpdatable(t *testing.T) { ImportStateVerifyIgnore: []string{"cluster_id", "location"}, }, { - Config: testAccAlloydbCluster_continuousBackupUsingCMEKAllowDeletion(context), + Config: testAccAlloydbCluster_continuousBackupUsingCMEKAllowDeletion(context2), }, { ResourceName: "google_alloydb_cluster.default", @@ -1058,19 +1062,18 @@ resource "google_alloydb_cluster" "default" { location = "us-central1" network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" encryption_config { - kms_key_name = google_kms_crypto_key.key.id + kms_key_name = "%{key_name}" } continuous_backup_config { enabled = true recovery_window_days = 20 encryption_config { - kms_key_name = google_kms_crypto_key.key.id + kms_key_name = "%{key_name}" } } lifecycle { prevent_destroy = true } - depends_on = [google_kms_crypto_key_iam_binding.crypto_key] } resource "google_compute_network" "default" { @@ -1078,85 +1081,6 @@ resource "google_compute_network" "default" { } data "google_project" "project" {} - -resource "google_kms_key_ring" "keyring" { - name = "%{key_name}" - location = "us-central1" -} - -resource "google_kms_crypto_key" "key" { - name = "%{key_name}" - key_ring = google_kms_key_ring.keyring.id -} - -resource "google_kms_crypto_key_iam_binding" "crypto_key" { - crypto_key_id = google_kms_crypto_key.key.id - role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - members = [ - "serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com", - ] -} -`, context) -} - -func testAccAlloydbCluster_updateCMEKInContinuousBackup(context map[string]interface{}) string { - return acctest.Nprintf(` -resource "google_alloydb_cluster" "default" { - cluster_id = "tf-test-alloydb-cluster%{random_suffix}" - location = "us-central1" - network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" - encryption_config { - kms_key_name = google_kms_crypto_key.key.id - } - continuous_backup_config { - enabled = true - recovery_window_days = 20 - encryption_config { - kms_key_name = google_kms_crypto_key.key2.id - } - } - lifecycle { - prevent_destroy = true - } - depends_on = [google_kms_crypto_key_iam_binding.crypto_key] -} - -resource "google_compute_network" "default" { - name = "tf-test-alloydb-cluster%{random_suffix}" -} - -data "google_project" "project" {} - -resource "google_kms_key_ring" "keyring" { - name = "%{key_name}" - location = "us-central1" -} - -resource "google_kms_crypto_key" "key" { - name = "%{key_name}" - key_ring = google_kms_key_ring.keyring.id -} - -resource "google_kms_crypto_key" "key2" { - name = "%{key_name}-2" - key_ring = google_kms_key_ring.keyring.id -} - -resource "google_kms_crypto_key_iam_binding" "crypto_key" { - crypto_key_id = google_kms_crypto_key.key.id - role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - members = [ - "serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com", - ] -} - -resource "google_kms_crypto_key_iam_binding" "crypto_key2" { - crypto_key_id = google_kms_crypto_key.key2.id - role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - members = [ - "serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com", - ] -} `, context) } @@ -1167,16 +1091,15 @@ resource "google_alloydb_cluster" "default" { location = "us-central1" network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" encryption_config { - kms_key_name = google_kms_crypto_key.key.id + kms_key_name = "%{key_name}" } continuous_backup_config { enabled = true recovery_window_days = 20 encryption_config { - kms_key_name = google_kms_crypto_key.key2.id + kms_key_name = "%{key_name}" } } - depends_on = [google_kms_crypto_key_iam_binding.crypto_key] } resource "google_compute_network" "default" { @@ -1184,36 +1107,5 @@ resource "google_compute_network" "default" { } data "google_project" "project" {} - -resource "google_kms_key_ring" "keyring" { - name = "%{key_name}" - location = "us-central1" -} - -resource "google_kms_crypto_key" "key" { - name = "%{key_name}" - key_ring = google_kms_key_ring.keyring.id -} - -resource "google_kms_crypto_key" "key2" { - name = "%{key_name}-2" - key_ring = google_kms_key_ring.keyring.id -} - -resource "google_kms_crypto_key_iam_binding" "crypto_key" { - crypto_key_id = google_kms_crypto_key.key.id - role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - members = [ - "serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com", - ] -} - -resource "google_kms_crypto_key_iam_binding" "crypto_key2" { - crypto_key_id = google_kms_crypto_key.key2.id - role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - members = [ - "serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com", - ] -} `, context) } From 95b98e6273a8b5ff19191f55212628de54db36c2 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Mon, 31 Jul 2023 18:52:23 -0400 Subject: [PATCH 09/28] condense update tests --- .../tests/resource_alloydb_cluster_test.go | 47 ++++--------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go index 4e00b80bc178..1bef923b985a 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go @@ -861,14 +861,20 @@ func TestAccAlloydbCluster_continuousBackup_noChangeIfRemoved(t *testing.T) { } // Ensures changes to the continuous backup config properly applies -func TestAccAlloydbCluster_continuousBackup_updateRecoveryWindowDays(t *testing.T) { +func TestAccAlloydbCluster_continuousBackup_update(t *testing.T) { t.Parallel() + suffix := acctest.RandString(t, 10) context := map[string]interface{}{ - "random_suffix": acctest.RandString(t, 10), + "random_suffix": suffix, "enabled": true, "recovery_window_days": 15, } + context2 := map[string]interface{}{ + "random_suffix": suffix, + "enabled": false, + "recovery_window_days": 14, + } acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, @@ -902,42 +908,7 @@ func TestAccAlloydbCluster_continuousBackup_updateRecoveryWindowDays(t *testing. ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, }, { - Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), - }, - }, - }) -} - -// Disabling continuous backups works correctly -func TestAccAlloydbCluster_continuousBackup_updateDisable(t *testing.T) { - t.Parallel() - - context := map[string]interface{}{ - "random_suffix": acctest.RandString(t, 10), - "enabled": false, - "recovery_window_days": 14, - } - - acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), - ), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, - }, - { - Config: testAccAlloydbCluster_continuousBackupConfig(context), + Config: testAccAlloydbCluster_continuousBackupConfig(context2), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "false"), resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), From 8c6cbbaa31e20e9fcff0385ee6954a4e04b2e88e Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Tue, 1 Aug 2023 11:58:39 -0400 Subject: [PATCH 10/28] Add restore fields to cluster --- mmv1/products/alloydb/Cluster.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index dd99ab9d86cd..46eb5a144b2b 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -197,6 +197,31 @@ properties: The initial password for the user. required: true sensitive: true + - !ruby/object:Api::Type::String + name: 'restoreSourceBackup' + conflicts: + - restore_source_cluster + - restore_source_point_in_time + description: | + The name of the backup that this cluster should be restored from. Conflicts with 'restore_source_cluster' and 'restore_source_point_in_time', both can't be set together. + - !ruby/object:Api::Type::String + name: 'restoreSourceCluster' + conflicts: + - restore_source_backup + description: | + The name of the source cluster that this cluster should be restored from. The source cluster must have continuous + backup enabled for restore to succeed. + + Requires `restore_source_point_in_time` to also be set. + Conflicts with 'restore_source_backup', both can't be set together. + - !ruby/object:Api::Type::String + name: 'restoreSourcePointInTime' + conflicts: + - restore_source_backup + description: | + The point in time that this cluster should be restored to. Requires `restore_source_cluster` to also be set. + + Conflicts with 'restore_source_backup', both can't be set together. - !ruby/object:Api::Type::NestedObject name: 'continuousBackupConfig' default_from_api: true From ef517d6e4c98d96f57b2b8dae6b0196116776692 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Thu, 3 Aug 2023 16:38:53 -0400 Subject: [PATCH 11/28] ongoing --- mmv1/products/alloydb/Cluster.yaml | 14 +++--- .../alloydb_restore_backup_expand.go.erb | 0 .../pre_create/alloydb_restore_cluster.go.erb | 44 +++++++++++++++++++ 3 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 mmv1/templates/terraform/custom_expand/alloydb_restore_backup_expand.go.erb create mode 100644 mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 46eb5a144b2b..fd3c64218b8a 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -62,6 +62,8 @@ examples: primary_resource_id: 'full' vars: alloydb_cluster_name: 'alloydb-cluster-full' +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' @@ -199,27 +201,27 @@ properties: sensitive: true - !ruby/object:Api::Type::String name: 'restoreSourceBackup' + # custom_expand: 'templates/terraform/custom_expand/alloydb_restore_backup_expand.go.erb' conflicts: - restore_source_cluster - - restore_source_point_in_time + - restore_point_in_time description: | - The name of the backup that this cluster should be restored from. Conflicts with 'restore_source_cluster' and 'restore_source_point_in_time', both can't be set together. + The name of the backup that this cluster should be restored from. Conflicts with 'restore_source_cluster' and 'restore_point_in_time', both can't be set together. - !ruby/object:Api::Type::String name: 'restoreSourceCluster' conflicts: - restore_source_backup description: | The name of the source cluster that this cluster should be restored from. The source cluster must have continuous - backup enabled for restore to succeed. + backup enabled for restore to succeed. Requires `restore_point_in_time` to also be set. - Requires `restore_source_point_in_time` to also be set. Conflicts with 'restore_source_backup', both can't be set together. - !ruby/object:Api::Type::String - name: 'restoreSourcePointInTime' + name: 'restorePointInTime' conflicts: - restore_source_backup description: | - The point in time that this cluster should be restored to. Requires `restore_source_cluster` to also be set. + The point in time that this cluster should be restored to, in RFC 3339 format. Requires `restore_source_cluster` to also be set. Conflicts with 'restore_source_backup', both can't be set together. - !ruby/object:Api::Type::NestedObject diff --git a/mmv1/templates/terraform/custom_expand/alloydb_restore_backup_expand.go.erb b/mmv1/templates/terraform/custom_expand/alloydb_restore_backup_expand.go.erb new file mode 100644 index 000000000000..e69de29bb2d1 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..d421988fb90e --- /dev/null +++ b/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb @@ -0,0 +1,44 @@ +// Read the restore variables from obj and remove them, since they do not map to anything in the cluster +var restoreBackup interface{} +var restoreSourceCluster interface{} +var restorePointInTime interface{} +if val, ok := obj["restoreSourceBackup"]; ok { + restoreBackup = val + delete(obj, "restoreSourceBackup") +} +if val, ok := obj["restoreSourceCluster"]; ok { + restoreSourceCluster = val + delete(obj, "restoreSourceCluster") +} +if val, ok := obj["restorePointInTime"]; ok { + restorePointInTime = val + delete(obj, "restorePointInTime") +} + +// Copy obj which contains the cluster into a cluster map +cluster := make(map[string]interface{}) +for k,v := range obj { + cluster[k] = v +} + +restoreClusterRequestBody := make(map[string]interface{}) +if restoreBackup != nil { + // If restoring from a backup, set the backupSource + backupSource := map[string]interface{}{"name": restoreBackup} + restoreClusterRequestBody["cluster"] = cluster + restoreClusterRequestBody["backupSource"] = backupSource +} else if restoreSourceCluster != nil { + // Otherwise if restoring via PITR, set the continuousBackupSource + continuousBackupSource := map[string]interface{}{ + "cluster": restoreSourceCluster, + "point_in_time": restorePointInTime, + } + restoreClusterRequestBody["cluster"] = cluster + restoreClusterRequestBody["continousBackupSource"] = continuousBackupSource +} + +if restoreBackup != nil || restoreSourceCluster != 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) + obj = restoreClusterRequestBody +} \ No newline at end of file From f37f890c9402450dbe69f6955abf7f380ad625b9 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Thu, 3 Aug 2023 16:50:54 -0400 Subject: [PATCH 12/28] Restore API working --- .../pre_create/alloydb_restore_cluster.go.erb | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb b/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb index d421988fb90e..c1858af2366e 100644 --- a/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb +++ b/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb @@ -15,30 +15,29 @@ if val, ok := obj["restorePointInTime"]; ok { delete(obj, "restorePointInTime") } -// Copy obj which contains the cluster into a cluster map -cluster := make(map[string]interface{}) -for k,v := range obj { - cluster[k] = v -} - restoreClusterRequestBody := make(map[string]interface{}) if restoreBackup != nil { // If restoring from a backup, set the backupSource - backupSource := map[string]interface{}{"name": restoreBackup} - restoreClusterRequestBody["cluster"] = cluster - restoreClusterRequestBody["backupSource"] = backupSource + backupSource := map[string]interface{}{"backup_name": restoreBackup} + restoreClusterRequestBody["backup_source"] = backupSource } else if restoreSourceCluster != nil { // Otherwise if restoring via PITR, set the continuousBackupSource continuousBackupSource := map[string]interface{}{ "cluster": restoreSourceCluster, "point_in_time": restorePointInTime, } - restoreClusterRequestBody["cluster"] = cluster - restoreClusterRequestBody["continousBackupSource"] = continuousBackupSource + restoreClusterRequestBody["continuous_backup_source"] = continuousBackupSource } if restoreBackup != nil || restoreSourceCluster != 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 From 8c47937d63a3f2696be9838ecca7eac23927a53f Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Thu, 3 Aug 2023 17:39:15 -0400 Subject: [PATCH 13/28] make fields immutable and ignored on read --- mmv1/products/alloydb/Cluster.yaml | 7 ++++++- .../custom_expand/alloydb_restore_backup_expand.go.erb | 0 2 files changed, 6 insertions(+), 1 deletion(-) delete mode 100644 mmv1/templates/terraform/custom_expand/alloydb_restore_backup_expand.go.erb diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index fd3c64218b8a..5ca1d2ad561c 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -201,7 +201,8 @@ properties: sensitive: true - !ruby/object:Api::Type::String name: 'restoreSourceBackup' - # custom_expand: 'templates/terraform/custom_expand/alloydb_restore_backup_expand.go.erb' + ignore_read: true + immutable: true conflicts: - restore_source_cluster - restore_point_in_time @@ -209,6 +210,8 @@ properties: The name of the backup that this cluster should be restored from. Conflicts with 'restore_source_cluster' and 'restore_point_in_time', both can't be set together. - !ruby/object:Api::Type::String name: 'restoreSourceCluster' + ignore_read: true + immutable: true conflicts: - restore_source_backup description: | @@ -218,6 +221,8 @@ properties: Conflicts with 'restore_source_backup', both can't be set together. - !ruby/object:Api::Type::String name: 'restorePointInTime' + ignore_read: true + immutable: true conflicts: - restore_source_backup description: | diff --git a/mmv1/templates/terraform/custom_expand/alloydb_restore_backup_expand.go.erb b/mmv1/templates/terraform/custom_expand/alloydb_restore_backup_expand.go.erb deleted file mode 100644 index e69de29bb2d1..000000000000 From 5fa7584b73cb09e436f6779b59385c9b2fa84918 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Fri, 4 Aug 2023 11:19:02 -0400 Subject: [PATCH 14/28] Add required_with field --- mmv1/products/alloydb/Cluster.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 5ca1d2ad561c..5c41be3ebc31 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -212,6 +212,8 @@ properties: name: 'restoreSourceCluster' ignore_read: true immutable: true + required_with: + - restore_point_in_time conflicts: - restore_source_backup description: | @@ -223,6 +225,8 @@ properties: name: 'restorePointInTime' ignore_read: true immutable: true + required_with: + - restore_source_cluster conflicts: - restore_source_backup description: | From 43565fdd66f2f8c56818762fa88ac8c4056814e4 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Mon, 7 Aug 2023 15:25:10 -0400 Subject: [PATCH 15/28] working E2E test for restoring backup and PITR --- .../resource_alloydb_cluster_restore_test.go | 321 ++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go new file mode 100644 index 000000000000..0fb2936a76d9 --- /dev/null +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go @@ -0,0 +1,321 @@ +package google + +import ( + "testing" + "time" + + "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. +// 1. Create the source cluster, instance, and backup +// 2. Restore from the backup directly +// 3. Determine the +func TestAccAlloydbCluster_restore(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "network_name": acctest.BootstrapSharedTestNetwork(t, "alloydbinstance-mandatory"), + } + + time.Sleep(10000 * time.Millisecond) + + 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"}, + }, + { + Config: testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackup(context), + }, + { + ResourceName: "google_alloydb_cluster.restored_from_backup", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "restore_source_backup"}, + }, + { + 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_source_cluster", "restore_point_in_time"}, + }, + { + 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) +} + +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_source_backup = 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_source_backup = 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_source_cluster = google_alloydb_cluster.source.name + restore_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) +} + +// 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_source_backup = 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_source_cluster = google_alloydb_cluster.source.name + restore_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) +} + +// // Validates that updating fields on a restored cluster works fine and doesn't require re-creating the cluster +// func TestAccAlloydbCluster_restore_updateRestoredCluster(t *testing.T) { +// } + +// // Validates that updating the restore source or point in time requires re-creating the cluster. +// // This encompasses both updates to the fields and removing the fields entirely. +// func TestAccAlloydbCluster_restore_cannotUpdateRestoreSource(t *testing.T) { +// } + +// // Validates that only one restore source can be provided +// func TestAccAlloydbCluster_restore_onlyOneSourceAllowed(t *testing.T) { +// } + +// // Validates that pointInTime and sourceCluster must come together +// func TestAccAlloydbCluster_restore_sourceClusterAndPointInTimeRequired(t *testing.T) { +// } From a06326f2bab5d9b5c2481820b729dcb1e0adec3b Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Mon, 7 Aug 2023 17:06:27 -0400 Subject: [PATCH 16/28] Added tests for invalid use cases --- .../resource_alloydb_cluster_restore_test.go | 333 ++++++++++++++++-- 1 file changed, 313 insertions(+), 20 deletions(-) diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go index 0fb2936a76d9..7769bd68372e 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go @@ -1,8 +1,8 @@ package google import ( + "regexp" "testing" - "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-provider-google/google/acctest" @@ -16,7 +16,9 @@ import ( // we condense everything into individual test cases. // 1. Create the source cluster, instance, and backup // 2. Restore from the backup directly -// 3. Determine the +// 3. Restore via PITR +// 4. Update the restored clusters inline +// 5. Allow destruction func TestAccAlloydbCluster_restore(t *testing.T) { t.Parallel() @@ -25,8 +27,6 @@ func TestAccAlloydbCluster_restore(t *testing.T) { "network_name": acctest.BootstrapSharedTestNetwork(t, "alloydbinstance-mandatory"), } - time.Sleep(10000 * time.Millisecond) - acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), @@ -42,6 +42,17 @@ func TestAccAlloydbCluster_restore(t *testing.T) { ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, }, { + // Invalid input check - cannot pass in both sources + Config: testAccAlloydbClusterAndInstanceAndBackup_OnlyOneSourceAllowed(context), + ExpectError: regexp.MustCompile("\"restore_source_cluster\": conflicts with restore_source_backup"), + }, + { + // Invalid input check - both source cluster and point in time are required + Config: testAccAlloydbClusterAndInstanceAndBackup_SourceClusterAndPointInTimeRequired(context), + ExpectError: regexp.MustCompile("`restore_point_in_time,restore_source_cluster` must be specified"), + }, + { + // Validate backup restore succeeds Config: testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackup(context), }, { @@ -51,6 +62,7 @@ func TestAccAlloydbCluster_restore(t *testing.T) { ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "restore_source_backup"}, }, { + // Validate PITR succeeds Config: testAccAlloydbClusterAndInstanceAndBackup_RestoredFromBackupAndRestoredFromPointInTime(context), }, { @@ -59,6 +71,14 @@ func TestAccAlloydbCluster_restore(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "restore_source_cluster", "restore_point_in_time"}, }, + { + // 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), }, @@ -112,6 +132,124 @@ resource "google_service_networking_connection" "vpc_connection" { `, 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_source_backup = google_alloydb_backup.default.name + restore_source_cluster = google_alloydb_cluster.source.name + restore_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_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" { @@ -240,9 +378,9 @@ resource "google_service_networking_connection" "vpc_connection" { `, 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 { +// 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}" @@ -271,6 +409,15 @@ resource "google_alloydb_cluster" "restored_from_backup" { location = "us-central1" network = data.google_compute_network.default.id restore_source_backup = 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" { @@ -279,6 +426,15 @@ resource "google_alloydb_cluster" "restored_from_point_in_time" { network = data.google_compute_network.default.id restore_source_cluster = google_alloydb_cluster.source.name restore_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" {} @@ -303,19 +459,156 @@ resource "google_service_networking_connection" "vpc_connection" { `, context) } -// // Validates that updating fields on a restored cluster works fine and doesn't require re-creating the cluster -// func TestAccAlloydbCluster_restore_updateRestoredCluster(t *testing.T) { -// } +// 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 -// // Validates that updating the restore source or point in time requires re-creating the cluster. -// // This encompasses both updates to the fields and removing the fields entirely. -// func TestAccAlloydbCluster_restore_cannotUpdateRestoreSource(t *testing.T) { -// } + depends_on = [google_alloydb_instance.source] +} -// // Validates that only one restore source can be provided -// func TestAccAlloydbCluster_restore_onlyOneSourceAllowed(t *testing.T) { -// } +resource "google_alloydb_backup" "default2" { + location = "us-central1" + backup_id = "tf-test-alloydb-backup2-%{random_suffix}" + cluster_name = google_alloydb_cluster.source.name -// // Validates that pointInTime and sourceCluster must come together -// func TestAccAlloydbCluster_restore_sourceClusterAndPointInTimeRequired(t *testing.T) { -// } + 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_source_backup = 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_source_cluster = google_alloydb_cluster.restored_from_backup.name + restore_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_source_backup = 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_source_cluster = google_alloydb_cluster.source.name + restore_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) +} From 3c4910984ea5434c89b4a31942ca8396a385a0e0 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Mon, 7 Aug 2023 17:22:01 -0400 Subject: [PATCH 17/28] Added example for how to use cluster restore --- mmv1/products/alloydb/Cluster.yaml | 10 +++ .../examples/alloydb_cluster_restore.tf.erb | 64 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 5c41be3ebc31..a08671e6b454 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -62,6 +62,16 @@ 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' + 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' custom_code: !ruby/object:Provider::Terraform::CustomCode pre_create: templates/terraform/pre_create/alloydb_restore_cluster.go.erb parameters: 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..302ad553e50f --- /dev/null +++ b/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb @@ -0,0 +1,64 @@ +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_source_backup = 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_source_cluster = google_alloydb_cluster.<%= ctx[:primary_resource_id] %>.name + restore_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] +} \ No newline at end of file From ed9730be95bd151db8c36372adc41f43de9517eb Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Mon, 7 Aug 2023 17:40:46 -0400 Subject: [PATCH 18/28] fix bad merge --- mmv1/products/alloydb/Cluster.yaml | 42 --- .../tests/resource_alloydb_cluster_test.go | 343 ------------------ 2 files changed, 385 deletions(-) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 773ad036e6bd..c7eafbc1e6f4 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -133,48 +133,6 @@ properties: description: | Output only. Cloud KMS key versions that are being used to protect the database or the backup. output: true - - !ruby/object:Api::Type::NestedObject - name: 'continuousBackupInfo' - description: | - ContinuousBackupInfo describes the continuous backup properties of a cluster. - output: true - properties: - - !ruby/object:Api::Type::String - name: enabledTime - description: | - When ContinuousBackup was most recently enabled. Set to null if ContinuousBackup is not enabled. - output: true - - !ruby/object:Api::Type::Array - name: schedule - item_type: Api::Type::String - description: | - Days of the week on which a continuous backup is taken. Output only field. Ignored if passed into the request. - output: true - - !ruby/object:Api::Type::String - name: earliestRestorableTime - description: | - The earliest restorable time that can be restored to. Output only field. - output: true - - !ruby/object:Api::Type::NestedObject - name: 'encryptionInfo' - description: | - Output only. The encryption information for the WALs and backups required for ContinuousBackup. - output: true - properties: - - !ruby/object:Api::Type::Enum - name: 'encryptionType' - description: 'Output only. Type of encryption.' - values: - - :TYPE_UNSPECIFIED - - :GOOGLE_DEFAULT_ENCRYPTION - - :CUSTOMER_MANAGED_ENCRYPTION - output: true - - !ruby/object:Api::Type::Array - name: kmsKeyVersions - item_type: Api::Type::String - description: | - Output only. Cloud KMS key versions that are being used to protect the database or the backup. - output: true - !ruby/object:Api::Type::NestedObject name: 'continuousBackupInfo' description: | diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go index 14b3ae300862..6df317a65185 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go @@ -972,349 +972,6 @@ resource "google_compute_network" "default" { `, context) } -func TestAccAlloydbCluster_continuousBackup_CMEKIsUpdatable(t *testing.T) { - t.Parallel() - - suffix := acctest.RandString(t, 10) - kms := acctest.BootstrapKMSKeyInLocation(t, "us-central1") - context := map[string]interface{}{ - "random_suffix": suffix, - "key_ring": kms.KeyRing.Name, - "key_name": kms.CryptoKey.Name, - } - - kms2 := acctest.BootstrapKMSKeyInLocation(t, "us-central1") - context2 := map[string]interface{}{ - "random_suffix": suffix, - "key_ring": kms2.KeyRing.Name, - "key_name": kms2.CryptoKey.Name, - } - - acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccAlloydbCluster_usingCMEKInClusterAndContinuousBackup(context), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"cluster_id", "location"}, - }, - { - Config: testAccAlloydbCluster_usingCMEKInClusterAndContinuousBackup(context2), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"cluster_id", "location"}, - }, - { - Config: testAccAlloydbCluster_continuousBackupUsingCMEKAllowDeletion(context2), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"cluster_id", "location"}, - }, - }, - }) -} - -func testAccAlloydbCluster_usingCMEKInClusterAndContinuousBackup(context map[string]interface{}) string { - return acctest.Nprintf(` -resource "google_alloydb_cluster" "default" { - cluster_id = "tf-test-alloydb-cluster%{random_suffix}" - location = "us-central1" - network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" - encryption_config { - kms_key_name = "%{key_name}" - } - continuous_backup_config { - enabled = true - recovery_window_days = 20 - encryption_config { - kms_key_name = "%{key_name}" - } - } - lifecycle { - prevent_destroy = true - } -} - -resource "google_compute_network" "default" { - name = "tf-test-alloydb-cluster%{random_suffix}" -} - -data "google_project" "project" {} -`, context) -} - -func testAccAlloydbCluster_continuousBackupUsingCMEKAllowDeletion(context map[string]interface{}) string { - return acctest.Nprintf(` -resource "google_alloydb_cluster" "default" { - cluster_id = "tf-test-alloydb-cluster%{random_suffix}" - location = "us-central1" - network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" - encryption_config { - kms_key_name = "%{key_name}" - } - continuous_backup_config { - enabled = true - recovery_window_days = 20 - encryption_config { - kms_key_name = "%{key_name}" - } - } -} - -resource "google_compute_network" "default" { - name = "tf-test-alloydb-cluster%{random_suffix}" -} - -data "google_project" "project" {} -`, context) -} - -// Validates continuous backups defaults to being enabled with 14d retention, even if not explicitly configured. -func TestAccAlloydbCluster_continuousBackup_enabledByDefault(t *testing.T) { - t.Parallel() - - context := map[string]interface{}{ - "random_suffix": acctest.RandString(t, 10), - } - - acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), - ), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, - }, - { - Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), - }, - }, - }) -} - -// Continuous backups defaults to being enabled with 14d retention. If the same configuration is set explicitly, terraform plan -// should return no changes. -func TestAccAlloydbCluster_continuousBackup_update_noChangeIfDefaultsSet(t *testing.T) { - t.Parallel() - - context := map[string]interface{}{ - "random_suffix": acctest.RandString(t, 10), - "enabled": true, - "recovery_window_days": 14, - } - - acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), - ), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, - }, - { - Config: testAccAlloydbCluster_continuousBackupConfig(context), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), - ), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, - }, - { - Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), - }, - }, - }) -} - -// This test ensures that if you start with a terraform configuration where continuous backups are explicitly set to the default configuration -// and then remove continuous backups and call terraform plan, no changes would be found. -func TestAccAlloydbCluster_continuousBackup_noChangeIfRemoved(t *testing.T) { - t.Parallel() - - context := map[string]interface{}{ - "random_suffix": acctest.RandString(t, 10), - "enabled": true, - "recovery_window_days": 14, - } - - acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccAlloydbCluster_continuousBackupConfig(context), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), - ), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, - }, - { - Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), - ), - }, - }, - }) -} - -// Ensures changes to the continuous backup config properly applies -func TestAccAlloydbCluster_continuousBackup_update(t *testing.T) { - t.Parallel() - - suffix := acctest.RandString(t, 10) - context := map[string]interface{}{ - "random_suffix": suffix, - "enabled": true, - "recovery_window_days": 15, - } - context2 := map[string]interface{}{ - "random_suffix": suffix, - "enabled": false, - "recovery_window_days": 14, - } - - acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), - ), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, - }, - { - Config: testAccAlloydbCluster_continuousBackupConfig(context), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"), - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "15"), - ), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, - }, - { - Config: testAccAlloydbCluster_continuousBackupConfig(context2), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "false"), - resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"), - ), - }, - { - ResourceName: "google_alloydb_cluster.default", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, - }, - { - Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), - }, - }, - }) -} - -func testAccAlloydbCluster_withoutContinuousBackupConfig(context map[string]interface{}) string { - return acctest.Nprintf(` -resource "google_alloydb_cluster" "default" { - cluster_id = "tf-test-alloydb-cluster%{random_suffix}" - location = "us-central1" - network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" - lifecycle { - prevent_destroy = true - } -} - -data "google_project" "project" { -} - -resource "google_compute_network" "default" { - name = "tf-test-alloydb-cluster%{random_suffix}" -} -`, context) -} - -func testAccAlloydbCluster_continuousBackupConfig(context map[string]interface{}) string { - return acctest.Nprintf(` -resource "google_alloydb_cluster" "default" { - cluster_id = "tf-test-alloydb-cluster%{random_suffix}" - location = "us-central1" - network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" - - continuous_backup_config { - enabled = %{enabled} - recovery_window_days = %{recovery_window_days} - } - lifecycle { - prevent_destroy = true - } -} - -data "google_project" "project" { -} - -resource "google_compute_network" "default" { - name = "tf-test-alloydb-cluster%{random_suffix}" -} -`, context) -} - func TestAccAlloydbCluster_continuousBackup_CMEKIsUpdatable(t *testing.T) { t.Parallel() From 81dd01f49bf66bae004c7c1cd0ad212c20ac3532 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Mon, 7 Aug 2023 17:42:20 -0400 Subject: [PATCH 19/28] remove test comment in favor of inline commenting --- .../terraform/tests/resource_alloydb_cluster_restore_test.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go index 7769bd68372e..fd9343d37469 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_restore_test.go @@ -14,11 +14,6 @@ import ( // 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. -// 1. Create the source cluster, instance, and backup -// 2. Restore from the backup directly -// 3. Restore via PITR -// 4. Update the restored clusters inline -// 5. Allow destruction func TestAccAlloydbCluster_restore(t *testing.T) { t.Parallel() From b6c5c8f2157615babee2496525ca178ada3bb3fa Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Tue, 8 Aug 2023 13:46:07 -0400 Subject: [PATCH 20/28] fix cluster restore example --- mmv1/products/alloydb/Cluster.yaml | 5 +++++ .../terraform/examples/alloydb_cluster_restore.tf.erb | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index c7eafbc1e6f4..78e72d6916d7 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -72,6 +72,11 @@ examples: 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: diff --git a/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb b/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb index 302ad553e50f..a52daa87db2a 100644 --- a/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb +++ b/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb @@ -40,7 +40,7 @@ resource "google_alloydb_cluster" "restored_via_pitr" { location = "us-central1" network = data.google_compute_network.default.id restore_source_cluster = google_alloydb_cluster.<%= ctx[:primary_resource_id] %>.name - restore_point_in_time = "2023-08-03T19:19:00.094Z" + restore_point_in_time = google_alloydb_backup.<%= ctx[:primary_resource_id] %>.update_time } data "google_project" "project" {} @@ -61,4 +61,4 @@ 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] -} \ No newline at end of file +} From bf6af4b7209014f5823f62de384021acadb603c6 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Tue, 8 Aug 2023 14:25:32 -0400 Subject: [PATCH 21/28] remove trailing spaces --- mmv1/products/alloydb/Cluster.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 78e72d6916d7..baa57bb5b2c2 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -214,7 +214,7 @@ properties: name: 'restoreSourceBackup' ignore_read: true immutable: true - conflicts: + conflicts: - restore_source_cluster - restore_point_in_time description: | @@ -225,7 +225,7 @@ properties: immutable: true required_with: - restore_point_in_time - conflicts: + conflicts: - restore_source_backup description: | The name of the source cluster that this cluster should be restored from. The source cluster must have continuous @@ -238,11 +238,11 @@ properties: immutable: true required_with: - restore_source_cluster - conflicts: + conflicts: - restore_source_backup description: | The point in time that this cluster should be restored to, in RFC 3339 format. Requires `restore_source_cluster` to also be set. - + Conflicts with 'restore_source_backup', both can't be set together. - !ruby/object:Api::Type::NestedObject name: 'continuousBackupConfig' From f6866e27cd022a3f7bca69251dac2c16632839b7 Mon Sep 17 00:00:00 2001 From: GoogleMarcfont <138053009+GoogleMarcfont@users.noreply.github.com> Date: Thu, 10 Aug 2023 10:52:53 -0400 Subject: [PATCH 22/28] Skip example test Co-authored-by: Nick Elliot --- mmv1/products/alloydb/Cluster.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index baa57bb5b2c2..9c98f7495dc0 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -65,6 +65,7 @@ examples: - !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' From b05962b7dd4fe35a11f776699abc18bcd1aa9baa Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Thu, 10 Aug 2023 11:30:44 -0400 Subject: [PATCH 23/28] change point in time in example to a date --- .../templates/terraform/examples/alloydb_cluster_restore.tf.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb b/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb index a52daa87db2a..6799207ab6f7 100644 --- a/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb +++ b/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb @@ -40,7 +40,7 @@ resource "google_alloydb_cluster" "restored_via_pitr" { location = "us-central1" network = data.google_compute_network.default.id restore_source_cluster = google_alloydb_cluster.<%= ctx[:primary_resource_id] %>.name - restore_point_in_time = google_alloydb_backup.<%= ctx[:primary_resource_id] %>.update_time + restore_point_in_time = "2023-08-03T19:19:00.094Z" } data "google_project" "project" {} From 8f109a47555326fb75df2838a9b191fc86242ddc Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Wed, 16 Aug 2023 14:45:50 -0700 Subject: [PATCH 24/28] move test --- .../resource_alloydb_cluster_restore_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename mmv1/third_party/terraform/services/{compute => alloydb}/resource_alloydb_cluster_restore_test.go (99%) diff --git a/mmv1/third_party/terraform/services/compute/resource_alloydb_cluster_restore_test.go b/mmv1/third_party/terraform/services/alloydb/resource_alloydb_cluster_restore_test.go similarity index 99% rename from mmv1/third_party/terraform/services/compute/resource_alloydb_cluster_restore_test.go rename to mmv1/third_party/terraform/services/alloydb/resource_alloydb_cluster_restore_test.go index fd9343d37469..042839349e40 100644 --- a/mmv1/third_party/terraform/services/compute/resource_alloydb_cluster_restore_test.go +++ b/mmv1/third_party/terraform/services/alloydb/resource_alloydb_cluster_restore_test.go @@ -1,4 +1,4 @@ -package google +package alloydb_test import ( "regexp" From 0344f20ec7f7de7b3cd3e547324fcb0cfc80dae3 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Wed, 16 Aug 2023 16:17:10 -0700 Subject: [PATCH 25/28] rename network name in restore test --- .../services/alloydb/resource_alloydb_cluster_restore_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 042839349e40..e36ceaf6029f 100644 --- 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 @@ -19,7 +19,7 @@ func TestAccAlloydbCluster_restore(t *testing.T) { context := map[string]interface{}{ "random_suffix": acctest.RandString(t, 10), - "network_name": acctest.BootstrapSharedTestNetwork(t, "alloydbinstance-mandatory"), + "network_name": acctest.BootstrapSharedTestNetwork(t, "alloydbinstance-restore"), } acctest.VcrTest(t, resource.TestCase{ From 944b4bbf50b4ffb7bdb615af1f895937fd392802 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Thu, 17 Aug 2023 15:04:25 -0700 Subject: [PATCH 26/28] Update cluster.yaml to use same structure as API --- mmv1/products/alloydb/Cluster.yaml | 62 ++++++++-------- .../examples/alloydb_cluster_restore.tf.erb | 11 ++- .../pre_create/alloydb_restore_cluster.go.erb | 32 +++------ .../resource_alloydb_cluster_restore_test.go | 71 +++++++++++++------ 4 files changed, 95 insertions(+), 81 deletions(-) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 97f932aa98b2..8ebbbb6a3660 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -211,40 +211,42 @@ properties: The initial password for the user. required: true sensitive: true - - !ruby/object:Api::Type::String - name: 'restoreSourceBackup' - ignore_read: true - immutable: true - conflicts: - - restore_source_cluster - - restore_point_in_time - description: | - The name of the backup that this cluster should be restored from. Conflicts with 'restore_source_cluster' and 'restore_point_in_time', both can't be set together. - - !ruby/object:Api::Type::String - name: 'restoreSourceCluster' + - !ruby/object:Api::Type::NestedObject + name: 'backupSource' ignore_read: true immutable: true - required_with: - - restore_point_in_time conflicts: - - restore_source_backup + - continuous_backup_source description: | - The name of the source cluster that this cluster should be restored from. The source cluster must have continuous - backup enabled for restore to succeed. Requires `restore_point_in_time` to also be set. - - Conflicts with 'restore_source_backup', both can't be set together. - - !ruby/object:Api::Type::String - name: 'restorePointInTime' + The source when restoring from a backup. Conflicts with '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: 'continuousBackupSource' ignore_read: true immutable: true - required_with: - - restore_source_cluster conflicts: - - restore_source_backup + - backup_source description: | - The point in time that this cluster should be restored to, in RFC 3339 format. Requires `restore_source_cluster` to also be set. - - Conflicts with 'restore_source_backup', both can't be set together. + The source when restoring via point in time recovery (PITR). Conflicts with '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 @@ -383,14 +385,6 @@ properties: default_from_api: true description: | Whether automated backups are enabled. - - !ruby/object:Api::Type::NestedObject - name: 'backupSource' - output: true - description: 'Cluster created from backup.' - properties: - - !ruby/object:Api::Type::String - name: 'backupName' - description: 'The name of the backup resource.' - !ruby/object:Api::Type::NestedObject name: 'migrationSource' output: true diff --git a/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb b/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb index 6799207ab6f7..6f1f6f9b9715 100644 --- a/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb +++ b/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb @@ -32,15 +32,20 @@ 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_source_backup = google_alloydb_backup.<%= ctx[:primary_resource_id] %>.name + 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_source_cluster = google_alloydb_cluster.<%= ctx[:primary_resource_id] %>.name - restore_point_in_time = "2023-08-03T19:19:00.094Z" + + 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" {} diff --git a/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb b/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb index c1858af2366e..e59de792ebde 100644 --- a/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb +++ b/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb @@ -1,35 +1,25 @@ // Read the restore variables from obj and remove them, since they do not map to anything in the cluster -var restoreBackup interface{} -var restoreSourceCluster interface{} -var restorePointInTime interface{} -if val, ok := obj["restoreSourceBackup"]; ok { - restoreBackup = val - delete(obj, "restoreSourceBackup") +var backupSource interface{} +var continuousBackupSource interface{} +if val, ok := obj["backupSource"]; ok { + backupSource = val + delete(obj, "backupSource") } -if val, ok := obj["restoreSourceCluster"]; ok { - restoreSourceCluster = val - delete(obj, "restoreSourceCluster") -} -if val, ok := obj["restorePointInTime"]; ok { - restorePointInTime = val - delete(obj, "restorePointInTime") +if val, ok := obj["continuousBackupSource"]; ok { + continuousBackupSource = val + delete(obj, "continuousBackupSource") } restoreClusterRequestBody := make(map[string]interface{}) -if restoreBackup != nil { +if backupSource != nil { // If restoring from a backup, set the backupSource - backupSource := map[string]interface{}{"backup_name": restoreBackup} restoreClusterRequestBody["backup_source"] = backupSource -} else if restoreSourceCluster != nil { +} else if continuousBackupSource != nil { // Otherwise if restoring via PITR, set the continuousBackupSource - continuousBackupSource := map[string]interface{}{ - "cluster": restoreSourceCluster, - "point_in_time": restorePointInTime, - } restoreClusterRequestBody["continuous_backup_source"] = continuousBackupSource } -if restoreBackup != nil || restoreSourceCluster != nil { +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) 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 index e36ceaf6029f..11847231a223 100644 --- 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 @@ -39,12 +39,12 @@ func TestAccAlloydbCluster_restore(t *testing.T) { { // Invalid input check - cannot pass in both sources Config: testAccAlloydbClusterAndInstanceAndBackup_OnlyOneSourceAllowed(context), - ExpectError: regexp.MustCompile("\"restore_source_cluster\": conflicts with restore_source_backup"), + ExpectError: regexp.MustCompile("\"continuous_backup_source\": conflicts with backup_source"), }, { // Invalid input check - both source cluster and point in time are required Config: testAccAlloydbClusterAndInstanceAndBackup_SourceClusterAndPointInTimeRequired(context), - ExpectError: regexp.MustCompile("`restore_point_in_time,restore_source_cluster` must be specified"), + ExpectError: regexp.MustCompile("The argument \"point_in_time\" is required, but no definition was found."), }, { // Validate backup restore succeeds @@ -54,7 +54,7 @@ func TestAccAlloydbCluster_restore(t *testing.T) { ResourceName: "google_alloydb_cluster.restored_from_backup", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "restore_source_backup"}, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "backup_source"}, }, { // Validate PITR succeeds @@ -64,7 +64,7 @@ func TestAccAlloydbCluster_restore(t *testing.T) { ResourceName: "google_alloydb_cluster.restored_from_point_in_time", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "restore_source_cluster", "restore_point_in_time"}, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "continuous_backup_source"}, }, { // Make sure updates work without recreating the clusters @@ -156,9 +156,13 @@ 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_source_backup = google_alloydb_backup.default.name - restore_source_cluster = google_alloydb_cluster.source.name - restore_point_in_time = google_alloydb_backup.default.update_time + backup_source { + backup_name = google_alloydb_backup.default.name + } + continuous_backup_source { + cluster = google_alloydb_cluster.source.name + point_in_time = google_alloydb_backup.default.update_time + } lifecycle { prevent_destroy = true @@ -216,7 +220,10 @@ 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_source_cluster = google_alloydb_cluster.source.name + + continuous_backup_source { + cluster = google_alloydb_cluster.source.name + } lifecycle { prevent_destroy = true @@ -273,7 +280,9 @@ 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_source_backup = google_alloydb_backup.default.name + backup_source { + backup_name = google_alloydb_backup.default.name + } lifecycle { prevent_destroy = true @@ -332,7 +341,9 @@ 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_source_backup = google_alloydb_backup.default.name + backup_source { + backup_name = google_alloydb_backup.default.name + } lifecycle { prevent_destroy = true @@ -343,8 +354,10 @@ 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_source_cluster = google_alloydb_cluster.source.name - restore_point_in_time = google_alloydb_backup.default.update_time + continuous_backup_source { + cluster = google_alloydb_cluster.source.name + point_in_time = google_alloydb_backup.default.update_time + } lifecycle { prevent_destroy = true @@ -403,7 +416,9 @@ 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_source_backup = google_alloydb_backup.default.name + backup_source { + backup_name = google_alloydb_backup.default.name + } continuous_backup_config { enabled = true @@ -419,9 +434,11 @@ 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_source_cluster = google_alloydb_cluster.source.name - restore_point_in_time = google_alloydb_backup.default.update_time - + 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 @@ -492,7 +509,9 @@ 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_source_backup = google_alloydb_backup.default2.name + backup_source { + backup_name = google_alloydb_backup.default2.name + } continuous_backup_config { enabled = true @@ -510,9 +529,11 @@ 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_source_cluster = google_alloydb_cluster.restored_from_backup.name - restore_point_in_time = google_alloydb_backup.default.update_time - + 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 @@ -575,15 +596,19 @@ 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_source_backup = google_alloydb_backup.default.name + 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_source_cluster = google_alloydb_cluster.source.name - restore_point_in_time = google_alloydb_backup.default.update_time + continuous_backup_source { + cluster = google_alloydb_cluster.source.name + point_in_time = google_alloydb_backup.default.update_time + } } data "google_project" "project" {} From f9a43790d65cdd8a6a29b0f584c5ff41b4f49578 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Fontenelle Date: Fri, 18 Aug 2023 09:42:55 -0700 Subject: [PATCH 27/28] rename backup and continuous backup source --- mmv1/products/alloydb/Cluster.yaml | 20 +++++++++---- .../examples/alloydb_cluster_restore.tf.erb | 4 +-- .../pre_create/alloydb_restore_cluster.go.erb | 8 ++--- .../resource_alloydb_cluster_restore_test.go | 30 +++++++++---------- 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 8ebbbb6a3660..cf597bad4d43 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -212,13 +212,13 @@ properties: required: true sensitive: true - !ruby/object:Api::Type::NestedObject - name: 'backupSource' + name: 'restoreBackupSource' ignore_read: true immutable: true conflicts: - - continuous_backup_source + - restore_continuous_backup_source description: | - The source when restoring from a backup. Conflicts with 'continuous_backup_source', both can't be set together. + 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' @@ -227,13 +227,13 @@ properties: description: | The name of the backup that this cluster is restored from. - !ruby/object:Api::Type::NestedObject - name: 'continuousBackupSource' + name: 'restoreContinuousBackupSource' ignore_read: true immutable: true conflicts: - - backup_source + - restore_backup_source description: | - The source when restoring via point in time recovery (PITR). Conflicts with 'backup_source', both can't be set together. + 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' @@ -385,6 +385,14 @@ properties: default_from_api: true description: | Whether automated backups are enabled. + - !ruby/object:Api::Type::NestedObject + name: 'backupSource' + output: true + description: 'Cluster created from backup.' + properties: + - !ruby/object:Api::Type::String + name: 'backupName' + description: 'The name of the backup resource.' - !ruby/object:Api::Type::NestedObject name: 'migrationSource' output: true diff --git a/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb b/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb index 6f1f6f9b9715..5b60c638c793 100644 --- a/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb +++ b/mmv1/templates/terraform/examples/alloydb_cluster_restore.tf.erb @@ -32,7 +32,7 @@ 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 - backup_source { + restore_backup_source { backup_name = google_alloydb_backup.<%= ctx[:primary_resource_id] %>.name } } @@ -42,7 +42,7 @@ resource "google_alloydb_cluster" "restored_via_pitr" { location = "us-central1" network = data.google_compute_network.default.id - continuous_backup_source { + restore_continuous_backup_source { cluster = google_alloydb_cluster.<%= ctx[:primary_resource_id] %>.name point_in_time = "2023-08-03T19:19:00.094Z" } diff --git a/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb b/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb index e59de792ebde..1cce1c5bf5b9 100644 --- a/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb +++ b/mmv1/templates/terraform/pre_create/alloydb_restore_cluster.go.erb @@ -1,13 +1,13 @@ // 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["backupSource"]; ok { +if val, ok := obj["restoreBackupSource"]; ok { backupSource = val - delete(obj, "backupSource") + delete(obj, "restoreBackupSource") } -if val, ok := obj["continuousBackupSource"]; ok { +if val, ok := obj["restoreContinuousBackupSource"]; ok { continuousBackupSource = val - delete(obj, "continuousBackupSource") + delete(obj, "restoreContinuousBackupSource") } restoreClusterRequestBody := make(map[string]interface{}) 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 index 11847231a223..6e28ac1bdfa9 100644 --- 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 @@ -39,7 +39,7 @@ func TestAccAlloydbCluster_restore(t *testing.T) { { // Invalid input check - cannot pass in both sources Config: testAccAlloydbClusterAndInstanceAndBackup_OnlyOneSourceAllowed(context), - ExpectError: regexp.MustCompile("\"continuous_backup_source\": conflicts with backup_source"), + ExpectError: regexp.MustCompile("\"restore_continuous_backup_source\": conflicts with restore_backup_source"), }, { // Invalid input check - both source cluster and point in time are required @@ -54,7 +54,7 @@ func TestAccAlloydbCluster_restore(t *testing.T) { ResourceName: "google_alloydb_cluster.restored_from_backup", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "backup_source"}, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "restore_backup_source"}, }, { // Validate PITR succeeds @@ -64,7 +64,7 @@ func TestAccAlloydbCluster_restore(t *testing.T) { ResourceName: "google_alloydb_cluster.restored_from_point_in_time", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "continuous_backup_source"}, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location", "restore_continuous_backup_source"}, }, { // Make sure updates work without recreating the clusters @@ -156,10 +156,10 @@ 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 - backup_source { + restore_backup_source { backup_name = google_alloydb_backup.default.name } - continuous_backup_source { + restore_continuous_backup_source { cluster = google_alloydb_cluster.source.name point_in_time = google_alloydb_backup.default.update_time } @@ -221,7 +221,7 @@ resource "google_alloydb_cluster" "restored" { location = "us-central1" network = data.google_compute_network.default.id - continuous_backup_source { + restore_continuous_backup_source { cluster = google_alloydb_cluster.source.name } @@ -280,7 +280,7 @@ 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 - backup_source { + restore_backup_source { backup_name = google_alloydb_backup.default.name } @@ -341,7 +341,7 @@ 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 - backup_source { + restore_backup_source { backup_name = google_alloydb_backup.default.name } @@ -354,7 +354,7 @@ 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 - continuous_backup_source { + restore_continuous_backup_source { cluster = google_alloydb_cluster.source.name point_in_time = google_alloydb_backup.default.update_time } @@ -416,7 +416,7 @@ 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 - backup_source { + restore_backup_source { backup_name = google_alloydb_backup.default.name } @@ -434,7 +434,7 @@ 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 - continuous_backup_source { + restore_continuous_backup_source { cluster = google_alloydb_cluster.source.name point_in_time = google_alloydb_backup.default.update_time } @@ -509,7 +509,7 @@ 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 - backup_source { + restore_backup_source { backup_name = google_alloydb_backup.default2.name } @@ -529,7 +529,7 @@ 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 - continuous_backup_source { + restore_continuous_backup_source { cluster = google_alloydb_cluster.restored_from_backup.name point_in_time = google_alloydb_backup.default.update_time } @@ -596,7 +596,7 @@ 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 - backup_source { + restore_backup_source { backup_name = google_alloydb_backup.default.name } } @@ -605,7 +605,7 @@ 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 - continuous_backup_source { + restore_continuous_backup_source { cluster = google_alloydb_cluster.source.name point_in_time = google_alloydb_backup.default.update_time } From 22d6b07dbfcd9af2f12bb95d86fb15e640408a16 Mon Sep 17 00:00:00 2001 From: Shuya Ma <87669292+shuyama1@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:07:52 -0700 Subject: [PATCH 28/28] Apply suggestions from code review --- .../resource_alloydb_cluster_restore_test.go | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) 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 index 6e28ac1bdfa9..d6def69f6832 100644 --- 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 @@ -159,10 +159,10 @@ resource "google_alloydb_cluster" "restored" { restore_backup_source { backup_name = google_alloydb_backup.default.name } - restore_continuous_backup_source { + restore_continuous_backup_source { cluster = google_alloydb_cluster.source.name point_in_time = google_alloydb_backup.default.update_time - } + } lifecycle { prevent_destroy = true @@ -221,9 +221,9 @@ resource "google_alloydb_cluster" "restored" { location = "us-central1" network = data.google_compute_network.default.id - restore_continuous_backup_source { + restore_continuous_backup_source { cluster = google_alloydb_cluster.source.name - } + } lifecycle { prevent_destroy = true @@ -354,10 +354,10 @@ 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 { + restore_continuous_backup_source { cluster = google_alloydb_cluster.source.name point_in_time = google_alloydb_backup.default.update_time - } + } lifecycle { prevent_destroy = true @@ -434,10 +434,10 @@ 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 { + restore_continuous_backup_source { cluster = google_alloydb_cluster.source.name point_in_time = google_alloydb_backup.default.update_time - } + } continuous_backup_config { enabled = true @@ -509,7 +509,7 @@ 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 { + restore_backup_source { backup_name = google_alloydb_backup.default2.name } @@ -529,10 +529,10 @@ 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 { + 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 @@ -596,7 +596,7 @@ 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 { + restore_backup_source { backup_name = google_alloydb_backup.default.name } } @@ -605,10 +605,10 @@ 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 { + restore_continuous_backup_source { cluster = google_alloydb_cluster.source.name point_in_time = google_alloydb_backup.default.update_time - } + } } data "google_project" "project" {}