From adb6e10e9cb1d25c3a65cc018ebea9e16847cd1d Mon Sep 17 00:00:00 2001 From: The Magician Date: Mon, 28 Mar 2022 14:34:22 -0500 Subject: [PATCH] Add dialect to spanner database (#5799) (#11363) Signed-off-by: Modular Magician --- .changelog/5799.txt | 3 + google/resource_spanner_database.go | 32 +++++++ google/resource_spanner_database_test.go | 84 +++++++++++++++++++ website/docs/r/spanner_database.html.markdown | 13 +++ 4 files changed, 132 insertions(+) create mode 100644 .changelog/5799.txt diff --git a/.changelog/5799.txt b/.changelog/5799.txt new file mode 100644 index 00000000000..6bc7114817a --- /dev/null +++ b/.changelog/5799.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +spanner: added support for setting database_dialect on `google_spanner_database` +``` diff --git a/google/resource_spanner_database.go b/google/resource_spanner_database.go index ebc01c4aab9..6b479a9799e 100644 --- a/google/resource_spanner_database.go +++ b/google/resource_spanner_database.go @@ -90,6 +90,18 @@ func resourceSpannerDatabase() *schema.Resource { ValidateFunc: validateRegexp(`^[a-z][a-z0-9_\-]*[a-z0-9]$`), Description: `A unique identifier for the database, which cannot be changed after the instance is created. Values are of the form [a-z][-a-z0-9]*[a-z0-9].`, + }, + "database_dialect": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + ValidateFunc: validateEnum([]string{"GOOGLE_STANDARD_SQL", "POSTGRESQL", ""}), + Description: `The dialect of the Cloud Spanner Database. +If it is not provided, "GOOGLE_STANDARD_SQL" will be used. +Note: Databases that are created with POSTGRESQL dialect do not support +extra DDL statements in the 'CreateDatabase' call. You must therefore re-apply +terraform with ddl on the same database after creation. Possible values: ["GOOGLE_STANDARD_SQL", "POSTGRESQL"]`, }, "ddl": { Type: schema.TypeList, @@ -167,6 +179,12 @@ func resourceSpannerDatabaseCreate(d *schema.ResourceData, meta interface{}) err } else if v, ok := d.GetOkExists("encryption_config"); !isEmptyValue(reflect.ValueOf(encryptionConfigProp)) && (ok || !reflect.DeepEqual(v, encryptionConfigProp)) { obj["encryptionConfig"] = encryptionConfigProp } + databaseDialectProp, err := expandSpannerDatabaseDatabaseDialect(d.Get("database_dialect"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("database_dialect"); !isEmptyValue(reflect.ValueOf(databaseDialectProp)) && (ok || !reflect.DeepEqual(v, databaseDialectProp)) { + obj["databaseDialect"] = databaseDialectProp + } instanceProp, err := expandSpannerDatabaseInstance(d.Get("instance"), d, config) if err != nil { return err @@ -307,6 +325,9 @@ func resourceSpannerDatabaseRead(d *schema.ResourceData, meta interface{}) error if err := d.Set("encryption_config", flattenSpannerDatabaseEncryptionConfig(res["encryptionConfig"], d, config)); err != nil { return fmt.Errorf("Error reading Database: %s", err) } + if err := d.Set("database_dialect", flattenSpannerDatabaseDatabaseDialect(res["databaseDialect"], d, config)); err != nil { + return fmt.Errorf("Error reading Database: %s", err) + } if err := d.Set("instance", flattenSpannerDatabaseInstance(res["instance"], d, config)); err != nil { return fmt.Errorf("Error reading Database: %s", err) } @@ -478,6 +499,10 @@ func flattenSpannerDatabaseEncryptionConfigKmsKeyName(v interface{}, d *schema.R return v } +func flattenSpannerDatabaseDatabaseDialect(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func flattenSpannerDatabaseInstance(v interface{}, d *schema.ResourceData, config *Config) interface{} { if v == nil { return v @@ -516,6 +541,10 @@ func expandSpannerDatabaseEncryptionConfigKmsKeyName(v interface{}, d TerraformR return v, nil } +func expandSpannerDatabaseDatabaseDialect(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandSpannerDatabaseInstance(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { f, err := parseGlobalFieldValue("instances", v.(string), "project", d, config, true) if err != nil { @@ -526,6 +555,9 @@ func expandSpannerDatabaseInstance(v interface{}, d TerraformResourceData, confi func resourceSpannerDatabaseEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { obj["createStatement"] = fmt.Sprintf("CREATE DATABASE `%s`", obj["name"]) + if dialect, ok := obj["databaseDialect"]; ok && dialect == "POSTGRESQL" { + obj["createStatement"] = fmt.Sprintf("CREATE DATABASE %s", obj["name"]) + } delete(obj, "name") delete(obj, "instance") return obj, nil diff --git a/google/resource_spanner_database_test.go b/google/resource_spanner_database_test.go index 7f9cbcc2f83..a00e2bfb050 100644 --- a/google/resource_spanner_database_test.go +++ b/google/resource_spanner_database_test.go @@ -116,6 +116,90 @@ resource "google_spanner_database" "basic" { `, instanceName, instanceName, databaseName) } +func TestAccSpannerDatabase_postgres(t *testing.T) { + t.Parallel() + + rnd := randString(t, 10) + instanceName := fmt.Sprintf("tf-test-%s", rnd) + databaseName := fmt.Sprintf("tfgen_%s", rnd) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckSpannerDatabaseDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccSpannerDatabase_postgres(instanceName, databaseName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("google_spanner_database.basic_spangres", "state"), + ), + }, + { + // Test import with default Terraform ID + ResourceName: "google_spanner_database.basic_spangres", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ddl", "deletion_protection"}, + }, + { + Config: testAccSpannerDatabase_postgresUpdate(instanceName, databaseName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("google_spanner_database.basic_spangres", "state"), + ), + }, + { + // Test import with default Terraform ID + ResourceName: "google_spanner_database.basic_spangres", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ddl", "deletion_protection"}, + }, + }, + }) +} + +func testAccSpannerDatabase_postgres(instanceName, databaseName string) string { + return fmt.Sprintf(` +resource "google_spanner_instance" "basic" { + name = "%s" + config = "regional-us-central1" + display_name = "%s-display" + num_nodes = 1 +} + +resource "google_spanner_database" "basic_spangres" { + instance = google_spanner_instance.basic.name + name = "%s_spangres" + database_dialect = "POSTGRESQL" + deletion_protection = false +} +`, instanceName, instanceName, databaseName) +} + +func testAccSpannerDatabase_postgresUpdate(instanceName, databaseName string) string { + return fmt.Sprintf(` +resource "google_spanner_instance" "basic" { + name = "%s" + config = "regional-us-central1" + display_name = "%s-display" + num_nodes = 1 +} + +resource "google_spanner_database" "basic_spangres" { + instance = google_spanner_instance.basic.name + name = "%s_spangres" + database_dialect = "POSTGRESQL" + ddl = [ + "CREATE TABLE t1 (t1 bigint NOT NULL PRIMARY KEY)", + "CREATE TABLE t2 (t2 bigint NOT NULL PRIMARY KEY)", + "CREATE TABLE t3 (t3 bigint NOT NULL PRIMARY KEY)", + "CREATE TABLE t4 (t4 bigint NOT NULL PRIMARY KEY)", + ] + deletion_protection = false +} +`, instanceName, instanceName, databaseName) +} + // Unit Tests for type spannerDatabaseId func TestDatabaseNameForApi(t *testing.T) { id := spannerDatabaseId{ diff --git a/website/docs/r/spanner_database.html.markdown b/website/docs/r/spanner_database.html.markdown index 69f105cbc67..07b8afcbdfb 100644 --- a/website/docs/r/spanner_database.html.markdown +++ b/website/docs/r/spanner_database.html.markdown @@ -38,6 +38,10 @@ On older versions, it is strongly recommended to set `lifecycle { prevent_destro on databases in order to prevent accidental data loss. See [Terraform docs](https://www.terraform.io/docs/configuration/resources.html#prevent_destroy) for more information on lifecycle parameters. +Note: Databases that are created with POSTGRESQL dialect do not support +extra DDL statements in the `CreateDatabase` call. You must therefore re-apply +terraform with ddl on the same database after creation. +