Skip to content

Commit

Permalink
migrate pull request and fix test case/documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
ScottSuarez committed Oct 8, 2024
1 parent f58f858 commit 3b28000
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 19 deletions.
64 changes: 46 additions & 18 deletions docs/content/develop/permadiff.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 >}}
Expand All @@ -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 >}}
Expand Down
16 changes: 15 additions & 1 deletion mmv1/products/spanner/Database.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
19 changes: 19 additions & 0 deletions mmv1/third_party/terraform/tpgresource/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.)
Expand Down

0 comments on commit 3b28000

Please sign in to comment.