From b43da493663b3a71e9b9349b86988ec3242c19a1 Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Wed, 31 Jul 2024 13:33:21 -0700 Subject: [PATCH 01/17] Update Database.yaml - Add kmsKeyNames to encryptionConfig - Make kmsKeyName and kmsKeyNames not required --- mmv1/products/spanner/Database.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mmv1/products/spanner/Database.yaml b/mmv1/products/spanner/Database.yaml index 39014777c206..772949e88073 100644 --- a/mmv1/products/spanner/Database.yaml +++ b/mmv1/products/spanner/Database.yaml @@ -153,10 +153,16 @@ properties: - !ruby/object:Api::Type::String name: 'kmsKeyName' immutable: true - required: true description: | Fully qualified name of the KMS key to use to encrypt this database. This key must exist in the same location as the Spanner Database. + - !ruby/object:Api::Type::Array + name: 'kmsKeyNames' + immutable: true + description: | + Fully qualified names of the KMS keys to use to encrypt this database. The keys + referenced by kms_key_names must fully cover all regions of the database + instance configuration. - !ruby/object:Api::Type::Enum name: 'databaseDialect' immutable: true From a7e959f30e0785b193416d72d7adecb8981b2608 Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Wed, 31 Jul 2024 13:42:10 -0700 Subject: [PATCH 02/17] Change kms_key_names to kmsKeyNames in description --- mmv1/products/spanner/Database.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmv1/products/spanner/Database.yaml b/mmv1/products/spanner/Database.yaml index 772949e88073..cfcc3e95fbdf 100644 --- a/mmv1/products/spanner/Database.yaml +++ b/mmv1/products/spanner/Database.yaml @@ -161,7 +161,7 @@ properties: immutable: true description: | Fully qualified names of the KMS keys to use to encrypt this database. The keys - referenced by kms_key_names must fully cover all regions of the database + referenced by kmsKeyNames must fully cover all regions of the database instance configuration. - !ruby/object:Api::Type::Enum name: 'databaseDialect' From 0f58e191e5eaf665ef10f2d96ca29f5c4cd4a3ce Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Wed, 31 Jul 2024 17:04:13 -0700 Subject: [PATCH 03/17] Update resource_spanner_database_test.go.erb Add MR CMEK test --- .../resource_spanner_database_test.go.erb | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.erb b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.erb index a5031b5925b1..870a03636d07 100644 --- a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.erb +++ b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.erb @@ -604,6 +604,141 @@ resource "google_project_service_identity" "ck_sa" { service = "spanner.googleapis.com" } +`, context) +} + +func TestAccSpannerDatabase_mrcmek(t *testing.T) { + acctest.SkipIfVcr(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.ProtoV5ProviderBetaFactories(t), + CheckDestroy: testAccCheckSpannerDatabaseDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccSpannerDatabase_mrcmek(context), + }, + { + ResourceName: "google_spanner_database.database", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ddl", "deletion_protection"}, + }, + }, + }) +} + +func testAccSpannerDatabase_mrcmek(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_spanner_instance" "main" { + provider = google-beta + config = "nam3" + display_name = "main-instance1" + num_nodes = 1 +} + +resource "google_spanner_database" "database" { + provider = google-beta + instance = google_spanner_instance.main.name + name = "tf-test-mrcmek-db%{random_suffix}" + ddl = [ + "CREATE TABLE t1 (t1 INT64 NOT NULL,) PRIMARY KEY(t1)", + "CREATE TABLE t2 (t2 INT64 NOT NULL,) PRIMARY KEY(t2)", + ] + + encryption_config { + kms_key_names = [ + "google_kms_crypto_key.example-key-us-central1.id", + "google_kms_crypto_key.example-key-us-east1.id", + "google_kms_crypto_key.example-key-us-east4.id", + ] + } + + deletion_protection = false + + depends_on = [google_kms_crypto_key_iam_member.crypto-key-binding-us-central1, + google_kms_crypto_key_iam_member.crypto-key-binding-us-east1, + google_kms_crypto_key_iam_member.crypto-key-binding-us-east4,] +} + +resource "google_kms_key_ring" "keyring-us-central1" { + provider = google-beta + name = "tf-test-ring%{random_suffix}" + location = "us-central1" +} + +resource "google_kms_crypto_key" "example-key-us-central1" { + provider = google-beta + name = "tf-test-key%{random_suffix}" + key_ring = google_kms_key_ring.keyring-us-central1.id + rotation_period = "100000s" +} + +resource "google_kms_crypto_key_iam_member" "crypto-key-binding-us-central1" { + provider = google-beta + crypto_key_id = google_kms_crypto_key.example-key-us-central1.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + member = google_project_service_identity.ck_sa.member +} + +resource "google_kms_key_ring" "keyring-us-east1" { + provider = google-beta + name = "tf-test-ring%{random_suffix}" + location = "us-east1" +} + +resource "google_kms_crypto_key" "example-key-us-east1" { + provider = google-beta + name = "tf-test-key%{random_suffix}" + key_ring = google_kms_key_ring.keyring-us-east1.id + rotation_period = "100000s" +} + +resource "google_kms_crypto_key_iam_member" "crypto-key-binding-us-east1" { + provider = google-beta + crypto_key_id = google_kms_crypto_key.example-key-us-east1.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + member = google_project_service_identity.ck_sa.member +} + +resource "google_kms_key_ring" "keyring-us-east4" { + provider = google-beta + name = "tf-test-ring%{random_suffix}" + location = "us-east4" +} + +resource "google_kms_crypto_key" "example-key-us-east4" { + provider = google-beta + name = "tf-test-key%{random_suffix}" + key_ring = google_kms_key_ring.keyring-us-east4.id + rotation_period = "100000s" +} + +resource "google_kms_crypto_key_iam_member" "crypto-key-binding-us-east4" { + provider = google-beta + crypto_key_id = google_kms_crypto_key.example-key-us-east4.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + member = google_project_service_identity.ck_sa.member +} + +data "google_project" "project" { + provider = google-beta +} + +resource "google_project_service_identity" "ck_sa" { + provider = google-beta + project = data.google_project.project.project_id + service = "spanner.googleapis.com" +} + `, context) } <% end -%> From 50929aa9c2cc1a83b75a8872fdca9e8b00d0803e Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:52:45 -0700 Subject: [PATCH 04/17] Update Database.yaml Add https://googlecloudplatform.github.io/magic-modules/develop/field-reference/#exactly_one_of for KmsKeyName and KmsKeyNames? --- mmv1/products/spanner/Database.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mmv1/products/spanner/Database.yaml b/mmv1/products/spanner/Database.yaml index cfcc3e95fbdf..ed0aab0940fa 100644 --- a/mmv1/products/spanner/Database.yaml +++ b/mmv1/products/spanner/Database.yaml @@ -156,6 +156,9 @@ properties: description: | Fully qualified name of the KMS key to use to encrypt this database. This key must exist in the same location as the Spanner Database. + exactly_one_of: + - kmsKeyName + - kmsKeyNames - !ruby/object:Api::Type::Array name: 'kmsKeyNames' immutable: true @@ -163,6 +166,9 @@ properties: Fully qualified names of the KMS keys to use to encrypt this database. The keys referenced by kmsKeyNames must fully cover all regions of the database instance configuration. + exactly_one_of: + - kmsKeyName + - kmsKeyNames - !ruby/object:Api::Type::Enum name: 'databaseDialect' immutable: true From 0a04792b6012bf939bf749aebb774fb32da2d508 Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Wed, 7 Aug 2024 13:32:51 -0700 Subject: [PATCH 05/17] Add item_type to kmsKeyNames array. --- mmv1/products/spanner/Database.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/mmv1/products/spanner/Database.yaml b/mmv1/products/spanner/Database.yaml index ed0aab0940fa..8dcc86df8543 100644 --- a/mmv1/products/spanner/Database.yaml +++ b/mmv1/products/spanner/Database.yaml @@ -166,6 +166,7 @@ properties: Fully qualified names of the KMS keys to use to encrypt this database. The keys referenced by kmsKeyNames must fully cover all regions of the database instance configuration. + item_type: Api::Type::String exactly_one_of: - kmsKeyName - kmsKeyNames From 8687ccc6ea5f6829c2ab0d2f3a52c39095079789 Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:13:35 -0700 Subject: [PATCH 06/17] Remove quotations from key names in resource_spanner_database_test.go.erb --- .../services/spanner/resource_spanner_database_test.go.erb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.erb b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.erb index 870a03636d07..c6fdf6678d6e 100644 --- a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.erb +++ b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.erb @@ -653,9 +653,9 @@ resource "google_spanner_database" "database" { encryption_config { kms_key_names = [ - "google_kms_crypto_key.example-key-us-central1.id", - "google_kms_crypto_key.example-key-us-east1.id", - "google_kms_crypto_key.example-key-us-east4.id", + google_kms_crypto_key.example-key-us-central1.id, + google_kms_crypto_key.example-key-us-east1.id, + google_kms_crypto_key.example-key-us-east4.id, ] } From 3b28000732a845ea73d61ce87179308cbda163b4 Mon Sep 17 00:00:00 2001 From: Scott Suarez Date: Tue, 8 Oct 2024 12:18:04 -0700 Subject: [PATCH 07/17] migrate pull request and fix test case/documentation --- docs/content/develop/permadiff.md | 64 ++++++--- mmv1/products/spanner/Database.yaml | 16 ++- .../spanner_database_kms_key_names.go.tmpl | 25 ++++ .../resource_spanner_database_test.go.tmpl | 136 ++++++++++++++++++ .../terraform/tpgresource/utils.go | 19 +++ 5 files changed, 241 insertions(+), 19 deletions(-) create mode 100644 mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl diff --git a/docs/content/develop/permadiff.md b/docs/content/develop/permadiff.md index ca1b94c48b04..560b39038589 100644 --- a/docs/content/develop/permadiff.md +++ b/docs/content/develop/permadiff.md @@ -234,15 +234,29 @@ Add a [custom flattener]({{< ref "/develop/custom-code#custom_flatten" >}}) for ```go func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - configValue := d.Get("path.0.to.0.parent_field.0.nested_field").([]string) - - sorted, err := tpgresource.SortStringsByConfigOrder(configValue, v.([]string)) - if err != nil { - log.Printf("[ERROR] Could not sort API response value: %s", err) - return v - } - - return sorted.(interface{}) + rawConfigValue := d.Get("path.0.to.0.parent_field.0.nested_field") + + // Convert config value to []string + configValue, err := tpgresource.InterfaceSliceToStringSlice(rawConfigValue) + if err != nil { + log.Printf("[ERROR] Failed to convert config value: %s", err) + return v + } + + // Convert v to []string + apiStringValue, err := tpgresource.InterfaceSliceToStringSlice(v) + if err != nil { + log.Printf("[ERROR] Failed to convert API value: %s", err) + return v + } + + sortedStrings, err := tpgresource.SortStringsByConfigOrder(configValue, apiStringValue) + if err != nil { + log.Printf("[ERROR] Could not sort API response value: %s", err) + return v + } + + return sortedStrings } ``` {{< /tab >}} @@ -251,15 +265,29 @@ Define resource-specific functions in your service package, for example at the t ```go func flattenResourceNameFieldName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - configValue := d.Get("path.0.to.0.parent_field.0.nested_field").([]string) - - sorted, err := tpgresource.SortStringsByConfigOrder(configValue, v.([]string)) - if err != nil { - log.Printf("[ERROR] Could not sort API response value: %s", err) - return v - } - - return sorted.(interface{}) + rawConfigValue := d.Get("path.0.to.0.parent_field.0.nested_field") + + // Convert config value to []string + configValue, err := tpgresource.InterfaceSliceToStringSlice(rawConfigValue) + if err != nil { + log.Printf("[ERROR] Failed to convert config value: %s", err) + return v + } + + // Convert v to []string + apiStringValue, err := tpgresource.InterfaceSliceToStringSlice(v) + if err != nil { + log.Printf("[ERROR] Failed to convert API value: %s", err) + return v + } + + sortedStrings, err := tpgresource.SortStringsByConfigOrder(configValue, apiStringValue) + if err != nil { + log.Printf("[ERROR] Could not sort API response value: %s", err) + return v + } + + return sortedStrings } ``` {{< /tab >}} diff --git a/mmv1/products/spanner/Database.yaml b/mmv1/products/spanner/Database.yaml index 5e0eca341608..b279f97319d4 100644 --- a/mmv1/products/spanner/Database.yaml +++ b/mmv1/products/spanner/Database.yaml @@ -150,8 +150,22 @@ properties: description: | Fully qualified name of the KMS key to use to encrypt this database. This key must exist in the same location as the Spanner Database. - required: true immutable: true + exactly_one_of: + - encryption_config.0.kms_key_name + - encryption_config.0.kms_key_names + - name: 'kmsKeyNames' + type: Array + description: | + Fully qualified name of the KMS key to use to encrypt this database. This key must exist + in the same location as the Spanner Database. + immutable: true + custom_flatten: templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl + item_type: + type: String + exactly_one_of: + - encryption_config.0.kms_key_name + - encryption_config.0.kms_key_names - name: 'databaseDialect' type: Enum description: | diff --git a/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl b/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl new file mode 100644 index 000000000000..03ae2ada7313 --- /dev/null +++ b/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl @@ -0,0 +1,25 @@ +func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + rawConfigValue := d.Get("encryption_config.0.kms_key_names") + + // Convert config value to []string + configValue, err := tpgresource.InterfaceSliceToStringSlice(rawConfigValue) + if err != nil { + log.Printf("[ERROR] Failed to convert config value: %s", err) + return v + } + + // Convert v to []string + apiStringValue, err := tpgresource.InterfaceSliceToStringSlice(v) + if err != nil { + log.Printf("[ERROR] Failed to convert API value: %s", err) + return v + } + + sortedStrings, err := tpgresource.SortStringsByConfigOrder(configValue, apiStringValue) + if err != nil { + log.Printf("[ERROR] Could not sort API response value: %s", err) + return v + } + + return sortedStrings +} diff --git a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl index ebbd3e9db26a..d330b2a81a8d 100644 --- a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl +++ b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl @@ -605,4 +605,140 @@ resource "google_project_service_identity" "ck_sa" { `, context) } + +func TestAccSpannerDatabase_mrcmek(t *testing.T) { + acctest.SkipIfVcr(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.ProtoV5ProviderBetaFactories(t), + CheckDestroy: testAccCheckSpannerDatabaseDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccSpannerDatabase_mrcmek(context), + }, + { + ResourceName: "google_spanner_database.database", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ddl", "deletion_protection"}, + }, + }, + }) +} + +func testAccSpannerDatabase_mrcmek(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_spanner_instance" "main" { + provider = google-beta + config = "nam3" + display_name = "main-instance1" + num_nodes = 1 +} + +resource "google_spanner_database" "database" { + provider = google-beta + instance = google_spanner_instance.main.name + name = "tf-test-mrcmek-db%{random_suffix}" + ddl = [ + "CREATE TABLE t1 (t1 INT64 NOT NULL,) PRIMARY KEY(t1)", + "CREATE TABLE t2 (t2 INT64 NOT NULL,) PRIMARY KEY(t2)", + ] + + encryption_config { + kms_key_names = [ + google_kms_crypto_key.example-key-us-central1.id, + google_kms_crypto_key.example-key-us-east1.id, + google_kms_crypto_key.example-key-us-east4.id, + ] + } + + deletion_protection = false + + depends_on = [google_kms_crypto_key_iam_member.crypto-key-binding-us-central1, + google_kms_crypto_key_iam_member.crypto-key-binding-us-east1, + google_kms_crypto_key_iam_member.crypto-key-binding-us-east4,] +} + +resource "google_kms_key_ring" "keyring-us-central1" { + provider = google-beta + name = "tf-test-ring%{random_suffix}" + location = "us-central1" +} + +resource "google_kms_crypto_key" "example-key-us-central1" { + provider = google-beta + name = "tf-test-key%{random_suffix}" + key_ring = google_kms_key_ring.keyring-us-central1.id + rotation_period = "100000s" +} + +resource "google_kms_crypto_key_iam_member" "crypto-key-binding-us-central1" { + provider = google-beta + crypto_key_id = google_kms_crypto_key.example-key-us-central1.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + member = google_project_service_identity.ck_sa.member +} + +resource "google_kms_key_ring" "keyring-us-east1" { + provider = google-beta + name = "tf-test-ring%{random_suffix}" + location = "us-east1" +} + +resource "google_kms_crypto_key" "example-key-us-east1" { + provider = google-beta + name = "tf-test-key%{random_suffix}" + key_ring = google_kms_key_ring.keyring-us-east1.id + rotation_period = "100000s" +} + +resource "google_kms_crypto_key_iam_member" "crypto-key-binding-us-east1" { + provider = google-beta + crypto_key_id = google_kms_crypto_key.example-key-us-east1.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + member = google_project_service_identity.ck_sa.member +} + +resource "google_kms_key_ring" "keyring-us-east4" { + provider = google-beta + name = "tf-test-ring%{random_suffix}" + location = "us-east4" +} + +resource "google_kms_crypto_key" "example-key-us-east4" { + provider = google-beta + name = "tf-test-key%{random_suffix}" + key_ring = google_kms_key_ring.keyring-us-east4.id + rotation_period = "100000s" +} + +resource "google_kms_crypto_key_iam_member" "crypto-key-binding-us-east4" { + provider = google-beta + crypto_key_id = google_kms_crypto_key.example-key-us-east4.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + member = google_project_service_identity.ck_sa.member +} + +data "google_project" "project" { + provider = google-beta +} + +resource "google_project_service_identity" "ck_sa" { + provider = google-beta + project = data.google_project.project.project_id + service = "spanner.googleapis.com" +} + +`, context) +} + {{- end }} diff --git a/mmv1/third_party/terraform/tpgresource/utils.go b/mmv1/third_party/terraform/tpgresource/utils.go index 2f83608ad77f..30be51214971 100644 --- a/mmv1/third_party/terraform/tpgresource/utils.go +++ b/mmv1/third_party/terraform/tpgresource/utils.go @@ -238,6 +238,25 @@ func ExpandStringMap(d TerraformResourceData, key string) map[string]string { return ConvertStringMap(v.(map[string]interface{})) } +// InterfaceSliceToStringSlice converts a []interface{} containing strings to []string +func InterfaceSliceToStringSlice(v interface{}) ([]string, error) { + interfaceSlice, ok := v.([]interface{}) + if !ok { + return nil, fmt.Errorf("expected []interface{}, got %T", v) + } + + stringSlice := make([]string, len(interfaceSlice)) + for i, item := range interfaceSlice { + strItem, ok := item.(string) + if !ok { + return nil, fmt.Errorf("expected string, got %T at index %d", item, i) + } + stringSlice[i] = strItem + } + + return stringSlice, nil +} + // SortStringsByConfigOrder takes a slice of map[string]interface{} from a TF config // and API data, and returns a new slice containing the API data, reorderd to match // the TF config as closely as possible (with new items at the end of the list.) From 95d98d77b1e6c0eb7273a639fec0e3ec8966419b Mon Sep 17 00:00:00 2001 From: Scott Suarez Date: Tue, 8 Oct 2024 13:13:53 -0700 Subject: [PATCH 08/17] Don't read kms_key_names if kms_key_name is set --- .../custom_flatten/spanner_database_kms_key_names.go.tmpl | 6 ++++++ .../services/spanner/resource_spanner_database_test.go.tmpl | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl b/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl index 03ae2ada7313..b1978202e3b4 100644 --- a/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl +++ b/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl @@ -1,4 +1,10 @@ func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Api returns `kms_key_names` if `kms_key_names` is set but we can ignore + _, kmsNameSet := d.GetOk("encryption_config.0.kms_key_name") + if kmsNameSet { + return nil + } + rawConfigValue := d.Get("encryption_config.0.kms_key_names") // Convert config value to []string diff --git a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl index d330b2a81a8d..61ddae0c06e2 100644 --- a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl +++ b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl @@ -539,7 +539,7 @@ func TestAccSpannerDatabase_cmek(t *testing.T) { ResourceName: "google_spanner_database.database", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"ddl", "deletion_protection"}, + ImportStateVerifyIgnore: []string{"ddl", "deletion_protection", "encryption_config.0.kms_key_names"}, }, }, }) From 37586d6f551d9b2686e546e697021a9fa2f65048 Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:54:01 -0700 Subject: [PATCH 09/17] Update permadiff.md Use spaces rather than tabs --- docs/content/develop/permadiff.md | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/content/develop/permadiff.md b/docs/content/develop/permadiff.md index 560b39038589..c68778f3713b 100644 --- a/docs/content/develop/permadiff.md +++ b/docs/content/develop/permadiff.md @@ -236,27 +236,27 @@ Add a [custom flattener]({{< ref "/develop/custom-code#custom_flatten" >}}) for func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { rawConfigValue := d.Get("path.0.to.0.parent_field.0.nested_field") - // Convert config value to []string - configValue, err := tpgresource.InterfaceSliceToStringSlice(rawConfigValue) - if err != nil { - log.Printf("[ERROR] Failed to convert config value: %s", err) - return v - } + // Convert config value to []string + configValue, err := tpgresource.InterfaceSliceToStringSlice(rawConfigValue) + if err != nil { + log.Printf("[ERROR] Failed to convert config value: %s", err) + return v + } - // Convert v to []string - apiStringValue, err := tpgresource.InterfaceSliceToStringSlice(v) - if err != nil { - log.Printf("[ERROR] Failed to convert API value: %s", err) - return v - } + // Convert v to []string + apiStringValue, err := tpgresource.InterfaceSliceToStringSlice(v) + if err != nil { + log.Printf("[ERROR] Failed to convert API value: %s", err) + return v + } - sortedStrings, err := tpgresource.SortStringsByConfigOrder(configValue, apiStringValue) - if err != nil { - log.Printf("[ERROR] Could not sort API response value: %s", err) - return v - } + sortedStrings, err := tpgresource.SortStringsByConfigOrder(configValue, apiStringValue) + if err != nil { + log.Printf("[ERROR] Could not sort API response value: %s", err) + return v + } - return sortedStrings + return sortedStrings } ``` {{< /tab >}} From 57956103050aafa3b416f9cc7d4b491d43b894f7 Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:11:11 -0700 Subject: [PATCH 10/17] Update permadiff.md Use spaces instead of tabs --- docs/content/develop/permadiff.md | 42 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/content/develop/permadiff.md b/docs/content/develop/permadiff.md index c68778f3713b..2b4bb3b1d8ad 100644 --- a/docs/content/develop/permadiff.md +++ b/docs/content/develop/permadiff.md @@ -267,27 +267,27 @@ Define resource-specific functions in your service package, for example at the t func flattenResourceNameFieldName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { rawConfigValue := d.Get("path.0.to.0.parent_field.0.nested_field") - // Convert config value to []string - configValue, err := tpgresource.InterfaceSliceToStringSlice(rawConfigValue) - if err != nil { - log.Printf("[ERROR] Failed to convert config value: %s", err) - return v - } - - // Convert v to []string - apiStringValue, err := tpgresource.InterfaceSliceToStringSlice(v) - if err != nil { - log.Printf("[ERROR] Failed to convert API value: %s", err) - return v - } - - sortedStrings, err := tpgresource.SortStringsByConfigOrder(configValue, apiStringValue) - if err != nil { - log.Printf("[ERROR] Could not sort API response value: %s", err) - return v - } - - return sortedStrings + // Convert config value to []string + configValue, err := tpgresource.InterfaceSliceToStringSlice(rawConfigValue) + if err != nil { + log.Printf("[ERROR] Failed to convert config value: %s", err) + return v + } + + // Convert v to []string + apiStringValue, err := tpgresource.InterfaceSliceToStringSlice(v) + if err != nil { + log.Printf("[ERROR] Failed to convert API value: %s", err) + return v + } + + sortedStrings, err := tpgresource.SortStringsByConfigOrder(configValue, apiStringValue) + if err != nil { + log.Printf("[ERROR] Could not sort API response value: %s", err) + return v + } + + return sortedStrings } ``` {{< /tab >}} From 084a6a0c7db7da58fa560f92fbab67b84d2a935c Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:13:16 -0700 Subject: [PATCH 11/17] Update Database.yaml Change description of kmsKeyNames to use plurals --- mmv1/products/spanner/Database.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmv1/products/spanner/Database.yaml b/mmv1/products/spanner/Database.yaml index b279f97319d4..ad4a0c45ecbd 100644 --- a/mmv1/products/spanner/Database.yaml +++ b/mmv1/products/spanner/Database.yaml @@ -157,8 +157,8 @@ properties: - name: 'kmsKeyNames' type: Array description: | - Fully qualified name of the KMS key to use to encrypt this database. This key must exist - in the same location as the Spanner Database. + Fully qualified name of the KMS keys to use to encrypt this database. The keys must exist + in the same locations as the Spanner Database. immutable: true custom_flatten: templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl item_type: From 0c0c9e53afe996d4b199b533868860036b6a6e67 Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:20:52 -0700 Subject: [PATCH 12/17] Update mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl Clarify comment Co-authored-by: Stephen Lewis (Burrows) --- .../custom_flatten/spanner_database_kms_key_names.go.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl b/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl index b1978202e3b4..b3ed02f148e5 100644 --- a/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl +++ b/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl @@ -1,5 +1,5 @@ func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - // Api returns `kms_key_names` if `kms_key_names` is set but we can ignore + // Ignore `kms_key_names` if `kms_key_name` is set, because that field takes precedence. _, kmsNameSet := d.GetOk("encryption_config.0.kms_key_name") if kmsNameSet { return nil From b416e1d9de7a167f85e423fbf4f5a676f70bb88a Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:24:37 -0700 Subject: [PATCH 13/17] Update spanner_database_kms_key_names.go.tmpl Use spaces instead of tabs --- .../spanner_database_kms_key_names.go.tmpl | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl b/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl index b3ed02f148e5..526fc566165c 100644 --- a/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl +++ b/mmv1/templates/terraform/custom_flatten/spanner_database_kms_key_names.go.tmpl @@ -1,31 +1,31 @@ func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - // Ignore `kms_key_names` if `kms_key_name` is set, because that field takes precedence. - _, kmsNameSet := d.GetOk("encryption_config.0.kms_key_name") + // Ignore `kms_key_names` if `kms_key_name` is set, because that field takes precedence. + _, kmsNameSet := d.GetOk("encryption_config.0.kms_key_name") if kmsNameSet { return nil } - rawConfigValue := d.Get("encryption_config.0.kms_key_names") + rawConfigValue := d.Get("encryption_config.0.kms_key_names") - // Convert config value to []string - configValue, err := tpgresource.InterfaceSliceToStringSlice(rawConfigValue) - if err != nil { - log.Printf("[ERROR] Failed to convert config value: %s", err) - return v - } + // Convert config value to []string + configValue, err := tpgresource.InterfaceSliceToStringSlice(rawConfigValue) + if err != nil { + log.Printf("[ERROR] Failed to convert config value: %s", err) + return v + } - // Convert v to []string - apiStringValue, err := tpgresource.InterfaceSliceToStringSlice(v) - if err != nil { - log.Printf("[ERROR] Failed to convert API value: %s", err) - return v - } + // Convert v to []string + apiStringValue, err := tpgresource.InterfaceSliceToStringSlice(v) + if err != nil { + log.Printf("[ERROR] Failed to convert API value: %s", err) + return v + } - sortedStrings, err := tpgresource.SortStringsByConfigOrder(configValue, apiStringValue) - if err != nil { - log.Printf("[ERROR] Could not sort API response value: %s", err) - return v - } + sortedStrings, err := tpgresource.SortStringsByConfigOrder(configValue, apiStringValue) + if err != nil { + log.Printf("[ERROR] Could not sort API response value: %s", err) + return v + } - return sortedStrings + return sortedStrings } From e2144b4143e4bae4fd64d2191eb4b0fa020c214d Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Thu, 10 Oct 2024 18:11:30 -0700 Subject: [PATCH 14/17] Update resource_spanner_database_test.go.tmpl Use BootstrapKMSKey instead of crypto keys because crypto keys can't be deleted --- .../resource_spanner_database_test.go.tmpl | 90 +++++++------------ 1 file changed, 30 insertions(+), 60 deletions(-) diff --git a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl index 61ddae0c06e2..22fbc58ead48 100644 --- a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl +++ b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl @@ -610,8 +610,17 @@ func TestAccSpannerDatabase_mrcmek(t *testing.T) { acctest.SkipIfVcr(t) t.Parallel() + kms1 := acctest.BootstrapKMSKeyWithPurposeInLocationAndName(t, "ENCRYPT_DECRYPT", "us-central1", "tf-mr-cmek-test-key-us-central1") + kms2 := acctest.BootstrapKMSKeyWithPurposeInLocationAndName(t, "ENCRYPT_DECRYPT", "us-east1", "tf-mr-cmek-test-key-us-east1") + kms3 := acctest.BootstrapKMSKeyWithPurposeInLocationAndName(t, "ENCRYPT_DECRYPT", "us-east4", "tf-mr-cmek-test-key-us-east4") context := map[string]interface{}{ "random_suffix": acctest.RandString(t, 10), + "key_ring1": kms1.KeyRing.Name, + "key_name1": kms1.CryptoKey.Name, + "key_ring2": kms2.KeyRing.Name, + "key_name2": kms2.CryptoKey.Name, + "key_ring3": kms3.KeyRing.Name, + "key_name3": kms3.CryptoKey.Name, } acctest.VcrTest(t, resource.TestCase{ @@ -652,80 +661,41 @@ resource "google_spanner_database" "database" { encryption_config { kms_key_names = [ - google_kms_crypto_key.example-key-us-central1.id, - google_kms_crypto_key.example-key-us-east1.id, - google_kms_crypto_key.example-key-us-east4.id, + "%{key_name1}", + "%{key_name2}", + "%{key_name3}", ] } deletion_protection = false - depends_on = [google_kms_crypto_key_iam_member.crypto-key-binding-us-central1, - google_kms_crypto_key_iam_member.crypto-key-binding-us-east1, - google_kms_crypto_key_iam_member.crypto-key-binding-us-east4,] + depends_on = [google_kms_crypto_key_iam_binding.crypto_key1, + google_kms_crypto_key_iam_binding.crypto_key2, + google_kms_crypto_key_iam_binding.crypto_key3,] } -resource "google_kms_key_ring" "keyring-us-central1" { - provider = google-beta - name = "tf-test-ring%{random_suffix}" - location = "us-central1" -} - -resource "google_kms_crypto_key" "example-key-us-central1" { - provider = google-beta - name = "tf-test-key%{random_suffix}" - key_ring = google_kms_key_ring.keyring-us-central1.id - rotation_period = "100000s" -} - -resource "google_kms_crypto_key_iam_member" "crypto-key-binding-us-central1" { - provider = google-beta - crypto_key_id = google_kms_crypto_key.example-key-us-central1.id +resource "google_kms_crypto_key_iam_binding" "crypto_key1" { + crypto_key_id = "%{key_name1}" role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - - member = google_project_service_identity.ck_sa.member -} - -resource "google_kms_key_ring" "keyring-us-east1" { - provider = google-beta - name = "tf-test-ring%{random_suffix}" - location = "us-east1" -} - -resource "google_kms_crypto_key" "example-key-us-east1" { - provider = google-beta - name = "tf-test-key%{random_suffix}" - key_ring = google_kms_key_ring.keyring-us-east1.id - rotation_period = "100000s" + members = [ + google_project_service_identity.ck_sa.member, + ] } -resource "google_kms_crypto_key_iam_member" "crypto-key-binding-us-east1" { - provider = google-beta - crypto_key_id = google_kms_crypto_key.example-key-us-east1.id +resource "google_kms_crypto_key_iam_binding" "crypto_key2" { + crypto_key_id = "%{key_name2}" role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - - member = google_project_service_identity.ck_sa.member -} - -resource "google_kms_key_ring" "keyring-us-east4" { - provider = google-beta - name = "tf-test-ring%{random_suffix}" - location = "us-east4" -} - -resource "google_kms_crypto_key" "example-key-us-east4" { - provider = google-beta - name = "tf-test-key%{random_suffix}" - key_ring = google_kms_key_ring.keyring-us-east4.id - rotation_period = "100000s" + members = [ + google_project_service_identity.ck_sa.member, + ] } -resource "google_kms_crypto_key_iam_member" "crypto-key-binding-us-east4" { - provider = google-beta - crypto_key_id = google_kms_crypto_key.example-key-us-east4.id +resource "google_kms_crypto_key_iam_binding" "crypto_key3" { + crypto_key_id = "%{key_name3}" role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - - member = google_project_service_identity.ck_sa.member + members = [ + google_project_service_identity.ck_sa.member, + ] } data "google_project" "project" { From 28874169b5ef6f101438d3b5a9fc82a9c41b3b78 Mon Sep 17 00:00:00 2001 From: panerorenn9541 <36008213+panerorenn9541@users.noreply.github.com> Date: Sun, 13 Oct 2024 14:34:04 -0700 Subject: [PATCH 15/17] Update resource_spanner_database_test.go.tmpl Remove IAM roles. --- .../resource_spanner_database_test.go.tmpl | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl index 22fbc58ead48..8ba30182f05e 100644 --- a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl +++ b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl @@ -674,30 +674,6 @@ resource "google_spanner_database" "database" { google_kms_crypto_key_iam_binding.crypto_key3,] } -resource "google_kms_crypto_key_iam_binding" "crypto_key1" { - crypto_key_id = "%{key_name1}" - role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - members = [ - google_project_service_identity.ck_sa.member, - ] -} - -resource "google_kms_crypto_key_iam_binding" "crypto_key2" { - crypto_key_id = "%{key_name2}" - role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - members = [ - google_project_service_identity.ck_sa.member, - ] -} - -resource "google_kms_crypto_key_iam_binding" "crypto_key3" { - crypto_key_id = "%{key_name3}" - role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - members = [ - google_project_service_identity.ck_sa.member, - ] -} - data "google_project" "project" { provider = google-beta } From 0482ae91442080181d9ef12d65a7a1003a9a98e3 Mon Sep 17 00:00:00 2001 From: Scott Suarez Date: Mon, 14 Oct 2024 10:23:44 -0700 Subject: [PATCH 16/17] Update mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl --- .../services/spanner/resource_spanner_database_test.go.tmpl | 3 --- 1 file changed, 3 deletions(-) diff --git a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl index 8ba30182f05e..f56367e57b9b 100644 --- a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl +++ b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl @@ -669,9 +669,6 @@ resource "google_spanner_database" "database" { deletion_protection = false - depends_on = [google_kms_crypto_key_iam_binding.crypto_key1, - google_kms_crypto_key_iam_binding.crypto_key2, - google_kms_crypto_key_iam_binding.crypto_key3,] } data "google_project" "project" { From 6aed796943d2f48de08ea75a12c6175a5b35dedf Mon Sep 17 00:00:00 2001 From: Scott Suarez Date: Mon, 14 Oct 2024 10:24:50 -0700 Subject: [PATCH 17/17] Update mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl --- .../spanner/resource_spanner_database_test.go.tmpl | 9 --------- 1 file changed, 9 deletions(-) diff --git a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl index f56367e57b9b..eba30f8dd202 100644 --- a/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl +++ b/mmv1/third_party/terraform/services/spanner/resource_spanner_database_test.go.tmpl @@ -671,15 +671,6 @@ resource "google_spanner_database" "database" { } -data "google_project" "project" { - provider = google-beta -} - -resource "google_project_service_identity" "ck_sa" { - provider = google-beta - project = data.google_project.project.project_id - service = "spanner.googleapis.com" -} `, context) }