diff --git a/mmv1/products/observability/FolderSettings.yaml b/mmv1/products/observability/FolderSettings.yaml new file mode 100644 index 000000000000..40e282582674 --- /dev/null +++ b/mmv1/products/observability/FolderSettings.yaml @@ -0,0 +1,94 @@ +# Copyright 2026 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +name: 'FolderSettings' +description: Manages Cloud Observability settings for a folder. +min_version: 'beta' + +base_url: 'folders/{{folder}}/locations/{{location}}/settings' +self_link: 'folders/{{folder}}/locations/{{location}}/settings' +create_url: 'folders/{{folder}}/locations/{{location}}/settings' +create_verb: 'PATCH' +update_url: 'folders/{{folder}}/locations/{{location}}/settings' +update_verb: 'PATCH' +exclude_delete: true +autogen_async: true +update_mask: true + +custom_code: + pre_create: templates/terraform/pre_create/observability_folder_settings.go.tmpl +import_format: + - 'folders/{{folder}}/locations/{{location}}/settings' + +async: + include_project: true + operation: + timeouts: + insert_minutes: 10 + update_minutes: 10 + base_url: '{{op_id}}' + result: + resource_inside_response: true + +examples: + - name: "observability_folder_settings_basic" + config_path: "templates/terraform/examples/observability_folder_settings_basic.tf.tmpl" + primary_resource_id: "primary" + external_providers: ["time"] + vars: + location: "us" + kms_key_name: "example-key" + folder_name: "tf-test-folder" + test_env_vars: + org_id: 'ORG_ID' + test_vars_overrides: + kms_key_name: 'acctest.BootstrapKMSKeyInLocation(t, "us").CryptoKey.Name' + - name: "observability_folder_settings_basic_global" + config_path: "templates/terraform/examples/observability_folder_settings_basic_global.tf.tmpl" + primary_resource_id: "primary_global" + external_providers: ["time"] + vars: + location: "global" + test_env_vars: + org_id: 'ORG_ID' + +parameters: + - name: 'location' + type: String + description: 'The location of the settings.' + url_param_only: true + required: true + immutable: true + - name: 'folder' + type: String + description: 'The folder ID.' + url_param_only: true + required: true + immutable: true + +properties: + - name: 'defaultStorageLocation' + type: String + description: 'The default storage location for new resources, e.g. buckets. Only valid for global location.' + - name: 'kmsKeyName' + type: String + description: 'The default Cloud KMS key to use for new resources. Only valid for regional locations.' + - name: 'name' + type: String + description: 'The resource name of the settings.' + output: true + - name: 'serviceAccountId' + type: String + description: 'The service account used by Cloud Observability for this folder.' + output: true diff --git a/mmv1/templates/terraform/examples/observability_folder_settings_basic.tf.tmpl b/mmv1/templates/terraform/examples/observability_folder_settings_basic.tf.tmpl new file mode 100644 index 000000000000..f8ecd91b8bc3 --- /dev/null +++ b/mmv1/templates/terraform/examples/observability_folder_settings_basic.tf.tmpl @@ -0,0 +1,41 @@ +resource "google_folder" "test_folder" { + provider = "google-beta" + display_name = "tf-test-%{random_suffix}" + parent = "organizations/{{index $.TestEnvVars "org_id"}}" + deletion_protection = false +} + +# Wait for the folder to be created and recognized by the Observability API +resource "time_sleep" "wait_for_settings_propagation" { + create_duration = "90s" + depends_on = [google_folder.test_folder] +} + +data "google_observability_folder_settings" "settings_data" { + provider = "google-beta" + folder = google_folder.test_folder.folder_id + location = "us" + depends_on = [time_sleep.wait_for_settings_propagation] +} + +# Add a delay to allow the service account to propagate +resource "time_sleep" "wait_for_sa_propagation" { + create_duration = "90s" + depends_on = [data.google_observability_folder_settings.settings_data] +} + +resource "google_kms_crypto_key_iam_member" "iam" { + provider = "google-beta" + crypto_key_id = "{{index $.Vars "kms_key_name"}}" + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + member = "serviceAccount:${data.google_observability_folder_settings.settings_data.service_account_id}" + depends_on = [time_sleep.wait_for_sa_propagation] +} + +resource "google_observability_folder_settings" "primary" { + provider = "google-beta" + location = "us" + folder = google_folder.test_folder.folder_id + kms_key_name = "{{index $.Vars "kms_key_name"}}" + depends_on = [google_kms_crypto_key_iam_member.iam] +} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/observability_folder_settings_basic_global.tf.tmpl b/mmv1/templates/terraform/examples/observability_folder_settings_basic_global.tf.tmpl new file mode 100644 index 000000000000..4e451bc078c7 --- /dev/null +++ b/mmv1/templates/terraform/examples/observability_folder_settings_basic_global.tf.tmpl @@ -0,0 +1,27 @@ +resource "google_folder" "test_folder" { + provider = "google-beta" + display_name = "tf-test-%{random_suffix}" + parent = "organizations/{{index $.TestEnvVars "org_id"}}" + deletion_protection = false +} + +# Wait for the folder to be created and recognized by the Observability API +resource "time_sleep" "wait_for_folder" { + create_duration = "90s" + depends_on = [google_folder.test_folder] +} + +data "google_observability_folder_settings" "settings_data" { + provider = "google-beta" + folder = google_folder.test_folder.folder_id + location = "global" + depends_on = [time_sleep.wait_for_folder] +} + +resource "google_observability_folder_settings" "primary_global" { + provider = "google-beta" + location = "global" + folder = google_folder.test_folder.folder_id + default_storage_location = "us" + depends_on = [data.google_observability_folder_settings.settings_data] +} diff --git a/mmv1/templates/terraform/pre_create/observability_folder_settings.go.tmpl b/mmv1/templates/terraform/pre_create/observability_folder_settings.go.tmpl new file mode 100644 index 000000000000..946f37a919f0 --- /dev/null +++ b/mmv1/templates/terraform/pre_create/observability_folder_settings.go.tmpl @@ -0,0 +1,14 @@ +var masks []string +if !d.GetRawConfig().GetAttr("default_storage_location").IsNull() { + masks = append(masks, "defaultStorageLocation") +} +if !d.GetRawConfig().GetAttr("kms_key_name").IsNull() { + masks = append(masks, "kmsKeyName") +} + +if len(masks) > 0 { + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(masks, ",")}) + if err != nil { + return err + } +} \ No newline at end of file diff --git a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl index ea10e97f9f62..cf82a52aaf99 100644 --- a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl +++ b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl @@ -216,6 +216,7 @@ var handwrittenDatasources = map[string]*schema.Resource{ "google_monitoring_uptime_check_ips": monitoring.DataSourceGoogleMonitoringUptimeCheckIps(), "google_netblock_ip_ranges": resourcemanager.DataSourceGoogleNetblockIpRanges(), {{- if ne $.TargetVersionName "ga" }} + "google_observability_folder_settings": observability.DataSourceObservabilityFolderSettings(), "google_observability_project_settings": observability.DataSourceObservabilityProjectSettings(), "google_observability_organization_settings": observability.DataSourceObservabilityOrganizationSettings(), {{- end }} diff --git a/mmv1/third_party/terraform/services/observability/data_source_observability_folder_settings.go.tmpl b/mmv1/third_party/terraform/services/observability/data_source_observability_folder_settings.go.tmpl new file mode 100644 index 000000000000..08c8563eebd0 --- /dev/null +++ b/mmv1/third_party/terraform/services/observability/data_source_observability_folder_settings.go.tmpl @@ -0,0 +1,39 @@ +package observability + +{{ if ne $.TargetVersionName "ga" -}} +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" +) + +func DataSourceObservabilityFolderSettings() *schema.Resource { + dsSchema := tpgresource.DatasourceSchemaFromResourceSchema(ResourceObservabilityFolderSettings().Schema) + + tpgresource.AddRequiredFieldsToSchema(dsSchema, "folder") + tpgresource.AddRequiredFieldsToSchema(dsSchema, "location") + + return &schema.Resource{ + Read: dataSourceObservabilityFolderSettingsRead, + Schema: dsSchema, + } +} + +func dataSourceObservabilityFolderSettingsRead(d *schema.ResourceData, meta interface{}) error { + folder := d.Get("folder").(string) + location := d.Get("location").(string) + + id := fmt.Sprintf("folders/%s/locations/%s/settings", folder, location) + d.SetId(id) + + err := resourceObservabilityFolderSettingsRead(d, meta) + if err != nil { + return nil + } + if d.Id() == "" { + return fmt.Errorf("%s not found", id) + } + return nil +} +{{- end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/observability/data_source_observability_folder_settings_test.go.tmpl b/mmv1/third_party/terraform/services/observability/data_source_observability_folder_settings_test.go.tmpl new file mode 100644 index 000000000000..44775a1439a8 --- /dev/null +++ b/mmv1/third_party/terraform/services/observability/data_source_observability_folder_settings_test.go.tmpl @@ -0,0 +1,72 @@ +package observability_test + +{{ if ne $.TargetVersionName "ga" -}} +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccObservabilityFolderSettings_datasource(t *testing.T) { + t.Parallel() + + orgId := envvar.GetTestOrgFromEnv(t) + folderDisplayName := "tf-test-" + acctest.RandString(t, 10) + + context := map[string]interface{}{ + "org_id": orgId, + "folder_display_name": folderDisplayName, + "location": "us", + } + dataResourceName := "data.google_observability_folder_settings.settings" + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccObservabilityFolderSettings_datasource(context), + Check: resource.ComposeTestCheckFunc( + acctest.CheckDataSourceStateMatchesResourceState(dataResourceName, "google_observability_folder_settings.settings"), + ), + }, + }, + }) +} + +func testAccObservabilityFolderSettings_datasource(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_folder" "test" { + provider = google-beta + display_name = "%{folder_display_name}" + parent = "organizations/%{org_id}" + deletion_protection = false +} + +resource "time_sleep" "wait_for_folder" { + create_duration = "90s" + depends_on = [google_folder.test] +} + +resource "google_observability_folder_settings" "settings" { + provider = google-beta + folder = google_folder.test.folder_id + location = "%{location}" + kms_key_name = "" + depends_on = [time_sleep.wait_for_folder] +} + +data "google_observability_folder_settings" "settings" { + provider = google-beta + folder = google_folder.test.folder_id + location = "%{location}" + depends_on = [time_sleep.wait_for_folder] +} +`, context) +} +{{- end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/observability/resource_observability_folder_settings_test.go.tmpl b/mmv1/third_party/terraform/services/observability/resource_observability_folder_settings_test.go.tmpl new file mode 100644 index 000000000000..e170a008e537 --- /dev/null +++ b/mmv1/third_party/terraform/services/observability/resource_observability_folder_settings_test.go.tmpl @@ -0,0 +1,255 @@ +package observability_test + +{{ if ne $.TargetVersionName "ga" -}} +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccObservabilityFolderSettings_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "kms_key_name": acctest.BootstrapKMSKeyInLocation(t, "us").CryptoKey.Name, + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccObservabilityFolderSettings_basic(context), + }, + { + ResourceName: "google_observability_folder_settings.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"folder", "location"}, + }, + { + Config: testAccObservabilityFolderSettings_update(context), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_observability_folder_settings.primary", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_observability_folder_settings.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"folder", "location"}, + }, + }, + }) +} + +func testAccObservabilityFolderSettings_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_folder" "test_folder" { + provider = google-beta + display_name = "tf-test-%{random_suffix}" + parent = "organizations/%{org_id}" + deletion_protection = false +} + +# Add a delay to allow the folder creation to propagate before reading settings +resource "time_sleep" "wait_for_folder" { + create_duration = "90s" + depends_on = [google_folder.test_folder] +} + +data "google_observability_folder_settings" "settings_data" { + provider = google-beta + folder = google_folder.test_folder.folder_id + location = "us" + depends_on = [time_sleep.wait_for_folder] +} + +# Added this to bridge the gap between discovery and IAM usage +resource "time_sleep" "wait_for_sa_propagation" { + create_duration = "60s" + depends_on = [data.google_observability_folder_settings.settings_data] +} + +resource "google_kms_crypto_key_iam_member" "iam" { + provider = google-beta + crypto_key_id = "%{kms_key_name}" + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + member = "serviceAccount:${data.google_observability_folder_settings.settings_data.service_account_id}" + depends_on = [time_sleep.wait_for_sa_propagation] +} + +resource "google_observability_folder_settings" "primary" { + provider = google-beta + location = "us" + folder = google_folder.test_folder.folder_id + kms_key_name = "%{kms_key_name}" + depends_on = [google_kms_crypto_key_iam_member.iam] +} +`, context) +} + +func testAccObservabilityFolderSettings_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_folder" "test_folder" { + provider = google-beta + display_name = "tf-test-%{random_suffix}" + parent = "organizations/%{org_id}" + deletion_protection = false +} + +# Add a delay to allow the folder creation to propagate before reading settings +resource "time_sleep" "wait_for_folder" { + create_duration = "90s" + depends_on = [google_folder.test_folder] +} + +data "google_observability_folder_settings" "settings_data" { + provider = google-beta + folder = google_folder.test_folder.folder_id + location = "us" + depends_on = [time_sleep.wait_for_folder] +} + +# Added this to bridge the gap between discovery and IAM usage +resource "time_sleep" "wait_for_sa_propagation" { + create_duration = "60s" + depends_on = [data.google_observability_folder_settings.settings_data] +} + +resource "google_kms_crypto_key_iam_member" "iam" { + provider = google-beta + crypto_key_id = "%{kms_key_name}" + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + member = "serviceAccount:${data.google_observability_folder_settings.settings_data.service_account_id}" + depends_on = [time_sleep.wait_for_sa_propagation] +} + +resource "google_observability_folder_settings" "primary" { + provider = google-beta + location = "us" + folder = google_folder.test_folder.folder_id + kms_key_name = "" # Unset KMS key + depends_on = [google_kms_crypto_key_iam_member.iam] +} +`, context) +} + +func TestAccObservabilityFolderSettings_globalUpdate(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccObservabilityFolderSettings_global(context, "us"), + }, + { + ResourceName: "google_observability_folder_settings.primary_global", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"folder", "location"}, + }, + { + Config: testAccObservabilityFolderSettings_globalUpdate(context, "eu"), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_observability_folder_settings.primary_global", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_observability_folder_settings.primary_global", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"folder", "location"}, + }, + }, + }) +} + +func testAccObservabilityFolderSettings_global(context map[string]interface{}, defaultLocation string) string { + return acctest.Nprintf(fmt.Sprintf(` +resource "google_folder" "test_folder" { + provider = google-beta + display_name = "tf-test-%%{random_suffix}" + parent = "organizations/%%{org_id}" + deletion_protection = false +} + +# Add a delay to allow the folder creation to propagate before reading settings +resource "time_sleep" "wait_for_folder" { + create_duration = "90s" + depends_on = [google_folder.test_folder] +} + +data "google_observability_folder_settings" "settings_data" { + provider = google-beta + folder = google_folder.test_folder.folder_id + location = "global" + depends_on = [time_sleep.wait_for_folder] +} + +resource "google_observability_folder_settings" "primary_global" { + provider = google-beta + location = "global" + folder = google_folder.test_folder.folder_id + default_storage_location = "%s" + depends_on = [data.google_observability_folder_settings.settings_data] +} +`, defaultLocation), context) +} + +func testAccObservabilityFolderSettings_globalUpdate(context map[string]interface{}, defaultLocation string) string { + return acctest.Nprintf(fmt.Sprintf(` +resource "google_folder" "test_folder" { + provider = google-beta + display_name = "tf-test-%%{random_suffix}" + parent = "organizations/%%{org_id}" + deletion_protection = false +} + +# Add a delay to allow the folder creation to propagate before reading settings +resource "time_sleep" "wait_for_folder" { + create_duration = "90s" + depends_on = [google_folder.test_folder] +} + +data "google_observability_folder_settings" "settings_data" { + provider = google-beta + folder = google_folder.test_folder.folder_id + location = "global" + depends_on = [time_sleep.wait_for_folder] +} + +resource "google_observability_folder_settings" "primary_global" { + provider = google-beta + location = "global" + folder = google_folder.test_folder.folder_id + default_storage_location = "%s" + depends_on = [data.google_observability_folder_settings.settings_data] +} +`, defaultLocation), context) +} +{{- end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/website/docs/d/observability_folder_settings.html.markdown b/mmv1/third_party/terraform/website/docs/d/observability_folder_settings.html.markdown new file mode 100644 index 000000000000..57118b228a0c --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/d/observability_folder_settings.html.markdown @@ -0,0 +1,41 @@ +--- +subcategory: "Cloud Observability" +description: |- + Describes the Google Cloud Observability settings associated with a folder. +--- + +# google_observability_folder_settings + +Describes the Google Cloud Observability Settings associated with a folder. + +To get more information about Observability Settings, see: + +* [API documentation](https://docs.cloud.google.com/stackdriver/docs/reference/observability/api/rest) +* How-to Guides + * [Official Documentation](https://docs.cloud.google.com/stackdriver/docs/observability/set-defaults-for-observability-buckets) + +~> **Warning:** This data source is in beta, and should be used with the terraform-provider-google-beta provider. +See [Provider Versions](../guides/provider_versions.html.markdown) for more details on beta resources. + +## Example Usage - Observability Folder Settings Basic + +```hcl +data "google_observability_folder_settings" "settings" { + folder = "my-folder-name" + location = "global" +} +``` + +## Argument Reference + +The following arguments are supported: + +- - - + +* `folder` - (Required) The folder for which to retrieve settings. + +* `location` - (Required) The location of the settings. + +## Attributes Reference + +See [observability_folder_settings](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/observability_folder_settings#argument-reference) resource for details of the available attributes. \ No newline at end of file