From 3eeed812d3bbeffb050002db14ffaefb8db3ea17 Mon Sep 17 00:00:00 2001 From: The Magician Date: Fri, 23 Jun 2023 16:19:04 -0700 Subject: [PATCH] Add support for locking to google_logging_project_bucket_config (#8201) (#14977) Signed-off-by: Modular Magician --- .changelog/8201.txt | 3 + google/resource_logging_bucket_config_test.go | 63 ++++++++++++++++++- .../logging/resource_logging_bucket_config.go | 1 - .../resource_logging_project_bucket_config.go | 36 ++++++++++- ...ogging_project_bucket_config.html.markdown | 2 + 5 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 .changelog/8201.txt diff --git a/.changelog/8201.txt b/.changelog/8201.txt new file mode 100644 index 00000000000..6120f3e3908 --- /dev/null +++ b/.changelog/8201.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +logging: added support for `locked` to `google_logging_project_bucket_config` +``` diff --git a/google/resource_logging_bucket_config_test.go b/google/resource_logging_bucket_config_test.go index b9b86af1525..5993b7f0542 100644 --- a/google/resource_logging_bucket_config_test.go +++ b/google/resource_logging_bucket_config_test.go @@ -124,6 +124,42 @@ func TestAccLoggingBucketConfigProject_analyticsEnabled(t *testing.T) { }) } +func TestAccLoggingBucketConfigProject_locked(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + "project_name": "tf-test-" + RandString(t, 10), + "org_id": acctest.GetTestOrgFromEnv(t), + "billing_account": acctest.GetTestBillingAccountFromEnv(t), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccLoggingBucketConfigProject_locked(context, false), + }, + { + ResourceName: "google_logging_project_bucket_config.variable_locked", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"project"}, + }, + { + Config: testAccLoggingBucketConfigProject_locked(context, true), + }, + { + ResourceName: "google_logging_project_bucket_config.variable_locked", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"project"}, + }, + }, + }) +} + func TestAccLoggingBucketConfigProject_cmekSettings(t *testing.T) { t.Parallel() @@ -285,6 +321,32 @@ resource "google_logging_project_bucket_config" "basic" { `, context), analytics) } +func testAccLoggingBucketConfigProject_locked(context map[string]interface{}, locked bool) string { + return fmt.Sprintf(Nprintf(` +resource "google_project" "default" { + project_id = "%{project_name}" + name = "%{project_name}" + org_id = "%{org_id}" + billing_account = "%{billing_account}" +} + +resource "google_logging_project_bucket_config" "fixed_locked" { + project = google_project.default.name + location = "global" + locked = true + bucket_id = "fixed-locked" +} + +resource "google_logging_project_bucket_config" "variable_locked" { + project = google_project.default.name + location = "global" + description = "lock status is %v" # test simultaneous update + locked = %t + bucket_id = "variable-locked" +} +`, context), locked, locked) +} + func testAccLoggingBucketConfigProject_preCmekSettings(context map[string]interface{}, keyRingName, cryptoKeyName, cryptoKeyNameUpdate string) string { return fmt.Sprintf(Nprintf(` resource "google_project" "default" { @@ -444,7 +506,6 @@ resource "google_logging_organization_bucket_config" "basic" { } func getLoggingBucketConfigs(context map[string]interface{}) map[string]string { - return map[string]string{ "project": Nprintf(`resource "google_project" "default" { project_id = "%{project_name}" diff --git a/google/services/logging/resource_logging_bucket_config.go b/google/services/logging/resource_logging_bucket_config.go index 683e8d1684d..8cdcfd0220b 100644 --- a/google/services/logging/resource_logging_bucket_config.go +++ b/google/services/logging/resource_logging_bucket_config.go @@ -204,7 +204,6 @@ func resourceLoggingBucketConfigCreate(d *schema.ResourceData, meta interface{}, obj["name"] = d.Get("name") obj["description"] = d.Get("description") obj["retentionDays"] = d.Get("retention_days") - obj["locked"] = d.Get("locked") obj["cmekSettings"] = expandCmekSettings(d.Get("cmek_settings")) url, err := tpgresource.ReplaceVars(d, config, "{{LoggingBasePath}}projects/{{project}}/locations/{{location}}/buckets?bucketId={{bucket_id}}") diff --git a/google/services/logging/resource_logging_project_bucket_config.go b/google/services/logging/resource_logging_project_bucket_config.go index be3e53319b6..a6786f8b8cc 100644 --- a/google/services/logging/resource_logging_project_bucket_config.go +++ b/google/services/logging/resource_logging_project_bucket_config.go @@ -44,6 +44,11 @@ var loggingProjectBucketConfigSchema = map[string]*schema.Schema{ Computed: true, Description: `An optional description for this bucket.`, }, + "locked": { + Type: schema.TypeBool, + Optional: true, + Description: `Whether the bucket is locked. The retention period on a locked bucket cannot be changed. Locked buckets may only be deleted if they are empty.`, + }, "retention_days": { Type: schema.TypeInt, Optional: true, @@ -185,9 +190,9 @@ func resourceLoggingProjectBucketConfigCreate(d *schema.ResourceData, meta inter obj := make(map[string]interface{}) obj["name"] = d.Get("name") obj["description"] = d.Get("description") + obj["locked"] = d.Get("locked") obj["retentionDays"] = d.Get("retention_days") obj["analyticsEnabled"] = d.Get("enable_analytics") - obj["locked"] = d.Get("locked") obj["cmekSettings"] = expandCmekSettings(d.Get("cmek_settings")) url, err := tpgresource.ReplaceVars(d, config, "{{LoggingBasePath}}projects/{{project}}/locations/{{location}}/buckets?bucketId={{bucket_id}}") @@ -262,6 +267,9 @@ func resourceLoggingProjectBucketConfigRead(d *schema.ResourceData, meta interfa if err := d.Set("description", res["description"]); err != nil { return fmt.Errorf("Error setting description: %s", err) } + if err := d.Set("locked", res["locked"]); err != nil { + return fmt.Errorf("Error setting locked: %s", err) + } if err := d.Set("lifecycle_state", res["lifecycleState"]); err != nil { return fmt.Errorf("Error setting lifecycle_state: %s", err) } @@ -347,6 +355,32 @@ func resourceLoggingProjectBucketConfigUpdate(d *schema.ResourceData, meta inter return fmt.Errorf("Error updating Logging Bucket Config %q: %s", d.Id(), err) } + // Check if locked is being changed (although removal will fail). Locking is + // an atomic operation and can not be performed while other fields. + // update locked last so that we lock *after* setting the right settings + if d.HasChange("locked") { + updateMaskLocked := []string{"locked"} + objLocked := map[string]interface{}{ + "locked": d.Get("locked"), + } + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMaskLocked, ",")}) + if err != nil { + return err + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PATCH", + RawURL: url, + UserAgent: userAgent, + Body: objLocked, + Timeout: d.Timeout(schema.TimeoutUpdate), + }) + if err != nil { + return fmt.Errorf("Error updating Logging Bucket Config %q: %s", d.Id(), err) + } + } + return resourceLoggingProjectBucketConfigRead(d, meta) } diff --git a/website/docs/r/logging_project_bucket_config.html.markdown b/website/docs/r/logging_project_bucket_config.html.markdown index b57afd87de8..fc44ebec447 100644 --- a/website/docs/r/logging_project_bucket_config.html.markdown +++ b/website/docs/r/logging_project_bucket_config.html.markdown @@ -105,6 +105,8 @@ The following arguments are supported: * `description` - (Optional) Describes this bucket. +* `locked` - (Optional) Whether the bucket is locked. The retention period on a locked bucket cannot be changed. Locked buckets may only be deleted if they are empty. + * `retention_days` - (Optional) Logs will be retained by default for this amount of time, after which they will automatically be deleted. The minimum retention period is 1 day. If this value is set to zero at bucket creation time, the default time of 30 days will be used. * `enable_analytics` - (Optional) Whether or not Log Analytics is enabled. Logs for buckets with Log Analytics enabled can be queried in the **Log Analytics** page using SQL queries. Cannot be disabled once enabled.