From 86cf5dfc842dd8d27303aae1127b4884c89fa46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Fri, 17 Nov 2023 11:47:44 +0000 Subject: [PATCH 1/6] Fix reporting non-empty plan after apply --- tests/fixtures.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/fixtures.py b/tests/fixtures.py index 01a89f423c..25b0b134ec 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -307,20 +307,20 @@ def e2e_validator(module_path, extra_files, tf_var_files, basedir=None): changes = {} for resource_name, value in plan.resource_changes.items(): if value.get('change', {}).get('actions') != ['no-op']: - changes[resource_name] = value + changes[resource_name] = value['change'] # compare before with after to raise more meaningful failure to the user, i.e one # that shows how resource will change - plan_before_state = {k: v['before'] for k, v in changes.items()} - plan_after_state = {k: v['after'] for k, v in changes.items()} + plan_before_state = {k: v.get('before') for k, v in changes.items()} + plan_after_state = {k: v.get('after') for k, v in changes.items()} assert plan_before_state == plan_after_state, f'Plan not empty after apply for values' plan_before_sensitive_state = { - k: v['before_sensitive'] for k, v in changes.items() + k: v.get('before_sensitive') for k, v in changes.items() } plan_after_sensitive_state = { - k: v['after_sensitive'] for k, v in changes.items() + k: v.get('after_sensitive') for k, v in changes.items() } assert plan_before_sensitive_state == plan_after_sensitive_state, f'Plan not empty after apply for sensitive values' From 7dd76c1003ac47226ce859719b1059df0da91fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Fri, 17 Nov 2023 11:48:25 +0000 Subject: [PATCH 2/6] Additional services for Cloud Run --- tests/examples_e2e/setup_module/main.tf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/examples_e2e/setup_module/main.tf b/tests/examples_e2e/setup_module/main.tf index 40a7dcb537..cd2fc8152b 100644 --- a/tests/examples_e2e/setup_module/main.tf +++ b/tests/examples_e2e/setup_module/main.tf @@ -26,12 +26,15 @@ locals { "cloudkms.googleapis.com", "cloudresourcemanager.googleapis.com", "compute.googleapis.com", + "eventarc.googleapis.com", "iam.googleapis.com", "run.googleapis.com", + "secretmanager.googleapis.com", "serviceusage.googleapis.com", "stackdriver.googleapis.com", "storage-component.googleapis.com", "storage.googleapis.com", + "vpcaccess.googleapis.com", ] } From 28b8edced5ed08a9476b09a8f8c90a3dacbc4c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Fri, 17 Nov 2023 11:49:26 +0000 Subject: [PATCH 3/6] Add end-to-end tests to Cloud Run --- modules/cloud-run/README.md | 171 +++++++++++------- modules/cloud-run/variables.tf | 8 + .../cloud_run/examples/audit-logs.yaml | 32 +++- .../modules/cloud_run/examples/connector.yaml | 7 +- .../modules/cloud_run/examples/eventarc.yaml | 39 ++-- tests/modules/cloud_run/examples/secrets.yaml | 18 +- .../examples/service-account-external.yaml | 4 +- .../cloud_run/examples/service-account.yaml | 4 +- tests/modules/cloud_run/examples/simple.yaml | 15 ++ .../trigger-service-account-external.yaml | 72 -------- .../examples/trigger-service-account.yaml | 51 ++---- 11 files changed, 212 insertions(+), 209 deletions(-) delete mode 100644 tests/modules/cloud_run/examples/trigger-service-account-external.yaml diff --git a/modules/cloud-run/README.md b/modules/cloud-run/README.md index bdfa3945a5..187f3bed6a 100644 --- a/modules/cloud-run/README.md +++ b/modules/cloud-run/README.md @@ -26,6 +26,20 @@ Cloud Run management, with support for IAM roles, revision annotations and optio IAM bindings support the usual syntax. Container environment values can be declared as key-value strings or as references to Secret Manager secrets. Both can be combined as long as there's no duplication of keys: ```hcl + +module "secret-manager" { + source = "./fabric/modules/secret-manager" + project_id = var.project_id + secrets = { + credentials = {} + } + iam = { + credentials = { + "roles/secretmanager.secretAccessor" = [module.cloud_run.service_account_iam_email] + } + } +} + module "cloud_run" { source = "./fabric/modules/cloud-run" project_id = var.project_id @@ -39,8 +53,8 @@ module "cloud_run" { } env_from = { SECRET1 = { - name = "credentials" - key = "1" + name = module.secret-manager.ids["credentials"] + key = "latest" } } } @@ -48,13 +62,33 @@ module "cloud_run" { iam = { "roles/run.invoker" = ["allUsers"] } + service_account_create = true } -# tftest modules=1 resources=2 inventory=simple.yaml e2e +# tftest modules=2 resources=5 inventory=simple.yaml e2e ``` ### Mounting secrets as volumes ```hcl +module "secret-manager" { + source = "./fabric/modules/secret-manager" + project_id = var.project_id + secrets = { + credentials = {} + } + versions = { + credentials = { + v1 = { enabled = true, data = "foo bar baz" } + } + } + iam = { + credentials = { + "roles/secretmanager.secretAccessor" = [module.cloud_run.service_account_iam_email] + } + } +} + + module "cloud_run" { source = "./fabric/modules/cloud-run" project_id = var.project_id @@ -68,17 +102,18 @@ module "cloud_run" { } } } + service_account_create = true volumes = { credentials = { - name = "credentials" - secret_name = "credentials" + name = module.secret-manager.secrets["credentials"].name + secret_name = "credentials" # TODO: module.secret-manager.secrets["credentials"].name items = { - v1 = { path = "v1.txt" } + latest = { path = "v1.txt" } } } } } -# tftest modules=1 resources=1 inventory=secrets.yaml +# tftest modules=2 resources=5 inventory=secrets.yaml e2e ``` ### Revision annotations @@ -124,7 +159,7 @@ module "cloud_run" { } gen2_execution_environment = true } -# tftest modules=1 resources=1 inventory=gen2.yaml +# tftest modules=1 resources=1 inventory=gen2.yaml e2e ``` ### VPC Access Connector creation @@ -142,11 +177,11 @@ module "cloud_run" { } } vpc_connector_create = { - ip_cidr_range = "10.10.10.0/24" - vpc_self_link = "projects/example/host/global/networks/host" + ip_cidr_range = "10.10.10.0/28" + vpc_self_link = var.vpc.self_link } } -# tftest modules=1 resources=2 inventory=connector.yaml +# tftest modules=1 resources=2 inventory=connector.yaml e2e ``` Note that if you are using Shared VPC you need to specify a subnet: @@ -178,7 +213,7 @@ This deploys a Cloud Run service with traffic split between two revisions. ```hcl module "cloud_run" { source = "./fabric/modules/cloud-run" - project_id = "my-project" + project_id = var.project_id name = "hello" revision_name = "green" containers = { @@ -201,9 +236,15 @@ module "cloud_run" { This deploys a Cloud Run service that will be triggered when messages are published to Pub/Sub topics. ```hcl +module "pubsub" { + source = "./fabric/modules/pubsub" + project_id = var.project_id + name = "pubsub_sink" +} + module "cloud_run" { source = "./fabric/modules/cloud-run" - project_id = "my-project" + project_id = var.project_id name = "hello" containers = { hello = { @@ -212,12 +253,11 @@ module "cloud_run" { } eventarc_triggers = { pubsub = { - topic-1 = "topic1" - topic-2 = "topic2" + topic-1 = module.pubsub.id } } } -# tftest modules=1 resources=3 inventory=eventarc.yaml +# tftest modules=2 resources=3 inventory=eventarc.yaml e2e ``` #### Audit logs @@ -225,9 +265,18 @@ module "cloud_run" { This deploys a Cloud Run service that will be triggered when specific log events are written to Google Cloud audit logs. ```hcl +module "sa" { + source = "./fabric/modules/iam-service-account" + project_id = var.project_id + name = "eventarc-trigger" + iam_project_roles = { + (var.project_id) = ["roles/eventarc.eventReceiver"] + } +} + module "cloud_run" { source = "./fabric/modules/cloud-run" - project_id = "my-project" + project_id = var.project_id name = "hello" containers = { hello = { @@ -241,46 +290,33 @@ module "cloud_run" { service = "cloudresourcemanager.googleapis.com" } } + service_account_email = module.sa.email + } + iam = { + "roles/run.invoker" = [module.sa.iam_email] } } -# tftest modules=1 resources=2 inventory=audit-logs.yaml +# tftest modules=2 resources=5 inventory=audit-logs.yaml e2e ``` #### Using custom service accounts for triggers By default `Compute default service account` is used to trigger Cloud Run. If you want to use custom Service Account you can either provide your own in `eventarc_triggers.service_account_email` or set `eventarc_triggers.service_account_create` to true and service account named `tf-cr-trigger-${var.name}` will be created with `roles/run.invoker` granted on this Cloud Run service. -Example using provided service account: - -```hcl -module "cloud_run" { - source = "./fabric/modules/cloud-run" - project_id = "my-project" - name = "hello" - containers = { - hello = { - image = "us-docker.pkg.dev/cloudrun/container/hello" - } - } - eventarc_triggers = { - audit_log = { - setiampolicy = { - method = "SetIamPolicy" - service = "cloudresourcemanager.googleapis.com" - } - } - service_account_email = "cloud-run-trigger@my-project.iam.gserviceaccount.com" - } -} -# tftest modules=1 resources=2 inventory=trigger-service-account-external.yaml -``` +For example using provided service account refer to [Audit logs](#audit-logs) example. Example using automatically created service account: ```hcl +module "pubsub" { + source = "./fabric/modules/pubsub" + project_id = var.project_id + name = "pubsub_sink" +} + module "cloud_run" { source = "./fabric/modules/cloud-run" - project_id = "my-project" + project_id = var.project_id name = "hello" containers = { hello = { @@ -289,13 +325,12 @@ module "cloud_run" { } eventarc_triggers = { pubsub = { - topic-1 = "topic1" - topic-2 = "topic2" + topic-1 = module.pubsub.id } service_account_create = true } } -# tftest modules=1 resources=5 inventory=trigger-service-account.yaml +# tftest modules=2 resources=5 inventory=trigger-service-account.yaml e2e ``` ### Service account @@ -305,7 +340,7 @@ To use a custom service account managed by the module, set `service_account_crea ```hcl module "cloud_run" { source = "./fabric/modules/cloud-run" - project_id = "my-project" + project_id = var.project_id name = "hello" containers = { hello = { @@ -314,7 +349,7 @@ module "cloud_run" { } service_account_create = true } -# tftest modules=1 resources=2 inventory=service-account.yaml +# tftest modules=1 resources=2 inventory=service-account.yaml e2e ``` To use an externally managed service account, pass its email in `service_account` and leave `service_account_create` to `false` (the default). @@ -322,42 +357,42 @@ To use an externally managed service account, pass its email in `service_account ```hcl module "cloud_run" { source = "./fabric/modules/cloud-run" - project_id = "my-project" + project_id = var.project_id name = "hello" containers = { hello = { image = "us-docker.pkg.dev/cloudrun/container/hello" } } - service_account = "cloud-run@my-project.iam.gserviceaccount.com" + service_account = var.service_account.email } -# tftest modules=1 resources=1 inventory=service-account-external.yaml +# tftest modules=1 resources=1 inventory=service-account-external.yaml e2e ``` ## Variables | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [name](variables.tf#L136) | Name used for cloud run service. | string | ✓ | | -| [project_id](variables.tf#L151) | Project id used for all resources. | string | ✓ | | +| [name](variables.tf#L144) | Name used for cloud run service. | string | ✓ | | +| [project_id](variables.tf#L159) | Project id used for all resources. | string | ✓ | | | [container_concurrency](variables.tf#L18) | Maximum allowed in-flight (concurrent) requests per container of the revision. | string | | null | | [containers](variables.tf#L24) | Containers in arbitrary key => attributes format. | map(object({…})) | | {} | | [eventarc_triggers](variables.tf#L91) | Event arc triggers for different sources. | object({…}) | | {} | -| [gen2_execution_environment](variables.tf#L105) | Use second generation execution environment. | bool | | false | -| [iam](variables.tf#L111) | IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | -| [ingress_settings](variables.tf#L117) | Ingress settings. | string | | null | -| [labels](variables.tf#L130) | Resource labels. | map(string) | | {} | -| [prefix](variables.tf#L141) | Optional prefix used for resource names. | string | | null | -| [region](variables.tf#L156) | Region used for all resources. | string | | "europe-west1" | -| [revision_annotations](variables.tf#L162) | Configure revision template annotations. | object({…}) | | {} | -| [revision_name](variables.tf#L177) | Revision name. | string | | null | -| [service_account](variables.tf#L183) | Service account email. Unused if service account is auto-created. | string | | null | -| [service_account_create](variables.tf#L189) | Auto-create service account. | bool | | false | -| [startup_cpu_boost](variables.tf#L195) | Enable startup cpu boost. | bool | | false | -| [timeout_seconds](variables.tf#L201) | Maximum duration the instance is allowed for responding to a request. | number | | null | -| [traffic](variables.tf#L207) | Traffic steering configuration. If revision name is null the latest revision will be used. | map(object({…})) | | {} | -| [volumes](variables.tf#L218) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} | -| [vpc_connector_create](variables.tf#L232) | Populate this to create a VPC connector. You can then refer to it in the template annotations. | object({…}) | | null | +| [gen2_execution_environment](variables.tf#L113) | Use second generation execution environment. | bool | | false | +| [iam](variables.tf#L119) | IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| [ingress_settings](variables.tf#L125) | Ingress settings. | string | | null | +| [labels](variables.tf#L138) | Resource labels. | map(string) | | {} | +| [prefix](variables.tf#L149) | Optional prefix used for resource names. | string | | null | +| [region](variables.tf#L164) | Region used for all resources. | string | | "europe-west1" | +| [revision_annotations](variables.tf#L170) | Configure revision template annotations. | object({…}) | | {} | +| [revision_name](variables.tf#L185) | Revision name. | string | | null | +| [service_account](variables.tf#L191) | Service account email. Unused if service account is auto-created. | string | | null | +| [service_account_create](variables.tf#L197) | Auto-create service account. | bool | | false | +| [startup_cpu_boost](variables.tf#L203) | Enable startup cpu boost. | bool | | false | +| [timeout_seconds](variables.tf#L209) | Maximum duration the instance is allowed for responding to a request. | number | | null | +| [traffic](variables.tf#L215) | Traffic steering configuration. If revision name is null the latest revision will be used. | map(object({…})) | | {} | +| [volumes](variables.tf#L226) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} | +| [vpc_connector_create](variables.tf#L240) | Populate this to create a VPC connector. You can then refer to it in the template annotations. | object({…}) | | null | ## Outputs diff --git a/modules/cloud-run/variables.tf b/modules/cloud-run/variables.tf index 2b7fd3af73..46e92b0d22 100644 --- a/modules/cloud-run/variables.tf +++ b/modules/cloud-run/variables.tf @@ -100,6 +100,14 @@ variable "eventarc_triggers" { service_account_create = optional(bool, false) }) default = {} + validation { + condition = ( + var.eventarc_triggers.service_account_email == null && length(var.eventarc_triggers.audit_log) == 0 + ) || ( + var.eventarc_triggers.service_account_email != null + ) + error_message = "service_account_email is required if providing audit_log" + } } variable "gen2_execution_environment" { diff --git a/tests/modules/cloud_run/examples/audit-logs.yaml b/tests/modules/cloud_run/examples/audit-logs.yaml index efdce1a76a..e4cfddf7b6 100644 --- a/tests/modules/cloud_run/examples/audit-logs.yaml +++ b/tests/modules/cloud_run/examples/audit-logs.yaml @@ -13,7 +13,23 @@ # limitations under the License. values: - module.cloud_run.google_cloud_run_service.service: {} + module.cloud_run.google_cloud_run_service.service: + name: hello + project: project-id + template: + - spec: + - containers: + - image: us-docker.pkg.dev/cloudrun/container/hello + + module.cloud_run.google_cloud_run_service_iam_binding.binding["roles/run.invoker"]: + condition: [] + location: europe-west1 + members: + - serviceAccount:eventarc-trigger@project-id.iam.gserviceaccount.com + project: project-id + role: roles/run.invoker + service: hello + module.cloud_run.google_eventarc_trigger.audit_log_triggers["setiampolicy"]: destination: - cloud_function: null @@ -35,8 +51,20 @@ values: operator: '' value: google.cloud.audit.log.v1.written name: audit-log-setiampolicy - project: my-project + project: project-id + + module.sa.google_project_iam_member.project-roles["project-id-roles/eventarc.eventReceiver"]: + condition: [] + project: project-id + role: roles/eventarc.eventReceiver + + module.sa.google_service_account.service_account[0]: + account_id: eventarc-trigger + project: project-id counts: google_cloud_run_service: 1 + google_cloud_run_service_iam_binding: 1 google_eventarc_trigger: 1 + google_project_iam_member: 1 + google_service_account: 1 diff --git a/tests/modules/cloud_run/examples/connector.yaml b/tests/modules/cloud_run/examples/connector.yaml index a23c5c7822..0733ee7ec4 100644 --- a/tests/modules/cloud_run/examples/connector.yaml +++ b/tests/modules/cloud_run/examples/connector.yaml @@ -35,16 +35,15 @@ values: working_dir: null volumes: [] module.cloud_run.google_vpc_access_connector.connector[0]: - ip_cidr_range: 10.10.10.0/24 + ip_cidr_range: 10.10.10.0/28 machine_type: e2-micro max_throughput: 300 min_throughput: 200 name: hello - network: projects/example/host/global/networks/host + network: projects/xxx/global/networks/aaa project: project-id region: europe-west1 - subnet: - - name: null + subnet: [] counts: google_cloud_run_service: 1 diff --git a/tests/modules/cloud_run/examples/eventarc.yaml b/tests/modules/cloud_run/examples/eventarc.yaml index 3f4eae9a8d..3c838e8f78 100644 --- a/tests/modules/cloud_run/examples/eventarc.yaml +++ b/tests/modules/cloud_run/examples/eventarc.yaml @@ -13,7 +13,13 @@ # limitations under the License. values: - module.cloud_run.google_cloud_run_service.service: {} + module.cloud_run.google_cloud_run_service.service: + name: hello + project: project-id + template: + - spec: + - containers: + - image: us-docker.pkg.dev/cloudrun/container/hello module.cloud_run.google_eventarc_trigger.pubsub_triggers["topic-1"]: destination: - cloud_function: null @@ -29,30 +35,17 @@ values: operator: '' value: google.cloud.pubsub.topic.v1.messagePublished name: pubsub-topic-1 - project: my-project + project: project-id transport: - pubsub: - - topic: topic1 - module.cloud_run.google_eventarc_trigger.pubsub_triggers["topic-2"]: - destination: - - cloud_function: null - cloud_run_service: - - path: null - region: europe-west1 - service: hello - gke: [] - workflow: null - location: europe-west1 - matching_criteria: - - attribute: type - operator: '' - value: google.cloud.pubsub.topic.v1.messagePublished - name: pubsub-topic-2 - project: my-project - transport: - - pubsub: - - topic: topic2 + - topic: projects/project-id/topics/pubsub_sink + + module.pubsub.google_pubsub_topic.default: + name: pubsub_sink + project: project-id + counts: google_cloud_run_service: 1 - google_eventarc_trigger: 2 + google_eventarc_trigger: 1 + google_pubsub_topic: 1 diff --git a/tests/modules/cloud_run/examples/secrets.yaml b/tests/modules/cloud_run/examples/secrets.yaml index c6d4d34d35..88e7ba5d3b 100644 --- a/tests/modules/cloud_run/examples/secrets.yaml +++ b/tests/modules/cloud_run/examples/secrets.yaml @@ -41,10 +41,24 @@ values: secret: - default_mode: null items: - - key: v1 + - key: latest mode: null path: v1.txt - secret_name: credentials + + module.cloud_run.google_service_account.service_account[0]: + account_id: tf-cr-hello + project: project-id + + module.secret-manager.google_secret_manager_secret.default["credentials"]: + project: project-id + secret_id: credentials + + module.secret-manager.google_secret_manager_secret_iam_binding.default["credentials.roles/secretmanager.secretAccessor"]: + condition: [] + role: roles/secretmanager.secretAccessor counts: google_cloud_run_service: 1 + google_secret_manager_secret: 1 + google_secret_manager_secret_iam_binding: 1 + google_service_account: 1 diff --git a/tests/modules/cloud_run/examples/service-account-external.yaml b/tests/modules/cloud_run/examples/service-account-external.yaml index fc291c9d08..c9aa892b59 100644 --- a/tests/modules/cloud_run/examples/service-account-external.yaml +++ b/tests/modules/cloud_run/examples/service-account-external.yaml @@ -19,7 +19,7 @@ values: metadata: - {} name: hello - project: my-project + project: project-id template: - metadata: - {} @@ -33,7 +33,7 @@ values: liveness_probe: [] volume_mounts: [] working_dir: null - service_account_name: cloud-run@my-project.iam.gserviceaccount.com + service_account_name: service_account_email volumes: [] counts: diff --git a/tests/modules/cloud_run/examples/service-account.yaml b/tests/modules/cloud_run/examples/service-account.yaml index 30b675948c..2d422397d1 100644 --- a/tests/modules/cloud_run/examples/service-account.yaml +++ b/tests/modules/cloud_run/examples/service-account.yaml @@ -19,7 +19,7 @@ values: metadata: - {} name: hello - project: my-project + project: project-id template: - metadata: - {} @@ -39,7 +39,7 @@ values: description: null disabled: false display_name: Terraform Cloud Run hello. - project: my-project + project: project-id counts: google_cloud_run_service: 1 diff --git a/tests/modules/cloud_run/examples/simple.yaml b/tests/modules/cloud_run/examples/simple.yaml index fa29c512ec..3d428c3dce 100644 --- a/tests/modules/cloud_run/examples/simple.yaml +++ b/tests/modules/cloud_run/examples/simple.yaml @@ -48,7 +48,22 @@ values: project: project-id role: roles/run.invoker service: hello + module.cloud_run.google_service_account.service_account[0]: + account_id: tf-cr-hello + disabled: false + display_name: Terraform Cloud Run hello. + project: project-id + module.secret-manager.google_secret_manager_secret.default["credentials"]: + project: project-id + secret_id: credentials + module.secret-manager.google_secret_manager_secret_iam_binding.default["credentials.roles/secretmanager.secretAccessor"]: + condition: [] + role: roles/secretmanager.secretAccessor + counts: google_cloud_run_service: 1 google_cloud_run_service_iam_binding: 1 + google_secret_manager_secret: 1 + google_secret_manager_secret_iam_binding: 1 + google_service_account: 1 diff --git a/tests/modules/cloud_run/examples/trigger-service-account-external.yaml b/tests/modules/cloud_run/examples/trigger-service-account-external.yaml deleted file mode 100644 index 5de6a53b48..0000000000 --- a/tests/modules/cloud_run/examples/trigger-service-account-external.yaml +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright 2023 Google LLC -# -# 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. - -values: - module.cloud_run.google_cloud_run_service.service: - autogenerate_revision_name: false - location: europe-west1 - metadata: - - {} - name: hello - project: my-project - template: - - metadata: - - {} - spec: - - containers: - - args: null - command: null - env: [] - env_from: [] - image: us-docker.pkg.dev/cloudrun/container/hello - liveness_probe: [] - volume_mounts: [] - working_dir: null - volumes: [] - timeouts: null - module.cloud_run.google_eventarc_trigger.audit_log_triggers["setiampolicy"]: - channel: null - destination: - - cloud_function: null - cloud_run_service: - - path: null - region: europe-west1 - service: hello - gke: [] - workflow: null - labels: null - location: europe-west1 - matching_criteria: - - attribute: methodName - operator: '' - value: SetIamPolicy - - attribute: serviceName - operator: '' - value: cloudresourcemanager.googleapis.com - - attribute: type - operator: '' - value: google.cloud.audit.log.v1.written - name: audit-log-setiampolicy - project: my-project - service_account: null - timeouts: null - -counts: - google_cloud_run_service: 1 - google_eventarc_trigger: 1 - modules: 1 - resources: 2 - -outputs: {} - diff --git a/tests/modules/cloud_run/examples/trigger-service-account.yaml b/tests/modules/cloud_run/examples/trigger-service-account.yaml index 35117b795f..eabdaa0fe4 100644 --- a/tests/modules/cloud_run/examples/trigger-service-account.yaml +++ b/tests/modules/cloud_run/examples/trigger-service-account.yaml @@ -19,7 +19,7 @@ values: metadata: - {} name: hello - project: my-project + project: project-id template: - metadata: - {} @@ -35,12 +35,14 @@ values: working_dir: null volumes: [] timeouts: null + module.cloud_run.google_cloud_run_service_iam_member.default[0]: condition: [] location: europe-west1 - project: my-project + project: project-id role: roles/run.invoker service: hello + module.cloud_run.google_eventarc_trigger.pubsub_triggers["topic-1"]: channel: null destination: @@ -58,48 +60,29 @@ values: operator: '' value: google.cloud.pubsub.topic.v1.messagePublished name: pubsub-topic-1 - project: my-project - timeouts: null - transport: - - pubsub: - - topic: topic1 - module.cloud_run.google_eventarc_trigger.pubsub_triggers["topic-2"]: - channel: null - destination: - - cloud_function: null - cloud_run_service: - - path: null - region: europe-west1 - service: hello - gke: [] - workflow: null - labels: null - location: europe-west1 - matching_criteria: - - attribute: type - operator: '' - value: google.cloud.pubsub.topic.v1.messagePublished - name: pubsub-topic-2 - project: my-project + project: project-id timeouts: null transport: - pubsub: - - topic: topic2 + - topic: projects/project-id/topics/pubsub_sink + module.cloud_run.google_service_account.trigger_service_account[0]: account_id: tf-cr-trigger-hello - description: null - disabled: false - display_name: Terraform trigger for Cloud Run hello. - project: my-project - timeouts: null + project: project-id + + module.pubsub.google_pubsub_topic.default: + kms_key_name: null + labels: null + message_retention_duration: null + name: pubsub_sink + project: project-id counts: google_cloud_run_service: 1 google_cloud_run_service_iam_member: 1 - google_eventarc_trigger: 2 + google_eventarc_trigger: 1 + google_pubsub_topic: 1 google_service_account: 1 - modules: 1 - resources: 5 outputs: {} From 35c58eb5c15fc309a5138b32891b3f303ce41a10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Fri, 17 Nov 2023 11:50:02 +0000 Subject: [PATCH 4/6] Fix non-empty plan after apply when using VPC connector --- modules/cloud-run/main.tf | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/cloud-run/main.tf b/modules/cloud-run/main.tf index 46f6e3a8d9..a114c17377 100644 --- a/modules/cloud-run/main.tf +++ b/modules/cloud-run/main.tf @@ -104,9 +104,12 @@ resource "google_vpc_access_connector" "connector" { max_throughput = var.vpc_connector_create.throughput.max min_instances = var.vpc_connector_create.instances.min min_throughput = var.vpc_connector_create.throughput.min - subnet { - name = var.vpc_connector_create.subnet.name - project_id = var.vpc_connector_create.subnet.project_id + dynamic "subnet" { + for_each = alltrue([for k, v in var.vpc_connector_create.subnet : (v == null)]) ? [] : [""] + content { + name = var.vpc_connector_create.subnet.name + project_id = var.vpc_connector_create.subnet.project_id + } } } From 950ad088e9052c6fb37fe367451c42b12701e3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Fri, 17 Nov 2023 16:48:02 +0000 Subject: [PATCH 5/6] Remove perma-diff when using VPC connector + fix trigger service account --- modules/cloud-run/main.tf | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/modules/cloud-run/main.tf b/modules/cloud-run/main.tf index a114c17377..c90a31d843 100644 --- a/modules/cloud-run/main.tf +++ b/modules/cloud-run/main.tf @@ -17,9 +17,19 @@ locals { _vpcaccess_annotation = ( local.vpc_connector_create - ? { + ? merge({ "run.googleapis.com/vpc-access-connector" = google_vpc_access_connector.connector.0.id - } + }, + var.revision_annotations.vpcaccess_egress == null ? { + # if creating a vpc connector and no explicit annotation is given, + # add "private-ranges-only" annotation to prevent permanent diff + "run.googleapis.com/vpc-access-egress" = "private-ranges-only" + } : { + "run.googleapis.com/vpc-access-egress" = ( + var.revision_annotations.vpcaccess_egress + ) + }, + ) : ( var.revision_annotations.vpcaccess_connector == null ? {} @@ -82,8 +92,10 @@ locals { trigger_sa_create = try( var.eventarc_triggers.service_account_create, false ) - trigger_sa_email = try( - google_service_account.trigger_service_account[0].email, null + trigger_sa_email = ( + local.trigger_sa_create ? + google_service_account.trigger_service_account[0].email + : try(var.eventarc_triggers.service_account_email, null) ) vpc_connector_create = var.vpc_connector_create != null } From 9577ac5c36504b354b3cc608b54059d3aebabd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sat, 18 Nov 2023 10:36:30 +0000 Subject: [PATCH 6/6] Disable EventArc E2E test The test fails with: Error: Error creating Trigger: googleapi: Error 400: Invalid resource state for "": Permission denied while using the Eventarc Service Agent. If you recently started to use Eventarc, it may take a few minutes before all necessary permissions are propagated to the Service Agent. Otherwise, verify that it has Eventarc Service Agent role. Retryig after 5 minutes fixes that, but thats not an option for automated tests. --- modules/cloud-run/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cloud-run/README.md b/modules/cloud-run/README.md index 187f3bed6a..91cc47e5a4 100644 --- a/modules/cloud-run/README.md +++ b/modules/cloud-run/README.md @@ -296,7 +296,7 @@ module "cloud_run" { "roles/run.invoker" = [module.sa.iam_email] } } -# tftest modules=2 resources=5 inventory=audit-logs.yaml e2e +# tftest modules=2 resources=5 inventory=audit-logs.yaml ``` #### Using custom service accounts for triggers