From 712cce7da0b4d17e9ee5295c2df2ae67df9d4118 Mon Sep 17 00:00:00 2001 From: Riley Karson Date: Mon, 4 Mar 2024 13:32:26 -0800 Subject: [PATCH 01/32] Revert "Fix hashicorp/terraform-provider-google#17388 (only run tests in beta)" (#10111) This reverts commit ae819d0619edd36414af1c5dc5f9e68a6b999174. --- mmv1/products/firebaseappcheck/AppAttestConfig.yaml | 2 -- mmv1/products/firebaseappcheck/DebugToken.yaml | 1 - mmv1/products/firebaseappcheck/PlayIntegrityConfig.yaml | 2 -- .../firebaseappcheck/RecaptchaEnterpriseConfig.yaml | 1 - mmv1/products/firebaseappcheck/RecaptchaV3Config.yaml | 1 - .../firebase_app_check_app_attest_config_full.tf.erb | 4 ---- .../firebase_app_check_app_attest_config_minimal.tf.erb | 4 ---- .../examples/firebase_app_check_debug_token_basic.tf.erb | 8 ++------ .../firebase_app_check_play_integrity_config_full.tf.erb | 4 ---- ...irebase_app_check_play_integrity_config_minimal.tf.erb | 4 ---- ...ase_app_check_recaptcha_enterprise_config_basic.tf.erb | 4 ---- .../firebase_app_check_recaptcha_v3_config_basic.tf.erb | 4 ---- .../resource_firebase_app_check_app_attest_config_test.go | 2 +- .../resource_firebase_app_check_debug_token_test.go | 6 +----- ...ource_firebase_app_check_play_integrity_config_test.go | 2 +- ...firebase_app_check_recaptcha_enterprise_config_test.go | 2 +- ...esource_firebase_app_check_recaptcha_v3_config_test.go | 2 +- 17 files changed, 7 insertions(+), 46 deletions(-) diff --git a/mmv1/products/firebaseappcheck/AppAttestConfig.yaml b/mmv1/products/firebaseappcheck/AppAttestConfig.yaml index 9a92b7ed0c6e..025e59fbcca9 100644 --- a/mmv1/products/firebaseappcheck/AppAttestConfig.yaml +++ b/mmv1/products/firebaseappcheck/AppAttestConfig.yaml @@ -37,7 +37,6 @@ import_format: examples: - !ruby/object:Provider::Terraform::Examples name: "firebase_app_check_app_attest_config_minimal" - min_version: 'beta' # Need the time_sleep resource pull_external: true primary_resource_id: "default" @@ -51,7 +50,6 @@ examples: project_id: :PROJECT_NAME - !ruby/object:Provider::Terraform::Examples name: "firebase_app_check_app_attest_config_full" - min_version: 'beta' # Need the time_sleep resource pull_external: true primary_resource_id: "default" diff --git a/mmv1/products/firebaseappcheck/DebugToken.yaml b/mmv1/products/firebaseappcheck/DebugToken.yaml index e555a2ecd794..4a6867760d36 100644 --- a/mmv1/products/firebaseappcheck/DebugToken.yaml +++ b/mmv1/products/firebaseappcheck/DebugToken.yaml @@ -38,7 +38,6 @@ import_format: examples: - !ruby/object:Provider::Terraform::Examples name: "firebase_app_check_debug_token_basic" - min_version: 'beta' # Need the time_sleep resource pull_external: true primary_resource_id: "default" diff --git a/mmv1/products/firebaseappcheck/PlayIntegrityConfig.yaml b/mmv1/products/firebaseappcheck/PlayIntegrityConfig.yaml index 8081a0c91f47..7631e64d1a4b 100644 --- a/mmv1/products/firebaseappcheck/PlayIntegrityConfig.yaml +++ b/mmv1/products/firebaseappcheck/PlayIntegrityConfig.yaml @@ -37,7 +37,6 @@ import_format: examples: - !ruby/object:Provider::Terraform::Examples name: "firebase_app_check_play_integrity_config_minimal" - min_version: 'beta' # Need the time_sleep resource pull_external: true primary_resource_id: "default" @@ -47,7 +46,6 @@ examples: project_id: :PROJECT_NAME - !ruby/object:Provider::Terraform::Examples name: "firebase_app_check_play_integrity_config_full" - min_version: 'beta' # Need the time_sleep resource pull_external: true primary_resource_id: "default" diff --git a/mmv1/products/firebaseappcheck/RecaptchaEnterpriseConfig.yaml b/mmv1/products/firebaseappcheck/RecaptchaEnterpriseConfig.yaml index 7d0dd0fb6b08..a103c5dfb226 100644 --- a/mmv1/products/firebaseappcheck/RecaptchaEnterpriseConfig.yaml +++ b/mmv1/products/firebaseappcheck/RecaptchaEnterpriseConfig.yaml @@ -36,7 +36,6 @@ import_format: examples: - !ruby/object:Provider::Terraform::Examples name: "firebase_app_check_recaptcha_enterprise_config_basic" - min_version: 'beta' # Need the time_sleep resource pull_external: true primary_resource_id: "default" diff --git a/mmv1/products/firebaseappcheck/RecaptchaV3Config.yaml b/mmv1/products/firebaseappcheck/RecaptchaV3Config.yaml index c259d076ee9e..1e42c4796246 100644 --- a/mmv1/products/firebaseappcheck/RecaptchaV3Config.yaml +++ b/mmv1/products/firebaseappcheck/RecaptchaV3Config.yaml @@ -36,7 +36,6 @@ import_format: examples: - !ruby/object:Provider::Terraform::Examples name: "firebase_app_check_recaptcha_v3_config_basic" - min_version: 'beta' # Need the time_sleep resource pull_external: true primary_resource_id: "default" diff --git a/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_full.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_full.tf.erb index 4ef023c54153..134ecacfc5f8 100644 --- a/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_full.tf.erb +++ b/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_full.tf.erb @@ -1,6 +1,4 @@ resource "google_firebase_apple_app" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" display_name = "Apple app" bundle_id = "<%= ctx[:vars]['bundle_id'] %>" @@ -15,8 +13,6 @@ resource "time_sleep" "wait_30s" { } resource "google_firebase_app_check_app_attest_config" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" app_id = google_firebase_apple_app.default.app_id token_ttl = "<%= ctx[:vars]['token_ttl'] %>" diff --git a/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_minimal.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_minimal.tf.erb index 4ecb2eb56a87..a25a7f2d698f 100644 --- a/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_minimal.tf.erb +++ b/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_minimal.tf.erb @@ -1,6 +1,4 @@ resource "google_firebase_apple_app" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" display_name = "Apple app" bundle_id = "<%= ctx[:vars]['bundle_id'] %>" @@ -15,8 +13,6 @@ resource "time_sleep" "wait_30s" { } resource "google_firebase_app_check_app_attest_config" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" app_id = google_firebase_apple_app.default.app_id diff --git a/mmv1/templates/terraform/examples/firebase_app_check_debug_token_basic.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_debug_token_basic.tf.erb index 4b27b397b226..2434f163f5c0 100644 --- a/mmv1/templates/terraform/examples/firebase_app_check_debug_token_basic.tf.erb +++ b/mmv1/templates/terraform/examples/firebase_app_check_debug_token_basic.tf.erb @@ -1,20 +1,16 @@ resource "google_firebase_web_app" "default" { - provider = google-beta - - project = "<%= ctx[:test_env_vars]['project_id'] %>" + project = "<%= ctx[:test_env_vars]['project_id'] %>" display_name = "Web App for debug token" } # It takes a while for App Check to recognize the new app # If your app already exists, you don't have to wait 30 seconds. resource "time_sleep" "wait_30s" { - depends_on = [google_firebase_web_app.default] + depends_on = [google_firebase_web_app.default] create_duration = "30s" } resource "google_firebase_app_check_debug_token" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" app_id = google_firebase_web_app.default.app_id display_name = "<%= ctx[:vars]['display_name'] %>" diff --git a/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_full.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_full.tf.erb index 5ec82cf383bb..78559763e319 100644 --- a/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_full.tf.erb +++ b/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_full.tf.erb @@ -1,6 +1,4 @@ resource "google_firebase_android_app" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" display_name = "Play Integrity app" package_name = "<%= ctx[:vars]['package_name'] %>" @@ -16,8 +14,6 @@ resource "time_sleep" "wait_30s" { } resource "google_firebase_app_check_play_integrity_config" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" app_id = google_firebase_android_app.default.app_id token_ttl = "<%= ctx[:vars]['token_ttl'] %>" diff --git a/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_minimal.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_minimal.tf.erb index e360e1e07d08..4aacde367414 100644 --- a/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_minimal.tf.erb +++ b/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_minimal.tf.erb @@ -1,6 +1,4 @@ resource "google_firebase_android_app" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" display_name = "Play Integrity app" package_name = "<%= ctx[:vars]['package_name'] %>" @@ -16,8 +14,6 @@ resource "time_sleep" "wait_30s" { } resource "google_firebase_app_check_play_integrity_config" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" app_id = google_firebase_android_app.default.app_id diff --git a/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_enterprise_config_basic.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_enterprise_config_basic.tf.erb index 88435881cd40..806dfe37a16d 100644 --- a/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_enterprise_config_basic.tf.erb +++ b/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_enterprise_config_basic.tf.erb @@ -1,6 +1,4 @@ resource "google_firebase_web_app" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" display_name = "Web App for reCAPTCHA Enterprise" } @@ -13,8 +11,6 @@ resource "time_sleep" "wait_30s" { } resource "google_firebase_app_check_recaptcha_enterprise_config" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" app_id = google_firebase_web_app.default.app_id site_key = "<%= ctx[:vars]['site_key'] %>" diff --git a/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_v3_config_basic.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_v3_config_basic.tf.erb index 18b6a671ea72..4b4c88b7ddd7 100644 --- a/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_v3_config_basic.tf.erb +++ b/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_v3_config_basic.tf.erb @@ -1,6 +1,4 @@ resource "google_firebase_web_app" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" display_name = "Web App for reCAPTCHA V3" } @@ -13,8 +11,6 @@ resource "time_sleep" "wait_30s" { } resource "google_firebase_app_check_recaptcha_v3_config" "default" { - provider = google-beta - project = "<%= ctx[:test_env_vars]['project_id'] %>" app_id = google_firebase_web_app.default.app_id site_secret = "<%= ctx[:vars]['site_secret'] %>" diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go index 2e3627bb5448..a1b05b852feb 100644 --- a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go +++ b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go @@ -21,7 +21,7 @@ func TestAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigUpdat acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), ExternalProviders: map[string]resource.ExternalProvider{ "random": {}, "time": {}, diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_debug_token_test.go b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_debug_token_test.go index 1016785e0fe5..e0e205580be9 100644 --- a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_debug_token_test.go +++ b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_debug_token_test.go @@ -26,7 +26,7 @@ func TestAccFirebaseAppCheckDebugToken_firebaseAppCheckDebugTokenUpdate(t *testi acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), ExternalProviders: map[string]resource.ExternalProvider{ "random": {}, "time": {}, @@ -58,8 +58,6 @@ func TestAccFirebaseAppCheckDebugToken_firebaseAppCheckDebugTokenUpdate(t *testi func testAccFirebaseAppCheckDebugToken_firebaseAppCheckDebugTokenTemplate(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_firebase_web_app" "default" { - provider = google-beta - project = "%{project_id}" display_name = "Web App for debug token" } @@ -72,8 +70,6 @@ resource "time_sleep" "wait_30s" { } resource "google_firebase_app_check_debug_token" "default" { - provider = google-beta - project = "%{project_id}" app_id = google_firebase_web_app.default.app_id display_name = "%{display_name}" diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go index a29a25a005a3..c97df9fd1fab 100644 --- a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go +++ b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go @@ -20,7 +20,7 @@ func TestAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityCon acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), ExternalProviders: map[string]resource.ExternalProvider{ "random": {}, "time": {}, diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_enterprise_config_test.go b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_enterprise_config_test.go index 77d3bb140a33..6d0a91601ea7 100644 --- a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_enterprise_config_test.go +++ b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_enterprise_config_test.go @@ -28,7 +28,7 @@ func TestAccFirebaseAppCheckRecaptchaEnterpriseConfig_firebaseAppCheckRecaptchaE acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), ExternalProviders: map[string]resource.ExternalProvider{ "random": {}, "time": {}, diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_v3_config_test.go b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_v3_config_test.go index 83d741a71c6c..961215b8f63e 100644 --- a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_v3_config_test.go +++ b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_v3_config_test.go @@ -28,7 +28,7 @@ func TestAccFirebaseAppCheckRecaptchaV3Config_firebaseAppCheckRecaptchaV3ConfigU acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), ExternalProviders: map[string]resource.ExternalProvider{ "random": {}, "time": {}, From 3ccc673c9b2202948591b546ae21658ea4f19d8a Mon Sep 17 00:00:00 2001 From: Sam Levenick Date: Mon, 4 Mar 2024 16:36:27 -0500 Subject: [PATCH 02/32] Add support for string --> object map for DCL resources (#10039) * Add support for string --> object map for DCL resources * Fix whitespace in template * Add test, need updated DCL to work * Add override for key name * Both overrides * Update docs, prepend key for maps * Update bundle descriptions * Comment update --- mmv1/third_party/terraform/go.mod.erb | 2 +- mmv1/third_party/terraform/go.sum | 2 + ...rce_gke_hub_feature_membership_test.go.erb | 96 ++++++++++++++++++- .../gke_hub_feature_membership.html.markdown | 89 +++++++++++++++++ tpgtools/go.mod | 2 +- tpgtools/go.sum | 8 +- tpgtools/override.go | 1 + tpgtools/override_details.go | 5 + .../gkehub/beta/feature_membership.yaml | 8 ++ .../overrides/gkehub/feature_membership.yaml | 10 +- tpgtools/property.go | 61 +++++++++++- tpgtools/templates/resource.go.tmpl | 60 +++++++++++- tpgtools/type.go | 7 +- 13 files changed, 330 insertions(+), 21 deletions(-) diff --git a/mmv1/third_party/terraform/go.mod.erb b/mmv1/third_party/terraform/go.mod.erb index b5d4fd065d93..fa30a092113d 100644 --- a/mmv1/third_party/terraform/go.mod.erb +++ b/mmv1/third_party/terraform/go.mod.erb @@ -5,7 +5,7 @@ go 1.20 require ( cloud.google.com/go/bigtable v1.19.0 - github.com/GoogleCloudPlatform/declarative-resource-client-library v1.62.0 + github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0 github.com/apparentlymart/go-cidr v1.1.0 github.com/davecgh/go-spew v1.1.1 github.com/dnaeon/go-vcr v1.0.1 diff --git a/mmv1/third_party/terraform/go.sum b/mmv1/third_party/terraform/go.sum index 6837513a22df..63d8188cf48c 100644 --- a/mmv1/third_party/terraform/go.sum +++ b/mmv1/third_party/terraform/go.sum @@ -413,3 +413,5 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0 h1:eSOBYPZVnU2fZul9sAJFGLVCgv6stNVKkmsogKF7UeY= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k= diff --git a/mmv1/third_party/terraform/services/gkehub/resource_gke_hub_feature_membership_test.go.erb b/mmv1/third_party/terraform/services/gkehub/resource_gke_hub_feature_membership_test.go.erb index d231ea19e62c..a7ab46c640a6 100644 --- a/mmv1/third_party/terraform/services/gkehub/resource_gke_hub_feature_membership_test.go.erb +++ b/mmv1/third_party/terraform/services/gkehub/resource_gke_hub_feature_membership_test.go.erb @@ -1008,6 +1008,17 @@ func TestAccGKEHubFeatureMembership_gkehubFeaturePolicyController(t *testing.T) ImportState: true, ImportStateVerify: true, }, + { + Config: testAccGKEHubFeatureMembership_policycontrollerUpdateMaps(context), + Check: resource.ComposeTestCheckFunc( + testAccCheckGkeHubFeatureMembershipPresent(t, fmt.Sprintf("tf-test-gkehub%s", context["random_suffix"]), "global", "policycontroller", fmt.Sprintf("tf-test1%s", context["random_suffix"])), + ), + }, + { + ResourceName: "google_gke_hub_feature_membership.feature_member", + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -1064,9 +1075,92 @@ resource "google_gke_hub_feature_membership" "feature_member" { "PROMETHEUS" ] } + deployment_configs { + component_name = "admission" + replica_count = 3 + pod_affinity = "ANTI_AFFINITY" + container_resources { + limits { + memory = "1Gi" + cpu = "1.5" + } + requests { + memory = "500Mi" + cpu = "150m" + } + } + pod_tolerations { + key = "key1" + operator = "Equal" + value = "value1" + effect = "NoSchedule" + } + } + deployment_configs { + component_name = "mutation" + replica_count = 3 + pod_affinity = "ANTI_AFFINITY" + } policy_content { template_library { - installation = "NOT_INSTALLED" + installation = "ALL" + } + bundles { + bundle_name = "pci-dss-v3.2.1" + exempted_namespaces = ["sample-namespace"] + } + bundles { + bundle_name = "nist-sp-800-190" + } + } + } + version = "1.17.0" + } +} +`, context) +} + +func testAccGKEHubFeatureMembership_policycontrollerUpdateMaps(context map[string]interface{}) string { + return gkeHubFeatureProjectSetup(context) + gkeHubClusterMembershipSetup(context) + acctest.Nprintf(` +resource "google_gke_hub_feature" "feature" { + project = google_project.project.project_id + name = "policycontroller" + location = "global" + depends_on = [google_project_service.container, google_project_service.gkehub, google_project_service.poco] +} + +resource "google_gke_hub_feature_membership" "feature_member" { + project = google_project.project.project_id + location = "global" + feature = google_gke_hub_feature.feature.name + membership = google_gke_hub_membership.membership.membership_id + policycontroller { + policy_controller_hub_config { + install_spec = "INSTALL_SPEC_SUSPENDED" + constraint_violation_limit = 50 + referential_rules_enabled = true + log_denies_enabled = true + mutation_enabled = true + monitoring { + backends = [ + "PROMETHEUS" + ] + } + deployment_configs { + component_name = "admission" + pod_affinity = "NO_AFFINITY" + } + deployment_configs { + component_name = "audit" + container_resources { + limits { + memory = "1Gi" + cpu = "1.5" + } + requests { + memory = "500Mi" + cpu = "150m" + } } } } diff --git a/mmv1/third_party/terraform/website/docs/r/gke_hub_feature_membership.html.markdown b/mmv1/third_party/terraform/website/docs/r/gke_hub_feature_membership.html.markdown index ed571b6d7bdd..bd79aaa35da8 100644 --- a/mmv1/third_party/terraform/website/docs/r/gke_hub_feature_membership.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/gke_hub_feature_membership.html.markdown @@ -504,6 +504,10 @@ The following arguments are supported: (Optional) The maximum number of audit violations to be stored in a constraint. If not set, the default of 20 will be used. + * `deployment_configs` - + (Optional) + Map of deployment configs to deployments ("admission", "audit", "mutation"). + * `policy_content` - (Optional) Specifies the desired policy content on the cluster. Structure is [documented below](#nested_policy_content). @@ -514,12 +518,97 @@ The following arguments are supported: (Optional) Specifies the list of backends Policy Controller will export to. Must be one of `CLOUD_MONITORING` or `PROMETHEUS`. Defaults to [`CLOUD_MONITORING`, `PROMETHEUS`]. Specifying an empty value `[]` disables metrics export. +The `deployment_configs` block supports: + +* `component_name` - + (Required) + The name of the component. One of `admission` `audit` or `mutation` + +* `container_resources` - + (Optional) + Container resource requirements. + +* `pod_affinity` - + (Optional) + Pod affinity configuration. Possible values: AFFINITY_UNSPECIFIED, NO_AFFINITY, ANTI_AFFINITY + +* `pod_tolerations` - + (Optional) + Pod tolerations of node taints. + +* `replica_count` - + (Optional) + Pod replica count. + +The `container_resources` block supports: + +* `limits` - + (Optional) + Limits describes the maximum amount of compute resources allowed for use by the running container. + +* `requests` - + (Optional) + Requests describes the amount of compute resources reserved for the container by the kube-scheduler. + +The `limits` block supports: + +* `cpu` - + (Optional) + CPU requirement expressed in Kubernetes resource units. + +* `memory` - + (Optional) + Memory requirement expressed in Kubernetes resource units. + +The `requests` block supports: + +* `cpu` - + (Optional) + CPU requirement expressed in Kubernetes resource units. + +* `memory` - + (Optional) + Memory requirement expressed in Kubernetes resource units. + +The `pod_tolerations` block supports: + +* `effect` - + (Optional) + Matches a taint effect. + +* `key` - + (Optional) + Matches a taint key (not necessarily unique). + +* `operator` - + (Optional) + Matches a taint operator. + +* `value` - + (Optional) + Matches a taint value. + The `policy_content` block supports: +* `bundles` - + (Optional) + map of bundle name to BundleInstallSpec. The bundle name maps to the `bundleName` key in the `policycontroller.gke.io/constraintData` annotation on a constraint. + * `template_library` (Optional) Configures the installation of the Template Library. Structure is [documented below](#nested_template_library). +The `template_library` block supports: +The `bundles` block supports: + +* `bundle_name` - + (Required) + The name of the bundle. + +* `exempted_namespaces` - + (Optional) + The set of namespaces to be exempted from the bundle. + The `template_library` block supports: * `installation` diff --git a/tpgtools/go.mod b/tpgtools/go.mod index 14c13f11e191..90f55b270e1e 100644 --- a/tpgtools/go.mod +++ b/tpgtools/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( bitbucket.org/creachadair/stringset v0.0.11 - github.com/GoogleCloudPlatform/declarative-resource-client-library v1.62.0 + github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0 github.com/golang/glog v1.1.2 github.com/hashicorp/hcl v1.0.0 github.com/kylelemons/godebug v1.1.0 diff --git a/tpgtools/go.sum b/tpgtools/go.sum index 86a5ac602ab9..30d683a7cf40 100644 --- a/tpgtools/go.sum +++ b/tpgtools/go.sum @@ -6,12 +6,8 @@ cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdi cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/GoogleCloudPlatform/declarative-resource-client-library v1.60.0 h1:RFZs9I3tXewC7cJf8RKbUMpQZO6jWZ9SHSnNd+auxsQ= -github.com/GoogleCloudPlatform/declarative-resource-client-library v1.60.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k= -github.com/GoogleCloudPlatform/declarative-resource-client-library v1.61.0 h1:IAr9UlYbxURIYABRMagXXo8pDlkFNFFXWz5J2+srrnc= -github.com/GoogleCloudPlatform/declarative-resource-client-library v1.61.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k= -github.com/GoogleCloudPlatform/declarative-resource-client-library v1.62.0 h1:s4Y6r6RrYLBnqosGXLwR0h1Gqr0VT3wgd6rqvHsD9OE= -github.com/GoogleCloudPlatform/declarative-resource-client-library v1.62.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0 h1:eSOBYPZVnU2fZul9sAJFGLVCgv6stNVKkmsogKF7UeY= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.63.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= diff --git a/tpgtools/override.go b/tpgtools/override.go index a190f8026e7e..5ce55962733c 100644 --- a/tpgtools/override.go +++ b/tpgtools/override.go @@ -79,6 +79,7 @@ const ( CustomListSize = "CUSTOM_LIST_SIZE_CONSTRAINT" CustomDefault = "CUSTOM_DEFAULT" CustomSchemaValues = "CUSTOM_SCHEMA_VALUES" + ComplexMapKey = "COMPLEX_MAP_KEY_NAME" ) // Overrides represents the type a resource's override file can be marshalled diff --git a/tpgtools/override_details.go b/tpgtools/override_details.go index 12ee16832a59..963c23656e92 100644 --- a/tpgtools/override_details.go +++ b/tpgtools/override_details.go @@ -230,3 +230,8 @@ type StateUpgradeDetails struct { // The current schema version SchemaVersion int } + +type ComplexMapKeyDetails struct { + // The name of the key as exposed by Terraform + KeyName string +} diff --git a/tpgtools/overrides/gkehub/beta/feature_membership.yaml b/tpgtools/overrides/gkehub/beta/feature_membership.yaml index 3eac7364e119..8acee09e053a 100644 --- a/tpgtools/overrides/gkehub/beta/feature_membership.yaml +++ b/tpgtools/overrides/gkehub/beta/feature_membership.yaml @@ -29,3 +29,11 @@ details: functions: - tpgresource.DefaultProviderProject +- type: COMPLEX_MAP_KEY_NAME + field: policycontroller.policy_controller_hub_config.policy_content.bundles + details: + keyname: bundle_name +- type: COMPLEX_MAP_KEY_NAME + field: policycontroller.policy_controller_hub_config.deployment_configs + details: + keyname: component_name \ No newline at end of file diff --git a/tpgtools/overrides/gkehub/feature_membership.yaml b/tpgtools/overrides/gkehub/feature_membership.yaml index 2e8b8f32503c..cd6cf1876fcc 100644 --- a/tpgtools/overrides/gkehub/feature_membership.yaml +++ b/tpgtools/overrides/gkehub/feature_membership.yaml @@ -24,4 +24,12 @@ field: mesh.control_plane details: message: >- - Deprecated in favor of the `management` field \ No newline at end of file + Deprecated in favor of the `management` field +- type: COMPLEX_MAP_KEY_NAME + field: policycontroller.policy_controller_hub_config.policy_content.bundles + details: + keyname: bundle_name +- type: COMPLEX_MAP_KEY_NAME + field: policycontroller.policy_controller_hub_config.deployment_configs + details: + keyname: component_name \ No newline at end of file diff --git a/tpgtools/property.go b/tpgtools/property.go index f7939be2a3d9..62e5aa4fa51c 100644 --- a/tpgtools/property.go +++ b/tpgtools/property.go @@ -107,6 +107,10 @@ type Property struct { // Sub-properties of nested objects or arrays with nested objects Properties []Property + // If this is a complex map type, this string represents the name of the + // field that the key to the map can be set with + ComplexMapKeyName string + // Reference to the parent resource. // note: "Properties" will not be available. resource *Resource @@ -198,13 +202,24 @@ func (p Property) ObjectType() string { } func (p Property) IsArray() bool { - return (p.Type.String() == SchemaTypeList || p.Type.String() == SchemaTypeSet) && !p.Type.IsObject() + return (p.Type.String() == SchemaTypeList || p.Type.String() == SchemaTypeSet) && !p.Type.IsObject() && !p.IsComplexMap() } func (t Type) IsSet() bool { return t.String() == SchemaTypeSet } +// Complex map is for maps of string --> object that are supported in DCL but +// not in Terraform. We handle this by adding a field in the Terraform schema +// for the key in the map. This must be added via a COMPLEX_MAP_KEY_NAME +// override +func (t Type) IsComplexMap() bool { + if t.typ.AdditionalProperties != nil { + return t.typ.AdditionalProperties.Type != "string" + } + return false +} + // ShouldGenerateNestedSchema returns true if an object's nested schema function should be generated. func (p Property) ShouldGenerateNestedSchema() bool { return len(p.Properties) > 0 && !p.Collapsed @@ -278,6 +293,9 @@ func buildGetter(p Property, rawGetter string) string { if p.Type.IsEnumArray() { return fmt.Sprintf("expand%s%sArray(%s)", p.resource.PathType(), p.PackagePath(), rawGetter) } + if p.Type.IsComplexMap() { + return fmt.Sprintf("expand%s%sMap(%s)", p.resource.PathType(), p.PackagePath(), rawGetter) + } if p.Type.typ.Items != nil && p.Type.typ.Items.Type == "string" { return fmt.Sprintf("tpgdclresource.ExpandStringArray(%s)", rawGetter) } @@ -317,6 +335,9 @@ func (p Property) DefaultStateSetter() string { return fmt.Sprintf("d.Set(%q, res.%s)", p.Name(), p.PackageName) case SchemaTypeList, SchemaTypeSet: + if p.IsComplexMap() { + return fmt.Sprintf("d.Set(%q, flatten%s%sMap(res.%s))", p.Name(), p.resource.PathType(), p.PackagePath(), p.PackageName) + } if p.typ.Items != nil && ((p.typ.Items.Type == "string" && len(p.typ.Items.Enum) == 0) || p.typ.Items.Type == "integer") { return fmt.Sprintf("d.Set(%q, res.%s)", p.Name(), p.PackageName) } @@ -365,6 +386,9 @@ func (p Property) flattenGetterWithParent(parent string) string { if p.Type.IsEnumArray() { return fmt.Sprintf("flatten%s%sArray(obj.%s)", p.resource.PathType(), p.PackagePath(), p.PackageName) } + if p.Type.IsComplexMap() { + return fmt.Sprintf("flatten%s%sMap(%s.%s)", p.resource.PathType(), p.PackagePath(), parent, p.PackageName) + } if p.Type.typ.Items != nil && p.Type.typ.Items.Type == "integer" { return fmt.Sprintf("%s.%s", parent, p.PackageName) } @@ -376,7 +400,6 @@ func (p Property) flattenGetterWithParent(parent string) string { return fmt.Sprintf("flatten%s%sArray(%s.%s)", p.resource.PathType(), p.PackagePath(), parent, p.PackageName) } } - if p.typ.Type == "object" { return fmt.Sprintf("flatten%s%s(%s.%s)", p.resource.PathType(), p.PackagePath(), parent, p.PackageName) } @@ -651,6 +674,38 @@ func createPropertiesFromSchema(schema *openapi.Schema, typeFetcher *TypeFetcher p.ElemIsBasicType = true } } + // Complex maps are represented as TypeSet but don't have v.Items set. + // Use AdditionalProperties instead, and add an additional `name` field + // that represents the key in the map + if p.Type.IsComplexMap() { + props, err := createPropertiesFromSchema(p.Type.typ.AdditionalProperties, typeFetcher, overrides, resource, &p, location) + if err != nil { + return nil, err + } + cm := ComplexMapKeyDetails{} + cmOk, err := overrides.PropertyOverrideWithDetails(ComplexMapKey, p, &cm, location) + if err != nil { + return nil, fmt.Errorf("failed to decode complex map key name details") + } + if !cmOk { + return nil, fmt.Errorf("failed to find complex map key name for map named: %s", p.Name()) + } + keyProp := Property{ + title: cm.KeyName, + Type: Type{&openapi.Schema{Type: "string"}}, + resource: resource, + parent: &p, + Required: true, + Description: "The name for the key in the map for which this object is mapped to in the API", + } + props = append([]Property{keyProp}, props...) + + p.Properties = props + e := fmt.Sprintf("%s%sSchema()", resource.PathType(), p.PackagePath()) + p.Elem = &e + p.ElemIsBasicType = false + p.ComplexMapKeyName = cm.KeyName + } if !p.Computed { if stringInSlice(v.Title, schema.Required) { @@ -779,7 +834,7 @@ func createPropertiesFromSchema(schema *openapi.Schema, typeFetcher *TypeFetcher p.ValidateFunc = &vf.Function } - if p.Type.String() == SchemaTypeSet { + if p.Type.IsSet() { shf := SetHashFuncDetails{} shfOk, err := overrides.PropertyOverrideWithDetails(SetHashFunc, p, &shf, location) if err != nil { diff --git a/tpgtools/templates/resource.go.tmpl b/tpgtools/templates/resource.go.tmpl index 8de8fa398c60..b65085ba771f 100644 --- a/tpgtools/templates/resource.go.tmpl +++ b/tpgtools/templates/resource.go.tmpl @@ -661,6 +661,39 @@ func expand{{$.PathType}}{{$v.PackagePath}}Array(o interface{}) []{{$.Package}}. items = append(items, *i) } + return items +} + {{- end }} + + {{ if $v.IsComplexMap -}} +func expand{{$.PathType}}{{$v.PackagePath}}Map(o interface{}) map[string]{{$.Package}}.{{$v.ObjectType}} { + if o == nil { + {{- if $v.Computed }} + return nil + {{- else }} + return make(map[string]{{$.Package}}.{{$v.ObjectType}}) + {{- end }} + } + + o = o.(*schema.Set).List() + + objs := o.([]interface{}) + if len(objs) == 0 || objs[0] == nil { + {{- if $v.Computed }} + return nil + {{- else }} + return make(map[string]{{$.Package}}.{{$v.ObjectType}}) + {{- end }} + } + + items := make(map[string]{{$.Package}}.{{$v.ObjectType}}) + for _, item := range objs { + i := expand{{$.PathType}}{{$v.PackagePath}}(item) + if item != nil { + items[item.(map[string]interface{})["{{$v.ComplexMapKeyName}}"].(string)] = *i + } + } + return items } {{- end }} @@ -688,7 +721,7 @@ func expand{{$.PathType}}{{$v.PackagePath}}(o interface{}) *{{$.Package}}.{{$v.O {{- end }} return &{{$.Package}}.{{$v.ObjectType}}{ {{- range $p := $v.Properties }} - {{- if and ($p.Settable) ($p.ExpandGetter) }} + {{- if and ($p.Settable) ($p.ExpandGetter) (or (not $v.IsComplexMap) (ne $p.Name $v.ComplexMapKeyName)) }} {{$p.PackageName}}: {{$p.ExpandGetter}}, {{- end -}} {{ end }} @@ -713,17 +746,36 @@ func flatten{{$.PathType}}{{$v.PackagePath}}Array(objs []{{$.Package}}.{{$v.Obje } {{- end }} -func flatten{{$.PathType}}{{$v.PackagePath}}(obj *{{$.Package}}.{{$v.ObjectType}}) interface{} { - if obj == nil || obj.Empty(){ + {{ if $v.IsComplexMap -}} +func flatten{{$.PathType}}{{$v.PackagePath}}Map(objs map[string]{{$.Package}}.{{$v.ObjectType}}) []interface{} { + if objs == nil { + return nil + } + + items := []interface{}{} + for name, item := range objs { + i := flatten{{$.PathType}}{{$v.PackagePath}}(&item, name) + items = append(items, i) + } + + return items +} + {{- end }} + +func flatten{{$.PathType}}{{$v.PackagePath}}(obj *{{$.Package}}.{{$v.ObjectType}}{{- if $v.IsComplexMap -}}, name string{{- end -}}) interface{} { + if obj == nil {{- if not $v.IsComplexMap -}}|| obj.Empty(){{- end -}}{ return nil } transformed := map[string]interface{}{ {{- range $p := $v.Properties }} - {{- if ($p.FlattenGetter) }} + {{- if or (not $v.IsComplexMap) (ne $p.Name $v.ComplexMapKeyName) }} "{{$p.Name}}": {{$p.FlattenGetter}}, {{- end -}} {{ end }} } +{{ if $v.IsComplexMap }} + transformed["{{$v.ComplexMapKeyName}}"] = name +{{ end }} {{ if $v.IsObject }} return []interface{}{transformed} {{ else }} diff --git a/tpgtools/type.go b/tpgtools/type.go index 47adedaa30c9..cb31f0a7c562 100644 --- a/tpgtools/type.go +++ b/tpgtools/type.go @@ -67,14 +67,13 @@ func (t Type) String() string { } return "unknown number type" case "object": - // assume if this is set, it's a string -> string map for now. - // https://swagger.io/docs/specification/data-models/dictionaries/ - // describes the behaviour of AdditionalProperties for type: object if t.typ.AdditionalProperties != nil { if v := t.typ.AdditionalProperties.Type; v == "string" { return SchemaTypeMap } else { - return fmt.Sprintf("unknown AdditionalProperties: %q", v) + // Complex maps are handled as sets with an extra value for the + // name of the object + return SchemaTypeSet } } return SchemaTypeList From c4d1efa32fa9aec82c1951a596f115b2ac443d88 Mon Sep 17 00:00:00 2001 From: Jared Date: Mon, 4 Mar 2024 13:55:57 -0800 Subject: [PATCH 03/32] fix permadiff by reading empty docker_config field (#10113) --- mmv1/products/artifactregistry/Repository.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/mmv1/products/artifactregistry/Repository.yaml b/mmv1/products/artifactregistry/Repository.yaml index 6e0c73eb468f..965a3fab1923 100644 --- a/mmv1/products/artifactregistry/Repository.yaml +++ b/mmv1/products/artifactregistry/Repository.yaml @@ -181,6 +181,7 @@ properties: name: 'dockerConfig' description: |- Docker repository config contains repository level configuration for the repositories of docker type. + allow_empty_object: true properties: - !ruby/object:Api::Type::Boolean name: 'immutableTags' From d62a06fc45213066de668f6a8dab4814ae382ec0 Mon Sep 17 00:00:00 2001 From: Zhenhua Li Date: Mon, 4 Mar 2024 14:07:53 -0800 Subject: [PATCH 04/32] Import package golang.org/x/exp/slices in MMv1 go compiler (#10108) --- mmv1/go.mod | 4 ++-- mmv1/go.sum | 1 + mmv1/main.go | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mmv1/go.mod b/mmv1/go.mod index e1751dddea23..24d9a6c630d1 100644 --- a/mmv1/go.mod +++ b/mmv1/go.mod @@ -3,6 +3,6 @@ module github.com/GoogleCloudPlatform/magic-modules/mmv1 go 1.20 require ( - golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 + gopkg.in/yaml.v2 v2.4.0 ) diff --git a/mmv1/go.sum b/mmv1/go.sum index 0423d8d040b3..b8ec4cc09d5a 100644 --- a/mmv1/go.sum +++ b/mmv1/go.sum @@ -1,5 +1,6 @@ golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/mmv1/main.go b/mmv1/main.go index e969a8f8d02e..b23108ac117a 100644 --- a/mmv1/main.go +++ b/mmv1/main.go @@ -6,10 +6,11 @@ import ( "os" "path" "path/filepath" - "slices" "sort" "strings" + "golang.org/x/exp/slices" + "github.com/GoogleCloudPlatform/magic-modules/mmv1/api" "github.com/GoogleCloudPlatform/magic-modules/mmv1/google" "github.com/GoogleCloudPlatform/magic-modules/mmv1/provider" From 216fffd274b08af2e3f718d3d8aeb8cb6410b420 Mon Sep 17 00:00:00 2001 From: Joakim Tangnes <10198932+Zarux@users.noreply.github.com> Date: Mon, 4 Mar 2024 23:49:48 +0100 Subject: [PATCH 05/32] fix(kms): certificate chain type to array of strings (#9582) --- mmv1/products/kms/CryptoKeyVersion.yaml | 9 ++- .../kms/resource_kms_crypto_key_test.go | 67 +++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/mmv1/products/kms/CryptoKeyVersion.yaml b/mmv1/products/kms/CryptoKeyVersion.yaml index b193fee87c02..4fc87f93a051 100644 --- a/mmv1/products/kms/CryptoKeyVersion.yaml +++ b/mmv1/products/kms/CryptoKeyVersion.yaml @@ -104,15 +104,18 @@ properties: description: | The certificate chains needed to validate the attestation properties: - - !ruby/object:Api::Type::String + - !ruby/object:Api::Type::Array + item_type: Api::Type::String name: 'caviumCerts' description: | Cavium certificate chain corresponding to the attestation. - - !ruby/object:Api::Type::String + - !ruby/object:Api::Type::Array + item_type: Api::Type::String name: 'googleCardCerts' description: | Google card certificate chain corresponding to the attestation. - - !ruby/object:Api::Type::String + - !ruby/object:Api::Type::Array + item_type: Api::Type::String name: 'googlePartitionCerts' description: | Google partition certificate chain corresponding to the attestation. diff --git a/mmv1/third_party/terraform/services/kms/resource_kms_crypto_key_test.go b/mmv1/third_party/terraform/services/kms/resource_kms_crypto_key_test.go index 328fc50734d7..29c650fa0ecb 100644 --- a/mmv1/third_party/terraform/services/kms/resource_kms_crypto_key_test.go +++ b/mmv1/third_party/terraform/services/kms/resource_kms_crypto_key_test.go @@ -444,6 +444,35 @@ func TestAccKmsCryptoKeyVersion_basic(t *testing.T) { }) } +func TestAccKmsCryptoKeyVersionWithSymmetricHSM(t *testing.T) { + t.Parallel() + + projectId := fmt.Sprintf("tf-test-%d", acctest.RandInt(t)) + projectOrg := envvar.GetTestOrgFromEnv(t) + projectBillingAccount := envvar.GetTestBillingAccountFromEnv(t) + keyRingName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + cryptoKeyName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testGoogleKmsCryptoKeyVersionWithSymmetricHSM(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName), + }, + { + ResourceName: "google_kms_crypto_key_version.crypto_key_version", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testGoogleKmsCryptoKeyVersion_removed(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName), + }, + }, + }) +} + func TestAccKmsCryptoKeyVersion_skipInitialVersion(t *testing.T) { t.Parallel() @@ -747,6 +776,44 @@ resource "google_kms_crypto_key_version" "crypto_key_version" { `, projectId, projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName) } +func testGoogleKmsCryptoKeyVersionWithSymmetricHSM(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName string) string { + return fmt.Sprintf(` +resource "google_project" "acceptance" { + name = "%s" + project_id = "%s" + org_id = "%s" + billing_account = "%s" +} + +resource "google_project_service" "acceptance" { + project = google_project.acceptance.project_id + service = "cloudkms.googleapis.com" +} + +resource "google_kms_key_ring" "key_ring" { + project = google_project_service.acceptance.project + name = "%s" + location = "us-central1" +} + +resource "google_kms_crypto_key" "crypto_key" { + name = "%s" + key_ring = google_kms_key_ring.key_ring.id + labels = { + key = "value" + } + version_template { + algorithm = "GOOGLE_SYMMETRIC_ENCRYPTION" + protection_level = "HSM" + } +} + +resource "google_kms_crypto_key_version" "crypto_key_version" { + crypto_key = google_kms_crypto_key.crypto_key.id +} +`, projectId, projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName) +} + func testGoogleKmsCryptoKeyVersion_removed(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName string) string { return fmt.Sprintf(` resource "google_project" "acceptance" { From 2c6c6a10d96b6489c88445b5c55f70a306fede5a Mon Sep 17 00:00:00 2001 From: Sarah French <15078782+SarahFrench@users.noreply.github.com> Date: Tue, 5 Mar 2024 10:53:25 +0000 Subject: [PATCH 06/32] Bump GHA actions to navigate deprecations of NodeJS 12 and 16 (#10110) * Update all uses of `actions/cache` to v3 * Update all uses of `actions/checkout` to v4 * Update all uses of `actions/upload-artifact` to v3.1.0 * Update all uses of `actions/setup-go` to v4.0.0 * Update all uses of `ruby/setup-ruby` to v1.160.0 from v1.144.2 [v1.160.0](https://github.com/ruby/setup-ruby/releases/tag/v1.160.0) is the version after they upgraded to NodeJS 20 where they fixed some issues from the upgrade from nodejs 16->20 The previous version, ruby/setup-ruby@ec02537da5712d66d4d50a0f33b7eb52773b5ed1, is v1.144.2 --- .github/workflows/build-downstream.yml | 12 ++++++------ .github/workflows/changelog-checker.yml | 2 +- .github/workflows/magic-modules.yml | 6 +++--- .github/workflows/membership-checker.yml | 2 +- .github/workflows/repository-documentation.yml | 2 +- .../teamcity-services-diff-check-weekly.yml | 4 ++-- .github/workflows/teamcity-services-diff-check.yml | 6 +++--- .github/workflows/test-tgc.yml | 4 ++-- .github/workflows/test-tpg.yml | 4 ++-- .github/workflows/unit-test-tgc.yml | 2 +- .github/workflows/unit-test-tpg.yml | 2 +- .github/workflows/unit-tests-diff-processor.yml | 2 +- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/build-downstream.yml b/.github/workflows/build-downstream.yml index f8446388ee65..91f33499bd10 100644 --- a/.github/workflows/build-downstream.yml +++ b/.github/workflows/build-downstream.yml @@ -21,17 +21,17 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Ruby - uses: ruby/setup-ruby@ec02537da5712d66d4d50a0f33b7eb52773b5ed1 + uses: ruby/setup-ruby@036ef458ddccddb148a2b9fb67e95a22fdbf728b # v1.160.0 with: ruby-version: '3.1' - name: Cache Bundler gems - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: mmv1/vendor/bundle key: ${{ runner.os }}-gems-${{ hashFiles('mmv1/**/Gemfile.lock') }} @@ -45,13 +45,13 @@ jobs: working-directory: mmv1 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: '^1.20' # Cache Go modules - name: Cache Go modules - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} @@ -108,7 +108,7 @@ jobs: (current_dir=$(pwd) && cd $OUTPUT_PATH && zip -r "$current_dir/output.zip" .) - name: Upload built artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 with: name: artifact-${{ inputs.repo }} path: output.zip \ No newline at end of file diff --git a/.github/workflows/changelog-checker.yml b/.github/workflows/changelog-checker.yml index 3158329b9c84..4e546f0e05e5 100644 --- a/.github/workflows/changelog-checker.yml +++ b/.github/workflows/changelog-checker.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: repo - name: Check Changelog diff --git a/.github/workflows/magic-modules.yml b/.github/workflows/magic-modules.yml index 1a2c88510fa2..d92e666e2b60 100644 --- a/.github/workflows/magic-modules.yml +++ b/.github/workflows/magic-modules.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: repo fetch-depth: 0 @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: repo fetch-depth: 2 @@ -49,7 +49,7 @@ jobs: git fetch origin ${{ github.base_ref }} # Fetch the base branch git merge --no-ff origin/${{ github.base_ref }} # Merge with the base branch - name: Set up Ruby - uses: ruby/setup-ruby@ec02537da5712d66d4d50a0f33b7eb52773b5ed1 + uses: ruby/setup-ruby@036ef458ddccddb148a2b9fb67e95a22fdbf728b # v1.160.0 with: ruby-version: '3.1' - name: Install dependencies diff --git a/.github/workflows/membership-checker.yml b/.github/workflows/membership-checker.yml index 2612f2c61679..7a206b519eaa 100644 --- a/.github/workflows/membership-checker.yml +++ b/.github/workflows/membership-checker.yml @@ -11,7 +11,7 @@ jobs: build-and-unit-tests: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v4 with: diff --git a/.github/workflows/repository-documentation.yml b/.github/workflows/repository-documentation.yml index 6ff5b1bbf966..531673c5788f 100644 --- a/.github/workflows/repository-documentation.yml +++ b/.github/workflows/repository-documentation.yml @@ -12,7 +12,7 @@ jobs: deploy: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true # Fetch Hugo themes (true OR recursive) fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod diff --git a/.github/workflows/teamcity-services-diff-check-weekly.yml b/.github/workflows/teamcity-services-diff-check-weekly.yml index 874fd3145913..5d857f0eda90 100644 --- a/.github/workflows/teamcity-services-diff-check-weekly.yml +++ b/.github/workflows/teamcity-services-diff-check-weekly.yml @@ -26,10 +26,10 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: '^1.20' diff --git a/.github/workflows/teamcity-services-diff-check.yml b/.github/workflows/teamcity-services-diff-check.yml index f425a6e009f4..37dd8e218554 100644 --- a/.github/workflows/teamcity-services-diff-check.yml +++ b/.github/workflows/teamcity-services-diff-check.yml @@ -15,7 +15,7 @@ jobs: services: ${{steps.services.outputs.services}} steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: "Check for New Services" @@ -45,10 +45,10 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: '^1.20' diff --git a/.github/workflows/test-tgc.yml b/.github/workflows/test-tgc.yml index 1546a5c856ee..32e290364067 100644 --- a/.github/workflows/test-tgc.yml +++ b/.github/workflows/test-tgc.yml @@ -36,7 +36,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ${{ github.event.inputs.owner }}/${{ github.event.inputs.repo }} ref: ${{ github.event.inputs.branch }} @@ -79,7 +79,7 @@ jobs: }' - name: Set up Go if: ${{ !failure() && steps.pull_request.outputs.has_changes == 'true' }} - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: '^1.20' - name: Build Terraform Google Conversion diff --git a/.github/workflows/test-tpg.yml b/.github/workflows/test-tpg.yml index dd05cecf003a..eff5cdc3755e 100644 --- a/.github/workflows/test-tpg.yml +++ b/.github/workflows/test-tpg.yml @@ -36,7 +36,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ${{ github.event.inputs.owner }}/${{ github.event.inputs.repo }} ref: ${{ github.event.inputs.branch }} @@ -70,7 +70,7 @@ jobs: }' - name: Set up Go if: ${{ !failure() && steps.pull_request.outputs.has_changes == 'true' }} - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: '^1.20' - name: Build Provider diff --git a/.github/workflows/unit-test-tgc.yml b/.github/workflows/unit-test-tgc.yml index e1c983d92ba8..f254f91240db 100644 --- a/.github/workflows/unit-test-tgc.yml +++ b/.github/workflows/unit-test-tgc.yml @@ -28,7 +28,7 @@ jobs: rm artifacts-tpgb/output.zip - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: '^1.20' diff --git a/.github/workflows/unit-test-tpg.yml b/.github/workflows/unit-test-tpg.yml index 23aa27e848ed..ac925a0fe621 100644 --- a/.github/workflows/unit-test-tpg.yml +++ b/.github/workflows/unit-test-tpg.yml @@ -26,7 +26,7 @@ jobs: rm artifacts/output.zip - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: '^1.20' diff --git a/.github/workflows/unit-tests-diff-processor.yml b/.github/workflows/unit-tests-diff-processor.yml index 638fb42c60c5..91d081716ab3 100644 --- a/.github/workflows/unit-tests-diff-processor.yml +++ b/.github/workflows/unit-tests-diff-processor.yml @@ -11,7 +11,7 @@ jobs: test: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v4 From 3791c34c28ff987929f1e1869c9eba723c80a095 Mon Sep 17 00:00:00 2001 From: Sarah French <15078782+SarahFrench@users.noreply.github.com> Date: Tue, 5 Mar 2024 11:14:28 +0000 Subject: [PATCH 07/32] Address dependency issues in TestAccFirestoreField_* tests (#9957) * Add additional wait in TestAccFirestoreField_* tests * Boost wait in test to 6 minutes * Add dependency between database and service to control delete order * Update dependency to explicitly include project * Make firestore fields be removed from state when they're 'deleted' * Add `destroy_duration` * Remove from state after log line that uses id value * Update destory check to accept a 403 as valid * Remove unneeded changes in PR * Remove call to SetId --- .../custom_check_destroy/firestore_field.go.erb | 11 ++++++++++- .../firestore/resource_firestore_field_test.go | 8 ++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/mmv1/templates/terraform/custom_check_destroy/firestore_field.go.erb b/mmv1/templates/terraform/custom_check_destroy/firestore_field.go.erb index f3caa9775cca..7b5fe9d1fffc 100644 --- a/mmv1/templates/terraform/custom_check_destroy/firestore_field.go.erb +++ b/mmv1/templates/terraform/custom_check_destroy/firestore_field.go.erb @@ -16,7 +16,16 @@ res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ UserAgent: config.UserAgent, }) if err != nil { - return err + e := err.(*googleapi.Error) + if e.Code == 403 && strings.Contains(e.Message, "Cloud Firestore API has not been used in project") { + // The acceptance test has provisioned the resources under test in a new project, and the destory check is seeing the + // effects of the project not existing. This means the service isn't enabled, and that the resource is definitely destroyed. + // We do not return the error in this case - destroy was successful + return nil + } + + // Return err in all other cases + return err } if v := res["indexConfig"]; v != nil { diff --git a/mmv1/third_party/terraform/services/firestore/resource_firestore_field_test.go b/mmv1/third_party/terraform/services/firestore/resource_firestore_field_test.go index 794b5f8369a5..8be524c6e99a 100644 --- a/mmv1/third_party/terraform/services/firestore/resource_firestore_field_test.go +++ b/mmv1/third_party/terraform/services/firestore/resource_firestore_field_test.go @@ -103,7 +103,11 @@ resource "google_firestore_database" "database" { location_id = "nam5" type = "FIRESTORE_NATIVE" - depends_on = [google_project_service.firestore] + # used to control delete order + depends_on = [ + google_project_service.firestore, + google_project.project + ] } `, context) } else { @@ -115,7 +119,7 @@ resource "google_firestore_database" "database" { type = "FIRESTORE_NATIVE" delete_protection_state = "DELETE_PROTECTION_DISABLED" - deletion_policy = "DELETE" + deletion_policy = "DELETE" } `, context) } From 0249d74bdb046afe63b6562f40b7cfa315eeb8b2 Mon Sep 17 00:00:00 2001 From: Laurens Knoll <3205006+laurensknoll@users.noreply.github.com> Date: Tue, 5 Mar 2024 15:45:55 +0100 Subject: [PATCH 08/32] add network_url attribute in consumer_accept_list block of google_compute_service_attachment resource (#9895) * add network_url attribute in consumer_accept_list block of google_compute_service_attachment resource * Bugfix: Use SelfLinkRelativePath check to prevent false positive resource changes --- mmv1/products/compute/ServiceAttachment.yaml | 26 ++++- .../compute_service_attachment.go.erb | 50 ++++++++++ ...ervice_attachment_explicit_networks.tf.erb | 97 +++++++++++++++++++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 mmv1/templates/terraform/constants/compute_service_attachment.go.erb create mode 100644 mmv1/templates/terraform/examples/service_attachment_explicit_networks.tf.erb diff --git a/mmv1/products/compute/ServiceAttachment.yaml b/mmv1/products/compute/ServiceAttachment.yaml index f913840817a1..a7609767f815 100644 --- a/mmv1/products/compute/ServiceAttachment.yaml +++ b/mmv1/products/compute/ServiceAttachment.yaml @@ -68,6 +68,20 @@ examples: producer_forwarding_rule_name: 'producer-forwarding-rule' consumer_address_name: 'psc-ilb-consumer-address' consumer_forwarding_rule_name: 'psc-ilb-consumer-forwarding-rule' + - !ruby/object:Provider::Terraform::Examples + name: 'service_attachment_explicit_networks' + primary_resource_id: 'psc_ilb_service_attachment' + vars: + service_attachment_name: 'my-psc-ilb' + network_name: 'psc-ilb-network' + nat_subnetwork_name: 'psc-ilb-nat' + producer_subnetwork_name: 'psc-ilb-producer-subnetwork' + producer_health_check_name: 'producer-service-health-check' + producer_service_name: 'producer-service' + producer_forwarding_rule_name: 'producer-forwarding-rule' + consumer_network_name: 'psc-ilb-consumer-network' + consumer_address_name: 'psc-ilb-consumer-address' + consumer_forwarding_rule_name: 'psc-ilb-consumer-forwarding-rule' - !ruby/object:Provider::Terraform::Examples name: 'service_attachment_reconcile_connections' primary_resource_id: 'psc_ilb_service_attachment' @@ -82,6 +96,7 @@ examples: consumer_address_name: 'psc-ilb-consumer-address' consumer_forwarding_rule_name: 'psc-ilb-consumer-forwarding-rule' custom_code: !ruby/object:Provider::Terraform::CustomCode + constants: templates/terraform/constants/compute_service_attachment.go.erb update_encoder: 'templates/terraform/update_encoder/compute_service_attachment.go.erb' parameters: - !ruby/object:Api::Type::ResourceRef @@ -194,13 +209,22 @@ properties: attachment. send_empty_value: true is_set: true + set_hash_func: computeServiceAttachmentConsumerAcceptListsHash item_type: !ruby/object:Api::Type::NestedObject properties: - !ruby/object:Api::Type::String name: 'projectIdOrNum' - required: true + # TODO (laurensknoll): add exactly_one_of when it can be applied to lists (https://github.com/hashicorp/terraform-plugin-sdk/issues/470) description: | A project that is allowed to connect to this service attachment. + Only one of project_id_or_num and network_url may be set. + - !ruby/object:Api::Type::String + name: 'networkUrl' + # TODO (laurensknoll): add exactly_one_of when it can be applied to lists (https://github.com/hashicorp/terraform-plugin-sdk/issues/470) + description: | + The network that is allowed to connect to this service attachment. + Only one of project_id_or_num and network_url may be set. + diff_suppress_func: 'tpgresource.CompareSelfLinkRelativePaths' - !ruby/object:Api::Type::Integer name: 'connectionLimit' required: true diff --git a/mmv1/templates/terraform/constants/compute_service_attachment.go.erb b/mmv1/templates/terraform/constants/compute_service_attachment.go.erb new file mode 100644 index 000000000000..ee6a557b2f22 --- /dev/null +++ b/mmv1/templates/terraform/constants/compute_service_attachment.go.erb @@ -0,0 +1,50 @@ +<%# The license inside this block applies to this file. + # Copyright 2020 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. +-%> + +// Hash based on key, which is either project_id_or_num or network_url. +func computeServiceAttachmentConsumerAcceptListsHash(v interface{}) int { + if v == nil { + return 0 + } + + var buf bytes.Buffer + m := v.(map[string]interface{}) + log.Printf("[DEBUG] hashing %v", m) + + if v, ok := m["project_id_or_num"]; ok { + if v == nil { + v = "" + } + + buf.WriteString(fmt.Sprintf("%v-", v)) + } + + if v, ok := m["network_url"]; ok { + if v == nil { + v = "" + } else { + if networkUrl, err := tpgresource.GetRelativePath(v.(string)); err != nil { + log.Printf("[WARN] Error on retrieving relative path of network url: %s", err) + } else { + v = networkUrl + } + } + + buf.WriteString(fmt.Sprintf("%v-", v)) + } + + log.Printf("[DEBUG] computed hash value of %v from %v", tpgresource.Hashcode(buf.String()), buf.String()) + return tpgresource.Hashcode(buf.String()) +} diff --git a/mmv1/templates/terraform/examples/service_attachment_explicit_networks.tf.erb b/mmv1/templates/terraform/examples/service_attachment_explicit_networks.tf.erb new file mode 100644 index 000000000000..a66f689582af --- /dev/null +++ b/mmv1/templates/terraform/examples/service_attachment_explicit_networks.tf.erb @@ -0,0 +1,97 @@ +resource "google_compute_service_attachment" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]['service_attachment_name'] %>" + region = "us-west2" + description = "A service attachment configured with Terraform" + + enable_proxy_protocol = false + + connection_preference = "ACCEPT_MANUAL" + nat_subnets = [google_compute_subnetwork.psc_ilb_nat.id] + target_service = google_compute_forwarding_rule.psc_ilb_target_service.id + + consumer_accept_lists { + network_url = google_compute_network.psc_ilb_consumer_network.self_link + connection_limit = 1 + } +} + +resource "google_compute_network" "psc_ilb_consumer_network" { + name = "<%= ctx[:vars]['consumer_network_name'] %>" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "psc_ilb_consumer_subnetwork" { + name = "<%= ctx[:vars]['consumer_network_name'] %>" + ip_cidr_range = "10.0.0.0/16" + region = "us-west2" + network = google_compute_network.psc_ilb_consumer_network.id +} + +resource "google_compute_address" "psc_ilb_consumer_address" { + name = "<%= ctx[:vars]['consumer_address_name'] %>" + region = "us-west2" + + subnetwork = google_compute_subnetwork.psc_ilb_consumer_subnetwork.id + address_type = "INTERNAL" +} + +resource "google_compute_forwarding_rule" "psc_ilb_consumer" { + name = "<%= ctx[:vars]['consumer_forwarding_rule_name'] %>" + region = "us-west2" + + target = google_compute_service_attachment.psc_ilb_service_attachment.id + load_balancing_scheme = "" # need to override EXTERNAL default when target is a service attachment + network = google_compute_network.psc_ilb_consumer_network.id + subnetwork = google_compute_subnetwork.psc_ilb_consumer_subnetwork.id + ip_address = google_compute_address.psc_ilb_consumer_address.id +} + +resource "google_compute_forwarding_rule" "psc_ilb_target_service" { + name = "<%= ctx[:vars]['producer_forwarding_rule_name'] %>" + region = "us-west2" + + load_balancing_scheme = "INTERNAL" + backend_service = google_compute_region_backend_service.producer_service_backend.id + all_ports = true + network = google_compute_network.psc_ilb_network.name + subnetwork = google_compute_subnetwork.psc_ilb_producer_subnetwork.name +} + +resource "google_compute_region_backend_service" "producer_service_backend" { + name = "<%= ctx[:vars]['producer_service_name'] %>" + region = "us-west2" + + health_checks = [google_compute_health_check.producer_service_health_check.id] +} + +resource "google_compute_health_check" "producer_service_health_check" { + name = "<%= ctx[:vars]['producer_health_check_name'] %>" + + check_interval_sec = 1 + timeout_sec = 1 + tcp_health_check { + port = "80" + } +} + +resource "google_compute_network" "psc_ilb_network" { + name = "<%= ctx[:vars]['network_name'] %>" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "psc_ilb_producer_subnetwork" { + name = "<%= ctx[:vars]['producer_subnetwork_name'] %>" + region = "us-west2" + + network = google_compute_network.psc_ilb_network.id + ip_cidr_range = "10.0.0.0/16" +} + +resource "google_compute_subnetwork" "psc_ilb_nat" { + name = "<%= ctx[:vars]['nat_subnetwork_name'] %>" + region = "us-west2" + + network = google_compute_network.psc_ilb_network.id + purpose = "PRIVATE_SERVICE_CONNECT" + ip_cidr_range = "10.1.0.0/16" +} From d9a016547e57b25a192bfb628f30d78b5a464ad8 Mon Sep 17 00:00:00 2001 From: Rustem Bekmukhametov Date: Tue, 5 Mar 2024 08:38:53 -0800 Subject: [PATCH 09/32] Update the GCF resource to reflect transition from Container Registry to Artifact Registry (#10058) --- .../cloudfunctions/resource_cloudfunctions_function.go | 2 +- .../resource_cloudfunctions_function_test.go.erb | 6 +++--- .../website/docs/r/cloudfunctions_function.html.markdown | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go index b6d3d77906e2..4c3c1489dd66 100644 --- a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go +++ b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go @@ -201,7 +201,7 @@ func ResourceCloudFunctionsFunction() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - Description: `Docker Registry to use for storing the function's Docker images. Allowed values are CONTAINER_REGISTRY (default) and ARTIFACT_REGISTRY.`, + Description: `Docker Registry to use for storing the function's Docker images. Allowed values are ARTIFACT_REGISTRY (default) and CONTAINER_REGISTRY.`, }, "docker_repository": { diff --git a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.erb b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.erb index 61a267c0fcd8..6288ae43d97b 100644 --- a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.erb +++ b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.erb @@ -52,7 +52,7 @@ func TestAccCloudFunctionsFunction_basic(t *testing.T) { resource.TestCheckResourceAttr(funcResourceName, "description", "test function"), resource.TestCheckResourceAttr(funcResourceName, - "docker_registry", "CONTAINER_REGISTRY"), + "docker_registry", "ARTIFACT_REGISTRY"), resource.TestCheckResourceAttr(funcResourceName, "available_memory_mb", "128"), resource.TestCheckResourceAttr(funcResourceName, @@ -659,7 +659,7 @@ resource "google_cloudfunctions_function" "function" { name = "%s" runtime = "nodejs10" description = "test function" - docker_registry = "CONTAINER_REGISTRY" + docker_registry = "ARTIFACT_REGISTRY" available_memory_mb = 128 source_archive_bucket = google_storage_bucket.bucket.name source_archive_object = google_storage_bucket_object.archive.name @@ -762,7 +762,7 @@ resource "google_cloudfunctions_function" "function" { name = "%[3]s" runtime = "nodejs10" description = "test function" - docker_registry = "CONTAINER_REGISTRY" + docker_registry = "ARTIFACT_REGISTRY" available_memory_mb = 128 source_archive_bucket = google_storage_bucket.bucket.name source_archive_object = google_storage_bucket_object.archive.name diff --git a/mmv1/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown b/mmv1/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown index 5cfb46f700fe..b24afb988530 100644 --- a/mmv1/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown @@ -162,9 +162,9 @@ Please refer to the field 'effective_labels' for all of the labels present on th * `source_repository` - (Optional) Represents parameters related to source repository where a function is hosted. Cannot be set alongside `source_archive_bucket` or `source_archive_object`. Structure is [documented below](#nested_source_repository). It must match the pattern `projects/{project}/locations/{location}/repositories/{repository}`.* -* `docker_registry` - (Optional) Docker Registry to use for storing the function's Docker images. Allowed values are CONTAINER_REGISTRY (default) and ARTIFACT_REGISTRY. +* `docker_registry` - (Optional) Docker Registry to use for storing the function's Docker images. Allowed values are ARTIFACT_REGISTRY (default) and CONTAINER_REGISTRY. -* `docker_repository` - (Optional) User managed repository created in Artifact Registry optionally with a customer managed encryption key. If specified, deployments will use Artifact Registry. This is the repository to which the function docker image will be pushed after it is built by Cloud Build. If unspecified, Container Registry will be used by default, unless specified otherwise by other means. +* `docker_repository` - (Optional) User-managed repository created in Artifact Registry to which the function's Docker image will be pushed after it is built by Cloud Build. May optionally be encrypted with a customer-managed encryption key (CMEK). If unspecified and `docker_registry` is not explicitly set to `CONTAINER_REGISTRY`, GCF will create and use a default Artifact Registry repository named 'gcf-artifacts' in the region. * `kms_key_name` - (Optional) Resource name of a KMS crypto key (managed by the user) used to encrypt/decrypt function resources. It must match the pattern `projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}`. If specified, you must also provide an artifact registry repository using the `docker_repository` field that was created with the same KMS crypto key. Before deploying, please complete all pre-requisites described in https://cloud.google.com/functions/docs/securing/cmek#granting_service_accounts_access_to_the_key From 1bc4aceace723ea0536f33b50c0230d86436dac2 Mon Sep 17 00:00:00 2001 From: hao-nan-li <100219545+hao-nan-li@users.noreply.github.com> Date: Tue, 5 Mar 2024 08:59:53 -0800 Subject: [PATCH 10/32] Handwrite sweepers for networkConnectivity hubs and spokes (#10069) --- ...ce_network_connectivity_hub_sweeper.go.erb | 127 ++++++++++++++++++ ..._network_connectivity_spoke_sweeper.go.erb | 127 ++++++++++++++++++ .../networkconnectivity/beta/hub.yaml | 1 + .../networkconnectivity/beta/spoke.yaml | 1 + 4 files changed, 256 insertions(+) create mode 100644 mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_hub_sweeper.go.erb create mode 100644 mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_spoke_sweeper.go.erb diff --git a/mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_hub_sweeper.go.erb b/mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_hub_sweeper.go.erb new file mode 100644 index 000000000000..573e4e0838fa --- /dev/null +++ b/mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_hub_sweeper.go.erb @@ -0,0 +1,127 @@ +<% autogen_exception -%> +package networkconnectivity + +<% unless version == "ga" -%> + +import ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-provider-google/google/envvar" + "github.com/hashicorp/terraform-provider-google/google/sweeper" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func init() { + sweeper.AddTestSweepers("NetworkConnectivityHub", testSweepNetworkConnectivityHub) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepNetworkConnectivityHub(region string) error { + resourceName := "NetworkConnectivityHub" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sweeper.SharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := envvar.GetTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &tpgresource.ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + + listTemplate := strings.Split("https://networkconnectivity.googleapis.com/v1/projects/{{project}}/locations/global/hubs", "?")[0] + listUrl, err := tpgresource.ReplaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: listUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["hubs"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + + rl := resourceList.([]interface{}) + + log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) + // Keep count of items that aren't sweepable for logging. + nonPrefixCount := 0 + for _, ri := range rl { + obj := ri.(map[string]interface{}) + if obj["name"] == nil { + log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) + return nil + } + + name := tpgresource.GetResourceNameFromSelfLink(obj["name"].(string)) + // Skip resources that shouldn't be sweeped + if !sweeper.IsSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + deleteTemplate := "https://networkconnectivity.googleapis.com/v1/projects/{{project}}/locations/global/hubs/{{name}}" + deleteUrl, err := tpgresource.ReplaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + + // Don't wait on operations as we may have a lot to delete + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: config.Project, + RawURL: deleteUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} + +<% end -%> \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_spoke_sweeper.go.erb b/mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_spoke_sweeper.go.erb new file mode 100644 index 000000000000..f1f1e49cb9a3 --- /dev/null +++ b/mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_spoke_sweeper.go.erb @@ -0,0 +1,127 @@ +<% autogen_exception -%> +package networkconnectivity + +<% unless version == "ga" -%> + +import ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-provider-google/google/envvar" + "github.com/hashicorp/terraform-provider-google/google/sweeper" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func init() { + sweeper.AddTestSweepers("NetworkConnectivitySpoke", testSweepNetworkConnectivitySpoke) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepNetworkConnectivitySpoke(region string) error { + resourceName := "NetworkConnectivitySpoke" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sweeper.SharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := envvar.GetTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &tpgresource.ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + + listTemplate := strings.Split("https://networkconnectivity.googleapis.com/v1/projects/{{project}}/locations/global/spokes", "?")[0] + listUrl, err := tpgresource.ReplaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: listUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["spokes"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + + rl := resourceList.([]interface{}) + + log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) + // Keep count of items that aren't sweepable for logging. + nonPrefixCount := 0 + for _, ri := range rl { + obj := ri.(map[string]interface{}) + if obj["name"] == nil { + log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) + return nil + } + + name := tpgresource.GetResourceNameFromSelfLink(obj["name"].(string)) + // Skip resources that shouldn't be sweeped + if !sweeper.IsSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + deleteTemplate := "https://networkconnectivity.googleapis.com/v1/projects/{{project}}/locations/global/spokes/{{name}}" + deleteUrl, err := tpgresource.ReplaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + + // Don't wait on operations as we may have a lot to delete + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: config.Project, + RawURL: deleteUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} + +<% end -%> \ No newline at end of file diff --git a/tpgtools/overrides/networkconnectivity/beta/hub.yaml b/tpgtools/overrides/networkconnectivity/beta/hub.yaml index af851d79a0c9..282feed97e5f 100644 --- a/tpgtools/overrides/networkconnectivity/beta/hub.yaml +++ b/tpgtools/overrides/networkconnectivity/beta/hub.yaml @@ -1,3 +1,4 @@ +- type: NO_SWEEPER - type: CUSTOMIZE_DIFF details: functions: diff --git a/tpgtools/overrides/networkconnectivity/beta/spoke.yaml b/tpgtools/overrides/networkconnectivity/beta/spoke.yaml index af851d79a0c9..282feed97e5f 100644 --- a/tpgtools/overrides/networkconnectivity/beta/spoke.yaml +++ b/tpgtools/overrides/networkconnectivity/beta/spoke.yaml @@ -1,3 +1,4 @@ +- type: NO_SWEEPER - type: CUSTOMIZE_DIFF details: functions: From 10450a2aaf2f01d2c84d93cefaac5fa5011b4fac Mon Sep 17 00:00:00 2001 From: Cameron Thornton Date: Tue, 5 Mar 2024 13:29:41 -0600 Subject: [PATCH 11/32] Fix wrong variable in override logic (#10125) --- mmv1/compiler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmv1/compiler.rb b/mmv1/compiler.rb index 9b2160026bc4..2e4bc8b5b3ce 100755 --- a/mmv1/compiler.rb +++ b/mmv1/compiler.rb @@ -199,7 +199,7 @@ Dir["#{ovr_prod_dir}/*"].each do |override_path| next if File.basename(override_path) == 'product.yaml' \ || File.extname(override_path) != '.yaml' \ - || File.basename(file_path).include?('go_') + || File.basename(override_path).include?('go_') file_path = File.join(product_name, File.basename(override_path)) res_yaml = if File.exist?(file_path) From 5ad9866e045ce0a1e675760f19773f81534b7210 Mon Sep 17 00:00:00 2001 From: Thomas Rodgers Date: Tue, 5 Mar 2024 13:14:39 -0800 Subject: [PATCH 12/32] Make missing test detector reader into a separate module (#10115) --- tools/missing-test-detector/detector.go | 7 ++++--- tools/missing-test-detector/detector_test.go | 4 +++- tools/missing-test-detector/go.mod | 2 +- tools/missing-test-detector/main.go | 3 ++- .../{ => reader}/reader.go | 8 ++++---- .../{ => reader}/reader_test.go | 18 +++++++++--------- .../testdata/service/config_variable_test.go | 0 .../testdata/service/covered_resource_test.go | 0 .../testdata/service/cross_file_1_test.go | 0 .../testdata/service/cross_file_2_test.go | 0 .../testdata/service/function_call_test.go | 0 .../testdata/service/multiple_resource_test.go | 0 .../testdata/service/serial_resource_test.go | 0 .../service/uncovered_resource_test.go | 0 14 files changed, 23 insertions(+), 19 deletions(-) rename tools/missing-test-detector/{ => reader}/reader.go (98%) rename tools/missing-test-detector/{ => reader}/reader_test.go (92%) rename tools/missing-test-detector/{ => reader}/testdata/service/config_variable_test.go (100%) rename tools/missing-test-detector/{ => reader}/testdata/service/covered_resource_test.go (100%) rename tools/missing-test-detector/{ => reader}/testdata/service/cross_file_1_test.go (100%) rename tools/missing-test-detector/{ => reader}/testdata/service/cross_file_2_test.go (100%) rename tools/missing-test-detector/{ => reader}/testdata/service/function_call_test.go (100%) rename tools/missing-test-detector/{ => reader}/testdata/service/multiple_resource_test.go (100%) rename tools/missing-test-detector/{ => reader}/testdata/service/serial_resource_test.go (100%) rename tools/missing-test-detector/{ => reader}/testdata/service/uncovered_resource_test.go (100%) diff --git a/tools/missing-test-detector/detector.go b/tools/missing-test-detector/detector.go index 72de96216d5f..2af06c169781 100644 --- a/tools/missing-test-detector/detector.go +++ b/tools/missing-test-detector/detector.go @@ -5,6 +5,7 @@ import ( "sort" "strings" + "github.com/GoogleCloudPlatform/magic-modules/tools/missing-test-detector/reader" "github.com/hashicorp/hcl/v2/hclwrite" "github.com/zclconf/go-cty/cty" ) @@ -19,7 +20,7 @@ type FieldSet map[string]struct{} // Detect missing tests for the given resource changes map in the given slice of tests. // Return a map of resource names to missing test info about that resource. -func detectMissingTests(changedFields map[string]ResourceChanges, allTests []*Test) (map[string]*MissingTestInfo, error) { +func detectMissingTests(changedFields map[string]ResourceChanges, allTests []*reader.Test) (map[string]*MissingTestInfo, error) { resourceNamesToTests := make(map[string][]string) for _, test := range allTests { for _, step := range test.Steps { @@ -51,13 +52,13 @@ func detectMissingTests(changedFields map[string]ResourceChanges, allTests []*Te return missingTests, nil } -func markCoverage(fieldCoverage ResourceChanges, config Resource) error { +func markCoverage(fieldCoverage ResourceChanges, config reader.Resource) error { for fieldName, fieldValue := range config { if coverage, ok := fieldCoverage[fieldName]; ok { if field, ok := coverage.(*Field); ok { field.Tested = true } else if objectCoverage, ok := coverage.(ResourceChanges); ok { - if fieldValueConfig, ok := fieldValue.(Resource); ok { + if fieldValueConfig, ok := fieldValue.(reader.Resource); ok { if err := markCoverage(objectCoverage, fieldValueConfig); err != nil { return fmt.Errorf("error parsing %q: %s", fieldName, err) } diff --git a/tools/missing-test-detector/detector_test.go b/tools/missing-test-detector/detector_test.go index 67855a3d44b7..69b6b1ec7a7c 100644 --- a/tools/missing-test-detector/detector_test.go +++ b/tools/missing-test-detector/detector_test.go @@ -3,10 +3,12 @@ package main import ( "reflect" "testing" + + "github.com/GoogleCloudPlatform/magic-modules/tools/missing-test-detector/reader" ) func TestDetectMissingTests(t *testing.T) { - allTests, errs := readAllTests("testdata") + allTests, errs := reader.ReadAllTests("reader/testdata") if len(errs) > 0 { t.Errorf("errors reading tests before testing detect missing tests: %v", errs) } diff --git a/tools/missing-test-detector/go.mod b/tools/missing-test-detector/go.mod index 3e25a00ea6e2..a074a5d1b471 100644 --- a/tools/missing-test-detector/go.mod +++ b/tools/missing-test-detector/go.mod @@ -1,4 +1,4 @@ -module github.com/trodge/magic-modules/tools/missing-test-detector +module github.com/GoogleCloudPlatform/magic-modules/tools/missing-test-detector go 1.20 diff --git a/tools/missing-test-detector/main.go b/tools/missing-test-detector/main.go index 16b6fdeba104..c8ba0672b02a 100644 --- a/tools/missing-test-detector/main.go +++ b/tools/missing-test-detector/main.go @@ -7,6 +7,7 @@ import ( "strings" "text/template" + "github.com/GoogleCloudPlatform/magic-modules/tools/missing-test-detector/reader" "github.com/golang/glog" ) @@ -15,7 +16,7 @@ var flagServicesDir = flag.String("services-dir", "", "directory where service d func main() { flag.Parse() - allTests, errs := readAllTests(*flagServicesDir) + allTests, errs := reader.ReadAllTests(*flagServicesDir) for path, err := range errs { glog.Infof("error reading path: %s, err: %v", path, err) } diff --git a/tools/missing-test-detector/reader.go b/tools/missing-test-detector/reader/reader.go similarity index 98% rename from tools/missing-test-detector/reader.go rename to tools/missing-test-detector/reader/reader.go index 7ef732636da6..0fa96586cb2b 100644 --- a/tools/missing-test-detector/reader.go +++ b/tools/missing-test-detector/reader/reader.go @@ -1,4 +1,4 @@ -package main +package reader import ( "fmt" @@ -33,7 +33,7 @@ func (t *Test) String() string { } // Return a slice of tests as well as a map of file or test names to errors encountered. -func readAllTests(servicesDir string) ([]*Test, map[string]error) { +func ReadAllTests(servicesDir string) ([]*Test, map[string]error) { dirs, err := os.ReadDir(servicesDir) if err != nil { return nil, map[string]error{servicesDir: err} @@ -52,7 +52,7 @@ func readAllTests(servicesDir string) ([]*Test, map[string]error) { testFileNames = append(testFileNames, filepath.Join(servicePath, file.Name())) } } - serviceTests, serviceErrs := readTestFiles(testFileNames) + serviceTests, serviceErrs := ReadTestFiles(testFileNames) for fileName, err := range serviceErrs { allErrs[fileName] = err } @@ -65,7 +65,7 @@ func readAllTests(servicesDir string) ([]*Test, map[string]error) { } // Read all the test files in a service directory together to capture cross-file function usage. -func readTestFiles(filenames []string) ([]*Test, map[string]error) { +func ReadTestFiles(filenames []string) ([]*Test, map[string]error) { funcDecls := make(map[string]*ast.FuncDecl) // map of function names to function declarations varDecls := make(map[string]*ast.BasicLit) // map of variable names to value expressions errs := make(map[string]error) // map of file or test names to errors encountered parsing diff --git a/tools/missing-test-detector/reader_test.go b/tools/missing-test-detector/reader/reader_test.go similarity index 92% rename from tools/missing-test-detector/reader_test.go rename to tools/missing-test-detector/reader/reader_test.go index b210c469a502..59a04c03c606 100644 --- a/tools/missing-test-detector/reader_test.go +++ b/tools/missing-test-detector/reader/reader_test.go @@ -1,4 +1,4 @@ -package main +package reader import ( "os" @@ -9,7 +9,7 @@ import ( // This test only ensures there isn't a panic reading tests in the provider. func TestReadAllTests(t *testing.T) { if servicesDir := os.Getenv("SERVICES_DIR"); servicesDir != "" { - _, errs := readAllTests(servicesDir) + _, errs := ReadAllTests(servicesDir) for path, err := range errs { t.Logf("path: %s, err: %v", path, err) } @@ -19,7 +19,7 @@ func TestReadAllTests(t *testing.T) { } func TestReadCoveredResourceTestFile(t *testing.T) { - tests, err := readTestFiles([]string{"testdata/service/covered_resource_test.go"}) + tests, err := ReadTestFiles([]string{"testdata/service/covered_resource_test.go"}) if err != nil { t.Fatalf("error reading covered resource test file: %v", err) } @@ -47,7 +47,7 @@ func TestReadCoveredResourceTestFile(t *testing.T) { } func TestReadConfigVariableTestFile(t *testing.T) { - tests, err := readTestFiles([]string{"testdata/service/config_variable_test.go"}) + tests, err := ReadTestFiles([]string{"testdata/service/config_variable_test.go"}) if err != nil { t.Fatalf("error reading config variable test file: %v", err) } @@ -67,7 +67,7 @@ func TestReadConfigVariableTestFile(t *testing.T) { } func TestReadMultipleResourcesTestFile(t *testing.T) { - tests, err := readTestFiles([]string{"testdata/service/multiple_resource_test.go"}) + tests, err := ReadTestFiles([]string{"testdata/service/multiple_resource_test.go"}) if err != nil { t.Fatalf("error reading multiple resources test file: %v", err) } @@ -101,7 +101,7 @@ func TestReadMultipleResourcesTestFile(t *testing.T) { } func TestReadSerialResourceTestFile(t *testing.T) { - tests, err := readTestFiles([]string{"testdata/service/serial_resource_test.go"}) + tests, err := ReadTestFiles([]string{"testdata/service/serial_resource_test.go"}) if err != nil { t.Fatalf("error reading serial resource test file: %v", err) } @@ -140,7 +140,7 @@ func TestReadSerialResourceTestFile(t *testing.T) { } func TestReadCrossFileTests(t *testing.T) { - tests, err := readTestFiles([]string{"testdata/service/cross_file_1_test.go", "testdata/service/cross_file_2_test.go"}) + tests, err := ReadTestFiles([]string{"testdata/service/cross_file_1_test.go", "testdata/service/cross_file_2_test.go"}) if err != nil { t.Fatalf("error reading cross file tests: %v", err) } @@ -183,7 +183,7 @@ func TestReadCrossFileTests(t *testing.T) { } func TestReadHelperFunctionCall(t *testing.T) { - tests, err := readTestFiles([]string{"testdata/service/function_call_test.go"}) + tests, err := ReadTestFiles([]string{"testdata/service/function_call_test.go"}) if err != nil { t.Fatalf("error reading function call test: %v", err) } @@ -193,7 +193,7 @@ func TestReadHelperFunctionCall(t *testing.T) { expectedTest := &Test{ Name: "TestAccFunctionCallResource", Steps: []Step{ - Step{ + { "helped_resource": Resources{ "primary": Resource{ "field_one": "\"value-one\"", diff --git a/tools/missing-test-detector/testdata/service/config_variable_test.go b/tools/missing-test-detector/reader/testdata/service/config_variable_test.go similarity index 100% rename from tools/missing-test-detector/testdata/service/config_variable_test.go rename to tools/missing-test-detector/reader/testdata/service/config_variable_test.go diff --git a/tools/missing-test-detector/testdata/service/covered_resource_test.go b/tools/missing-test-detector/reader/testdata/service/covered_resource_test.go similarity index 100% rename from tools/missing-test-detector/testdata/service/covered_resource_test.go rename to tools/missing-test-detector/reader/testdata/service/covered_resource_test.go diff --git a/tools/missing-test-detector/testdata/service/cross_file_1_test.go b/tools/missing-test-detector/reader/testdata/service/cross_file_1_test.go similarity index 100% rename from tools/missing-test-detector/testdata/service/cross_file_1_test.go rename to tools/missing-test-detector/reader/testdata/service/cross_file_1_test.go diff --git a/tools/missing-test-detector/testdata/service/cross_file_2_test.go b/tools/missing-test-detector/reader/testdata/service/cross_file_2_test.go similarity index 100% rename from tools/missing-test-detector/testdata/service/cross_file_2_test.go rename to tools/missing-test-detector/reader/testdata/service/cross_file_2_test.go diff --git a/tools/missing-test-detector/testdata/service/function_call_test.go b/tools/missing-test-detector/reader/testdata/service/function_call_test.go similarity index 100% rename from tools/missing-test-detector/testdata/service/function_call_test.go rename to tools/missing-test-detector/reader/testdata/service/function_call_test.go diff --git a/tools/missing-test-detector/testdata/service/multiple_resource_test.go b/tools/missing-test-detector/reader/testdata/service/multiple_resource_test.go similarity index 100% rename from tools/missing-test-detector/testdata/service/multiple_resource_test.go rename to tools/missing-test-detector/reader/testdata/service/multiple_resource_test.go diff --git a/tools/missing-test-detector/testdata/service/serial_resource_test.go b/tools/missing-test-detector/reader/testdata/service/serial_resource_test.go similarity index 100% rename from tools/missing-test-detector/testdata/service/serial_resource_test.go rename to tools/missing-test-detector/reader/testdata/service/serial_resource_test.go diff --git a/tools/missing-test-detector/testdata/service/uncovered_resource_test.go b/tools/missing-test-detector/reader/testdata/service/uncovered_resource_test.go similarity index 100% rename from tools/missing-test-detector/testdata/service/uncovered_resource_test.go rename to tools/missing-test-detector/reader/testdata/service/uncovered_resource_test.go From 978c66d4722b13f15b72ac0253666b5713814e85 Mon Sep 17 00:00:00 2001 From: Thomas Rodgers Date: Tue, 5 Mar 2024 14:30:09 -0800 Subject: [PATCH 13/32] Use old github token if new tokens are not available (#10114) * Use old github token if new tokens are not available * Add lookup function for github token or fallback * Add fall back * Add fallback --- .ci/magician/cmd/check_cassettes.go | 17 +++++++++++++++-- .ci/magician/cmd/community_checker.go | 4 ++-- .ci/magician/cmd/generate_comment.go | 10 ++++++++-- .ci/magician/cmd/generate_downstream.go | 1 + .ci/magician/cmd/membership_checker.go | 4 ++-- .ci/magician/cmd/request_service_reviewers.go | 4 ++-- .ci/magician/cmd/test_terraform_vcr.go | 11 +++++++++-- .ci/magician/cmd/test_tgc.go | 4 ++-- .ci/magician/cmd/test_tpg.go | 4 ++-- .../test_tgc_integration.sh | 5 +++++ 10 files changed, 48 insertions(+), 16 deletions(-) diff --git a/.ci/magician/cmd/check_cassettes.go b/.ci/magician/cmd/check_cassettes.go index f5977ec0be29..d31cebe44ddd 100644 --- a/.ci/magician/cmd/check_cassettes.go +++ b/.ci/magician/cmd/check_cassettes.go @@ -13,7 +13,6 @@ import ( var ccEnvironmentVariables = [...]string{ "COMMIT_SHA", - "GITHUB_TOKEN_DOWNSTREAMS", "GOCACHE", "GOPATH", "GOOGLE_BILLING_ACCOUNT", @@ -56,13 +55,19 @@ var checkCassettesCmd = &cobra.Command{ env[ev] = val } + githubToken, ok := lookupGithubTokenOrFallback("GITHUB_TOKEN_DOWNSTREAMS") + if !ok { + fmt.Println("Did not provide GITHUB_TOKEN_DOWNSTREAMS or GITHUB_TOKEN environment variables") + os.Exit(1) + } + rnr, err := exec.NewRunner() if err != nil { fmt.Println("Error creating Runner: ", err) os.Exit(1) } - ctlr := source.NewController(env["GOPATH"], "modular-magician", env["GITHUB_TOKEN_DOWNSTREAMS"], rnr) + ctlr := source.NewController(env["GOPATH"], "modular-magician", githubToken, rnr) vt, err := vcr.NewTester(env, rnr) if err != nil { @@ -73,6 +78,14 @@ var checkCassettesCmd = &cobra.Command{ }, } +func lookupGithubTokenOrFallback(tokenName string) (string, bool) { + val, ok := os.LookupEnv(tokenName) + if !ok { + return os.LookupEnv("GITHUB_TOKEN") + } + return val, ok +} + func listCCEnvironmentVariables() string { var result string for i, ev := range ccEnvironmentVariables { diff --git a/.ci/magician/cmd/community_checker.go b/.ci/magician/cmd/community_checker.go index 2ec024952520..9eb82a5e3e2e 100644 --- a/.ci/magician/cmd/community_checker.go +++ b/.ci/magician/cmd/community_checker.go @@ -64,9 +64,9 @@ var communityApprovalCmd = &cobra.Command{ baseBranch := args[5] fmt.Println("Base Branch: ", baseBranch) - githubToken, ok := os.LookupEnv("GITHUB_TOKEN_MAGIC_MODULES") + githubToken, ok := lookupGithubTokenOrFallback("GITHUB_TOKEN_MAGIC_MODULES") if !ok { - fmt.Println("Did not provide GITHUB_TOKEN_MAGIC_MODULES environment variable") + fmt.Println("Did not provide GITHUB_TOKEN_MAGIC_MODULES or GITHUB_TOKEN environment variables") os.Exit(1) } gh := github.NewClient(githubToken) diff --git a/.ci/magician/cmd/generate_comment.go b/.ci/magician/cmd/generate_comment.go index b00ab9986d6e..b78bbf35fd3c 100644 --- a/.ci/magician/cmd/generate_comment.go +++ b/.ci/magician/cmd/generate_comment.go @@ -35,8 +35,6 @@ var gcEnvironmentVariables = [...]string{ "BUILD_ID", "BUILD_STEP", "COMMIT_SHA", - "GITHUB_TOKEN_DOWNSTREAMS", - "GITHUB_TOKEN_MAGIC_MODULES", "GOPATH", "HOME", "PATH", @@ -71,6 +69,14 @@ var generateCommentCmd = &cobra.Command{ env[ev] = val } + for _, tokenName := range []string{"GITHUB_TOKEN_DOWNSTREAMS", "GITHUB_TOKEN_MAGIC_MODULES"} { + val, ok := lookupGithubTokenOrFallback(tokenName) + if !ok { + fmt.Printf("Did not provide %s or GITHUB_TOKEN environment variable\n", tokenName) + os.Exit(1) + } + env[tokenName] = val + } gh := github.NewClient(env["GITHUB_TOKEN_MAGIC_MODULES"]) rnr, err := exec.NewRunner() if err != nil { diff --git a/.ci/magician/cmd/generate_downstream.go b/.ci/magician/cmd/generate_downstream.go index b8605905f242..2e812d482069 100644 --- a/.ci/magician/cmd/generate_downstream.go +++ b/.ci/magician/cmd/generate_downstream.go @@ -25,6 +25,7 @@ var gdEnvironmentVariables = [...]string{ var gdTokenEnvironmentVariables = [...]string{ "GITHUB_TOKEN_CLASSIC", "GITHUB_TOKEN_DOWNSTREAMS", + "GITHUB_TOKEN", } var generateDownstreamCmd = &cobra.Command{ diff --git a/.ci/magician/cmd/membership_checker.go b/.ci/magician/cmd/membership_checker.go index 71ffda29a253..97210105dd08 100644 --- a/.ci/magician/cmd/membership_checker.go +++ b/.ci/magician/cmd/membership_checker.go @@ -72,9 +72,9 @@ var membershipCheckerCmd = &cobra.Command{ baseBranch := args[5] fmt.Println("Base Branch: ", baseBranch) - githubToken, ok := os.LookupEnv("GITHUB_TOKEN_MAGIC_MODULES") + githubToken, ok := lookupGithubTokenOrFallback("GITHUB_TOKEN_MAGIC_MODULES") if !ok { - fmt.Println("Did not provide GITHUB_TOKEN_MAGIC_MODULES environment variable") + fmt.Println("Did not provide GITHUB_TOKEN_MAGIC_MODULES or GITHUB_TOKEN environment variables") os.Exit(1) } gh := github.NewClient(githubToken) diff --git a/.ci/magician/cmd/request_service_reviewers.go b/.ci/magician/cmd/request_service_reviewers.go index 33abd8d1ca1f..6ef80c5283c0 100644 --- a/.ci/magician/cmd/request_service_reviewers.go +++ b/.ci/magician/cmd/request_service_reviewers.go @@ -40,9 +40,9 @@ var requestServiceReviewersCmd = &cobra.Command{ prNumber := args[0] fmt.Println("PR Number: ", prNumber) - githubToken, ok := os.LookupEnv("GITHUB_TOKEN_MAGIC_MODULES") + githubToken, ok := lookupGithubTokenOrFallback("GITHUB_TOKEN_MAGIC_MODULES") if !ok { - fmt.Println("Did not provide GITHUB_TOKEN_MAGIC_MODULES environment variable") + fmt.Println("Did not provide GITHUB_TOKEN_MAGIC_MODULES or GITHUB_TOKEN environment variable") os.Exit(1) } gh := github.NewClient(githubToken) diff --git a/.ci/magician/cmd/test_terraform_vcr.go b/.ci/magician/cmd/test_terraform_vcr.go index 3c979ef3ab84..60fda5577d82 100644 --- a/.ci/magician/cmd/test_terraform_vcr.go +++ b/.ci/magician/cmd/test_terraform_vcr.go @@ -15,8 +15,6 @@ import ( ) var ttvEnvironmentVariables = [...]string{ - "GITHUB_TOKEN_DOWNSTREAMS", - "GITHUB_TOKEN_MAGIC_MODULES", "GOCACHE", "GOPATH", "GOOGLE_BILLING_ACCOUNT", @@ -55,6 +53,15 @@ var testTerraformVCRCmd = &cobra.Command{ env[ev] = val } + for _, tokenName := range []string{"GITHUB_TOKEN_DOWNSTREAMS", "GITHUB_TOKEN_MAGIC_MODULES"} { + val, ok := lookupGithubTokenOrFallback(tokenName) + if !ok { + fmt.Printf("Did not provide %s or GITHUB_TOKEN environment variable\n", tokenName) + os.Exit(1) + } + env[tokenName] = val + } + baseBranch := os.Getenv("BASE_BRANCH") if baseBranch == "" { baseBranch = "main" diff --git a/.ci/magician/cmd/test_tgc.go b/.ci/magician/cmd/test_tgc.go index 54fd97394612..5f000d731b15 100644 --- a/.ci/magician/cmd/test_tgc.go +++ b/.ci/magician/cmd/test_tgc.go @@ -36,9 +36,9 @@ var testTGCCmd = &cobra.Command{ commit := os.Getenv("COMMIT_SHA") pr := os.Getenv("PR_NUMBER") - githubToken, ok := os.LookupEnv("GITHUB_TOKEN_MAGIC_MODULES") + githubToken, ok := lookupGithubTokenOrFallback("GITHUB_TOKEN_MAGIC_MODULES") if !ok { - fmt.Println("Did not provide GITHUB_TOKEN_MAGIC_MODULES environment variable") + fmt.Println("Did not provide GITHUB_TOKEN_MAGIC_MODULES or GITHUB_TOKEN environment variables") os.Exit(1) } gh := github.NewClient(githubToken) diff --git a/.ci/magician/cmd/test_tpg.go b/.ci/magician/cmd/test_tpg.go index 58d216d512ff..260b5b2a7466 100644 --- a/.ci/magician/cmd/test_tpg.go +++ b/.ci/magician/cmd/test_tpg.go @@ -42,9 +42,9 @@ var testTPGCmd = &cobra.Command{ commit := os.Getenv("COMMIT_SHA") pr := os.Getenv("PR_NUMBER") - githubToken, ok := os.LookupEnv("GITHUB_TOKEN_MAGIC_MODULES") + githubToken, ok := lookupGithubTokenOrFallback("GITHUB_TOKEN_MAGIC_MODULES") if !ok { - fmt.Println("Did not provide GITHUB_TOKEN_MAGIC_MODULES environment variable") + fmt.Println("Did not provide GITHUB_TOKEN_MAGIC_MODULES or GITHUB_TOKEN environment variables") os.Exit(1) } gh := github.NewClient(githubToken) diff --git a/.ci/scripts/go-plus/tgc-tester-integration/test_tgc_integration.sh b/.ci/scripts/go-plus/tgc-tester-integration/test_tgc_integration.sh index 8f4ead70dc18..be80ee454f1d 100755 --- a/.ci/scripts/go-plus/tgc-tester-integration/test_tgc_integration.sh +++ b/.ci/scripts/go-plus/tgc-tester-integration/test_tgc_integration.sh @@ -36,6 +36,11 @@ post_body=$( jq -n \ --arg state "pending" \ '{context: $context, target_url: $target_url, state: $state}') +# Fall back to old github token if new token is unavailable. +if [[ -z $GITHUB_TOKEN_MAGIC_MODULES ]]; then + GITHUB_TOKEN_MAGIC_MODULES=$GITHUB_TOKEN +fi + curl \ -X POST \ -u "$github_username:$GITHUB_TOKEN_MAGIC_MODULES" \ From 8373cea715cdb25197b639f8b8d340cf09b4fa83 Mon Sep 17 00:00:00 2001 From: xuchenma <67921399+xuchenma@users.noreply.github.com> Date: Wed, 6 Mar 2024 06:52:06 -0800 Subject: [PATCH 14/32] Add test for PATCH environment type (#10131) --- ...source_apigee_environment_type_test.go.erb | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 mmv1/third_party/terraform/services/apigee/resource_apigee_environment_type_test.go.erb diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_environment_type_test.go.erb b/mmv1/third_party/terraform/services/apigee/resource_apigee_environment_type_test.go.erb new file mode 100644 index 000000000000..bef24217d444 --- /dev/null +++ b/mmv1/third_party/terraform/services/apigee/resource_apigee_environment_type_test.go.erb @@ -0,0 +1,179 @@ +<% autogen_exception -%> +package apigee_test +<% unless version == 'ga' -%> + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccApigeeEnvironment_apigeeEnvironmentTypeTestExampleUpdate(t *testing.T) { + acctest.SkipIfVcr(t) + t.Parallel() + + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "billing_account": envvar.GetTestBillingAccountFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + CheckDestroy: testAccCheckApigeeEnvironmentDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccApigeeEnvironment_apigeeEnvironmentTypeTestExample(context), + }, + { + ResourceName: "google_apigee_environment.apigee_environment", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"org_id"}, + }, + { + Config: testAccApigeeEnvironment_apigeeEnvironmentTypeTestExampleUpdate(context), + }, + { + ResourceName: "google_apigee_environment.apigee_environment", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"org_id"}, + }, + }, + }) +} + +func testAccApigeeEnvironment_apigeeEnvironmentTypeTestExampleUpdate(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_project" "project" { + provider = google-beta + + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "%{org_id}" + billing_account = "%{billing_account}" +} + +resource "google_project_service" "apigee" { + provider = google-beta + + project = google_project.project.project_id + service = "apigee.googleapis.com" +} + +resource "google_project_service" "compute" { + provider = google-beta + + project = google_project.project.project_id + service = "compute.googleapis.com" +} + +resource "google_project_service" "servicenetworking" { + provider = google-beta + + project = google_project.project.project_id + service = "servicenetworking.googleapis.com" +} + +resource "google_project_service" "kms" { + provider = google-beta + + project = google_project.project.project_id + service = "cloudkms.googleapis.com" +} + +resource "google_compute_network" "apigee_network" { + provider = google-beta + + name = "apigee-network" + project = google_project.project.project_id + depends_on = [google_project_service.compute] +} + +resource "google_compute_global_address" "apigee_range" { + provider = google-beta + + name = "tf-test-apigee-range%{random_suffix}" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + prefix_length = 16 + network = google_compute_network.apigee_network.id + project = google_project.project.project_id +} + +resource "google_service_networking_connection" "apigee_vpc_connection" { + provider = google-beta + + network = google_compute_network.apigee_network.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.apigee_range.name] + depends_on = [google_project_service.servicenetworking] +} + +resource "google_kms_key_ring" "apigee_keyring" { + provider = google-beta + + name = "apigee-keyring" + location = "us-central1" + project = google_project.project.project_id + depends_on = [google_project_service.kms] +} + +resource "google_kms_crypto_key" "apigee_key" { + provider = google-beta + + name = "apigee-key" + key_ring = google_kms_key_ring.apigee_keyring.id +} + +resource "google_project_service_identity" "apigee_sa" { + provider = google-beta + + project = google_project.project.project_id + service = google_project_service.apigee.service +} + +resource "google_kms_crypto_key_iam_binding" "apigee_sa_keyuser" { + provider = google-beta + + crypto_key_id = google_kms_crypto_key.apigee_key.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + members = [ + "serviceAccount:${google_project_service_identity.apigee_sa.email}", + ] +} + +resource "google_apigee_organization" "apigee_org" { + provider = google-beta + + analytics_region = "us-central1" + project_id = google_project.project.project_id + authorized_network = google_compute_network.apigee_network.id + billing_type = "PAYG" + runtime_database_encryption_key_name = google_kms_crypto_key.apigee_key.id + + depends_on = [ + google_service_networking_connection.apigee_vpc_connection, + google_project_service.apigee, + google_kms_crypto_key_iam_binding.apigee_sa_keyuser, + ] +} + +resource "google_apigee_environment" "apigee_environment" { + provider = google-beta + + org_id = google_apigee_organization.apigee_org.id + name = "tf-test%{random_suffix}" + description = "Apigee Environment" + display_name = "tf-test%{random_suffix}" + type = "INTERMEDIATE" +} +`, context) +} + +<% end -%> From 55a1fa855d07e03b0ad43d070f3dc996fd6f2922 Mon Sep 17 00:00:00 2001 From: Esha Goel Date: Wed, 6 Mar 2024 15:16:57 +0000 Subject: [PATCH 15/32] Add new resource for Application for Apphub (#10079) * Add new resource for Application for Apphub * Add new resource for Application for Apphub * Enable Apphub API in test cases * Fix precheck error * Fix precheck error * Resolve comments * Fix lint error * Fix examples * Remove apphub from teamcity config This causes PR build failures, I'll add it later --------- Co-authored-by: Sam Levenick --- mmv1/products/apphub/Application.yaml | 189 ++++++++++++++++ mmv1/products/apphub/product.yaml | 23 ++ .../examples/apphub_application_basic.tf.erb | 7 + .../examples/apphub_application_full.tf.erb | 29 +++ .../components/inputs/services_beta.kt | 5 + .../components/inputs/services_ga.kt | 5 + .../resource_apphub_application_test.go | 210 ++++++++++++++++++ 7 files changed, 468 insertions(+) create mode 100644 mmv1/products/apphub/Application.yaml create mode 100644 mmv1/products/apphub/product.yaml create mode 100644 mmv1/templates/terraform/examples/apphub_application_basic.tf.erb create mode 100644 mmv1/templates/terraform/examples/apphub_application_full.tf.erb create mode 100644 mmv1/third_party/terraform/services/apphub/resource_apphub_application_test.go diff --git a/mmv1/products/apphub/Application.yaml b/mmv1/products/apphub/Application.yaml new file mode 100644 index 000000000000..fbac56d6ba63 --- /dev/null +++ b/mmv1/products/apphub/Application.yaml @@ -0,0 +1,189 @@ +# Copyright 2024 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. + +--- !ruby/object:Api::Resource +base_url: projects/{{project}}/locations/{{location}}/applications +create_url: projects/{{project}}/locations/{{location}}/applications?applicationId={{application_id}} +self_link: projects/{{project}}/locations/{{location}}/applications/{{application_id}} +id_format: projects/{{project}}/locations/{{location}}/applications/{{application_id}} +import_format: + - projects/{{project}}/locations/{{location}}/applications/{{application_id}} +name: Application +description: 'Application is a functional grouping of Services and Workloads that helps achieve a desired end-to-end business functionality. + Services and Workloads are owned by the Application.' +autogen_async: true +examples: + - !ruby/object:Provider::Terraform::Examples + name: "application_basic" + primary_resource_id: "example" + config_path: "templates/terraform/examples/apphub_application_basic.tf.erb" + vars: + application_id: "example-application" + - !ruby/object:Provider::Terraform::Examples + name: "application_full" + primary_resource_id: "example2" + config_path: "templates/terraform/examples/apphub_application_full.tf.erb" + vars: + application_id: "example-application" + display_name: "Application Full" + description: "Application for testing" + business_name: "Alice" + business_email: "alice@google.com" + developer_name: "Bob" + developer_email: "bob@google.com" + operator_name: "Charlie" + operator_email: "charlie@google.com" +properties: + - !ruby/object:Api::Type::String + name: name + output: true + description: "Identifier. The resource name of an Application. Format:\n\"projects/{host-project-id}/locations/{location}/applications/{application-id}\" " + - !ruby/object:Api::Type::String + name: displayName + description: 'Optional. User-defined name for the Application. ' + - !ruby/object:Api::Type::String + name: description + description: 'Optional. User-defined description of an Application. ' + - !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::Enum + name: type + description: 'Criticality type. ' + required: true + values: + - :MISSION_CRITICAL + - :HIGH + - :MEDIUM + - :LOW + name: criticality + description: 'Criticality of the Application, Service, or Workload ' + - !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::Enum + name: type + description: 'Environment type. ' + required: true + values: + - :PRODUCTION + - :STAGING + - :TEST + - :DEVELOPMENT + name: environment + description: 'Environment of the Application, Service, or Workload ' + - !ruby/object:Api::Type::Array + name: developerOwners + item_type: !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::String + name: displayName + description: 'Optional. Contact''s name. ' + - !ruby/object:Api::Type::String + name: email + required: true + description: 'Required. Email address of the contacts. ' + description: 'Optional. Developer team that owns development and coding. ' + - !ruby/object:Api::Type::Array + name: operatorOwners + item_type: !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::String + name: displayName + description: 'Optional. Contact''s name. ' + - !ruby/object:Api::Type::String + name: email + required: true + description: 'Required. Email address of the contacts. ' + description: 'Optional. Operator team that ensures runtime and operations. ' + - !ruby/object:Api::Type::Array + name: businessOwners + item_type: !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::String + name: displayName + description: 'Optional. Contact''s name. ' + - !ruby/object:Api::Type::String + name: email + required: true + description: 'Required. Email address of the contacts. ' + description: 'Optional. Business team that ensures user needs are met and value + is delivered ' + name: attributes + description: 'Consumer provided attributes. ' + - !ruby/object:Api::Type::String + name: createTime + description: 'Output only. Create time. ' + output: true + - !ruby/object:Api::Type::String + name: updateTime + description: 'Output only. Update time. ' + output: true + - !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::Enum + name: type + description: "Required. Scope Type. \n Possible values:\nREGIONAL" + required: true + values: + - :REGIONAL + name: scope + description: 'Scope of an application. ' + required: true + - !ruby/object:Api::Type::String + name: uid + description: 'Output only. A universally unique identifier (in UUID4 format) for + the `Application`. ' + output: true + - !ruby/object:Api::Type::Enum + name: state + description: "Output only. Application state. \n Possible values:\n STATE_UNSPECIFIED\nCREATING\nACTIVE\nDELETING" + output: true + values: + - :STATE_UNSPECIFIED + - :CREATING + - :ACTIVE + - :DELETING +parameters: + - !ruby/object:Api::Type::String + name: location + description: 'Part of `parent`. See documentation of `projectsId`. ' + url_param_only: true + required: true + immutable: true + - !ruby/object:Api::Type::String + name: applicationId + description: 'Required. The Application identifier. ' + url_param_only: true + required: true + immutable: true +async: !ruby/object:Api::OpAsync + operation: !ruby/object:Api::OpAsync::Operation + path: name + base_url: "{{op_id}}" + wait_ms: 1000 + timeouts: + result: !ruby/object:Api::OpAsync::Result + path: response + resource_inside_response: true + status: !ruby/object:Api::OpAsync::Status + path: done + complete: true + allowed: + - true + - false + error: !ruby/object:Api::OpAsync::Error + path: error + message: message +update_verb: :PATCH +update_mask: true diff --git a/mmv1/products/apphub/product.yaml b/mmv1/products/apphub/product.yaml new file mode 100644 index 000000000000..4df439355736 --- /dev/null +++ b/mmv1/products/apphub/product.yaml @@ -0,0 +1,23 @@ +# Copyright 2024 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. + + +--- !ruby/object:Api::Product +name: Apphub +display_name: App Hub +versions: + - !ruby/object:Api::Product::Version + name: ga + base_url: https://apphub.googleapis.com/v1/ +scopes: + - https://www.googleapis.com/auth/cloud-platform diff --git a/mmv1/templates/terraform/examples/apphub_application_basic.tf.erb b/mmv1/templates/terraform/examples/apphub_application_basic.tf.erb new file mode 100644 index 000000000000..7b7c50231dca --- /dev/null +++ b/mmv1/templates/terraform/examples/apphub_application_basic.tf.erb @@ -0,0 +1,7 @@ +resource "google_apphub_application" "<%= ctx[:primary_resource_id] %>" { + location = "us-east1" + application_id = "<%= ctx[:vars]['application_id'] %>" + scope { + type = "REGIONAL" + } +} diff --git a/mmv1/templates/terraform/examples/apphub_application_full.tf.erb b/mmv1/templates/terraform/examples/apphub_application_full.tf.erb new file mode 100644 index 000000000000..42d9de520464 --- /dev/null +++ b/mmv1/templates/terraform/examples/apphub_application_full.tf.erb @@ -0,0 +1,29 @@ +resource "google_apphub_application" "<%= ctx[:primary_resource_id] %>" { + location = "us-east1" + application_id = "<%= ctx[:vars]['application_id'] %>" + display_name = "<%= ctx[:vars]['display_name'] %>" + scope { + type = "REGIONAL" + } + description = "<%= ctx[:vars]['description'] %>" + attributes { + environment { + type = "STAGING" + } + criticality { + type = "MISSION_CRITICAL" + } + business_owners { + display_name = "<%= ctx[:vars]['business_name'] %>" + email = "<%= ctx[:vars]['business_email'] %>" + } + developer_owners { + display_name = "<%= ctx[:vars]['developer_name'] %>" + email = "<%= ctx[:vars]['developer_email'] %>" + } + operator_owners { + display_name = "<%= ctx[:vars]['operator_name'] %>" + email = "<%= ctx[:vars]['operator_email'] %>" + } + } +} diff --git a/mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt b/mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt index 27550dabce13..443987885a6f 100644 --- a/mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt +++ b/mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt @@ -48,6 +48,11 @@ var ServicesListBeta = mapOf( "displayName" to "Appengine", "path" to "./google-beta/services/appengine" ), + "apphub" to mapOf( + "name" to "apphub", + "displayName" to "Apphub", + "path" to "./google-beta/services/apphub" + ), "artifactregistry" to mapOf( "name" to "artifactregistry", "displayName" to "Artifactregistry", diff --git a/mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt b/mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt index 51f98ed08a05..08ce6c2ee82f 100644 --- a/mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt +++ b/mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt @@ -48,6 +48,11 @@ var ServicesListGa = mapOf( "displayName" to "Appengine", "path" to "./google/services/appengine" ), + "apphub" to mapOf( + "name" to "apphub", + "displayName" to "Apphub", + "path" to "./google/services/apphub" + ), "artifactregistry" to mapOf( "name" to "artifactregistry", "displayName" to "Artifactregistry", diff --git a/mmv1/third_party/terraform/services/apphub/resource_apphub_application_test.go b/mmv1/third_party/terraform/services/apphub/resource_apphub_application_test.go new file mode 100644 index 000000000000..3e68916cc73e --- /dev/null +++ b/mmv1/third_party/terraform/services/apphub/resource_apphub_application_test.go @@ -0,0 +1,210 @@ +package apphub_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccApphubApplication_applicationUpdateFull(t *testing.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.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckApphubApplicationDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccApphubApplication_applicationFullExample(context), + }, + { + ResourceName: "google_apphub_application.example2", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "application_id"}, + }, + { + Config: testAccApphubApplication_applicationUpdateDisplayName(context), + }, + { + ResourceName: "google_apphub_application.example2", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "application_id"}, + }, + { + Config: testAccApphubApplication_applicationUpdateEnvironment(context), + }, + { + ResourceName: "google_apphub_application.example2", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "application_id"}, + }, + { + Config: testAccApphubApplication_applicationUpdateCriticality(context), + }, + { + ResourceName: "google_apphub_application.example2", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "application_id"}, + }, + { + Config: testAccApphubApplication_applicationUpdateOwners(context), + }, + { + ResourceName: "google_apphub_application.example2", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "application_id"}, + }, + }, + }) +} + +func testAccApphubApplication_applicationUpdateDisplayName(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_apphub_application" "example2" { + location = "us-east1" + application_id = "tf-test-example-application%{random_suffix}" + display_name = "Application Full New%{random_suffix}" + scope { + type = "REGIONAL" + } + attributes { + environment { + type = "STAGING" + } + criticality { + type = "MISSION_CRITICAL" + } + business_owners { + display_name = "Alice%{random_suffix}" + email = "alice@google.com%{random_suffix}" + } + developer_owners { + display_name = "Bob%{random_suffix}" + email = "bob@google.com%{random_suffix}" + } + operator_owners { + display_name = "Charlie%{random_suffix}" + email = "charlie@google.com%{random_suffix}" + } + } +} +`, context) +} + +func testAccApphubApplication_applicationUpdateEnvironment(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_apphub_application" "example2" { + location = "us-east1" + application_id = "tf-test-example-application%{random_suffix}" + display_name = "Application Full New%{random_suffix}" + scope { + type = "REGIONAL" + } + attributes { + environment { + type = "TEST" + } + criticality { + type = "MISSION_CRITICAL" + } + business_owners { + display_name = "Alice%{random_suffix}" + email = "alice@google.com%{random_suffix}" + } + developer_owners { + display_name = "Bob%{random_suffix}" + email = "bob@google.com%{random_suffix}" + } + operator_owners { + display_name = "Charlie%{random_suffix}" + email = "charlie@google.com%{random_suffix}" + } + } +} +`, context) +} + +func testAccApphubApplication_applicationUpdateCriticality(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_apphub_application" "example2" { + location = "us-east1" + application_id = "tf-test-example-application%{random_suffix}" + display_name = "Application Full New%{random_suffix}" + scope { + type = "REGIONAL" + } + attributes { + environment { + type = "TEST" + } + criticality { + type = "MEDIUM" + } + business_owners { + display_name = "Alice%{random_suffix}" + email = "alice@google.com%{random_suffix}" + } + developer_owners { + display_name = "Bob%{random_suffix}" + email = "bob@google.com%{random_suffix}" + } + operator_owners { + display_name = "Charlie%{random_suffix}" + email = "charlie@google.com%{random_suffix}" + } + } +} +`, context) +} + +func testAccApphubApplication_applicationUpdateOwners(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_apphub_application" "example2" { + location = "us-east1" + application_id = "tf-test-example-application%{random_suffix}" + display_name = "Application Full New%{random_suffix}" + scope { + type = "REGIONAL" + } + attributes { + environment { + type = "TEST" + } + criticality { + type = "MEDIUM" + } + business_owners { + display_name = "Alice%{random_suffix}" + email = "alice@google.com%{random_suffix}" + } + developer_owners { + display_name = "Bob%{random_suffix}" + email = "bob@google.com%{random_suffix}" + } + developer_owners { + display_name = "Derek%{random_suffix}" + email = "derek@google.com%{random_suffix}" + } + operator_owners { + display_name = "Charlie%{random_suffix}" + email = "charlie@google.com%{random_suffix}" + } + } +} +`, context) +} From 17300fa53535dabccabb6ec869d43f378b27780e Mon Sep 17 00:00:00 2001 From: Sam Levenick Date: Wed, 6 Mar 2024 10:37:19 -0500 Subject: [PATCH 16/32] Add apphub (#10133) Adds AppHub to APIs to activate --- .ci/infra/terraform/main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/infra/terraform/main.tf b/.ci/infra/terraform/main.tf index a6f8c58a5f69..439d37f5e8b3 100644 --- a/.ci/infra/terraform/main.tf +++ b/.ci/infra/terraform/main.tf @@ -168,6 +168,7 @@ module "project-services" { "apikeys.googleapis.com", "appengine.googleapis.com", "appengineflex.googleapis.com", + "apphub.googleapis.com", "artifactregistry.googleapis.com", "assuredworkloads.googleapis.com", "autoscaling.googleapis.com", From 1b12d6c903c6ef15fe8395918f47c9f476195cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20=27Cherit=27=20Sz=C3=B3stak?= Date: Wed, 6 Mar 2024 17:20:01 +0100 Subject: [PATCH 17/32] Allow sending empty app_engine and serverless google_compute_region_network_endpoint_group (#10031) --- mmv1/products/compute/RegionNetworkEndpointGroup.yaml | 7 +++++++ .../region_network_endpoint_group_appengine_empty.tf.erb | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 mmv1/templates/terraform/examples/region_network_endpoint_group_appengine_empty.tf.erb diff --git a/mmv1/products/compute/RegionNetworkEndpointGroup.yaml b/mmv1/products/compute/RegionNetworkEndpointGroup.yaml index 2dc6d82c64cc..177ce9001bf1 100644 --- a/mmv1/products/compute/RegionNetworkEndpointGroup.yaml +++ b/mmv1/products/compute/RegionNetworkEndpointGroup.yaml @@ -68,6 +68,11 @@ examples: primary_resource_id: 'appengine_neg' vars: neg_name: 'appengine-neg' + - !ruby/object:Provider::Terraform::Examples + name: 'region_network_endpoint_group_appengine_empty' + primary_resource_id: 'appengine_neg' + vars: + neg_name: 'appengine-neg' - !ruby/object:Provider::Terraform::Examples name: 'region_network_endpoint_group_psc' primary_resource_id: 'psc_neg' @@ -209,6 +214,7 @@ properties: - cloud_function - serverless_deployment allow_empty_object: true + send_empty_value: true description: | This field is only used for SERVERLESS NEGs. @@ -278,6 +284,7 @@ properties: - cloud_function - app_engine allow_empty_object: true + send_empty_value: true description: | This field is only used for SERVERLESS NEGs. diff --git a/mmv1/templates/terraform/examples/region_network_endpoint_group_appengine_empty.tf.erb b/mmv1/templates/terraform/examples/region_network_endpoint_group_appengine_empty.tf.erb new file mode 100644 index 000000000000..fe794ed86e7b --- /dev/null +++ b/mmv1/templates/terraform/examples/region_network_endpoint_group_appengine_empty.tf.erb @@ -0,0 +1,8 @@ +// App Engine Example +resource "google_compute_region_network_endpoint_group" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]['neg_name'] %>" + network_endpoint_type = "SERVERLESS" + region = "us-central1" + app_engine { + } +} From ffd2cf300a8b5652a4638c772880bb5eeee24b34 Mon Sep 17 00:00:00 2001 From: Benjamin Kaplan <58792807+bskaplan@users.noreply.github.com> Date: Wed, 6 Mar 2024 09:13:14 -0800 Subject: [PATCH 18/32] Support service-level min instances in Cloud Run v2 services. (#10083) --- mmv1/products/cloudrunv2/Service.yaml | 10 ++ .../resource_cloud_run_v2_service_test.go.erb | 101 ++++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/mmv1/products/cloudrunv2/Service.yaml b/mmv1/products/cloudrunv2/Service.yaml index 4c7198049bfe..bbedcc2cf10c 100644 --- a/mmv1/products/cloudrunv2/Service.yaml +++ b/mmv1/products/cloudrunv2/Service.yaml @@ -256,6 +256,16 @@ properties: One or more custom audiences that you want this service to support. Specify each custom audience as the full URL in a string. The custom audiences are encoded in the token and used to authenticate requests. For more information, see https://cloud.google.com/run/docs/configuring/custom-audiences. item_type: Api::Type::String + - !ruby/object:Api::Type::NestedObject + name: 'scaling' + min_version: beta + description: | + Scaling settings that apply to the whole service + properties: + - !ruby/object:Api::Type::Integer + name: 'minInstanceCount' + description: | + Minimum number of instances for the service, to be divided among all revisions receiving traffic. - !ruby/object:Api::Type::NestedObject name: 'template' required: true diff --git a/mmv1/third_party/terraform/services/cloudrunv2/resource_cloud_run_v2_service_test.go.erb b/mmv1/third_party/terraform/services/cloudrunv2/resource_cloud_run_v2_service_test.go.erb index f74b09be0e2f..bacaa401b2d6 100644 --- a/mmv1/third_party/terraform/services/cloudrunv2/resource_cloud_run_v2_service_test.go.erb +++ b/mmv1/third_party/terraform/services/cloudrunv2/resource_cloud_run_v2_service_test.go.erb @@ -794,6 +794,107 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceAttributionLabel(t *testing.T) { }) } +<% unless version == 'ga' -%> +func TestAccCloudRunV2Service_cloudrunv2ServiceWithServiceMinInstances(t *testing.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.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckCloudRunV2ServiceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccCloudRunV2Service_cloudrunv2ServiceWithMinInstances(context), + }, + { + ResourceName: "google_cloud_run_v2_service.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "launch_stage"}, + }, + { + Config: testAccCloudRunV2Service_cloudrunv2ServiceWithNoMinInstances(context), + }, + { + ResourceName: "google_cloud_run_v2_service.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "launch_stage"}, + }, + + }, + }) +} + +func testAccCloudRunV2Service_cloudrunv2ServiceWithNoMinInstances(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_cloud_run_v2_service" "default" { + name = "tf-test-cloudrun-service%{random_suffix}" + description = "description creating" + location = "us-central1" + launch_stage = "BETA" + annotations = { + generated-by = "magic-modules" + } + ingress = "INGRESS_TRAFFIC_ALL" + labels = { + label-1 = "value-1" + } + client = "client-1" + client_version = "client-version-1" + template { + containers { + name = "container-1" + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + lifecycle { + ignore_changes = [ + launch_stage, + ] + } +} + +`, context) +} +func testAccCloudRunV2Service_cloudrunv2ServiceWithMinInstances(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_cloud_run_v2_service" "default" { + name = "tf-test-cloudrun-service%{random_suffix}" + description = "description creating" + location = "us-central1" + launch_stage = "BETA" + annotations = { + generated-by = "magic-modules" + } + ingress = "INGRESS_TRAFFIC_ALL" + labels = { + label-1 = "value-1" + } + client = "client-1" + client_version = "client-version-1" + scaling { + min_instance_count = 1 + } + template { + containers { + name = "container-1" + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + lifecycle { + ignore_changes = [ + launch_stage, + ] + } +} + +`, context) +} +<% end -%> + func testAccCloudRunV2Service_cloudrunv2ServiceWithAttributionLabel(context map[string]interface{}) string { return acctest.Nprintf(` provider "google" { From 787da35afeb5c4fa51a73001a2c0de59bb366ba8 Mon Sep 17 00:00:00 2001 From: jinyangtang <147192056+jinyangtang@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:00:27 -0800 Subject: [PATCH 19/32] feat: Add CMEK support for Firestore database in Beta provider (#10044) * Modify database.yaml to add cmek related fields * Add two examples for firestore CMEK databases for testing * Resolve trailing space * Update documentation for kmsKeyName field * Resolve trailing space * Make field immutable * Update field documentation * Update field description --- mmv1/products/firestore/Database.yaml | 72 +++++++++++++++++++ .../examples/firestore_cmek_database.tf.erb | 50 +++++++++++++ ...ore_cmek_database_in_datastore_mode.tf.erb | 50 +++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 mmv1/templates/terraform/examples/firestore_cmek_database.tf.erb create mode 100644 mmv1/templates/terraform/examples/firestore_cmek_database_in_datastore_mode.tf.erb diff --git a/mmv1/products/firestore/Database.yaml b/mmv1/products/firestore/Database.yaml index 051872d7bc1a..d294f94c147a 100644 --- a/mmv1/products/firestore/Database.yaml +++ b/mmv1/products/firestore/Database.yaml @@ -78,6 +78,23 @@ examples: - project - etag - deletion_policy + - !ruby/object:Provider::Terraform::Examples + name: 'firestore_cmek_database' + min_version: beta + primary_resource_id: 'database' + vars: + database_id: "cmek-database-id" + delete_protection_state: "DELETE_PROTECTION_ENABLED" + kms_key_ring_name: "kms-key-ring" + kms_key_name: "kms-key" + test_env_vars: + project_id: :PROJECT_NAME + test_vars_overrides: + delete_protection_state: '"DELETE_PROTECTION_DISABLED"' + ignore_read_extra: + - project + - etag + - deletion_policy - !ruby/object:Provider::Terraform::Examples name: 'firestore_default_database_in_datastore_mode' primary_resource_id: 'datastore_mode_database' @@ -102,6 +119,23 @@ examples: - project - etag - deletion_policy + - !ruby/object:Provider::Terraform::Examples + name: 'firestore_cmek_database_in_datastore_mode' + min_version: beta + primary_resource_id: 'database' + vars: + database_id: "cmek-database-id" + delete_protection_state: "DELETE_PROTECTION_ENABLED" + kms_key_ring_name: "kms-key-ring" + kms_key_name: "kms-key" + test_env_vars: + project_id: :PROJECT_NAME + test_vars_overrides: + delete_protection_state: '"DELETE_PROTECTION_DISABLED"' + ignore_read_extra: + - project + - etag + - deletion_policy virtual_fields: - !ruby/object:Api::Type::Enum name: 'deletion_policy' @@ -234,3 +268,41 @@ properties: This value is continuously updated, and becomes stale the moment it is queried. If you are using this value to recover data, make sure to account for the time from the moment when the value is queried to the moment when you initiate the recovery. A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". output: true + - !ruby/object:Api::Type::NestedObject + name: cmekConfig + min_version: beta + immutable: true + description: | + The CMEK (Customer Managed Encryption Key) configuration for a Firestore + database. If not present, the database is secured by the default Google + encryption key. + properties: + - !ruby/object:Api::Type::String + name: kmsKeyName + required: true + immutable: true + description: | + The resource ID of a Cloud KMS key. If set, the database created will + be a Customer-managed Encryption Key (CMEK) database encrypted with + this key. This feature is allowlist only in initial launch. + + Only keys in the same location as this database are allowed to be used + for encryption. For Firestore's nam5 multi-region, this corresponds to Cloud KMS + multi-region us. For Firestore's eur3 multi-region, this corresponds to + Cloud KMS multi-region europe. See https://cloud.google.com/kms/docs/locations. + + This value should be the KMS key resource ID in the format of + `projects/{project_id}/locations/{kms_location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}`. + How to retrive this resource ID is listed at + https://cloud.google.com/kms/docs/getting-resource-ids#getting_the_id_for_a_key_and_version. + - !ruby/object:Api::Type::Array + name: activeKeyVersion + output: true + description: | + Currently in-use KMS key versions (https://cloud.google.com/kms/docs/resource-hierarchy#key_versions). + During key rotation (https://cloud.google.com/kms/docs/key-rotation), there can be + multiple in-use key versions. + + The expected format is + `projects/{project_id}/locations/{kms_location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}/cryptoKeyVersions/{key_version}`. + item_type: Api::Type::String diff --git a/mmv1/templates/terraform/examples/firestore_cmek_database.tf.erb b/mmv1/templates/terraform/examples/firestore_cmek_database.tf.erb new file mode 100644 index 000000000000..330b16d32eab --- /dev/null +++ b/mmv1/templates/terraform/examples/firestore_cmek_database.tf.erb @@ -0,0 +1,50 @@ +data "google_project" "project" { + provider = google-beta +} + +resource "google_firestore_database" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + + project = "<%= ctx[:test_env_vars]['project_id'] %>" + name = "<%= ctx[:vars]['database_id']%>" + location_id = "nam5" + type = "FIRESTORE_NATIVE" + concurrency_mode = "OPTIMISTIC" + app_engine_integration_mode = "DISABLED" + point_in_time_recovery_enablement = "POINT_IN_TIME_RECOVERY_ENABLED" + delete_protection_state = "<%= ctx[:vars]['delete_protection_state'] %>" + deletion_policy = "DELETE" + cmek_config { + kms_key_name = google_kms_crypto_key.crypto_key.id + } + + depends_on = [ + google_kms_crypto_key_iam_binding.firestore_cmek_keyuser + ] +} + +resource "google_kms_crypto_key" "crypto_key" { + provider = google-beta + + name = "<%= ctx[:vars]['kms_key_name'] %>" + key_ring = google_kms_key_ring.key_ring.id + purpose = "ENCRYPT_DECRYPT" +} + +resource "google_kms_key_ring" "key_ring" { + provider = google-beta + + name = "<%= ctx[:vars]['kms_key_ring_name'] %>" + location = "us" +} + +resource "google_kms_crypto_key_iam_binding" "firestore_cmek_keyuser" { + provider = google-beta + + crypto_key_id = google_kms_crypto_key.crypto_key.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + members = [ + "serviceAccount:service-${data.google_project.project.number}@gcp-sa-firestore.iam.gserviceaccount.com", + ] +} diff --git a/mmv1/templates/terraform/examples/firestore_cmek_database_in_datastore_mode.tf.erb b/mmv1/templates/terraform/examples/firestore_cmek_database_in_datastore_mode.tf.erb new file mode 100644 index 000000000000..ac2a33a8ce06 --- /dev/null +++ b/mmv1/templates/terraform/examples/firestore_cmek_database_in_datastore_mode.tf.erb @@ -0,0 +1,50 @@ +data "google_project" "project" { + provider = google-beta +} + +resource "google_firestore_database" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + + project = "<%= ctx[:test_env_vars]['project_id'] %>" + name = "<%= ctx[:vars]['database_id']%>" + location_id = "nam5" + type = "DATASTORE_MODE" + concurrency_mode = "OPTIMISTIC" + app_engine_integration_mode = "DISABLED" + point_in_time_recovery_enablement = "POINT_IN_TIME_RECOVERY_ENABLED" + delete_protection_state = "<%= ctx[:vars]['delete_protection_state'] %>" + deletion_policy = "DELETE" + cmek_config { + kms_key_name = google_kms_crypto_key.crypto_key.id + } + + depends_on = [ + google_kms_crypto_key_iam_binding.firestore_cmek_keyuser + ] +} + +resource "google_kms_crypto_key" "crypto_key" { + provider = google-beta + + name = "<%= ctx[:vars]['kms_key_name'] %>" + key_ring = google_kms_key_ring.key_ring.id + purpose = "ENCRYPT_DECRYPT" +} + +resource "google_kms_key_ring" "key_ring" { + provider = google-beta + + name = "<%= ctx[:vars]['kms_key_ring_name'] %>" + location = "us" +} + +resource "google_kms_crypto_key_iam_binding" "firestore_cmek_keyuser" { + provider = google-beta + + crypto_key_id = google_kms_crypto_key.crypto_key.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + members = [ + "serviceAccount:service-${data.google_project.project.number}@gcp-sa-firestore.iam.gserviceaccount.com", + ] +} From bbb072140e12dd22cfc72dd5dfe2c182337cb497 Mon Sep 17 00:00:00 2001 From: Naitian Liu <83430653+naitianliu-google@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:28:02 -0800 Subject: [PATCH 20/32] Allow vcenter_network to be set (#9946) * Allow vcenter_network to be set * set default from api --- mmv1/products/gkeonprem/VmwareCluster.yaml | 3 ++- .../terraform/examples/gkeonprem_vmware_cluster_f5lb.tf.erb | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mmv1/products/gkeonprem/VmwareCluster.yaml b/mmv1/products/gkeonprem/VmwareCluster.yaml index 26a32312ce27..0e2e265fac87 100644 --- a/mmv1/products/gkeonprem/VmwareCluster.yaml +++ b/mmv1/products/gkeonprem/VmwareCluster.yaml @@ -252,7 +252,8 @@ properties: description: vcenter_network specifies vCenter network name. Inherited from the admin cluster. - output: true + immutable: true + default_from_api: true - !ruby/object:Api::Type::NestedObject name: 'hostConfig' description: diff --git a/mmv1/templates/terraform/examples/gkeonprem_vmware_cluster_f5lb.tf.erb b/mmv1/templates/terraform/examples/gkeonprem_vmware_cluster_f5lb.tf.erb index 3f9f6a15c69b..dbab108ee6bf 100644 --- a/mmv1/templates/terraform/examples/gkeonprem_vmware_cluster_f5lb.tf.erb +++ b/mmv1/templates/terraform/examples/gkeonprem_vmware_cluster_f5lb.tf.erb @@ -21,6 +21,7 @@ resource "google_gkeonprem_vmware_cluster" "<%= ctx[:primary_resource_id] %>" { gateway="test-gateway" } } + vcenter_network = "test-vcenter-network" } control_plane_node { cpus = 4 From 5780286152c4dcfa0d1b7caa6f9214dc6ffc73c4 Mon Sep 17 00:00:00 2001 From: Zhenhua Li Date: Wed, 6 Mar 2024 16:43:27 -0800 Subject: [PATCH 21/32] Sort resources and set in product in go compiler (#10135) --- mmv1/api/product.go | 10 +++++++++- mmv1/api/resource.go | 23 +++++++++++++++++++++-- mmv1/api/type.go | 5 ++--- mmv1/main.go | 25 ++++++++++++++++--------- mmv1/provider/terraform.go | 2 +- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/mmv1/api/product.go b/mmv1/api/product.go index cf3bd9d33a48..d56edeefb9be 100644 --- a/mmv1/api/product.go +++ b/mmv1/api/product.go @@ -39,7 +39,7 @@ type Product struct { // Display Name: The full name of the GCP product; eg "Cloud Bigtable" - Objects []interface{} + Objects []*Resource // The list of permission scopes available for the service // For example: `https://www.googleapis.com/auth/compute` @@ -69,6 +69,14 @@ type Product struct { ClientName string `yaml:"client_name"` } +func (p *Product) Validate() { + // TODO Q1 Rewrite super + // super + for _, o := range p.Objects { + o.ProductMetadata = p + } +} + // def validate // super // set_variables @objects, :__product diff --git a/mmv1/api/resource.go b/mmv1/api/resource.go index 75557aaee73b..894850e765c1 100644 --- a/mmv1/api/resource.go +++ b/mmv1/api/resource.go @@ -267,9 +267,28 @@ type Resource struct { // Add a deprecation message for a resource that's been deprecated in the API. DeprecationMessage string `yaml:"deprecation_message"` - Properties []Type + Properties []*Type - Parameters []Type + Parameters []*Type + + ProductMetadata *Product } // TODO: rewrite functions +func (r *Resource) Validate() { + // TODO Q1 Rewrite super + // super + + r.setResourceMetada(r.Parameters) + r.setResourceMetada(r.Properties) +} + +func (r *Resource) setResourceMetada(properties []*Type) { + if properties == nil { + return + } + + for _, property := range properties { + property.ResourceMetadata = r + } +} diff --git a/mmv1/api/type.go b/mmv1/api/type.go index b65547f1c9f3..0fe6f165e6dd 100644 --- a/mmv1/api/type.go +++ b/mmv1/api/type.go @@ -231,10 +231,9 @@ type Type struct { // just as they are in the standard flattener template. CustomFlatten string `yaml:"custom_flatten"` - __resource Resource + ResourceMetadata *Resource - // TODO: set a specific type intead of interface{} - __parent interface{} // is nil for top-level properties + ParentMetadata *Type // is nil for top-level properties } const MAX_NAME = 20 diff --git a/mmv1/main.go b/mmv1/main.go index b23108ac117a..b01aad864eaf 100644 --- a/mmv1/main.go +++ b/mmv1/main.go @@ -80,17 +80,17 @@ func main() { // TODO Q1: remove these lines, which are for debugging // log.Printf("productYamlPath %#v", productYamlPath) - var resources []api.Resource + var resources []*api.Resource = make([]*api.Resource, 0) productYaml, err := os.ReadFile(productYamlPath) if err != nil { log.Fatalf("Cannot open the file: %v", productYaml) } - productApi := api.Product{} - yamlValidator.Parse(productYaml, &productApi) + productApi := &api.Product{} + yamlValidator.Parse(productYaml, productApi) // TODO Q1: remove these lines, which are for debugging - // prod, _ := json.Marshal(&productApi) + // prod, _ := json.Marshal(productApi) // log.Printf("prod %s", string(prod)) if !productApi.ExistsAtVersionOrLower(version) { @@ -118,21 +118,29 @@ func main() { if err != nil { log.Fatalf("Cannot open the file: %v", resourceYamlPath) } - resource := api.Resource{} - yamlValidator.Parse(resourceYaml, &resource) + resource := &api.Resource{} + yamlValidator.Parse(resourceYaml, resource) // TODO Q1: remove these lines, which are for debugging - // res, _ := json.Marshal(&resource) + // res, _ := json.Marshal(resource) // log.Printf("resource %s", string(res)) // TODO Q1: add labels related fields + resource.Validate() resources = append(resources, resource) } // TODO Q2: override resources + log.Printf("resources before sorting %#v", resources) - // TODO Q1: sort resources by name and set in product + // Sort resources by name + sort.Slice(resources, func(i, j int) bool { + return resources[i].Name < resources[j].Name + }) + + productApi.Objects = resources + productApi.Validate() // TODO Q2: set other providers via flag providerToGenerate := provider.NewTerraform(productApi) @@ -142,7 +150,6 @@ func main() { continue } - // TODO Q1: generate templates log.Printf("%s: Generating files", productName) providerToGenerate.Generate(outputPath, productName, generateCode, generateDocs) } diff --git a/mmv1/provider/terraform.go b/mmv1/provider/terraform.go index 154e89c12736..fb620c1ddce5 100644 --- a/mmv1/provider/terraform.go +++ b/mmv1/provider/terraform.go @@ -34,7 +34,7 @@ type Terraform struct { ResourcesForVersion []api.Resource } -func NewTerraform(product api.Product) *Terraform { +func NewTerraform(product *api.Product) *Terraform { t := Terraform{ResourceCount: 0, IAMResourceCount: 0} // TODO Q1 From a68867619922a8f947e59c9246281f4c6c741f34 Mon Sep 17 00:00:00 2001 From: Sneha Prasad <32434989+snpd25@users.noreply.github.com> Date: Thu, 7 Mar 2024 20:19:17 +0530 Subject: [PATCH 22/32] fix failing posture test (#10086) * fix failing posture test * modify posture name --------- Co-authored-by: Sneha Prasad --- .../terraform/examples/securityposture_posture_basic.tf.erb | 2 +- .../securityposture_posture_deployment_basic.tf.erb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mmv1/templates/terraform/examples/securityposture_posture_basic.tf.erb b/mmv1/templates/terraform/examples/securityposture_posture_basic.tf.erb index 9101034c48c2..32205bb0ae71 100644 --- a/mmv1/templates/terraform/examples/securityposture_posture_basic.tf.erb +++ b/mmv1/templates/terraform/examples/securityposture_posture_basic.tf.erb @@ -1,5 +1,5 @@ resource "google_securityposture_posture" "<%= ctx[:primary_resource_id] %>"{ - posture_id = "posture_1" + posture_id = "posture_example" parent = "organizations/<%= ctx[:test_env_vars]['org_id'] %>" location = "global" state = "ACTIVE" diff --git a/mmv1/templates/terraform/examples/securityposture_posture_deployment_basic.tf.erb b/mmv1/templates/terraform/examples/securityposture_posture_deployment_basic.tf.erb index 8a514eb735e2..45cd4d886073 100644 --- a/mmv1/templates/terraform/examples/securityposture_posture_deployment_basic.tf.erb +++ b/mmv1/templates/terraform/examples/securityposture_posture_deployment_basic.tf.erb @@ -1,4 +1,4 @@ -resource "google_securityposture_posture" "posture1" { +resource "google_securityposture_posture" "posture_1" { posture_id = "posture_1" parent = "organizations/<%= ctx[:test_env_vars]['org_id'] %>" location = "global" @@ -27,6 +27,6 @@ resource "google_securityposture_posture_deployment" "<%= ctx[:primary_resource_ location = "global" description = "a new posture deployment" target_resource = "projects/<%= ctx[:test_env_vars]['project_number'] %>" - posture_id = google_securityposture_posture.posture1.name - posture_revision_id = google_securityposture_posture.posture1.revision_id + posture_id = google_securityposture_posture.posture_1.name + posture_revision_id = google_securityposture_posture.posture_1.revision_id } \ No newline at end of file From 5c5b415c6c20bb760b511e8589d270dcc3728a50 Mon Sep 17 00:00:00 2001 From: rishamchokshi <44479344+rishamchokshi@users.noreply.github.com> Date: Thu, 7 Mar 2024 09:19:13 -0700 Subject: [PATCH 23/32] Create support for KMS Ekmconnection resource (#10094) --- mmv1/products/kms/EkmConnection.yaml | 166 ++++++++++++++++++ .../examples/kms_ekm_connection_basic.tf.erb | 12 ++ .../kms/resource_kms_ekm_connection_test.go | 139 +++++++++++++++ 3 files changed, 317 insertions(+) create mode 100644 mmv1/products/kms/EkmConnection.yaml create mode 100644 mmv1/templates/terraform/examples/kms_ekm_connection_basic.tf.erb create mode 100644 mmv1/third_party/terraform/services/kms/resource_kms_ekm_connection_test.go diff --git a/mmv1/products/kms/EkmConnection.yaml b/mmv1/products/kms/EkmConnection.yaml new file mode 100644 index 000000000000..191bf70d852d --- /dev/null +++ b/mmv1/products/kms/EkmConnection.yaml @@ -0,0 +1,166 @@ +# Copyright 2023 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. + +--- !ruby/object:Api::Resource +name: 'EkmConnection' +base_url: 'projects/{{project}}/locations/{{location}}/ekmConnections' +create_url: 'projects/{{project}}/locations/{{location}}/ekmConnections?ekmConnectionId={{name}}' +self_link: 'projects/{{project}}/locations/{{location}}/ekmConnections/{{name}}' +update_verb: :PATCH +update_mask: true +description: | + `Ekm Connections` are used to control the connection settings for an `EXTERNAL_VPC` CryptoKey. + It is used to connect customer's external key manager to Google Cloud EKM. + + + ~> **Note:** Ekm Connections cannot be deleted from Google Cloud Platform. +references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Creating a Ekm Connection': 'https://cloud.google.com/kms/docs/create-ekm-connection' + api: 'https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.ekmConnections' +id_format: 'projects/{{project}}/locations/{{location}}/ekmConnections/{{name}}' +import_format: ['projects/{{project}}/locations/{{location}}/ekmConnections/{{name}}'] +skip_delete: true +examples: + - !ruby/object:Provider::Terraform::Examples + name: 'kms_ekm_connection_basic' + primary_resource_id: + 'example-ekmconnection' + skip_test: true + vars: + ekmconnection_name: 'ekmconnection_example' +parameters: + - !ruby/object:Api::Type::String + name: 'location' + description: | + The location for the EkmConnection. + A full list of valid locations can be found by running `gcloud kms locations list`. + required: true + ignore_read: true + url_param_only: true + immutable: true +properties: + - !ruby/object:Api::Type::String + name: 'name' + description: | + The resource name for the EkmConnection. + required: true + immutable: true + diff_suppress_func: 'tpgresource.CompareResourceNames' + custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.erb' + - !ruby/object:Api::Type::Array + name: 'serviceResolvers' + description: | + A list of ServiceResolvers where the EKM can be reached. There should be one ServiceResolver per EKM replica. Currently, only a single ServiceResolver is supported + required: true + item_type: !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::String + name: 'serviceDirectoryService' + description: | + Required. The resource name of the Service Directory service pointing to an EKM replica, in the format projects/*/locations/*/namespaces/*/services/* + required: true + - !ruby/object:Api::Type::String + name: 'hostname' + description: | + Required. The hostname of the EKM replica used at TLS and HTTP layers. + required: true + - !ruby/object:Api::Type::Array + name: 'serverCertificates' + description: | + Required. A list of leaf server certificates used to authenticate HTTPS connections to the EKM replica. Currently, a maximum of 10 Certificate is supported. + required: true + item_type: !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::String + name: 'rawDer' + description: | + Required. The raw certificate bytes in DER format. A base64-encoded string. + required: true + - !ruby/object:Api::Type::Boolean + name: 'parsed' + description: | + Output only. True if the certificate was parsed successfully. + output: true + - !ruby/object:Api::Type::String + name: 'issuer' + description: | + Output only. The issuer distinguished name in RFC 2253 format. Only present if parsed is true. + output: true + - !ruby/object:Api::Type::String + name: 'subject' + description: | + Output only. The subject distinguished name in RFC 2253 format. Only present if parsed is true. + output: true + - !ruby/object:Api::Type::String + name: 'notBeforeTime' + description: | + Output only. The certificate is not valid before this time. Only present if parsed is true. + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". + output: true + - !ruby/object:Api::Type::String + name: 'notAfterTime' + description: | + Output only. The certificate is not valid after this time. Only present if parsed is true. + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". + output: true + - !ruby/object:Api::Type::String + name: 'sha256Fingerprint' + description: | + Output only. The SHA-256 certificate fingerprint as a hex string. Only present if parsed is true. + output: true + - !ruby/object:Api::Type::String + name: 'serialNumber' + description: | + Output only. The certificate serial number as a hex string. Only present if parsed is true. + output: true + - !ruby/object:Api::Type::Array + name: 'subjectAlternativeDnsNames' + description: | + Output only. The subject Alternative DNS names. Only present if parsed is true. + output: true + default_from_api: true + item_type: Api::Type::String + - !ruby/object:Api::Type::String + name: 'endpointFilter' + description: | + Optional. The filter applied to the endpoints of the resolved service. If no filter is specified, all endpoints will be considered. An endpoint will be chosen arbitrarily from the filtered list for each request. For endpoint filter syntax and examples, see https://cloud.google.com/service-directory/docs/reference/rpc/google.cloud.servicedirectory.v1#resolveservicerequest. + required: false + default_from_api: true + - !ruby/object:Api::Type::Enum + name: 'keyManagementMode' + description: | + Optional. Describes who can perform control plane operations on the EKM. If unset, this defaults to MANUAL + required: false + default_value: :MANUAL + values: + - :MANUAL + - :CLOUD_KMS + - !ruby/object:Api::Type::String + name: 'etag' + required: false + default_from_api: true + description: | + Optional. Etag of the currently stored EkmConnection. + - !ruby/object:Api::Type::String + name: 'cryptoSpacePath' + description: | + Optional. Identifies the EKM Crypto Space that this EkmConnection maps to. Note: This field is required if KeyManagementMode is CLOUD_KMS. + required: false + default_from_api: true + - !ruby/object:Api::Type::String + name: 'createTime' + description: | + Output only. The time at which the EkmConnection was created. + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". + output: true diff --git a/mmv1/templates/terraform/examples/kms_ekm_connection_basic.tf.erb b/mmv1/templates/terraform/examples/kms_ekm_connection_basic.tf.erb new file mode 100644 index 000000000000..49fcd7f8769c --- /dev/null +++ b/mmv1/templates/terraform/examples/kms_ekm_connection_basic.tf.erb @@ -0,0 +1,12 @@ +resource "google_kms_ekm_connection" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]['ekmconnection_name'] %>" + location = "us-central1" + key_management_mode = "MANUAL" + service_resolvers { + service_directory_service = "projects/project_id/locations/us-central1/namespaces/namespace_name/services/service_name" + hostname = "example-ekm.goog" + server_certificates { + raw_der = "==HAwIBCCAr6gAwIBAgIUWR+EV4lqiV7Ql12VY==" + } + } +} diff --git a/mmv1/third_party/terraform/services/kms/resource_kms_ekm_connection_test.go b/mmv1/third_party/terraform/services/kms/resource_kms_ekm_connection_test.go new file mode 100644 index 000000000000..38d9b6c39fd5 --- /dev/null +++ b/mmv1/third_party/terraform/services/kms/resource_kms_ekm_connection_test.go @@ -0,0 +1,139 @@ +package kms_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccKMSEkmConnection_kmsEkmConnectionBasicExample_update(t *testing.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.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccKMSEkmConnection_kmsEkmConnectionBasicExample_full(context), + }, + { + ResourceName: "google_kms_ekm_connection.example-ekmconnection", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "name"}, + }, + { + Config: testAccKMSEkmConnection_kmsEkmConnectionBasicExample_update(context), + }, + { + ResourceName: "google_kms_ekm_connection.example-ekmconnection", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "name"}, + }, + }, + }) +} + +func testAccKMSEkmConnection_kmsEkmConnectionBasicExample_full(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_secret_manager_secret_version" "raw_der" { + secret = "playground-cert" + project = "315636579862" +} +data "google_secret_manager_secret_version" "hostname" { + secret = "external-uri" + project = "315636579862" +} +data "google_secret_manager_secret_version" "servicedirectoryservice" { + secret = "external-servicedirectoryservice" + project = "315636579862" +} +data "google_project" "vpc-project" { + project_id = "cloud-ekm-refekm-playground" +} +data "google_project" "project" { +} +resource "google_project_iam_member" "add_sdviewer" { + project = data.google_project.vpc-project.number + role = "roles/servicedirectory.viewer" + member = "serviceAccount:service-${data.google_project.project.number}@gcp-sa-ekms.iam.gserviceaccount.com" +} +resource "google_project_iam_member" "add_pscAuthorizedService" { + project = data.google_project.vpc-project.number + role = "roles/servicedirectory.pscAuthorizedService" + member = "serviceAccount:service-${data.google_project.project.number}@gcp-sa-ekms.iam.gserviceaccount.com" +} +resource "google_kms_ekm_connection" "example-ekmconnection" { + name = "tf_test_ekmconnection_example%{random_suffix}" + location = "us-central1" + key_management_mode = "MANUAL" + service_resolvers { + service_directory_service = data.google_secret_manager_secret_version.servicedirectoryservice.secret_data + hostname = data.google_secret_manager_secret_version.hostname.secret_data + server_certificates { + raw_der = data.google_secret_manager_secret_version.raw_der.secret_data + } + } + depends_on = [ + google_project_iam_member.add_pscAuthorizedService, + google_project_iam_member.add_sdviewer + ] +} +`, context) +} + +func testAccKMSEkmConnection_kmsEkmConnectionBasicExample_update(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_project" "vpc-project" { + project_id = "cloud-ekm-refekm-playground" +} +data "google_project" "project" { +} +data "google_secret_manager_secret_version" "raw_der" { + secret = "playground-cert" + project = "315636579862" +} +data "google_secret_manager_secret_version" "hostname" { + secret = "external-uri" + project = "315636579862" +} +data "google_secret_manager_secret_version" "servicedirectoryservice" { + secret = "external-servicedirectoryservice" + project = "315636579862" +} +resource "google_project_iam_member" "add_sdviewer_updateekmconnection" { + project = data.google_project.vpc-project.number + role = "roles/servicedirectory.viewer" + member = "serviceAccount:service-${data.google_project.project.number}@gcp-sa-ekms.iam.gserviceaccount.com" +} +resource "google_project_iam_member" "add_pscAuthorizedService_updateekmconnection" { + project = data.google_project.vpc-project.number + role = "roles/servicedirectory.pscAuthorizedService" + member = "serviceAccount:service-${data.google_project.project.number}@gcp-sa-ekms.iam.gserviceaccount.com" +} +resource "google_kms_ekm_connection" "example-ekmconnection" { + name = "tf_test_ekmconnection_example%{random_suffix}" + location = "us-central1" + key_management_mode = "CLOUD_KMS" + crypto_space_path = "v0/longlived/crypto-space-placeholder" + service_resolvers { + service_directory_service = data.google_secret_manager_secret_version.servicedirectoryservice.secret_data + hostname = data.google_secret_manager_secret_version.hostname.secret_data + server_certificates { + raw_der = data.google_secret_manager_secret_version.raw_der.secret_data + } + } + depends_on = [ + google_project_iam_member.add_pscAuthorizedService_updateekmconnection, + google_project_iam_member.add_sdviewer_updateekmconnection + ] +} +`, context) +} From 12b3ce1062029cd144b66e51d511c12532df9363 Mon Sep 17 00:00:00 2001 From: kautikdk <144651627+kautikdk@users.noreply.github.com> Date: Thu, 7 Mar 2024 17:54:07 +0000 Subject: [PATCH 24/32] Fixes two lifecycle rules with different no_age value always generates change. (#10137) --- .../storage/resource_storage_bucket.go.erb | 8 +++--- .../resource_storage_bucket_test.go.erb | 26 ++++++++++++++++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.erb b/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.erb index 8f9d429e3408..ed7422389d82 100644 --- a/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.erb +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.erb @@ -1237,10 +1237,10 @@ func flattenBucketLifecycle(d *schema.ResourceData, lifecycle *storage.BucketLif rules := make([]map[string]interface{}, 0, len(lifecycle.Rule)) - for _, rule := range lifecycle.Rule { + for index, rule := range lifecycle.Rule { rules = append(rules, map[string]interface{}{ "action": schema.NewSet(resourceGCSBucketLifecycleRuleActionHash, []interface{}{flattenBucketLifecycleRuleAction(rule.Action)}), - "condition": schema.NewSet(resourceGCSBucketLifecycleRuleConditionHash, []interface{}{flattenBucketLifecycleRuleCondition(d, rule.Condition)}), + "condition": schema.NewSet(resourceGCSBucketLifecycleRuleConditionHash, []interface{}{flattenBucketLifecycleRuleCondition(index, d, rule.Condition)}), }) } @@ -1254,7 +1254,7 @@ func flattenBucketLifecycleRuleAction(action *storage.BucketLifecycleRuleAction) } } -func flattenBucketLifecycleRuleCondition(d *schema.ResourceData, condition *storage.BucketLifecycleRuleCondition) map[string]interface{} { +func flattenBucketLifecycleRuleCondition(index int, d *schema.ResourceData, condition *storage.BucketLifecycleRuleCondition) map[string]interface{} { ruleCondition := map[string]interface{}{ "created_before": condition.CreatedBefore, "matches_storage_class": tpgresource.ConvertStringArrToInterface(condition.MatchesStorageClass), @@ -1279,7 +1279,7 @@ func flattenBucketLifecycleRuleCondition(d *schema.ResourceData, condition *stor } } // setting no_age value from state config since it is terraform only variable and not getting value from backend. - if v, ok := d.GetOk("lifecycle_rule.0.condition"); ok{ + if v, ok := d.GetOk(fmt.Sprintf("lifecycle_rule.%d.condition",index)); ok{ state_condition := v.(*schema.Set).List()[0].(map[string]interface{}) ruleCondition["no_age"] = state_condition["no_age"].(bool) } diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go.erb b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go.erb index 7c686a2878cd..f62447cb399e 100644 --- a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go.erb +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go.erb @@ -508,7 +508,7 @@ func TestAccStorageBucket_lifecycleRulesNoAge(t *testing.T) { ResourceName: "google_storage_bucket.bucket", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"force_destroy","lifecycle_rule.0.condition.0.no_age"}, + ImportStateVerifyIgnore: []string{"force_destroy","lifecycle_rule.1.condition.0.no_age"}, }, { Config: testAccStorageBucket_customAttributes_withLifecycleNoAgeAndAge(bucketName), @@ -522,7 +522,7 @@ func TestAccStorageBucket_lifecycleRulesNoAge(t *testing.T) { ResourceName: "google_storage_bucket.bucket", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"force_destroy","lifecycle_rule.0.condition.0.no_age"}, + ImportStateVerifyIgnore: []string{"force_destroy","lifecycle_rule.1.condition.0.no_age"}, }, { Config: testAccStorageBucket_customAttributes_withLifecycle1(bucketName), @@ -1477,8 +1477,8 @@ func testAccCheckStorageBucketLifecycleConditionState(expected *bool, b *storage func testAccCheckStorageBucketLifecycleConditionNoAge(expected *int64, b *storage.Bucket) resource.TestCheckFunc { return func(s *terraform.State) error { - actual := b.Lifecycle.Rule[0].Condition.Age - if expected == nil && b.Lifecycle.Rule[0].Condition.Age== nil { + actual := b.Lifecycle.Rule[1].Condition.Age + if expected == nil && b.Lifecycle.Rule[1].Condition.Age == nil { return nil } if expected == nil { @@ -1688,6 +1688,15 @@ resource "google_storage_bucket" "bucket" { name = "%s" location = "EU" force_destroy = "true" + lifecycle_rule { + action { + type = "Delete" + } + condition { + age = 10 + no_age = false + } + } lifecycle_rule { action { type = "Delete" @@ -1707,6 +1716,15 @@ resource "google_storage_bucket" "bucket" { name = "%s" location = "EU" force_destroy = "true" + lifecycle_rule { + action { + type = "Delete" + } + condition { + age = 10 + no_age = false + } + } lifecycle_rule { action { type = "Delete" From e75074de0ad046be7c842eb6fea56adb59b32bd8 Mon Sep 17 00:00:00 2001 From: Sarah French <15078782+SarahFrench@users.noreply.github.com> Date: Thu, 7 Mar 2024 18:27:37 +0000 Subject: [PATCH 25/32] TeamCity: Add project for testing the provider functions feature branch (#10088) * Add ability to use non-default versions of Terraform in TeamCity builds * Add function to enable making build configs for single packages at a time * Add new sub project that contains 2 builds for testing provider functions the 2 builds: 1) only pulls code from the feature branch on the downstream hashicorp/terraform-provider-google repo 2) only pulls code from the feature branch on the downstream hashicorp/terraform-provider-google-beta repo These builds both use an alpha release of TF 1.8.0 * Add builds for testing auto generated branches in the MM upstream repos These re-use existing VCR Roots. * Make the builds that test the `FEATURE-BRANCH-provider-functions branches in the downstream repos run every night at the default time * Fix defect in 'Download Terraform' build step definition * Update build step to solve bug * Update build_configuration_per_package.kt --- .../builds/build_configuration_per_package.kt | 11 +- .../components/builds/build_parameters.kt | 14 ++- .../components/builds/build_steps.kt | 7 +- .../.teamcity/components/inputs/packages.kt | 10 ++ .../FEATURE-BRANCH-provider-functions.kt | 102 ++++++++++++++++++ .../components/projects/root_project.kt | 5 + 6 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 mmv1/third_party/terraform/.teamcity/components/projects/feature_branches/FEATURE-BRANCH-provider-functions.kt diff --git a/mmv1/third_party/terraform/.teamcity/components/builds/build_configuration_per_package.kt b/mmv1/third_party/terraform/.teamcity/components/builds/build_configuration_per_package.kt index 21d956030d68..395dc4da4a9c 100644 --- a/mmv1/third_party/terraform/.teamcity/components/builds/build_configuration_per_package.kt +++ b/mmv1/third_party/terraform/.teamcity/components/builds/build_configuration_per_package.kt @@ -15,6 +15,8 @@ import jetbrains.buildServer.configs.kotlin.sharedResources import jetbrains.buildServer.configs.kotlin.vcs.GitVcsRoot import replaceCharsId +// BuildConfigurationsForPackages accepts a map containing details of multiple packages in a provider and returns a list of build configurations for them all. +// Intended to be used in projects where we're testing all packages, e.g. the nightly test projects fun BuildConfigurationsForPackages(packages: Map>, providerName: String, parentProjectName: String, vcsRoot: GitVcsRoot, sharedResources: List, environmentVariables: AccTestConfiguration): List { val list = ArrayList() @@ -31,6 +33,13 @@ fun BuildConfigurationsForPackages(packages: Map>, p return list } +// BuildConfigurationForSinglePackage accepts details of a single package in a provider and returns a build configuration for it +// Intended to be used in short-lived projects where we're testing specific packages, e.g. feature branch testing +fun BuildConfigurationForSinglePackage(packageName: String, packagePath: String, packageDisplayName: String, providerName: String, parentProjectName: String, vcsRoot: GitVcsRoot, sharedResources: List, environmentVariables: AccTestConfiguration): BuildType{ + val pkg = PackageDetails(packageName, packageDisplayName, providerName, parentProjectName) + return pkg.buildConfiguration(packagePath, vcsRoot, sharedResources, environmentVariables) +} + class PackageDetails(private val packageName: String, private val displayName: String, private val providerName: String, private val parentProjectName: String) { // buildConfiguration returns a BuildType for a service package @@ -102,4 +111,4 @@ class PackageDetails(private val packageName: String, private val displayName: S var id = "%s_%s_PACKAGE_%s".format(this.parentProjectName, this.providerName, this.packageName) return replaceCharsId(id) } -} \ No newline at end of file +} diff --git a/mmv1/third_party/terraform/.teamcity/components/builds/build_parameters.kt b/mmv1/third_party/terraform/.teamcity/components/builds/build_parameters.kt index 88928ed37a23..7641bc858592 100644 --- a/mmv1/third_party/terraform/.teamcity/components/builds/build_parameters.kt +++ b/mmv1/third_party/terraform/.teamcity/components/builds/build_parameters.kt @@ -252,12 +252,20 @@ fun ParametrizedWithType.readOnlySettings() { } // ParametrizedWithType.terraformCoreBinaryTesting sets environment variables that control what Terraform version is downloaded -// and ensures the testing framework uses that downloaded version -fun ParametrizedWithType.terraformCoreBinaryTesting() { - text("env.TERRAFORM_CORE_VERSION", DefaultTerraformCoreVersion, "The version of Terraform Core which should be used for testing") +// and ensures the testing framework uses that downloaded version. The default Terraform core version is used if no argument is supplied. +fun ParametrizedWithType.terraformCoreBinaryTesting(tfVersion: String = DefaultTerraformCoreVersion) { + text("env.TERRAFORM_CORE_VERSION", tfVersion, "The version of Terraform Core which should be used for testing") hiddenVariable("env.TF_ACC_TERRAFORM_PATH", "%system.teamcity.build.checkoutDir%/tools/terraform", "The path where the Terraform Binary is located. Used by the testing framework.") } +// BuildType.overrideTerraformCoreVersion is used to override the value of TERRAFORM_CORE_VERSION in special cases where we're testing new features +// that rely on a specific version of Terraform we might not want to be used for all our tests in TeamCity. +fun BuildType.overrideTerraformCoreVersion(tfVersion: String){ + params { + terraformCoreBinaryTesting(tfVersion) + } +} + fun ParametrizedWithType.terraformShouldPanicForSchemaErrors() { hiddenVariable("env.TF_SCHEMA_PANIC_ON_ERROR", "1", "Panic if unknown/unmatched fields are set into the state") } diff --git a/mmv1/third_party/terraform/.teamcity/components/builds/build_steps.kt b/mmv1/third_party/terraform/.teamcity/components/builds/build_steps.kt index 78f942cf380d..4682f1240eb9 100644 --- a/mmv1/third_party/terraform/.teamcity/components/builds/build_steps.kt +++ b/mmv1/third_party/terraform/.teamcity/components/builds/build_steps.kt @@ -64,14 +64,15 @@ fun BuildSteps.downloadTerraformBinary() { // https://releases.hashicorp.com/terraform/0.12.28/terraform_0.12.28_linux_amd64.zip val terraformUrl = "https://releases.hashicorp.com/terraform/%env.TERRAFORM_CORE_VERSION%/terraform_%env.TERRAFORM_CORE_VERSION%_linux_amd64.zip" step(ScriptBuildStep { - name = "Download Terraform version %s".format(DefaultTerraformCoreVersion) + name = "Download Terraform" scriptContent = """ #!/bin/bash + echo "Downloading Terraform version %env.TERRAFORM_CORE_VERSION%" mkdir -p tools - wget -O tf.zip %s + wget -O tf.zip $terraformUrl unzip tf.zip mv terraform tools/ - """.format(terraformUrl).trimIndent() + """.trimIndent() }) } diff --git a/mmv1/third_party/terraform/.teamcity/components/inputs/packages.kt b/mmv1/third_party/terraform/.teamcity/components/inputs/packages.kt index 5ea3d2a5d48a..2e4b11ffb516 100644 --- a/mmv1/third_party/terraform/.teamcity/components/inputs/packages.kt +++ b/mmv1/third_party/terraform/.teamcity/components/inputs/packages.kt @@ -13,6 +13,11 @@ var PackagesListGa = mapOf( "displayName" to "Environment Variables", "path" to "./google/envvar" ), + "functions" to mapOf( + "name" to "functions", + "displayName" to "Provider-Defined Functions", + "path" to "./google/functions" + ), "fwmodels" to mapOf( "name" to "fwmodels", "displayName" to "Framework Models", @@ -64,6 +69,11 @@ var PackagesListBeta = mapOf( "displayName" to "Environment Variables", "path" to "./google-beta/envvar" ), + "functions" to mapOf( + "name" to "functions", + "displayName" to "Provider-Defined Functions", + "path" to "./google-beta/functions" + ), "fwmodels" to mapOf( "name" to "fwmodels", "displayName" to "Framework Models", diff --git a/mmv1/third_party/terraform/.teamcity/components/projects/feature_branches/FEATURE-BRANCH-provider-functions.kt b/mmv1/third_party/terraform/.teamcity/components/projects/feature_branches/FEATURE-BRANCH-provider-functions.kt new file mode 100644 index 000000000000..3c1752e227f7 --- /dev/null +++ b/mmv1/third_party/terraform/.teamcity/components/projects/feature_branches/FEATURE-BRANCH-provider-functions.kt @@ -0,0 +1,102 @@ +/* + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +// This file is controlled by MMv1, any changes made here will be overwritten + +package projects.feature_branches + +import ProviderNameBeta +import ProviderNameGa +import builds.* +import generated.PackagesListBeta +import generated.PackagesListGa +import jetbrains.buildServer.configs.kotlin.Project +import jetbrains.buildServer.configs.kotlin.vcs.GitVcsRoot +import replaceCharsId +import vcs_roots.ModularMagicianVCSRootBeta +import vcs_roots.ModularMagicianVCSRootGa + +const val featureBranchProviderFunctionsName = "FEATURE-BRANCH-provider-functions" +const val providerFunctionsTfCoreVersion = "1.8.0-alpha20240228" + +// VCS Roots specifically for pulling code from the feature branches in the downstream and upstream repos +object HashicorpVCSRootGa_featureBranchProviderFunctions: GitVcsRoot({ + name = "VCS root for the hashicorp/terraform-provider-${ProviderNameGa} repo @ refs/heads/${featureBranchProviderFunctionsName}" + url = "https://github.com/hashicorp/terraform-provider-${ProviderNameGa}" + branch = "refs/heads/${featureBranchProviderFunctionsName}" + branchSpec = "" // empty as we'll access no other branches +}) + +object HashicorpVCSRootBeta_featureBranchProviderFunctions: GitVcsRoot({ + name = "VCS root for the hashicorp/terraform-provider-${ProviderNameBeta} repo @ refs/heads/${featureBranchProviderFunctionsName}" + url = "https://github.com/hashicorp/terraform-provider-${ProviderNameBeta}" + branch = "refs/heads/${featureBranchProviderFunctionsName}" + branchSpec = "" // empty as we'll access no other branches +}) + +fun featureBranchProviderFunctionSubProject(allConfig: AllContextParameters): Project { + + val projectId = replaceCharsId(featureBranchProviderFunctionsName) + + val packageName = "functions" // This project will contain only builds to test this single package + val sharedResourcesEmpty: List = listOf() // No locking when testing functions + val vcrConfig = getVcrAcceptanceTestConfig(allConfig) // Reused below for both MM testing build configs + val trigger = NightlyTriggerConfiguration() // Resued below for running tests against the downstream repos every night. + + var parentId: String // To be overwritten when each build config is generated below. + + // GA + val gaConfig = getGaAcceptanceTestConfig(allConfig) + // How to make only build configuration to the relevant package(s) + val functionPackageGa = PackagesListGa.getValue(packageName) + + // Enable testing using hashicorp/terraform-provider-google + parentId = "${projectId}_HC_GA" + val buildConfigHashiCorpGa = BuildConfigurationForSinglePackage(packageName, functionPackageGa.getValue("path"), "Provider-Defined Functions (GA provider, HashiCorp downstream)", ProviderNameGa, parentId, HashicorpVCSRootGa_featureBranchProviderFunctions, sharedResourcesEmpty, gaConfig) + buildConfigHashiCorpGa.addTrigger(trigger) + + // Enable testing using modular-magician/terraform-provider-google + parentId = "${projectId}_MM_GA" + val buildConfigModularMagicianGa = BuildConfigurationForSinglePackage(packageName, functionPackageGa.getValue("path"), "Provider-Defined Functions (GA provider, MM upstream)", ProviderNameGa, parentId, ModularMagicianVCSRootGa, sharedResourcesEmpty, vcrConfig) + + // Beta + val betaConfig = getBetaAcceptanceTestConfig(allConfig) + val functionPackageBeta = PackagesListBeta.getValue("functions") + + // Enable testing using hashicorp/terraform-provider-google-beta + parentId = "${projectId}_HC_BETA" + val buildConfigHashiCorpBeta = BuildConfigurationForSinglePackage(packageName, functionPackageBeta.getValue("path"), "Provider-Defined Functions (Beta provider, HashiCorp downstream)", ProviderNameBeta, parentId, HashicorpVCSRootBeta_featureBranchProviderFunctions, sharedResourcesEmpty, betaConfig) + buildConfigHashiCorpBeta.addTrigger(trigger) + + // Enable testing using modular-magician/terraform-provider-google-beta + parentId = "${projectId}_MM_BETA" + val buildConfigModularMagicianBeta = BuildConfigurationForSinglePackage(packageName, functionPackageBeta.getValue("path"), "Provider-Defined Functions (Beta provider, MM upstream)", ProviderNameBeta, parentId, ModularMagicianVCSRootBeta, sharedResourcesEmpty, vcrConfig) + + val allBuildConfigs = listOf(buildConfigHashiCorpGa, buildConfigModularMagicianGa, buildConfigHashiCorpBeta, buildConfigModularMagicianBeta) + + // Make these builds use a 1.8.0-ish version of TF core + allBuildConfigs.forEach{ b -> + b.overrideTerraformCoreVersion(providerFunctionsTfCoreVersion) + } + + return Project{ + id(projectId) + name = featureBranchProviderFunctionsName + description = "Subproject for testing feature branch $featureBranchProviderFunctionsName" + + // Register feature branch-specific VCS roots in the project + vcsRoot(HashicorpVCSRootGa_featureBranchProviderFunctions) + vcsRoot(HashicorpVCSRootBeta_featureBranchProviderFunctions) + + // Register all build configs in the project + allBuildConfigs.forEach{ b -> + buildType(b) + } + + params { + readOnlySettings() + } + } +} \ No newline at end of file diff --git a/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt b/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt index 0c130da8eca5..a78260dfe650 100644 --- a/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt +++ b/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt @@ -18,6 +18,7 @@ import generated.ServicesListBeta import generated.ServicesListGa import jetbrains.buildServer.configs.kotlin.Project import jetbrains.buildServer.configs.kotlin.sharedResource +import projects.feature_branches.featureBranchProviderFunctionSubProject // googleCloudRootProject returns a root project that contains a subprojects for the GA and Beta version of the // Google provider. There are also resources to help manage the test projects used for acceptance tests. @@ -57,10 +58,14 @@ fun googleCloudRootProject(allConfig: AllContextParameters): Project { } } + // Projects required for nightly testing, testing MM upstreams, and sweepers subProject(googleSubProjectGa(allConfig)) subProject(googleSubProjectBeta(allConfig)) subProject(projectSweeperSubProject(allConfig)) + // Feature branch-testing projects - these will be added and removed as needed + subProject(featureBranchProviderFunctionSubProject(allConfig)) + params { readOnlySettings() } From 7d69486c5abeca313d2ce35ae053b073e34ca03a Mon Sep 17 00:00:00 2001 From: kangy-google Date: Thu, 7 Mar 2024 10:53:09 -0800 Subject: [PATCH 26/32] Add `ephemeral_directories` to google_workstations_workstation_config (#10042) * Add `ephemeral_directories` to google_workstations_workstation_config * Remove trailing spaces * Add a test for ephemeral_directories * Fix test * Add a test for source_image * Fix typo in test * Remove unnecessary immutable field --- .../workstations/WorkstationConfig.yaml | 42 +++++ ...orkstations_workstation_config_test.go.erb | 178 ++++++++++++++++++ 2 files changed, 220 insertions(+) diff --git a/mmv1/products/workstations/WorkstationConfig.yaml b/mmv1/products/workstations/WorkstationConfig.yaml index 624e5593fd20..39fada27bca8 100644 --- a/mmv1/products/workstations/WorkstationConfig.yaml +++ b/mmv1/products/workstations/WorkstationConfig.yaml @@ -369,6 +369,48 @@ properties: description: | Name of the snapshot to use as the source for the disk. This can be the snapshot's `self_link`, `id`, or a string in the format of `projects/{project}/global/snapshots/{snapshot}`. If set, `sizeGb` and `fsType` must be empty. Can only be updated if it has an existing value. # TODO(esu): Add conflicting fields once complex lists are supported. + - !ruby/object:Api::Type::Array + name: 'ephemeralDirectories' + description: | + Ephemeral directories which won't persist across workstation sessions. + default_from_api: true + item_type: !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::String + name: 'mountPath' + description: | + Location of this directory in the running workstation. + default_from_api: true + - !ruby/object:Api::Type::NestedObject + name: 'gcePd' + description: | + An EphemeralDirectory backed by a Compute Engine persistent disk. + default_from_api: true + properties: + - !ruby/object:Api::Type::String + name: 'diskType' + description: | + Type of the disk to use. Defaults to `"pd-standard"`. + default_from_api: true + - !ruby/object:Api::Type::String + name: 'sourceSnapshot' + description: | + Name of the snapshot to use as the source for the disk. + + Must be empty if `sourceImage` is set. + Must be empty if `read_only` is false. + Updating `source_snapshot` will update content in the ephemeral directory after the workstation is restarted. + - !ruby/object:Api::Type::String + name: 'sourceImage' + description: | + Name of the disk image to use as the source for the disk. + + Must be empty `sourceSnapshot` is set. + Updating `sourceImage` will update content in the ephemeral directory after the workstation is restarted. + - !ruby/object:Api::Type::Boolean + name: 'readOnly' + description: | + Whether the disk is read only. If true, the disk may be shared by multiple VMs and `sourceSnapshot` must be set. - !ruby/object:Api::Type::NestedObject name: 'container' description: | diff --git a/mmv1/third_party/terraform/services/workstations/resource_workstations_workstation_config_test.go.erb b/mmv1/third_party/terraform/services/workstations/resource_workstations_workstation_config_test.go.erb index 72565a7f5219..e29069d6ab11 100644 --- a/mmv1/third_party/terraform/services/workstations/resource_workstations_workstation_config_test.go.erb +++ b/mmv1/third_party/terraform/services/workstations/resource_workstations_workstation_config_test.go.erb @@ -223,6 +223,184 @@ resource "google_workstations_workstation_config" "default" { `, context) } +func TestAccWorkstationsWorkstationConfig_ephemeralDirectories(t *testing.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: testAccCheckWorkstationsWorkstationConfigDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccWorkstationsWorkstationConfig_ephemeralDirectories(context), + }, + { + ResourceName: "google_workstations_workstation_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"etag", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccWorkstationsWorkstationConfig_ephemeralDirectories(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "default" { + provider = google-beta + name = "tf-test-workstation-cluster%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "default" { + provider = google-beta + name = "tf-test-workstation-cluster%{random_suffix}" + ip_cidr_range = "10.0.0.0/24" + region = "us-central1" + network = google_compute_network.default.name +} + +resource "google_compute_disk" "test_source_disk" { + provider = google-beta + name = "tf-test-workstation-source-disk%{random_suffix}" + size = 10 + type = "pd-ssd" + zone = "us-central1-a" +} + +resource "google_compute_snapshot" "test_source_snapshot" { + provider = google-beta + name = "tf-test-workstation-source-snapshot%{random_suffix}" + source_disk = google_compute_disk.test_source_disk.name + zone = "us-central1-a" +} + +resource "google_workstations_workstation_cluster" "default" { + provider = google-beta + workstation_cluster_id = "tf-test-workstation-cluster%{random_suffix}" + network = google_compute_network.default.id + subnetwork = google_compute_subnetwork.default.id + location = "us-central1" + + labels = { + foo = "bar" + } +} + +resource "google_workstations_workstation_config" "default" { + provider = google-beta + workstation_config_id = "tf-test-workstation-config%{random_suffix}" + workstation_cluster_id = google_workstations_workstation_cluster.default.workstation_cluster_id + location = "us-central1" + + ephemeral_directories { + mount_path = "/cache" + gce_pd { + source_snapshot = google_compute_snapshot.test_source_snapshot.id + read_only = true + } + } + + labels = { + foo = "bar" + } +} +`, context) +} + +func TestAccWorkstationsWorkstationConfig_ephemeralDirectories_withSourceImage(t *testing.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: testAccCheckWorkstationsWorkstationConfigDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccWorkstationsWorkstationConfig_ephemeralDirectories_withSourceImage(context), + }, + { + ResourceName: "google_workstations_workstation_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"etag", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccWorkstationsWorkstationConfig_ephemeralDirectories_withSourceImage(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "default" { + provider = google-beta + name = "tf-test-workstation-cluster%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "default" { + provider = google-beta + name = "tf-test-workstation-cluster%{random_suffix}" + ip_cidr_range = "10.0.0.0/24" + region = "us-central1" + network = google_compute_network.default.name +} + +resource "google_compute_disk" "test_source_disk" { + provider = google-beta + name = "tf-test-workstation-source-disk%{random_suffix}" + size = 10 + type = "pd-ssd" + zone = "us-central1-a" +} + +resource "google_compute_image" "test_source_image" { + provider = google-beta + name = "tf-test-workstation-source-image%{random_suffix}" + source_disk = google_compute_disk.test_source_disk.name + storage_locations = ["us-central1"] +} + +resource "google_workstations_workstation_cluster" "default" { + provider = google-beta + workstation_cluster_id = "tf-test-workstation-cluster%{random_suffix}" + network = google_compute_network.default.id + subnetwork = google_compute_subnetwork.default.id + location = "us-central1" + + labels = { + foo = "bar" + } +} + +resource "google_workstations_workstation_config" "default" { + provider = google-beta + workstation_config_id = "tf-test-workstation-config%{random_suffix}" + workstation_cluster_id = google_workstations_workstation_cluster.default.workstation_cluster_id + location = "us-central1" + + ephemeral_directories { + mount_path = "/cache" + gce_pd { + disk_type = "pd-standard" + source_image = google_compute_image.test_source_image.id + read_only = true + } + } + + labels = { + foo = "bar" + } +} +`, context) +} func TestAccWorkstationsWorkstationConfig_serviceAccount(t *testing.T) { t.Parallel() From e285c09c0a21af2e5fe3721a23522331599c415e Mon Sep 17 00:00:00 2001 From: Lingkai Shen Date: Thu, 7 Mar 2024 14:57:08 -0500 Subject: [PATCH 27/32] App Check DeviceCheck provider (#9978) * App Check DeviceCheck provider * Remove minimal example & pattern field * Add real private keys that are not useful anywhere * Limit tests to beta --- .../firebaseappcheck/DeviceCheckConfig.yaml | 97 +++++++++++++++++++ ..._app_check_device_check_config_full.tf.erb | 34 +++++++ ..._app_check_device_check_config_test.go.erb | 63 ++++++++++++ .../test-fixtures/private-key-2.p8 | 15 +++ .../test-fixtures/private-key.p8 | 15 +++ 5 files changed, 224 insertions(+) create mode 100644 mmv1/products/firebaseappcheck/DeviceCheckConfig.yaml create mode 100644 mmv1/templates/terraform/examples/firebase_app_check_device_check_config_full.tf.erb create mode 100644 mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_device_check_config_test.go.erb create mode 100644 mmv1/third_party/terraform/services/firebaseappcheck/test-fixtures/private-key-2.p8 create mode 100644 mmv1/third_party/terraform/services/firebaseappcheck/test-fixtures/private-key.p8 diff --git a/mmv1/products/firebaseappcheck/DeviceCheckConfig.yaml b/mmv1/products/firebaseappcheck/DeviceCheckConfig.yaml new file mode 100644 index 000000000000..3b708a93471d --- /dev/null +++ b/mmv1/products/firebaseappcheck/DeviceCheckConfig.yaml @@ -0,0 +1,97 @@ +# Copyright 2024 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. + +--- +!ruby/object:Api::Resource +name: "DeviceCheckConfig" +base_url: projects/{{project}}/apps/{{app_id}}/deviceCheckConfig +self_link: projects/{{project}}/apps/{{app_id}}/deviceCheckConfig +create_url: projects/{{project}}/apps/{{app_id}}/deviceCheckConfig?updateMask=tokenTtl,keyId,privateKey +create_verb: :PATCH +update_verb: :PATCH +update_mask: true +skip_delete: true +description: | + An app's DeviceCheck configuration object. Note that the Team ID registered with your + app is used as part of the validation process. Make sure your `google_firebase_apple_app` has a team_id present. +references: !ruby/object:Api::Resource::ReferenceLinks + guides: + "Official Documentation": "https://firebase.google.com/docs/app-check" + api: "https://firebase.google.com/docs/reference/appcheck/rest/v1/projects.apps.deviceCheckConfig" +import_format: + [ + "projects/{{project}}/apps/{{app_id}}/deviceCheckConfig", + "{{project}}/{{app_id}}", + "{{app_id}}", + ] +examples: + - !ruby/object:Provider::Terraform::Examples + name: "firebase_app_check_device_check_config_full" + min_version: 'beta' + # Need the time_sleep resource + pull_external: true + primary_resource_id: "default" + vars: + bundle_id: "bundle.id.devicecheck" + key_id: "Key ID" + private_key_path: "path/to/private-key.p8" + team_id: "9987654321" + token_ttl: "7200s" + test_vars_overrides: + # Don't add random suffix + private_key_path: '"test-fixtures/private-key-2.p8"' + team_id: '"9987654321"' + token_ttl: '"7200s"' + test_env_vars: + project_id: :PROJECT_NAME +parameters: + - !ruby/object:Api::Type::String + name: app_id + description: | + The ID of an + [Apple App](https://firebase.google.com/docs/reference/firebase-management/rest/v1beta1/projects.iosApps#IosApp.FIELDS.app_id). + required: true + immutable: true + url_param_only: true +properties: + - !ruby/object:Api::Type::String + name: name + description: | + The relative resource name of the DeviceCheck configuration object + output: true + - !ruby/object:Api::Type::String + name: tokenTtl + description: | + Specifies the duration for which App Check tokens exchanged from DeviceCheck artifacts will be valid. + If unset, a default value of 1 hour is assumed. Must be between 30 minutes and 7 days, inclusive. + + A duration in seconds with up to nine fractional digits, ending with 's'. Example: "3.5s". + default_from_api: true + - !ruby/object:Api::Type::String + name: keyId + description: | + The key identifier of a private key enabled with DeviceCheck, created in your Apple Developer account. + required: true + - !ruby/object:Api::Type::String + name: privateKey + description: | + The contents of the private key (.p8) file associated with the key specified by keyId. + required: true + sensitive: true + ignore_read: true + - !ruby/object:Api::Type::Boolean + name: privateKeySet + description: | + Whether the privateKey field was previously set. Since App Check will never return the + privateKey field, this field is the only way to find out whether it was previously set. + output: true diff --git a/mmv1/templates/terraform/examples/firebase_app_check_device_check_config_full.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_device_check_config_full.tf.erb new file mode 100644 index 000000000000..72b6a96fbafb --- /dev/null +++ b/mmv1/templates/terraform/examples/firebase_app_check_device_check_config_full.tf.erb @@ -0,0 +1,34 @@ +resource "google_firebase_apple_app" "default" { + provider = google-beta + + project = "<%= ctx[:test_env_vars]['project_id'] %>" + display_name = "Apple app" + bundle_id = "<%= ctx[:vars]['bundle_id'] %>" + team_id = "<%= ctx[:vars]['team_id'] %>" +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_apple_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_device_check_config" "default" { + provider = google-beta + + project = "<%= ctx[:test_env_vars]['project_id'] %>" + app_id = google_firebase_apple_app.default.app_id + token_ttl = "<%= ctx[:vars]['token_ttl'] %>" + key_id = "<%= ctx[:vars]['key_id'] %>" + private_key = file("<%= ctx[:vars]['private_key_path'] %>") + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = google_firebase_apple_app.default.team_id != "" + error_message = "Provide a Team ID on the Apple App to use App Check" + } + } +} diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_device_check_config_test.go.erb b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_device_check_config_test.go.erb new file mode 100644 index 000000000000..156a2cac1e59 --- /dev/null +++ b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_device_check_config_test.go.erb @@ -0,0 +1,63 @@ +<% autogen_exception -%> +package firebaseappcheck_test +<% unless version == 'ga' -%> + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccFirebaseAppCheckDeviceCheckConfig_firebaseAppCheckDeviceCheckConfigUpdate(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "team_id": "9987654321", + "private_key_path": "test-fixtures/private-key.p8", + "token_ttl": "3900s", + "random_suffix": acctest.RandString(t, 10), + } + + contextUpdated := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "team_id": "9987654321", + "private_key_path": "test-fixtures/private-key-2.p8", + "token_ttl": "7200s", + // Bundle ID needs to be the same between updates but different between tests + "random_suffix": context["random_suffix"], + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirebaseAppCheckDeviceCheckConfig_firebaseAppCheckDeviceCheckConfigFullExample(context), + }, + { + ResourceName: "google_firebase_app_check_device_check_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"private_key", "app_id"}, + }, + { + Config: testAccFirebaseAppCheckDeviceCheckConfig_firebaseAppCheckDeviceCheckConfigFullExample(contextUpdated), + }, + { + ResourceName: "google_firebase_app_check_device_check_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"private_key", "app_id"}, + }, + }, + }) +} +<% end -%> diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/test-fixtures/private-key-2.p8 b/mmv1/third_party/terraform/services/firebaseappcheck/test-fixtures/private-key-2.p8 new file mode 100644 index 000000000000..f581bea0e054 --- /dev/null +++ b/mmv1/third_party/terraform/services/firebaseappcheck/test-fixtures/private-key-2.p8 @@ -0,0 +1,15 @@ +-----BEGIN PRIVATE KEY----- +MIICWwIBAAKBgQCVA/2LQtUYJI8KlNHWzNPzGzVv01qavSbmuW0QYjshxRnXDBk+ +fWZePJAmsyuhU4Y2SkM5Wqvgjo/rDPaRPdTiEtKQuNesRgQeOVmAWDkIXEiieTwb +RYuXbdpZhH86Vt6xOMt14tGPKE5VuuySvTqgQRCvRTylrF3koBc0d/8NVQIDAQAB +AoGAG7qBXH+ULYjoAR0OKv00V2FxwRxAGNknuvk4HTtaK3+Evmpm7CTjfpegb0MZ +1Ew5hjKtbae8oe2FRETGQOKTkS68I/D9PGP4aTzmSkf6PjwXwhlBYp09xxv4nmxV +BCbsoicNMvdk0F7SPblnZBO9i0DpZ8pT9wyPo8QzWBfi5IECQQD8gIOja3Zim4R9 +HVL7Blvhzhl2ibuITV2PKfQ11v0a+Om+rZKwdrhxKgWoguDvvP7ExWSPTZJKSm0J +bzhU+APhAkEAlxR3fY+zSpxHaxbOqZ6cea5cZtyHcX607nW8N037yBErIjcJKL65 +gHx9Vq1Xo24o4C6kyzmh00BnkyXul4439QJAPWvtmaUcaSQ3eE/XzaRgWW9PFlyu +t5tKNPcZprcjXppKEc4bLr3SZAS616DuoqKwvqDds1ZFTbkJCRB6/YBPQQJAeyGG +JYKJyKRIHMJw2pNXymBOFNNlXB29jp/ML3LSYwODGRar01ZmT46mhI8wXxV4IQZC +7xLgjhDumWIP69tQRQJAfuOy4TP2drxNI7fP7YenV1ks6CiLHcBN04f6NItWilTN +Cc+Mv/rio9xO56Yp9oePMaFT9QEzfO/cqX6QvyfblQ== +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/test-fixtures/private-key.p8 b/mmv1/third_party/terraform/services/firebaseappcheck/test-fixtures/private-key.p8 new file mode 100644 index 000000000000..d48a562a97bd --- /dev/null +++ b/mmv1/third_party/terraform/services/firebaseappcheck/test-fixtures/private-key.p8 @@ -0,0 +1,15 @@ +-----BEGIN PRIVATE KEY----- +MIICXAIBAAKBgG3vDegwb8uUvns/Iuodo/cNK0eMHxqb+2n16dQnxL7az+ShNWKQ +jTSzXY5y4VexrTdPEU5ZiTPONZXyl4/iFvOnyFxnC6Zjyr+xeIU5X4TmjYq0yCuZ +xbovAWw+E4KUKt1V62avd+hGZHPtCKLfV/uYITG7I8R+GyEAdMoaXP8JAgMBAAEC +gYBsQFf7aabMWx3uks84phNNNOSHQY1nUG2Te5nTVY3BOgo44h2Ffz3sxSq9GJaZ +GdatfehWtIgMQWQ20Xk5L7LUzSxmndHbUIzYU17xZrAsgmjYTwvAQ13If2L6S+pz +EUbTLkMnlbAgvtJ2AqZZZ3LE41N9ey60gVB1cCu9fCXLuQJBANAeoDXXvh7nXdyN +Zd84zXpSk8SLmAmQn1JB7z3oPkrZ0dG42GMOzYw9MP8n2bATHV+OB0/gdUFJAYYp +kwz+bJ8CQQCHObHelAlkH3or+JVECpovNMHs2UGB6yF1ZX0Nep3iR90fhi3BsnVo +IQGdHlQC2NL+iaBF4Mv2/dfZTen1vMtXAkEAk7+KQW8+G7ZpXjBLyCMNTO/e08O+ +VdwEH2OLsslzn7PvTxIJHJnfttWiOSJTWrrXOYUdD8nrtENd/574NFtTRQJAaExD +uJ0NsT/mB0wwNM7IpWhXusrHD+G/aMDidyb/56vuDYZ8fE2c6LesevcNbTS3aMPV +7o+4QcUAWwcRUQxQ+QJBAJEAwwzFnLJtrFYEnz7YNufgjiMrX7CBJCwrXGZpZrHX +EdDDOGiLrm871hc3tNQWmzou9AFIwZFeIOXVdIHIQzk= +-----END PRIVATE KEY----- \ No newline at end of file From 6caf25d3237cf1a05160638ab1b9f6bdde6d074a Mon Sep 17 00:00:00 2001 From: Salome Papiashvili Date: Thu, 7 Mar 2024 22:17:45 +0100 Subject: [PATCH 28/32] Documentation (#10012) * duplicate Composer 2 argument reference * remove fields that are not supported in Composer 3 * move fields that are new in Composer 3 to Composer 3 section only * make suggested changes, add description if new versioning schema * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown, remove outdated info Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * add notice that composer 3 is not yet released. * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Stephen Lewis (Burrows) * specify composer version in section links. * specify composer version in composer 1 documentation links * add section links in composer 2 argument reference * add section links in composer 3 argument reference * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> * Update mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> --------- Co-authored-by: Pavel Salnikov <90701144+pavel-salnikov@users.noreply.github.com> Co-authored-by: Stephen Lewis (Burrows) --- .../docs/r/composer_environment.html.markdown | 450 +++++++++++++++--- 1 file changed, 384 insertions(+), 66 deletions(-) diff --git a/mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown b/mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown index 61e961b78b54..81865ec37908 100644 --- a/mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown @@ -229,7 +229,7 @@ The following arguments are supported: * `config` - (Optional) - Configuration parameters for this environment Structure is [documented below](#nested_config). + Configuration parameters for this environment Structure is [documented below](#nested_config_c1). * `labels` - (Optional) @@ -260,7 +260,7 @@ The following arguments are supported: (Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used. -The `config` block supports: +The `config` block supports: * `node_count` - (Optional, Cloud Composer 1 only) @@ -268,28 +268,19 @@ The following arguments are supported: * `node_config` - (Optional) - The configuration used for the Kubernetes Engine cluster. Structure is [documented below](#nested_node_config). + The configuration used for the Kubernetes Engine cluster. Structure is [documented below](#nested_node_config_c1). * `recovery_config` - (Optional, Cloud Composer 2 only) - The configuration settings for recovery. Structure is [documented below](#nested_recovery_config). + The configuration settings for recovery. Structure is [documented below](#nested_recovery_config_c1). * `software_config` - (Optional) - The configuration settings for software inside the environment. Structure is [documented below](#nested_software_config). + The configuration settings for software inside the environment. Structure is [documented below](#nested_software_config_c1). * `private_environment_config` - (Optional) - The configuration used for the Private IP Cloud Composer environment. Structure is [documented below](#nested_private_environment_config). - -* `enable_private_environment` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) - If true, a private Composer environment will be created. - -* `enable_private_builds_only` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) - If true, builds performed during operations that install Python packages have only private connectivity to Google services. - If false, the builds also have access to the internet. + The configuration used for the Private IP Cloud Composer environment. Structure is [documented below](#nested_private_environment_config_c1). * `web_server_network_access_control` - The network-level access control policy for the Airflow web server. @@ -319,9 +310,9 @@ The following arguments are supported: master authorized networks will disallow all external traffic to access Kubernetes master through HTTPS except traffic from the given CIDR blocks, Google Compute Engine Public IPs and Google Prod IPs. Structure is - [documented below](#nested_master_authorized_networks_config). + [documented below](#nested_master_authorized_networks_config_c1). -The `node_config` block supports: +The `node_config` block supports: * `zone` - (Optional, Cloud Composer 1 only) @@ -382,7 +373,7 @@ The following arguments are supported: * `ip_allocation_policy` - (Optional) Configuration for controlling how IPs are allocated in the GKE cluster. - Structure is [documented below](#nested_ip_allocation_policy). + Structure is [documented below](#nested_ip_allocation_policy_c1). Cannot be updated. * `max_pods_per_node` - @@ -401,7 +392,7 @@ The following arguments are supported: all destination addresses, except between pods traffic. See the [documentation](https://cloud.google.com/composer/docs/enable-ip-masquerade-agent). -The `software_config` block supports: +The `software_config` block supports: * `airflow_config_overrides` - (Optional) Apache Airflow configuration properties to override. Property keys contain the section and property names, @@ -444,7 +435,7 @@ The following arguments are supported: ``` * `image_version` - - (Optional in Cloud Composer 1, required in Cloud Composer 2) +(Required) In Composer 1, use a specific Composer 1 version in this parameter. If omitted, the default is the latest version of Composer 2. The version of the software running in the environment. This encapsulates both the version of Cloud Composer functionality and the version of Apache Airflow. It must match the regular expression @@ -465,12 +456,8 @@ The following arguments are supported: (Optional, Cloud Composer 1 with Airflow 2 only) The number of schedulers for Airflow. -* `web_server_plugins_mode` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) - Web server plugins configuration. Should be either 'ENABLED' or 'DISABLED'. Defaults to 'ENABLED'. - -See [documentation](https://cloud.google.com/composer/docs/how-to/managing/configuring-private-ip) for setting up private environments. The `private_environment_config` block supports: +See [documentation](https://cloud.google.com/composer/docs/how-to/managing/configuring-private-ip) for setting up private environments. The `private_environment_config` block supports: * `connection_type` - (Optional, Cloud Composer 2 only) @@ -506,9 +493,9 @@ See [documentation](https://cloud.google.com/composer/docs/how-to/managing/confi The `web_server_network_access_control` supports: * `allowed_ip_range` - - A collection of allowed IP ranges with descriptions. Structure is [documented below](#nested_allowed_ip_range). + A collection of allowed IP ranges with descriptions. Structure is [documented below](#nested_allowed_ip_range_c1). -The `allowed_ip_range` supports: +The `allowed_ip_range` supports: * `value` - (Required) @@ -521,7 +508,7 @@ The `web_server_network_access_control` supports: (Optional) A description of this ip range. -The `ip_allocation_policy` block supports: +The `ip_allocation_policy` block supports: * `use_ip_aliases` - (Optional, Cloud Composer 1 only) @@ -560,7 +547,7 @@ The `web_server_network_access_control` supports: (e.g. 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) to pick a specific range to use. Specify either `services_secondary_range_name` or `services_ipv4_cidr_block` but not both. -The `database_config` block supports: +The `database_config` block supports: * `machine_type` - (Optional) @@ -571,7 +558,7 @@ The `web_server_network_access_control` supports: (Optional) Preferred Cloud SQL database zone. -The `web_server_config` block supports: +The `web_server_config` block supports: * `machine_type` - (Required) @@ -580,7 +567,7 @@ The `web_server_network_access_control` supports: Value custom is returned only in response, if Airflow web server parameters were manually changed to a non-standard values. -The `encryption_config` block supports: +The `encryption_config` block supports: * `kms_key_name` - (Required) @@ -588,7 +575,7 @@ The `web_server_network_access_control` supports: be the fully qualified resource name, i.e. projects/project-id/locations/location/keyRings/keyring/cryptoKeys/key. Cannot be updated. -The `maintenance_window` block supports: +The `maintenance_window` block supports: * `start_time` - (Required) Start time of the first recurrence of the maintenance window. @@ -604,15 +591,15 @@ The `web_server_network_access_control` supports: The only allowed values for 'FREQ' field are 'FREQ=DAILY' and 'FREQ=WEEKLY;BYDAY=...'. Example values: 'FREQ=WEEKLY;BYDAY=TU,WE', 'FREQ=DAILY'. -The `master_authorized_networks_config` block supports: +The `master_authorized_networks_config` block supports: * `enabled` - (Required) Whether or not master authorized networks is enabled. * `cidr_blocks` - - `cidr_blocks `define up to 50 external networks that could access Kubernetes master through HTTPS. Structure is [documented below](#nested_cidr_blocks). + `cidr_blocks `define up to 50 external networks that could access Kubernetes master through HTTPS. Structure is [documented below](#nested_cidr_blocks_c1). -The `cidr_blocks` supports: +The `cidr_blocks` supports: * `display_name` - (Optional) @@ -632,7 +619,7 @@ The following arguments are supported: * `config` - (Optional) - Configuration parameters for this environment. Structure is documented below. + Configuration parameters for this environment. Structure is [documented below](#nested_config_c2). * `labels` - (Optional) @@ -656,24 +643,23 @@ The following arguments are supported: * `storage_config` - (Optional) - Configuration options for storage used by Composer environment. Structure is documented below. + Configuration options for storage used by Composer environment. Structure is [documented below](#nested_storage_config_c2). -The `config` block supports: +The `config` block supports: * `node_config` - (Optional) - The configuration used for the Kubernetes Engine cluster. Structure is documented below. + The configuration used for the Kubernetes Engine cluster. Structure is [documented below](#nested_node_config_c2). * `software_config` - (Optional) The configuration settings for software (Airflow) inside the environment. Structure is - documented below. + [documented below](#nested_software_config_c2). * `private_environment_config` - (Optional) - The configuration used for the Private IP Cloud Composer environment. Structure is documented - below. + The configuration used for the Private IP Cloud Composer environment. Structure is [documented below](#nested_private_environment_config_c2). * `encryption_config` - (Optional) @@ -685,12 +671,12 @@ The `config` block supports: The configuration settings for Cloud Composer maintenance windows. * `workloads_config` - - (Optional, Cloud Composer 2 only) + (Optional) The Kubernetes workloads configuration for GKE cluster associated with the Cloud Composer environment. * `environment_size` - - (Optional, Cloud Composer 2 only) + (Optional) The environment size controls the performance parameters of the managed Cloud Composer infrastructure that includes the Airflow database. Values for environment size are `ENVIRONMENT_SIZE_SMALL`, `ENVIRONMENT_SIZE_MEDIUM`, @@ -709,20 +695,20 @@ The `config` block supports: master authorized networks will disallow all external traffic to access Kubernetes master through HTTPS except traffic from the given CIDR blocks, Google Compute Engine Public IPs and Google Prod IPs. Structure is - documented below. + [documented below](#nested_master_authorized_networks_config_c1). * `data_retention_config` - (Optional, Cloud Composer 2.0.23 or newer only) Configuration setting for airflow data rentention mechanism. Structure is - [documented below](#nested_data_retention_config). + [documented below](#nested_data_retention_config_c2). -The `data_retention_config` block supports: +The `data_retention_config` block supports: * `task_logs_retention_config` - (Optional) The configuration setting for Task Logs. Structure is - [documented below](#nested_task_logs_retention_config). + [documented below](#nested_task_logs_retention_config_c2). -The `task_logs_retention_config` block supports: +The `task_logs_retention_config` block supports: * `storage_mode` - (Optional) The mode of storage for Airflow workers task logs. Values for storage mode are @@ -730,14 +716,14 @@ The `config` block supports: `CLOUD_LOGGING_AND_CLOUD_STORAGE` to store logs in cloud logging and cloud storage. -The `storage_config` block supports: +The `storage_config` block supports: * `bucket` - (Required) Name of an existing Cloud Storage bucket to be used by the environment. -The `node_config` block supports: +The `node_config` block supports: * `network` - (Optional) @@ -773,7 +759,7 @@ The `node_config` block supports: * `ip_allocation_policy` - (Optional) Configuration for controlling how IPs are allocated in the GKE cluster. - Structure is documented below. + Structure is [documented below](#nested_ip_allocation_policy_c2). Cannot be updated. * `enable_ip_masq_agent` - @@ -783,12 +769,7 @@ The `node_config` block supports: packets from node IP addresses instead of Pod IP addresses See the [documentation](https://cloud.google.com/composer/docs/enable-ip-masquerade-agent). -* `composer_internal_ipv4_cidr_block` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) - At least /20 IPv4 cidr range that will be used by Composer internal components. - Cannot be updated. - -The `software_config` block supports: +The `software_config` block supports: * `airflow_config_overrides` - (Optional) Apache Airflow configuration properties to override. Property keys contain the section and property names, @@ -831,10 +812,8 @@ The `software_config` block supports: ``` * `image_version` - - (Required in Cloud Composer 2, optional in Cloud Composer 1) +(Optional) If omitted, the default is the latest version of Composer 2. - **In Cloud Composer 2, you must specify an image with Cloud Composer 2**. Otherwise, the default image for Cloud Composer 1 is used. For more information about Cloud Composer images, see - [Cloud Composer version list](https://cloud.google.com/composer/docs/concepts/versioning/composer-versions). The version of the software running in the environment. This encapsulates both the version of Cloud Composer functionality and the version of Apache Airflow. It must match the regular expression @@ -853,14 +832,14 @@ The `software_config` block supports: (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer environments in versions composer-2.1.2-airflow-*.*.* and newer) The configuration for Cloud Data Lineage integration. Structure is - [documented below](#nested_cloud_data_lineage_integration). + [documented below](#nested_cloud_data_lineage_integration_c2). -The `cloud_data_lineage_integration` block supports: +The `cloud_data_lineage_integration` block supports: * `enabled` - (Required) Whether or not Cloud Data Lineage integration is enabled. -See [documentation](https://cloud.google.com/composer/docs/how-to/managing/configuring-private-ip) for setting up private environments. The `private_environment_config` block supports: +See [documentation](https://cloud.google.com/composer/docs/how-to/managing/configuring-private-ip) for setting up private environments. The `private_environment_config` block supports: * `enable_private_endpoint` - If true, access to the public endpoint of the GKE cluster is denied. @@ -894,7 +873,7 @@ See [documentation](https://cloud.google.com/composer/docs/how-to/managing/confi versions `composer-2.*.*-airflow-*.*.*` and newer. -The `ip_allocation_policy` block supports: +The `ip_allocation_policy` block supports: * `cluster_secondary_range_name` - (Optional) @@ -951,7 +930,7 @@ The `ip_allocation_policy` block supports: The only allowed values for 'FREQ' field are 'FREQ=DAILY' and 'FREQ=WEEKLY;BYDAY=...'. Example values: 'FREQ=WEEKLY;BYDAY=TU,WE', 'FREQ=DAILY'. -The `recovery_config` block supports: +The `recovery_config` block supports: * `scheduled_snapshots_config` - (Optional) @@ -993,6 +972,345 @@ The `workloads_config` block supports: (Optional) Configuration for resources used by Airflow workers. +The `scheduler` block supports: + +* `cpu` - + (Optional) + The number of CPUs for a single Airflow scheduler. + +* `memory_gb` - + (Optional) + The amount of memory (GB) for a single Airflow scheduler. + +* `storage_gb` - + (Optional) + The amount of storage (GB) for a single Airflow scheduler. + +* `count` - + (Optional) + The number of schedulers. + +The `triggerer` block supports: + +* `cpu` - + (Required) + The number of CPUs for a single Airflow triggerer. + +* `memory_gb` - + (Required) + The amount of memory (GB) for a single Airflow triggerer. + +* `count` - + (Required) + The number of Airflow triggerers. + +The `web_server` block supports: + +* `cpu` - + (Optional) + The number of CPUs for the Airflow web server. + +* `memory_gb` - + (Optional) + The amount of memory (GB) for the Airflow web server. + +* `storage_gb` - + (Optional) + The amount of storage (GB) for the Airflow web server. + +The `worker` block supports: + +* `cpu` - + (Optional) + The number of CPUs for a single Airflow worker. + +* `memory_gb` - + (Optional) + The amount of memory (GB) for a single Airflow worker. + +* `storage_gb` + (Optional) + The amount of storage (GB) for a single Airflow worker. + +* `min_count` - + (Optional) + The minimum number of Airflow workers that the environment can run. The number of workers in the + environment does not go above this number, even if a lower number of workers can handle the load. + +* `max_count` - + (Optional) + The maximum number of Airflow workers that the environment can run. The number of workers in the + environment does not go above this number, even if a higher number of workers is required to + handle the load. + + +## Argument Reference - Cloud Composer 3 + +**Please note: This documentation corresponds to Composer 3, which is not yet released.** + +The following arguments are supported: + +* `name` - + (Required) + Name of the environment + +* `config` - + (Optional) + Configuration parameters for this environment. Structure is [documented below](#nested_config_c3). + +* `labels` - + (Optional) + User-defined labels for this environment. The labels map can contain + no more than 64 entries. Entries of the labels map are UTF8 strings + that comply with the following restrictions: + Label keys must be between 1 and 63 characters long and must conform + to the following regular expression: `[a-z]([-a-z0-9]*[a-z0-9])?`. + Label values must be between 0 and 63 characters long and must + conform to the regular expression `([a-z]([-a-z0-9]*[a-z0-9])?)?`. + No more than 64 labels can be associated with a given environment. + Both keys and values must be <= 128 bytes in size. + +* `region` - + (Optional) + The location or Compute Engine region for the environment. + +* `project` - + (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + +* `storage_config` - + (Optional) + Configuration options for storage used by Composer environment. Structure is [documented below](#nested_storage_config_c3). + + +The `config` block supports: + +* `node_config` - + (Optional) + The configuration used for the Kubernetes Engine cluster. Structure is [documented below](#nested_node_config_c3). + +* `software_config` - + (Optional) + The configuration settings for software (Airflow) inside the environment. Structure is [documented below](#nested_software_config_c3). + +* `enable_private_environment` - + (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) + If true, a private Composer environment will be created. + +* `enable_private_builds_only` - + (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) + If true, builds performed during operations that install Python packages have only private connectivity to Google services. + If false, the builds also have access to the internet. + +* `encryption_config` - + (Optional) + The encryption options for the Cloud Composer environment and its + dependencies. + +* `maintenance_window` - + (Optional) + The configuration settings for Cloud Composer maintenance windows. + +* `workloads_config` - + (Optional) + The Kubernetes workloads configuration for GKE cluster associated with the + Cloud Composer environment. + +* `environment_size` - + (Optional) + The environment size controls the performance parameters of the managed + Cloud Composer infrastructure that includes the Airflow database. Values for + environment size are `ENVIRONMENT_SIZE_SMALL`, `ENVIRONMENT_SIZE_MEDIUM`, + and `ENVIRONMENT_SIZE_LARGE`. + +* `data_retention_config` - + (Optional, Cloud Composer 2.0.23 or later only) + Configuration setting for Airflow database retention mechanism. Structure is + [documented below](#nested_data_retention_config_c3). + +The `data_retention_config` block supports: +* `task_logs_retention_config` - + (Optional) + The configuration setting for Airflow task logs. Structure is + [documented below](#nested_task_logs_retention_config_c3). + +The `task_logs_retention_config` block supports: +* `storage_mode` - + (Optional) + The mode of storage for Airflow task logs. Values for storage mode are + `CLOUD_LOGGING_ONLY` to only store logs in cloud logging and + `CLOUD_LOGGING_AND_CLOUD_STORAGE` to store logs in cloud logging and cloud storage. + + +The `storage_config` block supports: + +* `bucket` - + (Required) + Name of an existing Cloud Storage bucket to be used by the environment. + + +The `node_config` block supports: + +* `network` - + (Optional) + The Compute Engine network to be used for machine + communications, specified as a self-link, relative resource name + (for example "projects/{project}/global/networks/{network}"), by name. + + The network must belong to the environment's project. If unspecified, the "default" network ID in the environment's + project is used. If a Custom Subnet Network is provided, subnetwork must also be provided. + +* `subnetwork` - + (Optional) + The Compute Engine subnetwork to be used for machine + communications, specified as a self-link, relative resource name (for example, + "projects/{project}/regions/{region}/subnetworks/{subnetwork}"), or by name. If subnetwork is provided, + network must also be provided and the subnetwork must belong to the enclosing environment's project and region. + +* `composer_network_attachment` - + (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) + PSC (Private Service Connect) Network entry point. Customers can pre-create the Network Attachment + and point Cloud Composer environment to use. It is possible to share network attachment among many environments, + provided enough IP addresses are available. + +* `service_account` - + (Optional) + The Google Cloud Platform Service Account to be used by the + node VMs. If a service account is not specified, the "default" + Compute Engine service account is used. Cannot be updated. If given, + note that the service account must have `roles/composer.worker` + for any GCP resources created under the Cloud Composer Environment. + +* `tags` - + (Optional) + The list of instance tags applied to all node VMs. Tags are + used to identify valid sources or targets for network + firewalls. Each tag within the list must comply with RFC1035. + Cannot be updated. + +* `composer_internal_ipv4_cidr_block` - + (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) + /20 IPv4 cidr range that will be used by Composer internal components. + Cannot be updated. + +The `software_config` block supports: + +* `airflow_config_overrides` - + (Optional) Apache Airflow configuration properties to override. Property keys contain the section and property names, + separated by a hyphen, for example "core-dags_are_paused_at_creation". + + Section names must not contain hyphens ("-"), opening square brackets ("["), or closing square brackets ("]"). + The property name must not be empty and cannot contain "=" or ";". Section and property names cannot contain + characters: "." Apache Airflow configuration property names must be written in snake_case. Property values can + contain any character, and can be written in any lower/upper case format. Certain Apache Airflow configuration + property values are [blacklisted](https://cloud.google.com/composer/docs/concepts/airflow-configurations#airflow_configuration_blacklists), + and cannot be overridden. + +* `pypi_packages` - + (Optional) + Custom Python Package Index (PyPI) packages to be installed + in the environment. Keys refer to the lowercase package name (e.g. "numpy"). Values are the lowercase extras and + version specifier (e.g. "==1.12.0", "[devel,gcp_api]", "[devel]>=1.8.2, <1.9.2"). To specify a package without + pinning it to a version specifier, use the empty string as the value. + +* `env_variables` - + (Optional) + Additional environment variables to provide to the Apache Airflow scheduler, worker, and webserver processes. + Environment variable names must match the regular expression `[a-zA-Z_][a-zA-Z0-9_]*`. + They cannot specify Apache Airflow software configuration overrides (they cannot match the regular expression + `AIRFLOW__[A-Z0-9_]+__[A-Z0-9_]+`), and they cannot match any of the following reserved names: + ``` + AIRFLOW_HOME + C_FORCE_ROOT + CONTAINER_NAME + DAGS_FOLDER + GCP_PROJECT + GCS_BUCKET + GKE_CLUSTER_NAME + SQL_DATABASE + SQL_INSTANCE + SQL_PASSWORD + SQL_PROJECT + SQL_REGION + SQL_USER + ``` + +* `image_version` - + (Required) If omitted, the default is the latest version of Composer 2. + + In Cloud Composer 3, you can only specify 3 in the Cloud Composer portion of the image version. Example: composer-3-airflow-x.y.z-build.t. + + The Apache Airflow portion of the image version is a full semantic version that points to one of the + supported Apache Airflow versions, or an alias in the form of only major, major.minor or major.minor.patch versions specified. + Like in Composer 1 and 2, a given Airflow version is released multiple times in Composer, with different patches + and versions of dependencies. To distinguish between these versions in Composer 3, you can optionally specify a + build number to pin to a specific Airflow release. + Example: composer-3-airflow-2.6.3-build.4. + + The image version in Composer 3 must match the regular expression: + `composer-(([0-9]+)(\.[0-9]+\.[0-9]+(-preview\.[0-9]+)?)?|latest)-airflow-(([0-9]+)((\.[0-9]+)(\.[0-9]+)?)?(-build\.[0-9]+)?)` + Example: composer-3-airflow-2.6.3-build.4 + + **Important**: In-place upgrade for Composer 3 is not yet supported. + +* `cloud_data_lineage_integration` - + (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), + Cloud Composer environments in versions composer-2.1.2-airflow-*.*.* and later) + The configuration for Cloud Data Lineage integration. Structure is + [documented below](#nested_cloud_data_lineage_integration_c3). + +* `web_server_plugins_mode` - + (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) + Web server plugins configuration. Can be either 'ENABLED' or 'DISABLED'. Defaults to 'ENABLED'. + +The `cloud_data_lineage_integration` block supports: +* `enabled` - + (Required) + Whether or not Cloud Data Lineage integration is enabled. + +The `encryption_config` block supports: + +* `kms_key_name` - + (Required) + Customer-managed Encryption Key available through Google's Key Management Service. It must + be the fully qualified resource name, + i.e. projects/project-id/locations/location/keyRings/keyring/cryptoKeys/key. Cannot be updated. + +The `maintenance_window` block supports: + +* `start_time` - + (Required) + Start time of the first recurrence of the maintenance window. + +* `end_time` - + (Required) + Maintenance window end time. It is used only to calculate the duration of the maintenance window. + The value for end-time must be in the future, relative to 'start_time'. + +* `recurrence` - + (Required) + Maintenance window recurrence. Format is a subset of RFC-5545 (https://tools.ietf.org/html/rfc5545) 'RRULE'. + The only allowed values for 'FREQ' field are 'FREQ=DAILY' and 'FREQ=WEEKLY;BYDAY=...'. + Example values: 'FREQ=WEEKLY;BYDAY=TU,WE', 'FREQ=DAILY'. + +The `workloads_config` block supports: + +* `scheduler` - + (Optional) + Configuration for resources used by Airflow scheduler. + +* `triggerer` - + (Optional) + Configuration for resources used by Airflow triggerer. + +* `web_server` - + (Optional) + Configuration for resources used by Airflow web server. + +* `worker` - + (Optional) + Configuration for resources used by Airflow workers. + * `dag_processor` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) Configuration for resources used by DAG processor. From 4940461a14c96e28bd3575efa0eef98bcbe3f47f Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 7 Mar 2024 21:45:14 +0000 Subject: [PATCH 29/32] Promote metric settings in compute region autoscaler to GA (#10103) --- mmv1/products/compute/RegionAutoscaler.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/mmv1/products/compute/RegionAutoscaler.yaml b/mmv1/products/compute/RegionAutoscaler.yaml index 931e07443408..fa9991ee61aa 100644 --- a/mmv1/products/compute/RegionAutoscaler.yaml +++ b/mmv1/products/compute/RegionAutoscaler.yaml @@ -265,7 +265,6 @@ properties: required: true - !ruby/object:Api::Type::Double name: 'singleInstanceAssignment' - min_version: beta description: | If scaling is based on a per-group metric value that represents the total amount of work to be done or resource usage, set this value to @@ -341,7 +340,6 @@ properties: (if you are using gce_instance resource type). If multiple TimeSeries are returned upon the query execution, the autoscaler will sum their respective values to obtain its scaling value. - min_version: beta - !ruby/object:Api::Type::NestedObject name: 'loadBalancingUtilization' description: | From 00f7bfb27208915fd7fb5c133bf9f4934c363c58 Mon Sep 17 00:00:00 2001 From: "Stephen Lewis (Burrows)" Date: Thu, 7 Mar 2024 14:14:10 -0800 Subject: [PATCH 30/32] Clarified permissions for a few workflows (#10124) * Clarified permissions for a few workflows * fixed conditions for running repository-documentation workflows * Bumped actions/checkout to v4 * force downstream generation * Revert "force downstream generation" This reverts commit d54857b4dc5767ab8f98543e6a84d25c8be1104a. --- ...ml => repository-documentation-deploy.yml} | 12 ++++----- .../repository-documentation-test.yml | 27 +++++++++++++++++++ .github/workflows/test-tgc.yml | 7 +++-- .github/workflows/test-tpg.yml | 7 +++-- 4 files changed, 39 insertions(+), 14 deletions(-) rename .github/workflows/{repository-documentation.yml => repository-documentation-deploy.yml} (82%) create mode 100644 .github/workflows/repository-documentation-test.yml diff --git a/.github/workflows/repository-documentation.yml b/.github/workflows/repository-documentation-deploy.yml similarity index 82% rename from .github/workflows/repository-documentation.yml rename to .github/workflows/repository-documentation-deploy.yml index 531673c5788f..f94df4ce4ffd 100644 --- a/.github/workflows/repository-documentation.yml +++ b/.github/workflows/repository-documentation-deploy.yml @@ -1,16 +1,17 @@ -name: repository-documentation +name: repository-documentation-deploy + +permissions: read-all on: push: branches: - - main # Set a branch to deploy - pull_request: - paths: - - 'docs/**' + - main jobs: deploy: runs-on: ubuntu-22.04 + permissions: + contents: write steps: - uses: actions/checkout@v4 with: @@ -29,7 +30,6 @@ jobs: - name: Deploy uses: peaceiris/actions-gh-pages@de7ea6f8efb354206b205ef54722213d99067935 # v3.9.0 - if: github.ref == 'refs/heads/main' with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./docs/public diff --git a/.github/workflows/repository-documentation-test.yml b/.github/workflows/repository-documentation-test.yml new file mode 100644 index 000000000000..f2952926ef2a --- /dev/null +++ b/.github/workflows/repository-documentation-test.yml @@ -0,0 +1,27 @@ +name: repository-documentation-test + +permissions: read-all + +on: + pull_request: + paths: + - 'docs/**' + +jobs: + deploy: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: true # Fetch Hugo themes (true OR recursive) + fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod + + - name: Setup Hugo + uses: peaceiris/actions-hugo@16361eb4acea8698b220b76c0d4e84e1fd22c61d # v2.6.0 + with: + hugo-version: '0.115.0' + extended: true + + - name: Build + working-directory: ./docs + run: hugo --minify diff --git a/.github/workflows/test-tgc.yml b/.github/workflows/test-tgc.yml index 32e290364067..3eb9aaad4121 100644 --- a/.github/workflows/test-tgc.yml +++ b/.github/workflows/test-tgc.yml @@ -1,9 +1,6 @@ name: TGC Build and Unit Test -permissions: - actions: read - contents: read - statuses: write +permissions: read-all env: status_suffix: "-build-and-unit-tests" @@ -32,6 +29,8 @@ concurrency: jobs: build-and-unit-test: + permissions: + statuses: write runs-on: ubuntu-latest timeout-minutes: 30 steps: diff --git a/.github/workflows/test-tpg.yml b/.github/workflows/test-tpg.yml index eff5cdc3755e..46d83b487def 100644 --- a/.github/workflows/test-tpg.yml +++ b/.github/workflows/test-tpg.yml @@ -1,9 +1,6 @@ name: Provider Build and Unit Test -permissions: - actions: read - contents: read - statuses: write +permissions: read-all env: status_suffix: "-build-and-unit-tests" @@ -32,6 +29,8 @@ concurrency: jobs: build-and-unit-test: + permissions: + statuses: write runs-on: ubuntu-latest timeout-minutes: 30 steps: From 3e97dde391dd776251199d68de1e696e4244c4b8 Mon Sep 17 00:00:00 2001 From: "Stephen Lewis (Burrows)" Date: Thu, 7 Mar 2024 14:14:26 -0800 Subject: [PATCH 31/32] Post statuses earlier (#10128) * Post initial statuses earlier so that we are resilient issues during cloning * force generation * Revert "force generation" This reverts commit 864ec92ec03b75dea021cdb617d86d31112d9140. --- .github/workflows/test-tgc.yml | 36 +++++++++++++++++----------------- .github/workflows/test-tpg.yml | 31 ++++++++++++++--------------- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/.github/workflows/test-tgc.yml b/.github/workflows/test-tgc.yml index 3eb9aaad4121..190bb6ae68c0 100644 --- a/.github/workflows/test-tgc.yml +++ b/.github/workflows/test-tgc.yml @@ -34,6 +34,24 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: + - name: Get Job URL + if: ${{ !cancelled() }} + id: get_job + run: | + response=$(curl --get -Ss -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}/jobs") + html_url=$(echo "$response" | jq -r --arg job_name "${{ github.job }}" '.jobs | map(select(.name == $job_name)) | .[0].html_url') + echo "url=${html_url}" >> $GITHUB_OUTPUT + - name: Post Pending Status to Pull Request + if: ${{ !cancelled() }} + run: | + curl -X POST -H "Authorization: token ${{secrets.GITHUB_TOKEN}}" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/GoogleCloudPlatform/magic-modules/statuses/${{github.event.inputs.sha}}" \ + -d '{ + "context": "${{ github.event.inputs.repo }}${{ env.status_suffix }}", + "target_url": "${{ steps.get_job.outputs.url }}", + "state": "pending" + }' - name: Checkout Repository uses: actions/checkout@v4 with: @@ -58,24 +76,6 @@ jobs: else echo "has_changes=true" >> $GITHUB_OUTPUT fi - - name: Get Job URL - if: ${{ !cancelled() }} - id: get_job - run: | - response=$(curl --get -Ss -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}/jobs") - html_url=$(echo "$response" | jq -r --arg job_name "${{ github.job }}" '.jobs | map(select(.name == $job_name)) | .[0].html_url') - echo "url=${html_url}" >> $GITHUB_OUTPUT - - name: Post Pending Status to Pull Request - if: ${{ !cancelled() }} - run: | - curl -X POST -H "Authorization: token ${{secrets.GITHUB_TOKEN}}" \ - -H "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/GoogleCloudPlatform/magic-modules/statuses/${{github.event.inputs.sha}}" \ - -d '{ - "context": "${{ github.event.inputs.repo }}${{ env.status_suffix }}", - "target_url": "${{ steps.get_job.outputs.url }}", - "state": "pending" - }' - name: Set up Go if: ${{ !failure() && steps.pull_request.outputs.has_changes == 'true' }} uses: actions/setup-go@v4 diff --git a/.github/workflows/test-tpg.yml b/.github/workflows/test-tpg.yml index 46d83b487def..9edca790e1ec 100644 --- a/.github/workflows/test-tpg.yml +++ b/.github/workflows/test-tpg.yml @@ -34,23 +34,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - name: Checkout Repository - uses: actions/checkout@v4 - with: - repository: ${{ github.event.inputs.owner }}/${{ github.event.inputs.repo }} - ref: ${{ github.event.inputs.branch }} - fetch-depth: 2 - - name: Check for Code Changes - id: pull_request - run: | - gofiles=$(git diff --name-only HEAD~1 | { grep -e "\.go$" -e "go.mod$" -e "go.sum$" || test $? = 1; }) - if [ -z "$gofiles" ]; then - echo "has_changes=false" >> $GITHUB_OUTPUT - else - echo "has_changes=true" >> $GITHUB_OUTPUT - fi - name: Get Job URL - if: ${{ !cancelled() }} id: get_job run: | response=$(curl --get -Ss -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}/jobs") @@ -67,6 +51,21 @@ jobs: "target_url": "${{ steps.get_job.outputs.url }}", "state": "pending" }' + - name: Checkout Repository + uses: actions/checkout@v4 + with: + repository: ${{ github.event.inputs.owner }}/${{ github.event.inputs.repo }} + ref: ${{ github.event.inputs.branch }} + fetch-depth: 2 + - name: Check for Code Changes + id: pull_request + run: | + gofiles=$(git diff --name-only HEAD~1 | { grep -e "\.go$" -e "go.mod$" -e "go.sum$" || test $? = 1; }) + if [ -z "$gofiles" ]; then + echo "has_changes=false" >> $GITHUB_OUTPUT + else + echo "has_changes=true" >> $GITHUB_OUTPUT + fi - name: Set up Go if: ${{ !failure() && steps.pull_request.outputs.has_changes == 'true' }} uses: actions/setup-go@v4 From 5989a16860b84d15ac84f0994cc31e27c0c59422 Mon Sep 17 00:00:00 2001 From: Cameron Thornton Date: Thu, 7 Mar 2024 17:52:14 -0600 Subject: [PATCH 32/32] Make TestAccDefaultUniverseDomain_doesNotMatchExplicit independent from test credentials (#10140) --- mmv1/third_party/terraform/provider/provider.go.erb | 6 +++--- .../provider/universe/universe_domain_compute_test.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mmv1/third_party/terraform/provider/provider.go.erb b/mmv1/third_party/terraform/provider/provider.go.erb index 4f7195a37355..c090b8c43096 100644 --- a/mmv1/third_party/terraform/provider/provider.go.erb +++ b/mmv1/third_party/terraform/provider/provider.go.erb @@ -299,12 +299,12 @@ func ProviderConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr // Check if the user provided a value from the universe_domain field other than the default if v, ok := d.GetOk("universe_domain"); ok && v.(string) != "googleapis.com" { if config.UniverseDomain == "" { - return nil, diag.FromErr(fmt.Errorf("Universe domain '%s' supplied directly to Terraform with no matching universe domain in credentials. Credentials with no 'universe_domain' set are assumed to be in the default universe.", v)) + return nil, diag.FromErr(fmt.Errorf("Universe domain mismatch: '%s' supplied directly to Terraform with no matching universe domain in credentials. Credentials with no 'universe_domain' set are assumed to be in the default universe.", v)) } else if v.(string) != config.UniverseDomain { if _, err := os.Stat(config.Credentials); err == nil { - return nil, diag.FromErr(fmt.Errorf("'%s' does not match the universe domain '%s' already set in the credential file '%s'. The 'universe_domain' provider configuration can not be used to override the universe domain that is defined in the active credential. Set the 'universe_domain' provider configuration when universe domain information is not already available in the credential, e.g. when authenticating with a JWT token.", v, config.UniverseDomain, config.Credentials)) + return nil, diag.FromErr(fmt.Errorf("Universe domain mismatch: '%s' does not match the universe domain '%s' already set in the credential file '%s'. The 'universe_domain' provider configuration can not be used to override the universe domain that is defined in the active credential. Set the 'universe_domain' provider configuration when universe domain information is not already available in the credential, e.g. when authenticating with a JWT token.", v, config.UniverseDomain, config.Credentials)) } else { - return nil, diag.FromErr(fmt.Errorf("'%s' does not match the universe domain '%s' supplied directly to Terraform. The 'universe_domain' provider configuration can not be used to override the universe domain that is defined in the active credential. Set the 'universe_domain' provider configuration when universe domain information is not already available in the credential, e.g. when authenticating with a JWT token.", v, config.UniverseDomain)) + return nil, diag.FromErr(fmt.Errorf("Universe domain mismatch: '%s' does not match the universe domain '%s' supplied directly to Terraform. The 'universe_domain' provider configuration can not be used to override the universe domain that is defined in the active credential. Set the 'universe_domain' provider configuration when universe domain information is not already available in the credential, e.g. when authenticating with a JWT token.", v, config.UniverseDomain)) } } } diff --git a/mmv1/third_party/terraform/provider/universe/universe_domain_compute_test.go b/mmv1/third_party/terraform/provider/universe/universe_domain_compute_test.go index c895e952970e..f345ac3d1968 100644 --- a/mmv1/third_party/terraform/provider/universe/universe_domain_compute_test.go +++ b/mmv1/third_party/terraform/provider/universe/universe_domain_compute_test.go @@ -57,7 +57,7 @@ func TestAccDefaultUniverseDomain_doesNotMatchExplicit(t *testing.T) { Steps: []resource.TestStep{ resource.TestStep{ Config: testAccUniverseDomain_basic_disk(universeDomainFake), - ExpectError: regexp.MustCompile("supplied directly to Terraform with no matching universe domain in credentials"), + ExpectError: regexp.MustCompile("Universe domain mismatch"), }, }, })