From 2378b071aece5573f4373661020eefd938e47b6c Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Wed, 1 Mar 2023 17:08:42 +0000 Subject: [PATCH] enhancement: Promote Firestore database resource to GA (#7360) Signed-off-by: Modular Magician --- .changelog/7360.txt | 3 + google/provider.go | 5 +- google/resource_firestore_database.go | 464 ++++++++++++++++++ ...ource_firestore_database_generated_test.go | 149 ++++++ ...resource_firestore_database_update_test.go | 77 +++ .../docs/r/firestore_database.html.markdown | 14 - 6 files changed, 696 insertions(+), 16 deletions(-) create mode 100644 .changelog/7360.txt create mode 100644 google/resource_firestore_database.go create mode 100644 google/resource_firestore_database_generated_test.go diff --git a/.changelog/7360.txt b/.changelog/7360.txt new file mode 100644 index 00000000000..032a0b49178 --- /dev/null +++ b/.changelog/7360.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +firestore: Promote `google_firestore_database` to GA +``` diff --git a/google/provider.go b/google/provider.go index 48c9e460c69..59eb77f8a53 100644 --- a/google/provider.go +++ b/google/provider.go @@ -991,9 +991,9 @@ func Provider() *schema.Provider { return provider } -// Generated resources: 268 +// Generated resources: 269 // Generated IAM resources: 174 -// Total generated resources: 442 +// Total generated resources: 443 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -1262,6 +1262,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_filestore_backup": ResourceFilestoreBackup(), "google_filestore_instance": ResourceFilestoreInstance(), "google_filestore_snapshot": ResourceFilestoreSnapshot(), + "google_firestore_database": ResourceFirestoreDatabase(), "google_firestore_document": ResourceFirestoreDocument(), "google_firestore_index": ResourceFirestoreIndex(), "google_game_services_game_server_cluster": ResourceGameServicesGameServerCluster(), diff --git a/google/resource_firestore_database.go b/google/resource_firestore_database.go new file mode 100644 index 00000000000..088f9c151ac --- /dev/null +++ b/google/resource_firestore_database.go @@ -0,0 +1,464 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "log" + "reflect" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceFirestoreDatabase() *schema.Resource { + return &schema.Resource{ + Create: resourceFirestoreDatabaseCreate, + Read: resourceFirestoreDatabaseRead, + Update: resourceFirestoreDatabaseUpdate, + Delete: resourceFirestoreDatabaseDelete, + + Importer: &schema.ResourceImporter{ + State: resourceFirestoreDatabaseImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "location_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The location of the database. Available databases are listed at +https://cloud.google.com/firestore/docs/locations.`, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `Required. The ID to use for the database, which will become the final +component of the database's resource name. This value should be 4-63 +characters. Valid characters are /[a-z][0-9]-/ with first character +a letter and the last a letter or a number. Must not be +UUID-like /[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}/. +"(default)" database id is also valid.`, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateEnum([]string{"FIRESTORE_NATIVE", "DATASTORE_MODE"}), + Description: `The type of the database. +See https://cloud.google.com/datastore/docs/firestore-or-datastore +for information about how to choose. Possible values: ["FIRESTORE_NATIVE", "DATASTORE_MODE"]`, + }, + "app_engine_integration_mode": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ValidateFunc: validateEnum([]string{"ENABLED", "DISABLED", ""}), + Description: `The App Engine integration mode to use for this database. Possible values: ["ENABLED", "DISABLED"]`, + }, + "concurrency_mode": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ValidateFunc: validateEnum([]string{"OPTIMISTIC", "PESSIMISTIC", "OPTIMISTIC_WITH_ENTITY_GROUPS", ""}), + Description: `The concurrency control mode to use for this database. Possible values: ["OPTIMISTIC", "PESSIMISTIC", "OPTIMISTIC_WITH_ENTITY_GROUPS"]`, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: `The timestamp at which this database was created.`, + }, + "etag": { + Type: schema.TypeString, + Computed: true, + Description: `This checksum is computed by the server based on the value of other fields, +and may be sent on update and delete requests to ensure the client has an +up-to-date value before proceeding.`, + }, + "key_prefix": { + Type: schema.TypeString, + Computed: true, + Description: `Output only. The keyPrefix for this database. +This keyPrefix is used, in combination with the project id ("~") to construct the application id +that is returned from the Cloud Datastore APIs in Google App Engine first generation runtimes. +This value may be empty in which case the appid to use for URL-encoded keys is the project_id (eg: foo instead of v~foo).`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceFirestoreDatabaseCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + nameProp, err := expandFirestoreDatabaseName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + locationIdProp, err := expandFirestoreDatabaseLocationId(d.Get("location_id"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("location_id"); !isEmptyValue(reflect.ValueOf(locationIdProp)) && (ok || !reflect.DeepEqual(v, locationIdProp)) { + obj["locationId"] = locationIdProp + } + typeProp, err := expandFirestoreDatabaseType(d.Get("type"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("type"); !isEmptyValue(reflect.ValueOf(typeProp)) && (ok || !reflect.DeepEqual(v, typeProp)) { + obj["type"] = typeProp + } + concurrencyModeProp, err := expandFirestoreDatabaseConcurrencyMode(d.Get("concurrency_mode"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("concurrency_mode"); !isEmptyValue(reflect.ValueOf(concurrencyModeProp)) && (ok || !reflect.DeepEqual(v, concurrencyModeProp)) { + obj["concurrencyMode"] = concurrencyModeProp + } + appEngineIntegrationModeProp, err := expandFirestoreDatabaseAppEngineIntegrationMode(d.Get("app_engine_integration_mode"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("app_engine_integration_mode"); !isEmptyValue(reflect.ValueOf(appEngineIntegrationModeProp)) && (ok || !reflect.DeepEqual(v, appEngineIntegrationModeProp)) { + obj["appEngineIntegrationMode"] = appEngineIntegrationModeProp + } + etagProp, err := expandFirestoreDatabaseEtag(d.Get("etag"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("etag"); !isEmptyValue(reflect.ValueOf(etagProp)) && (ok || !reflect.DeepEqual(v, etagProp)) { + obj["etag"] = etagProp + } + + url, err := replaceVars(d, config, "{{FirestoreBasePath}}projects/{{project}}/databases?databaseId={{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Database: %#v", obj) + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Database: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "POST", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating Database: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "projects/{{project}}/databases/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + // Use the resource in the operation response to populate + // identity fields and d.Id() before read + var opRes map[string]interface{} + err = firestoreOperationWaitTimeWithResponse( + config, res, &opRes, project, "Creating Database", userAgent, + d.Timeout(schema.TimeoutCreate)) + if err != nil { + // The resource didn't actually create + d.SetId("") + + return fmt.Errorf("Error waiting to create Database: %s", err) + } + + if err := d.Set("name", flattenFirestoreDatabaseName(opRes["name"], d, config)); err != nil { + return err + } + + // This may have caused the ID to update - update it if so. + id, err = replaceVars(d, config, "projects/{{project}}/databases/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating Database %q: %#v", d.Id(), res) + + return resourceFirestoreDatabaseRead(d, meta) +} + +func resourceFirestoreDatabaseRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{FirestoreBasePath}}projects/{{project}}/databases/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Database: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequest(config, "GET", billingProject, url, userAgent, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("FirestoreDatabase %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Database: %s", err) + } + + if err := d.Set("name", flattenFirestoreDatabaseName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading Database: %s", err) + } + if err := d.Set("location_id", flattenFirestoreDatabaseLocationId(res["locationId"], d, config)); err != nil { + return fmt.Errorf("Error reading Database: %s", err) + } + if err := d.Set("type", flattenFirestoreDatabaseType(res["type"], d, config)); err != nil { + return fmt.Errorf("Error reading Database: %s", err) + } + if err := d.Set("concurrency_mode", flattenFirestoreDatabaseConcurrencyMode(res["concurrencyMode"], d, config)); err != nil { + return fmt.Errorf("Error reading Database: %s", err) + } + if err := d.Set("app_engine_integration_mode", flattenFirestoreDatabaseAppEngineIntegrationMode(res["appEngineIntegrationMode"], d, config)); err != nil { + return fmt.Errorf("Error reading Database: %s", err) + } + if err := d.Set("key_prefix", flattenFirestoreDatabaseKeyPrefix(res["key_prefix"], d, config)); err != nil { + return fmt.Errorf("Error reading Database: %s", err) + } + if err := d.Set("etag", flattenFirestoreDatabaseEtag(res["etag"], d, config)); err != nil { + return fmt.Errorf("Error reading Database: %s", err) + } + if err := d.Set("create_time", flattenFirestoreDatabaseCreateTime(res["create_time"], d, config)); err != nil { + return fmt.Errorf("Error reading Database: %s", err) + } + + return nil +} + +func resourceFirestoreDatabaseUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Database: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + typeProp, err := expandFirestoreDatabaseType(d.Get("type"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("type"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, typeProp)) { + obj["type"] = typeProp + } + concurrencyModeProp, err := expandFirestoreDatabaseConcurrencyMode(d.Get("concurrency_mode"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("concurrency_mode"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, concurrencyModeProp)) { + obj["concurrencyMode"] = concurrencyModeProp + } + appEngineIntegrationModeProp, err := expandFirestoreDatabaseAppEngineIntegrationMode(d.Get("app_engine_integration_mode"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("app_engine_integration_mode"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, appEngineIntegrationModeProp)) { + obj["appEngineIntegrationMode"] = appEngineIntegrationModeProp + } + etagProp, err := expandFirestoreDatabaseEtag(d.Get("etag"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("etag"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, etagProp)) { + obj["etag"] = etagProp + } + + url, err := replaceVars(d, config, "{{FirestoreBasePath}}projects/{{project}}/databases/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating Database %q: %#v", d.Id(), obj) + updateMask := []string{} + + if d.HasChange("type") { + updateMask = append(updateMask, "type") + } + + if d.HasChange("concurrency_mode") { + updateMask = append(updateMask, "concurrencyMode") + } + + if d.HasChange("app_engine_integration_mode") { + updateMask = append(updateMask, "appEngineIntegrationMode") + } + + if d.HasChange("etag") { + updateMask = append(updateMask, "etag") + } + // updateMask is a URL parameter but not present in the schema, so replaceVars + // won't set it + url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "PATCH", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("Error updating Database %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating Database %q: %#v", d.Id(), res) + } + + err = firestoreOperationWaitTime( + config, res, project, "Updating Database", userAgent, + d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return err + } + + return resourceFirestoreDatabaseRead(d, meta) +} + +func resourceFirestoreDatabaseDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[WARNING] Firestore Database resources"+ + " cannot be deleted from Google Cloud. The resource %s will be removed from Terraform"+ + " state, but will still be present on Google Cloud.", d.Id()) + d.SetId("") + + return nil +} + +func resourceFirestoreDatabaseImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{ + "projects/(?P[^/]+)/databases/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "projects/{{project}}/databases/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenFirestoreDatabaseName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return v + } + return NameFromSelfLinkStateFunc(v) +} + +func flattenFirestoreDatabaseLocationId(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenFirestoreDatabaseType(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenFirestoreDatabaseConcurrencyMode(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenFirestoreDatabaseAppEngineIntegrationMode(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenFirestoreDatabaseKeyPrefix(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenFirestoreDatabaseEtag(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenFirestoreDatabaseCreateTime(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func expandFirestoreDatabaseName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return replaceVars(d, config, "projects/{{project}}/databases/{{name}}") +} + +func expandFirestoreDatabaseLocationId(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandFirestoreDatabaseType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandFirestoreDatabaseConcurrencyMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandFirestoreDatabaseAppEngineIntegrationMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandFirestoreDatabaseEtag(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google/resource_firestore_database_generated_test.go b/google/resource_firestore_database_generated_test.go new file mode 100644 index 00000000000..17e4e9a757b --- /dev/null +++ b/google/resource_firestore_database_generated_test.go @@ -0,0 +1,149 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccFirestoreDatabase_firestoreDatabaseExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirestoreDatabase_firestoreDatabaseExample(context), + }, + { + ResourceName: "google_firestore_database.database", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"project", "etag"}, + }, + }, + }) +} + +func testAccFirestoreDatabase_firestoreDatabaseExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_project" "project" { + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "%{org_id}" +} + +resource "time_sleep" "wait_60_seconds" { + depends_on = [google_project.project] + + create_duration = "60s" +} + +resource "google_project_service" "firestore" { + project = google_project.project.project_id + service = "firestore.googleapis.com" + + # Needed for CI tests for permissions to propagate, should not be needed for actual usage + depends_on = [time_sleep.wait_60_seconds] +} + +resource "google_firestore_database" "database" { + project = google_project.project.project_id + name = "(default)" + location_id = "nam5" + type = "FIRESTORE_NATIVE" + concurrency_mode = "OPTIMISTIC" + app_engine_integration_mode = "DISABLED" + + depends_on = [google_project_service.firestore] +} +`, context) +} + +func TestAccFirestoreDatabase_firestoreDatabaseDatastoreModeExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirestoreDatabase_firestoreDatabaseDatastoreModeExample(context), + }, + { + ResourceName: "google_firestore_database.datastore_mode_database", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"project", "etag"}, + }, + }, + }) +} + +func testAccFirestoreDatabase_firestoreDatabaseDatastoreModeExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_project" "project" { + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "%{org_id}" +} + +resource "time_sleep" "wait_60_seconds" { + depends_on = [google_project.project] + + create_duration = "60s" +} + +resource "google_project_service" "firestore" { + project = google_project.project.project_id + service = "firestore.googleapis.com" + + # Needed for CI tests for permissions to propagate, should not be needed for actual usage + depends_on = [time_sleep.wait_60_seconds] +} + +resource "google_firestore_database" "datastore_mode_database" { + project = google_project.project.project_id + + name = "(default)" + + location_id = "nam5" + type = "DATASTORE_MODE" + + depends_on = [google_project_service.firestore] +} +`, context) +} diff --git a/google/resource_firestore_database_update_test.go b/google/resource_firestore_database_update_test.go index 71664db3c87..7048a75020e 100644 --- a/google/resource_firestore_database_update_test.go +++ b/google/resource_firestore_database_update_test.go @@ -1 +1,78 @@ package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccFirestoreDatabase_update(t *testing.T) { + t.Parallel() + + orgId := getTestOrgFromEnv(t) + randomSuffix := randString(t, 10) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirestoreDatabase_concurrencyMode(orgId, randomSuffix, "OPTIMISTIC"), + }, + { + ResourceName: "google_firestore_database.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"etag", "project"}, + }, + { + Config: testAccFirestoreDatabase_concurrencyMode(orgId, randomSuffix, "PESSIMISTIC"), + }, + { + ResourceName: "google_firestore_database.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"etag", "project"}, + }, + }, + }) +} + +func testAccFirestoreDatabase_concurrencyMode(orgId string, randomSuffix string, concurrencyMode string) string { + return fmt.Sprintf(` +resource "google_project" "default" { + project_id = "tf-test%s" + name = "tf-test%s" + org_id = "%s" +} + +resource "time_sleep" "wait_60_seconds" { + depends_on = [google_project.default] + + create_duration = "60s" +} + +resource "google_project_service" "firestore" { + project = google_project.default.project_id + service = "firestore.googleapis.com" + + # Needed for CI tests for permissions to propagate, should not be needed for actual usage + depends_on = [time_sleep.wait_60_seconds] +} + +resource "google_firestore_database" "default" { + name = "(default)" + type = "DATASTORE_MODE" + location_id = "nam5" + concurrency_mode = "%s" + + project = google_project.default.project_id + + depends_on = [google_project_service.firestore] +} +`, randomSuffix, randomSuffix, orgId, concurrencyMode) +} diff --git a/website/docs/r/firestore_database.html.markdown b/website/docs/r/firestore_database.html.markdown index 569fb989183..54bed1114bb 100644 --- a/website/docs/r/firestore_database.html.markdown +++ b/website/docs/r/firestore_database.html.markdown @@ -22,8 +22,6 @@ description: |- A Cloud Firestore Database. Currently only one database is allowed per cloud project; this database must have a `database_id` of '(default)'. -~> **Warning:** This resource is in beta, and should be used with the terraform-provider-google-beta provider. -See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. To get more information about Database, see: @@ -36,8 +34,6 @@ To get more information about Database, see: ```hcl resource "google_project" "project" { - provider = "google-beta" - project_id = "tf-test%{random_suffix}" name = "tf-test%{random_suffix}" org_id = "123456789" @@ -50,8 +46,6 @@ resource "time_sleep" "wait_60_seconds" { } resource "google_project_service" "firestore" { - provider = "google-beta" - project = google_project.project.project_id service = "firestore.googleapis.com" @@ -60,8 +54,6 @@ resource "google_project_service" "firestore" { } resource "google_firestore_database" "database" { - provider = "google-beta" - project = google_project.project.project_id name = "(default)" location_id = "nam5" @@ -77,8 +69,6 @@ resource "google_firestore_database" "database" { ```hcl resource "google_project" "project" { - provider = "google-beta" - project_id = "tf-test%{random_suffix}" name = "tf-test%{random_suffix}" org_id = "123456789" @@ -91,8 +81,6 @@ resource "time_sleep" "wait_60_seconds" { } resource "google_project_service" "firestore" { - provider = "google-beta" - project = google_project.project.project_id service = "firestore.googleapis.com" @@ -101,8 +89,6 @@ resource "google_project_service" "firestore" { } resource "google_firestore_database" "datastore_mode_database" { - provider = "google-beta" - project = google_project.project.project_id name = "(default)"