diff --git a/modules/cloud-run-v2/README.md b/modules/cloud-run-v2/README.md index bef0f0fed6..e714eb33f6 100644 --- a/modules/cloud-run-v2/README.md +++ b/modules/cloud-run-v2/README.md @@ -1,8 +1,6 @@ # Cloud Run Module -Cloud Run management, with support for IAM roles and Eventarc trigger creation. - -## Examples +Cloud Run Services and Jobs, with support for IAM roles and Eventarc trigger creation. - [Examples](#examples) @@ -15,10 +13,14 @@ Cloud Run management, with support for IAM roles and Eventarc trigger creation. - [Audit logs](#audit-logs) - [Using custom service accounts for triggers](#using-custom-service-accounts-for-triggers) - [Cloud Run Service Account](#cloud-run-service-account) + - [Creating Cloud Run Jobs](#creating-cloud-run-jobs) - [Variables](#variables) - [Outputs](#outputs) +- [Fixtures](#fixtures) +## Examples + ### IAM and environment variables 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 is no duplication of keys: @@ -38,8 +40,8 @@ module "cloud_run" { } env_from_key = { SECRET1 = { - secret = "credentials" - version = "1" + secret = module.secret-manager.secrets["credentials"].name + version = module.secret-manager.version_versions["credentials:v1"] } } } @@ -48,7 +50,7 @@ module "cloud_run" { "roles/run.invoker" = ["allUsers"] } } -# tftest modules=1 resources=2 +# tftest modules=2 resources=5 fixtures=fixtures/secret-credentials.tf inventory=service-iam-env.yaml e2e ``` ### Mounting secrets as volumes @@ -70,13 +72,14 @@ module "cloud_run" { volumes = { credentials = { secret = { - name = "secret-manager-id" - path = "my-secret" + name = module.secret-manager.secrets["credentials"].id + path = "my-secret" + version = "latest" # TODO: should be optional, but results in API error } } } } -# tftest modules=1 resources=1 +# tftest modules=2 resources=4 fixtures=fixtures/secret-credentials.tf inventory=service-volume-secretes.yaml e2e ``` ### Beta features @@ -105,7 +108,7 @@ module "cloud_run" { } } } -# tftest modules=1 resources=1 +# tftest modules=1 resources=1 inventory=service-beta-features.yaml ``` ### VPC Access Connector @@ -125,12 +128,12 @@ module "cloud_run" { } revision = { vpc_access = { - connector = "connector-id" + connector = google_vpc_access_connector.connector.id egress = "ALL_TRAFFIC" } } } -# tftest modules=1 resources=1 +# tftest modules=1 resources=2 fixtures=fixtures/vpc-connector.tf inventory=service-vpc-access-connector.yaml e2e ``` If creation of the VPC Access Connector is required, use the `vpc_connector_create` variable which also supports optional attributes like number of instances, machine type, or throughput. The connector will be used automatically. @@ -147,15 +150,15 @@ module "cloud_run" { } } vpc_connector_create = { - ip_cidr_range = "10.10.10.0/24" - vpc_self_link = "projects/example/global/networks/vpc" + ip_cidr_range = "10.10.10.0/28" + network = var.vpc.self_link instances = { max = 10 min = 2 } } } -# tftest modules=1 resources=2 +# tftest modules=1 resources=2 inventory=service-vpc-access-connector-create.yaml e2e ``` Note that if you are using a Shared VPC for the connector, you need to specify a subnet and the host project if this is not where the Cloud Run service is deployed. @@ -163,7 +166,7 @@ Note that if you are using a Shared VPC for the connector, you need to specify a ```hcl module "cloud_run" { source = "./fabric/modules/cloud-run-v2" - project_id = var.project_id + project_id = module.project-service.project_id region = var.region name = "hello" containers = { @@ -174,12 +177,12 @@ module "cloud_run" { vpc_connector_create = { machine_type = "e2-standard-4" subnet = { - name = "subnet-name" - project_id = "host-project" + name = module.net-vpc-host.subnets["${var.region}/fixture-subnet-28"].name + project_id = module.project-host.project_id } } } -# tftest modules=1 resources=2 +# tftest modules=4 resources=40 fixtures=fixtures/shared-vpc.tf inventory=service-vpc-access-connector-create-sharedvpc.yaml e2e ``` ### Eventarc triggers @@ -201,12 +204,11 @@ module "cloud_run" { } eventarc_triggers = { pubsub = { - topic-1 = "topic1" - topic-2 = "topic2" + topic-1 = module.pubsub.topic.name } } } -# tftest modules=1 resources=3 +# tftest modules=2 resources=4 fixtures=fixtures/pubsub.tf inventory=service-eventarc-pubsub.yaml e2e ``` #### Audit logs @@ -231,9 +233,10 @@ module "cloud_run" { service = "cloudresourcemanager.googleapis.com" } } + service_account_create = true } } -# tftest modules=1 resources=2 +# tftest modules=1 resources=4 inventory=service-eventarc-auditlogs-sa-create.yaml ``` #### Using custom service accounts for triggers @@ -263,7 +266,7 @@ module "cloud_run" { service_account_email = "cloud-run-trigger@my-project.iam.gserviceaccount.com" } } -# tftest modules=1 resources=2 +# tftest modules=1 resources=2 inventory=service-eventarc-auditlogs-external-sa.yaml ``` Example using automatically created service account: @@ -281,13 +284,12 @@ module "cloud_run" { } eventarc_triggers = { pubsub = { - topic-1 = "topic1" - topic-2 = "topic2" + topic-1 = module.pubsub.topic.name } service_account_create = true } } -# tftest modules=1 resources=5 +# tftest modules=2 resources=6 fixtures=fixtures/pubsub.tf inventory=service-eventarc-pubsub-sa-create.yaml e2e ``` ### Cloud Run Service Account @@ -307,7 +309,7 @@ module "cloud_run" { } service_account_create = true } -# tftest modules=1 resources=2 +# tftest modules=1 resources=2 inventory=service-sa-create.yaml e2e ``` To use an externally managed service account, use its email in `service_account` and leave `service_account_create` to `false` (default). @@ -323,40 +325,86 @@ module "cloud_run" { image = "us-docker.pkg.dev/cloudrun/container/hello" } } - service_account = "cloud-run@my-project.iam.gserviceaccount.com" + service_account = module.iam-service-account.email } -# tftest modules=1 resources=1 +# tftest modules=2 resources=2 fixtures=fixtures/iam-service-account.tf inventory=service-external-sa.yaml e2e +``` + +### Creating Cloud Run Jobs +To create a job instead of service set `create_job` to `true`. Jobs support all functions above apart from triggers. + +Unsupported variables / attributes: +* ingress +* revision.gen2_execution_environment (they run by default in gen2) +* revision.name +* containers.liveness_probe +* containers.startup_probe +* containers.resources.cpu_idle +* containers.resources.startup_cpu_boost + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "hello" + region = var.region + create_job = true + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + env = { + VAR1 = "VALUE1" + VAR2 = "VALUE2" + } + } + } + iam = { + "roles/run.invoker" = ["group:${var.group_email}"] + } +} + +# tftest modules=1 resources=2 inventory=job-iam-env.yaml e2e ``` ## Variables | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [name](variables.tf#L137) | Name used for Cloud Run service. | string | ✓ | | -| [project_id](variables.tf#L152) | Project id used for all resources. | string | ✓ | | -| [region](variables.tf#L157) | Region used for all resources. | string | ✓ | | +| [name](variables.tf#L147) | Name used for Cloud Run service. | string | ✓ | | +| [project_id](variables.tf#L162) | Project id used for all resources. | string | ✓ | | +| [region](variables.tf#L167) | Region used for all resources. | string | ✓ | | | [containers](variables.tf#L17) | Containers in name => attributes format. | map(object({…})) | | {} | -| [eventarc_triggers](variables.tf#L77) | Event arc triggers for different sources. | object({…}) | | {} | -| [iam](variables.tf#L91) | IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | -| [ingress](variables.tf#L97) | Ingress settings. | string | | null | -| [labels](variables.tf#L114) | Resource labels. | map(string) | | {} | -| [launch_stage](variables.tf#L120) | The launch stage as defined by Google Cloud Platform Launch Stages. | string | | null | -| [prefix](variables.tf#L142) | Optional prefix used for resource names. | string | | null | -| [revision](variables.tf#L162) | Revision template configurations. | object({…}) | | {} | -| [service_account](variables.tf#L189) | Service account email. Unused if service account is auto-created. | string | | null | -| [service_account_create](variables.tf#L195) | Auto-create service account. | bool | | false | -| [volumes](variables.tf#L201) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} | -| [vpc_connector_create](variables-vpcconnector.tf#L17) | Populate this to create a Serverless VPC Access connector. | object({…}) | | null | +| [create_job](variables.tf#L77) | Create Cloud Run Job instead of Service. | bool | | false | +| [eventarc_triggers](variables.tf#L83) | Event arc triggers for different sources. | object({…}) | | {} | +| [iam](variables.tf#L101) | IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| [ingress](variables.tf#L107) | Ingress settings. | string | | null | +| [labels](variables.tf#L124) | Resource labels. | map(string) | | {} | +| [launch_stage](variables.tf#L130) | The launch stage as defined by Google Cloud Platform Launch Stages. | string | | null | +| [prefix](variables.tf#L152) | Optional prefix used for resource names. | string | | null | +| [revision](variables.tf#L172) | Revision template configurations. | object({…}) | | {} | +| [service_account](variables.tf#L199) | Service account email. Unused if service account is auto-created. | string | | null | +| [service_account_create](variables.tf#L205) | Auto-create service account. | bool | | false | +| [volumes](variables.tf#L211) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} | +| [vpc_connector_create](variables-vpcconnector.tf#L17) | Populate this to create a Serverless VPC Access connector. | object({…}) | | null | ## Outputs | name | description | sensitive | |---|---|:---:| -| [id](outputs.tf#L17) | Fully qualified service id. | | -| [service](outputs.tf#L22) | Cloud Run service. | | -| [service_account](outputs.tf#L27) | Service account resource. | | -| [service_account_email](outputs.tf#L32) | Service account email. | | -| [service_account_iam_email](outputs.tf#L37) | Service account email. | | -| [service_name](outputs.tf#L45) | Cloud Run service name. | | -| [vpc_connector](outputs.tf#L50) | VPC connector resource if created. | | +| [id](outputs.tf#L17) | Fully qualified job or service id. | | +| [job](outputs.tf#L22) | Cloud Run Job. | | +| [service](outputs.tf#L27) | Cloud Run Service. | | +| [service_account](outputs.tf#L32) | Service account resource. | | +| [service_account_email](outputs.tf#L37) | Service account email. | | +| [service_account_iam_email](outputs.tf#L42) | Service account email. | | +| [service_name](outputs.tf#L50) | Cloud Run service name. | | +| [vpc_connector](outputs.tf#L55) | VPC connector resource if created. | | + +## Fixtures + +- [iam-service-account.tf](../../tests/fixtures/iam-service-account.tf) +- [pubsub.tf](../../tests/fixtures/pubsub.tf) +- [secret-credentials.tf](../../tests/fixtures/secret-credentials.tf) +- [shared-vpc.tf](../../tests/fixtures/shared-vpc.tf) +- [vpc-connector.tf](../../tests/fixtures/vpc-connector.tf) diff --git a/modules/cloud-run-v2/job.tf b/modules/cloud-run-v2/job.tf new file mode 100644 index 0000000000..b685c945cd --- /dev/null +++ b/modules/cloud-run-v2/job.tf @@ -0,0 +1,146 @@ +/** + * 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. + */ + +resource "google_cloud_run_v2_job" "job" { + count = var.create_job ? 1 : 0 + provider = google-beta + project = var.project_id + location = var.region + name = "${local.prefix}${var.name}" + labels = var.labels + launch_stage = var.launch_stage + template { + template { + dynamic "vpc_access" { + for_each = local.connector == null ? [] : [""] + content { + connector = local.connector + egress = try(var.revision.vpc_access.egress, null) + } + } + dynamic "vpc_access" { + for_each = try(var.revision.vpc_access.subnet, null) == null ? [] : [""] + content { + egress = var.revision.vpc_access.egress + network_interfaces { + subnetwork = var.revision.vpc_access.subnet + tags = var.revision.vpc_access.tags + } + } + } + timeout = var.revision.timeout + service_account = local.service_account_email + dynamic "containers" { + for_each = var.containers + content { + name = containers.key + image = containers.value.image + command = containers.value.command + args = containers.value.args + dynamic "env" { + for_each = coalesce(containers.value.env, tomap({})) + content { + name = env.key + value = env.value + } + } + dynamic "env" { + for_each = coalesce(containers.value.env_from_key, tomap({})) + content { + name = env.key + value_source { + secret_key_ref { + secret = env.value.secret + version = env.value.version + } + } + } + } + dynamic "resources" { + for_each = containers.value.resources == null ? [] : [""] + content { + limits = containers.value.resources.limits + } + } + dynamic "ports" { + for_each = coalesce(containers.value.ports, tomap({})) + content { + container_port = ports.value.container_port + name = ports.value.name + } + } + dynamic "volume_mounts" { + for_each = coalesce(containers.value.volume_mounts, tomap({})) + content { + name = volume_mounts.key + mount_path = volume_mounts.value + } + } + } + } + dynamic "volumes" { + for_each = var.volumes + content { + name = volumes.key + dynamic "secret" { + for_each = volumes.value.secret == null ? [] : [""] + content { + secret = volumes.value.secret.name + default_mode = volumes.value.secret.default_mode + dynamic "items" { + for_each = volumes.value.secret.path == null ? [] : [""] + content { + path = volumes.value.secret.path + version = volumes.value.secret.version + mode = volumes.value.secret.mode + } + } + } + } + dynamic "cloud_sql_instance" { + for_each = length(coalesce(volumes.value.cloud_sql_instances, [])) == 0 ? [] : [""] + content { + instances = volumes.value.cloud_sql_instances + } + } + dynamic "empty_dir" { + for_each = volumes.value.empty_dir_size == null ? [] : [""] + content { + medium = "MEMORY" + size_limit = volumes.value.empty_dir_size + } + } + } + } + } + } + + lifecycle { + ignore_changes = [ + template.0.annotations["run.googleapis.com/operation-id"], + ] + } +} + +resource "google_cloud_run_v2_job_iam_binding" "binding" { + for_each = var.create_job ? var.iam : {} + project = google_cloud_run_v2_job.job[0].project + location = google_cloud_run_v2_job.job[0].location + name = google_cloud_run_v2_job.job[0].name + role = each.key + members = each.value +} + diff --git a/modules/cloud-run-v2/main.tf b/modules/cloud-run-v2/main.tf index b0492d45bb..8ea430fc7e 100644 --- a/modules/cloud-run-v2/main.tf +++ b/modules/cloud-run-v2/main.tf @@ -37,229 +37,22 @@ locals { var.eventarc_triggers.service_account_create, false ) trigger_sa_email = try( - google_service_account.trigger_service_account[0].email, null + google_service_account.trigger_service_account[0].email, + var.eventarc_triggers.service_account_email, + null ) } -resource "google_cloud_run_v2_service" "service" { - provider = google-beta - project = var.project_id - location = var.region - name = "${local.prefix}${var.name}" - ingress = var.ingress - labels = var.labels - launch_stage = var.launch_stage - - template { - revision = local.revision_name - execution_environment = ( - var.revision.gen2_execution_environment == true - ? "EXECUTION_ENVIRONMENT_GEN2" : "EXECUTION_ENVIRONMENT_GEN1" - ) - max_instance_request_concurrency = var.revision.max_concurrency - scaling { - max_instance_count = var.revision.max_instance_count - min_instance_count = var.revision.min_instance_count - } - dynamic "vpc_access" { - for_each = local.connector == null ? [] : [""] - content { - connector = local.connector - egress = try(var.revision.vpc_access.egress, null) - } - } - dynamic "vpc_access" { - for_each = try(var.revision.vpc_access.subnet, null) == null ? [] : [""] - content { - egress = var.revision.vpc_access.egress - network_interfaces { - subnetwork = var.revision.vpc_access.subnet - tags = var.revision.vpc_access.tags - } - } - } - timeout = var.revision.timeout - service_account = local.service_account_email - dynamic "containers" { - for_each = var.containers - content { - name = containers.key - image = containers.value.image - command = containers.value.command - args = containers.value.args - dynamic "env" { - for_each = coalesce(containers.value.env, tomap({})) - content { - name = env.key - value = env.value - } - } - dynamic "env" { - for_each = coalesce(containers.value.env_from_key, tomap({})) - content { - name = env.key - value_source { - secret_key_ref { - secret = env.value.secret - version = env.value.version - } - } - } - } - dynamic "resources" { - for_each = containers.value.resources == null ? [] : [""] - content { - limits = containers.value.resources.limits - cpu_idle = containers.value.resources.cpu_idle - startup_cpu_boost = containers.value.resources.startup_cpu_boost - } - } - dynamic "ports" { - for_each = coalesce(containers.value.ports, tomap({})) - content { - container_port = ports.value.container_port - name = ports.value.name - } - } - dynamic "volume_mounts" { - for_each = coalesce(containers.value.volume_mounts, tomap({})) - content { - name = volume_mounts.key - mount_path = volume_mounts.value - } - } - dynamic "liveness_probe" { - for_each = containers.value.liveness_probe == null ? [] : [""] - content { - initial_delay_seconds = containers.value.liveness_probe.initial_delay_seconds - timeout_seconds = containers.value.liveness_probe.timeout_seconds - period_seconds = containers.value.liveness_probe.period_seconds - failure_threshold = containers.value.liveness_probe.failure_threshold - dynamic "http_get" { - for_each = containers.value.liveness_probe.http_get == null ? [] : [""] - content { - path = containers.value.liveness_probe.http_get.path - dynamic "http_headers" { - for_each = coalesce(containers.value.liveness_probe.http_get.http_headers, tomap({})) - content { - name = http_headers.key - value = http_headers.value - } - } - } - } - dynamic "grpc" { - for_each = containers.value.liveness_probe.grpc == null ? [] : [""] - content { - port = containers.value.liveness_probe.grpc.port - service = containers.value.liveness_probe.grpc.service - } - } - } - } - dynamic "startup_probe" { - for_each = containers.value.startup_probe == null ? [] : [""] - content { - initial_delay_seconds = containers.value.startup_probe.initial_delay_seconds - timeout_seconds = containers.value.startup_probe.timeout_seconds - period_seconds = containers.value.startup_probe.period_seconds - failure_threshold = containers.value.startup_probe.failure_threshold - dynamic "http_get" { - for_each = containers.value.startup_probe.http_get == null ? [] : [""] - content { - path = containers.value.startup_probe.http_get.path - dynamic "http_headers" { - for_each = coalesce(containers.value.startup_probe.http_get.http_headers, tomap({})) - content { - name = http_headers.key - value = http_headers.value - } - } - } - } - dynamic "tcp_socket" { - for_each = containers.value.startup_probe.tcp_socket == null ? [] : [""] - content { - port = ontainers.value.startup_probe.tcp_socket.port - } - } - dynamic "grpc" { - for_each = containers.value.startup_probe.grpc == null ? [] : [""] - content { - port = containers.value.startup_probe.grpc.port - service = containers.value.startup_probe.grpc.service - } - } - } - } - } - } - dynamic "volumes" { - for_each = var.volumes - content { - name = volumes.key - dynamic "secret" { - for_each = volumes.value.secret == null ? [] : [""] - content { - secret = volumes.value.secret.name - default_mode = volumes.value.secret.default_mode - dynamic "items" { - for_each = volumes.value.secret.path == null ? [] : [""] - content { - path = volumes.value.secret.path - version = volumes.value.secret.version - mode = volumes.value.secret.mode - } - } - } - } - cloud_sql_instance { - instances = volumes.value.cloud_sql_instances - } - dynamic "empty_dir" { - for_each = volumes.value.empty_dir_size == null ? [] : [""] - content { - medium = "MEMORY" - size_limit = volumes.value.empty_dir_size - } - } - } - } - } - - lifecycle { - ignore_changes = [ - template.0.annotations["run.googleapis.com/operation-id"], - ] - } -} - -resource "google_cloud_run_service_iam_binding" "binding" { - for_each = var.iam - project = google_cloud_run_v2_service.service.project - location = google_cloud_run_v2_service.service.location - service = google_cloud_run_v2_service.service.name - role = each.key - members = ( - each.key != "roles/run.invoker" || !local.trigger_sa_create - ? each.value - # if invoker role is present and we create trigger sa, add it as member - : concat( - each.value, ["serviceAccount:${local.trigger_sa_email}"] - ) - ) -} - -resource "google_cloud_run_service_iam_member" "default" { +resource "google_cloud_run_v2_service_iam_member" "default" { # if authoritative invoker role is not present and we create trigger sa # use additive binding to grant it the role count = ( lookup(var.iam, "roles/run.invoker", null) == null && local.trigger_sa_create ) ? 1 : 0 - project = google_cloud_run_v2_service.service.project - location = google_cloud_run_v2_service.service.location - service = google_cloud_run_v2_service.service.name + project = google_cloud_run_v2_service.service[0].project + location = google_cloud_run_v2_service.service[0].location + name = google_cloud_run_v2_service.service[0].name role = "roles/run.invoker" member = "serviceAccount:${local.trigger_sa_email}" } @@ -274,8 +67,8 @@ resource "google_service_account" "service_account" { resource "google_eventarc_trigger" "audit_log_triggers" { for_each = coalesce(var.eventarc_triggers.audit_log, tomap({})) name = "${local.prefix}audit-log-${each.key}" - location = google_cloud_run_v2_service.service.location - project = google_cloud_run_v2_service.service.project + location = google_cloud_run_v2_service.service[0].location + project = google_cloud_run_v2_service.service[0].project matching_criteria { attribute = "type" value = "google.cloud.audit.log.v1.written" @@ -290,8 +83,8 @@ resource "google_eventarc_trigger" "audit_log_triggers" { } destination { cloud_run_service { - service = google_cloud_run_v2_service.service.name - region = google_cloud_run_v2_service.service.location + service = google_cloud_run_v2_service.service[0].name + region = google_cloud_run_v2_service.service[0].location } } service_account = local.trigger_sa_email @@ -300,8 +93,8 @@ resource "google_eventarc_trigger" "audit_log_triggers" { resource "google_eventarc_trigger" "pubsub_triggers" { for_each = coalesce(var.eventarc_triggers.pubsub, tomap({})) name = "${local.prefix}pubsub-${each.key}" - location = google_cloud_run_v2_service.service.location - project = google_cloud_run_v2_service.service.project + location = google_cloud_run_v2_service.service[0].location + project = google_cloud_run_v2_service.service[0].project matching_criteria { attribute = "type" value = "google.cloud.pubsub.topic.v1.messagePublished" @@ -313,8 +106,8 @@ resource "google_eventarc_trigger" "pubsub_triggers" { } destination { cloud_run_service { - service = google_cloud_run_v2_service.service.name - region = google_cloud_run_v2_service.service.location + service = google_cloud_run_v2_service.service[0].name + region = google_cloud_run_v2_service.service[0].location } } service_account = local.trigger_sa_email diff --git a/modules/cloud-run-v2/outputs.tf b/modules/cloud-run-v2/outputs.tf index d3c61784c9..4275039e89 100644 --- a/modules/cloud-run-v2/outputs.tf +++ b/modules/cloud-run-v2/outputs.tf @@ -15,13 +15,18 @@ */ output "id" { - description = "Fully qualified service id." - value = google_cloud_run_v2_service.service.id + description = "Fully qualified job or service id." + value = var.create_job ? google_cloud_run_v2_job.job[0].id : google_cloud_run_v2_service.service[0].id +} + +output "job" { + description = "Cloud Run Job." + value = var.create_job ? google_cloud_run_v2_job.job[0] : null } output "service" { - description = "Cloud Run service." - value = google_cloud_run_v2_service.service + description = "Cloud Run Service." + value = var.create_job ? null : google_cloud_run_v2_service.service[0] } output "service_account" { @@ -44,7 +49,7 @@ output "service_account_iam_email" { output "service_name" { description = "Cloud Run service name." - value = google_cloud_run_v2_service.service.name + value = var.create_job ? null : google_cloud_run_v2_service.service[0].name } output "vpc_connector" { diff --git a/modules/cloud-run-v2/service.tf b/modules/cloud-run-v2/service.tf new file mode 100644 index 0000000000..4517fbce1e --- /dev/null +++ b/modules/cloud-run-v2/service.tf @@ -0,0 +1,232 @@ +/** + * 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. + */ + +resource "google_cloud_run_v2_service" "service" { + count = var.create_job ? 0 : 1 + provider = google-beta + project = var.project_id + location = var.region + name = "${local.prefix}${var.name}" + ingress = var.ingress + labels = var.labels + launch_stage = var.launch_stage + + template { + revision = local.revision_name + execution_environment = ( + var.revision.gen2_execution_environment == true + ? "EXECUTION_ENVIRONMENT_GEN2" : "EXECUTION_ENVIRONMENT_GEN1" + ) + max_instance_request_concurrency = var.revision.max_concurrency + dynamic "scaling" { + for_each = (var.revision.max_instance_count == null && var.revision.min_instance_count == null) ? [] : [""] + content { + max_instance_count = var.revision.max_instance_count + min_instance_count = var.revision.min_instance_count + } + } + dynamic "vpc_access" { + for_each = local.connector == null ? [] : [""] + content { + connector = local.connector + egress = try(var.revision.vpc_access.egress, null) + } + } + dynamic "vpc_access" { + for_each = try(var.revision.vpc_access.subnet, null) == null ? [] : [""] + content { + egress = var.revision.vpc_access.egress + network_interfaces { + subnetwork = var.revision.vpc_access.subnet + tags = var.revision.vpc_access.tags + } + } + } + timeout = var.revision.timeout + service_account = local.service_account_email + dynamic "containers" { + for_each = var.containers + content { + name = containers.key + image = containers.value.image + command = containers.value.command + args = containers.value.args + dynamic "env" { + for_each = coalesce(containers.value.env, tomap({})) + content { + name = env.key + value = env.value + } + } + dynamic "env" { + for_each = coalesce(containers.value.env_from_key, tomap({})) + content { + name = env.key + value_source { + secret_key_ref { + secret = env.value.secret + version = env.value.version + } + } + } + } + dynamic "resources" { + for_each = containers.value.resources == null ? [] : [""] + content { + limits = containers.value.resources.limits + cpu_idle = containers.value.resources.cpu_idle + startup_cpu_boost = containers.value.resources.startup_cpu_boost + } + } + dynamic "ports" { + for_each = coalesce(containers.value.ports, tomap({})) + content { + container_port = ports.value.container_port + name = ports.value.name + } + } + dynamic "volume_mounts" { + for_each = coalesce(containers.value.volume_mounts, tomap({})) + content { + name = volume_mounts.key + mount_path = volume_mounts.value + } + } + dynamic "liveness_probe" { + for_each = containers.value.liveness_probe == null ? [] : [""] + content { + initial_delay_seconds = containers.value.liveness_probe.initial_delay_seconds + timeout_seconds = containers.value.liveness_probe.timeout_seconds + period_seconds = containers.value.liveness_probe.period_seconds + failure_threshold = containers.value.liveness_probe.failure_threshold + dynamic "http_get" { + for_each = containers.value.liveness_probe.http_get == null ? [] : [""] + content { + path = containers.value.liveness_probe.http_get.path + dynamic "http_headers" { + for_each = coalesce(containers.value.liveness_probe.http_get.http_headers, tomap({})) + content { + name = http_headers.key + value = http_headers.value + } + } + } + } + dynamic "grpc" { + for_each = containers.value.liveness_probe.grpc == null ? [] : [""] + content { + port = containers.value.liveness_probe.grpc.port + service = containers.value.liveness_probe.grpc.service + } + } + } + } + dynamic "startup_probe" { + for_each = containers.value.startup_probe == null ? [] : [""] + content { + initial_delay_seconds = containers.value.startup_probe.initial_delay_seconds + timeout_seconds = containers.value.startup_probe.timeout_seconds + period_seconds = containers.value.startup_probe.period_seconds + failure_threshold = containers.value.startup_probe.failure_threshold + dynamic "http_get" { + for_each = containers.value.startup_probe.http_get == null ? [] : [""] + content { + path = containers.value.startup_probe.http_get.path + dynamic "http_headers" { + for_each = coalesce(containers.value.startup_probe.http_get.http_headers, tomap({})) + content { + name = http_headers.key + value = http_headers.value + } + } + } + } + dynamic "tcp_socket" { + for_each = containers.value.startup_probe.tcp_socket == null ? [] : [""] + content { + port = containers.value.startup_probe.tcp_socket.port + } + } + dynamic "grpc" { + for_each = containers.value.startup_probe.grpc == null ? [] : [""] + content { + port = containers.value.startup_probe.grpc.port + service = containers.value.startup_probe.grpc.service + } + } + } + } + } + } + dynamic "volumes" { + for_each = var.volumes + content { + name = volumes.key + dynamic "secret" { + for_each = volumes.value.secret == null ? [] : [""] + content { + secret = volumes.value.secret.name + default_mode = volumes.value.secret.default_mode + dynamic "items" { + for_each = volumes.value.secret.path == null ? [] : [""] + content { + path = volumes.value.secret.path + version = volumes.value.secret.version + mode = volumes.value.secret.mode + } + } + } + } + dynamic "cloud_sql_instance" { + for_each = length(coalesce(volumes.value.cloud_sql_instances, [])) == 0 ? [] : [""] + content { + instances = volumes.value.cloud_sql_instances + } + } + dynamic "empty_dir" { + for_each = volumes.value.empty_dir_size == null ? [] : [""] + content { + medium = "MEMORY" + size_limit = volumes.value.empty_dir_size + } + } + } + } + } + + lifecycle { + ignore_changes = [ + template.0.annotations["run.googleapis.com/operation-id"], + ] + } +} + +resource "google_cloud_run_v2_service_iam_binding" "binding" { + for_each = var.create_job ? {} : var.iam + project = google_cloud_run_v2_service.service[0].project + location = google_cloud_run_v2_service.service[0].location + name = google_cloud_run_v2_service.service[0].name + role = each.key + members = ( + each.key != "roles/run.invoker" || !local.trigger_sa_create + ? each.value + # if invoker role is present and we create trigger sa, add it as member + : concat( + each.value, ["serviceAccount:${local.trigger_sa_email}"] + ) + ) +} + diff --git a/modules/cloud-run-v2/variables-vpcconnector.tf b/modules/cloud-run-v2/variables-vpcconnector.tf index 53dbdc5361..7a26187324 100644 --- a/modules/cloud-run-v2/variables-vpcconnector.tf +++ b/modules/cloud-run-v2/variables-vpcconnector.tf @@ -18,15 +18,15 @@ variable "vpc_connector_create" { description = "Populate this to create a Serverless VPC Access connector." type = object({ ip_cidr_range = optional(string) - vpc_self_link = optional(string) machine_type = optional(string) name = optional(string) + network = optional(string) instances = optional(object({ max = optional(number) min = optional(number) }), {}) throughput = optional(object({ - max = optional(number) + max = optional(number, 1000) # workaround for a wrong default in provider min = optional(number) }), {}) subnet = optional(object({ diff --git a/modules/cloud-run-v2/variables.tf b/modules/cloud-run-v2/variables.tf index d518823259..7e9c294119 100644 --- a/modules/cloud-run-v2/variables.tf +++ b/modules/cloud-run-v2/variables.tf @@ -74,6 +74,12 @@ variable "containers" { nullable = false } +variable "create_job" { + description = "Create Cloud Run Job instead of Service." + type = bool + default = false +} + variable "eventarc_triggers" { description = "Event arc triggers for different sources." type = object({ @@ -86,6 +92,10 @@ variable "eventarc_triggers" { service_account_create = optional(bool, false) }) default = {} + validation { + condition = var.eventarc_triggers.audit_log == null || (var.eventarc_triggers.audit_log != null && (var.eventarc_triggers.service_account_email != null || var.eventarc_triggers.service_account_create)) + error_message = "When setting var.eventarc_triggers.audit_log provide either service_account_email or set service_account_create to true" + } } variable "iam" { diff --git a/modules/cloud-run-v2/vpcconnector.tf b/modules/cloud-run-v2/vpcconnector.tf index aacf1ced64..50a7904c95 100644 --- a/modules/cloud-run-v2/vpcconnector.tf +++ b/modules/cloud-run-v2/vpcconnector.tf @@ -24,15 +24,18 @@ resource "google_vpc_access_connector" "connector" { ) region = var.region ip_cidr_range = var.vpc_connector_create.ip_cidr_range - network = var.vpc_connector_create.vpc_self_link + network = var.vpc_connector_create.network machine_type = var.vpc_connector_create.machine_type max_instances = var.vpc_connector_create.instances.max 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 = var.vpc_connector_create.subnet.name == null ? [] : [""] + content { + name = var.vpc_connector_create.subnet.name + project_id = var.vpc_connector_create.subnet.project_id + } } } diff --git a/modules/secret-manager/README.md b/modules/secret-manager/README.md index 8d1d8b110b..8133399722 100644 --- a/modules/secret-manager/README.md +++ b/modules/secret-manager/README.md @@ -123,7 +123,8 @@ module "secret-manager" { | [ids](outputs.tf#L17) | Fully qualified secret ids. | | | [secrets](outputs.tf#L24) | Secret resources. | | | [version_ids](outputs.tf#L29) | Version ids keyed by secret name : version name. | | -| [versions](outputs.tf#L36) | Secret versions. | ✓ | +| [version_versions](outputs.tf#L36) | Version versions keyed by secret name : version name. | | +| [versions](outputs.tf#L43) | Secret versions. | ✓ | ## Requirements diff --git a/modules/secret-manager/outputs.tf b/modules/secret-manager/outputs.tf index fcd6e1fce0..7450ad742a 100644 --- a/modules/secret-manager/outputs.tf +++ b/modules/secret-manager/outputs.tf @@ -33,6 +33,13 @@ output "version_ids" { } } +output "version_versions" { + description = "Version versions keyed by secret name : version name." + value = { + for k, v in google_secret_manager_secret_version.default : k => v.version + } +} + output "versions" { description = "Secret versions." value = google_secret_manager_secret_version.default diff --git a/tests/examples/variables.tf b/tests/examples/variables.tf index 373d2492ba..bc50b1ee94 100644 --- a/tests/examples/variables.tf +++ b/tests/examples/variables.tf @@ -48,6 +48,10 @@ variable "project_id" { default = "project-id" } +variable "project_number" { + default = "123" +} + variable "region" { default = "europe-west8" } diff --git a/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl b/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl index d23c39a47b..023baabaa2 100644 --- a/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl +++ b/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl @@ -12,16 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -bucket = "${bucket}" +bucket = "${bucket}" billing_account_id = "${billing_account_id}" kms_key = { id = "${kms_key_id}" } -group_email = "${group_email}" +group_email = "${group_email}" organization_id = "organizations/${organization_id}" -folder_id = "folders/${folder_id}" -project_id = "${project_id}" -region = "${region}" +folder_id = "folders/${folder_id}" +project_id = "${project_id}" +project_number = "${project_number}" +region = "${region}" service_account = { id = "${service_account.id}" email = "${service_account.email}" diff --git a/tests/examples_e2e/setup_module/main.tf b/tests/examples_e2e/setup_module/main.tf index d212f58240..1091d2b89d 100644 --- a/tests/examples_e2e/setup_module/main.tf +++ b/tests/examples_e2e/setup_module/main.tf @@ -151,6 +151,7 @@ resource "local_file" "terraform_tfvars" { kms_key_id = google_kms_crypto_key.key.id organization_id = var.organization_id project_id = google_project.project.project_id + project_number = google_project.project.number region = var.region service_account = { id = google_service_account.service_account.id diff --git a/tests/fixtures.py b/tests/fixtures.py index 7a46f21101..e3ff5a06c5 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -254,7 +254,7 @@ def validate_plan_object(expected_value, plan_value, relative_path, if isinstance(expected_value, dict) and isinstance(plan_value, dict): for k, v in expected_value.items(): assert k in plan_value, \ - f'{relative_path}: {k} is not a valid address in the plan' + f'{relative_path}: {relative_address}.{k} is not a valid address in the plan' validate_plan_object(v, plan_value[k], relative_path, f'{relative_address}.{k}') diff --git a/tests/fixtures/iam-service-account.tf b/tests/fixtures/iam-service-account.tf new file mode 100644 index 0000000000..49a36a09e0 --- /dev/null +++ b/tests/fixtures/iam-service-account.tf @@ -0,0 +1,21 @@ +/** + * 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. + */ + +module "iam-service-account" { + source = "./fabric/modules/iam-service-account" + project_id = var.project_id + name = "fixture-service-account" +} diff --git a/tests/fixtures/pubsub.tf b/tests/fixtures/pubsub.tf new file mode 100644 index 0000000000..f777799cb3 --- /dev/null +++ b/tests/fixtures/pubsub.tf @@ -0,0 +1,24 @@ +/** + * 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. + */ + +module "pubsub" { + source = "./fabric/modules/pubsub" + project_id = var.project_id + name = "topic" + iam = { + "roles/pubsub.subscriber" = ["serviceAccount:${var.project_number}-compute@developer.gserviceaccount.com"] + } +} diff --git a/tests/fixtures/secret-credentials.tf b/tests/fixtures/secret-credentials.tf new file mode 100644 index 0000000000..2207e6a29b --- /dev/null +++ b/tests/fixtures/secret-credentials.tf @@ -0,0 +1,33 @@ +/** + * 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. + */ + +module "secret-manager" { + source = "./fabric/modules/secret-manager" + project_id = var.project_id + secrets = { + credentials = {} + } + iam = { + credentials = { + "roles/secretmanager.secretAccessor" = ["serviceAccount:${var.project_number}-compute@developer.gserviceaccount.com"] + } + } + versions = { + credentials = { + v1 = { enabled = true, data = "manual foo bar spam" } + } + } +} diff --git a/tests/fixtures/shared-vpc.tf b/tests/fixtures/shared-vpc.tf new file mode 100644 index 0000000000..24767d228d --- /dev/null +++ b/tests/fixtures/shared-vpc.tf @@ -0,0 +1,87 @@ +/** + * 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. + */ + +module "project-host" { + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "host" + parent = var.folder_id + prefix = var.prefix + shared_vpc_host_config = { + enabled = true + } +} + +module "project-service" { + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "service" + parent = var.folder_id + prefix = var.prefix + services = [ + # trimmed down list of services, to be extended as needed + "apigee.googleapis.com", + "bigquery.googleapis.com", + "cloudbuild.googleapis.com", + "cloudfunctions.googleapis.com", + "cloudkms.googleapis.com", + "cloudresourcemanager.googleapis.com", + "compute.googleapis.com", + "dns.googleapis.com", + "eventarc.googleapis.com", + "iam.googleapis.com", + "run.googleapis.com", + "secretmanager.googleapis.com", + "servicenetworking.googleapis.com", + "serviceusage.googleapis.com", + "stackdriver.googleapis.com", + "storage-component.googleapis.com", + "storage.googleapis.com", + "vpcaccess.googleapis.com", + ] + shared_vpc_service_config = { + host_project = module.project-host.project_id + # reuse the list of services from the module's outputs + service_iam_grants = module.project-service.services + } +} + +module "net-vpc-host" { + source = "./fabric/modules/net-vpc" + project_id = module.project-host.project_id + name = "host-network" + subnets = [ + { + ip_cidr_range = "10.0.0.0/24" + name = "fixture-subnet-24" + region = var.region + secondary_ip_ranges = { + pods = "172.16.0.0/20" + services = "192.168.0.0/24" + } + }, + { + ip_cidr_range = "10.0.1.0/28" + name = "fixture-subnet-28" + region = var.region + secondary_ip_ranges = { + pods = "172.16.16.0/20" + services = "192.168.1.0/24" + } + } + + ] +} diff --git a/tests/fixtures/vpc-connector.tf b/tests/fixtures/vpc-connector.tf new file mode 100644 index 0000000000..707ddf1687 --- /dev/null +++ b/tests/fixtures/vpc-connector.tf @@ -0,0 +1,23 @@ +/** + * 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. + */ + +resource "google_vpc_access_connector" "connector" { + project = var.project_id + name = "vpc-connector" + region = var.region + ip_cidr_range = "192.168.0.0/28" + network = var.vpc.self_link +} diff --git a/tests/modules/cloud_run_v2/examples/job-iam-env.yaml b/tests/modules/cloud_run_v2/examples/job-iam-env.yaml new file mode 100644 index 0000000000..e0f1aef4de --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/job-iam-env.yaml @@ -0,0 +1,55 @@ +# 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_v2_job.job[0]: + location: europe-west8 + name: hello + project: project-id + template: + - template: + - containers: + - args: null + command: null + env: + - name: VAR1 + value: VALUE1 + value_source: [] + - name: VAR2 + value: VALUE2 + value_source: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + ports: [] + volume_mounts: [] + working_dir: null + max_retries: 3 + volumes: [] + vpc_access: [] + module.cloud_run.google_cloud_run_v2_job_iam_binding.binding["roles/run.invoker"]: + condition: [] + location: europe-west8 + members: + - group:organization-admins@example.org + name: hello + project: project-id + role: roles/run.invoker + +counts: + google_cloud_run_v2_job: 1 + google_cloud_run_v2_job_iam_binding: 1 + modules: 1 + resources: 2 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-beta-features.yaml b/tests/modules/cloud_run_v2/examples/service-beta-features.yaml new file mode 100644 index 0000000000..2f1bd086f6 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-beta-features.yaml @@ -0,0 +1,48 @@ +# 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_v2_service.service[0]: + location: europe-west8 + name: hello + project: project-id + template: + - annotations: null + containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN2 + volumes: [] + vpc_access: + - connector: null + egress: ALL_TRAFFIC + network_interfaces: + - subnetwork: default + tags: + - tag1 + - tag2 + - tag3 + +counts: + google_cloud_run_v2_service: 1 + modules: 1 + resources: 1 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-eventarc-auditlogs-external-sa.yaml b/tests/modules/cloud_run_v2/examples/service-eventarc-auditlogs-external-sa.yaml new file mode 100644 index 0000000000..4b58ee7dd0 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-eventarc-auditlogs-external-sa.yaml @@ -0,0 +1,60 @@ +# 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_v2_service.service[0]: + location: europe-west8 + name: hello + project: project-id + template: + - containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + volumes: [] + vpc_access: [] + module.cloud_run.google_eventarc_trigger.audit_log_triggers["setiampolicy"]: + destination: + - cloud_run_service: + - path: null + region: europe-west8 + service: hello + location: europe-west8 + 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: project-id + service_account: cloud-run-trigger@my-project.iam.gserviceaccount.com + +counts: + google_cloud_run_v2_service: 1 + google_eventarc_trigger: 1 + modules: 1 + resources: 2 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-eventarc-auditlogs-sa-create.yaml b/tests/modules/cloud_run_v2/examples/service-eventarc-auditlogs-sa-create.yaml new file mode 100644 index 0000000000..bafabe8152 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-eventarc-auditlogs-sa-create.yaml @@ -0,0 +1,74 @@ +# 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_v2_service_iam_member.default[0]: + condition: [] + location: europe-west8 + name: hello + project: project-id + role: roles/run.invoker + module.cloud_run.google_cloud_run_v2_service.service[0]: + location: europe-west8 + name: hello + project: project-id + template: + - containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + volumes: [] + vpc_access: [] + timeouts: null + module.cloud_run.google_eventarc_trigger.audit_log_triggers["setiampolicy"]: + destination: + - cloud_run_service: + - path: null + region: europe-west8 + service: hello + location: europe-west8 + 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: project-id + 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: project-id + +counts: + google_cloud_run_v2_service_iam_member: 1 + google_cloud_run_v2_service: 1 + google_eventarc_trigger: 1 + google_service_account: 1 + modules: 1 + resources: 4 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-eventarc-pubsub-sa-create.yaml b/tests/modules/cloud_run_v2/examples/service-eventarc-pubsub-sa-create.yaml new file mode 100644 index 0000000000..595d01aaf2 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-eventarc-pubsub-sa-create.yaml @@ -0,0 +1,71 @@ +# 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_v2_service_iam_member.default[0]: + condition: [] + location: europe-west8 + name: hello + project: project-id + role: roles/run.invoker + module.cloud_run.google_cloud_run_v2_service.service[0]: + location: europe-west8 + name: hello + project: project-id + template: + - containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + volumes: [] + vpc_access: [] + module.cloud_run.google_eventarc_trigger.pubsub_triggers["topic-1"]: + destination: + - cloud_run_service: + - path: null + region: europe-west8 + service: hello + location: europe-west8 + matching_criteria: + - attribute: type + operator: '' + value: google.cloud.pubsub.topic.v1.messagePublished + name: pubsub-topic-1 + project: project-id + transport: + - pubsub: + - topic: topic + 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: project-id + timeouts: null + +counts: + google_cloud_run_v2_service_iam_member: 1 + google_cloud_run_v2_service: 1 + google_eventarc_trigger: 1 + google_service_account: 1 + modules: 2 + resources: 6 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-eventarc-pubsub.yaml b/tests/modules/cloud_run_v2/examples/service-eventarc-pubsub.yaml new file mode 100644 index 0000000000..125fecbea8 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-eventarc-pubsub.yaml @@ -0,0 +1,58 @@ +# 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_v2_service.service[0]: + location: europe-west8 + name: hello + project: project-id + template: + - containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + volumes: [] + vpc_access: [] + + module.cloud_run.google_eventarc_trigger.pubsub_triggers["topic-1"]: + destination: + - cloud_run_service: + - path: null + region: europe-west8 + service: hello + location: europe-west8 + matching_criteria: + - attribute: type + operator: '' + value: google.cloud.pubsub.topic.v1.messagePublished + name: pubsub-topic-1 + project: project-id + service_account: null + transport: + - pubsub: + - topic: topic + +counts: + google_cloud_run_v2_service: 1 + google_eventarc_trigger: 1 + modules: 2 + resources: 4 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-external-sa.yaml b/tests/modules/cloud_run_v2/examples/service-external-sa.yaml new file mode 100644 index 0000000000..a9d65dd421 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-external-sa.yaml @@ -0,0 +1,40 @@ +# 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_v2_service.service[0]: + location: europe-west8 + name: hello + project: project-id + template: + - containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + service_account: fixture-service-account@project-id.iam.gserviceaccount.com + volumes: [] + vpc_access: [] + +counts: + google_cloud_run_v2_service: 1 + modules: 2 + resources: 2 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-iam-env.yaml b/tests/modules/cloud_run_v2/examples/service-iam-env.yaml new file mode 100644 index 0000000000..6feb47a663 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-iam-env.yaml @@ -0,0 +1,59 @@ +# 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_v2_service_iam_binding.binding["roles/run.invoker"]: + condition: [] + location: europe-west8 + name: hello + members: + - allUsers + project: project-id + role: roles/run.invoker + module.cloud_run.google_cloud_run_v2_service.service[0]: + location: europe-west8 + name: hello + project: project-id + template: + - containers: + - args: null + command: null + depends_on: null + env: + - name: VAR1 + value: VALUE1 + value_source: [] + - name: VAR2 + value: VALUE2 + value_source: [] + - name: SECRET1 + value: null + value_source: + - secret_key_ref: + - {} + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + volumes: [] + vpc_access: [] + +counts: + google_cloud_run_v2_service_iam_binding: 1 + google_cloud_run_v2_service: 1 + modules: 2 + resources: 5 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-sa-create.yaml b/tests/modules/cloud_run_v2/examples/service-sa-create.yaml new file mode 100644 index 0000000000..cdc3699a33 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-sa-create.yaml @@ -0,0 +1,47 @@ +# 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_v2_service.service[0]: + location: europe-west8 + name: hello + project: project-id + template: + - containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + volumes: [] + vpc_access: [] + module.cloud_run.google_service_account.service_account[0]: + account_id: tf-cr-hello + description: null + disabled: false + display_name: Terraform Cloud Run hello. + project: project-id + timeouts: null + +counts: + google_cloud_run_v2_service: 1 + google_service_account: 1 + modules: 1 + resources: 2 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-volume-secretes.yaml b/tests/modules/cloud_run_v2/examples/service-volume-secretes.yaml new file mode 100644 index 0000000000..cace77effa --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-volume-secretes.yaml @@ -0,0 +1,62 @@ +# 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_v2_service.service[0]: + annotations: null + binary_authorization: [] + client: null + client_version: null + custom_audiences: null + description: null + labels: null + location: europe-west8 + name: hello + project: project-id + template: + - annotations: null + containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: + - mount_path: /credentials + name: credentials + working_dir: null + encryption_key: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + labels: null + revision: null + session_affinity: null + volumes: + - empty_dir: [] + name: credentials + secret: + - default_mode: null + items: + - mode: null + path: my-secret + version: latest + vpc_access: [] + timeouts: null + +counts: + google_cloud_run_v2_service: 1 + modules: 2 + resources: 4 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-vpc-access-connector-create-sharedvpc.yaml b/tests/modules/cloud_run_v2/examples/service-vpc-access-connector-create-sharedvpc.yaml new file mode 100644 index 0000000000..9d355be768 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-vpc-access-connector-create-sharedvpc.yaml @@ -0,0 +1,49 @@ +# 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_v2_service.service[0]: + location: europe-west8 + name: hello + project: test-service + template: + - containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + module.cloud_run.google_vpc_access_connector.connector[0]: + ip_cidr_range: null + machine_type: e2-standard-4 + max_throughput: 1000 + min_throughput: 200 + name: hello + project: test-service + region: europe-west8 + subnet: + - name: fixture-subnet-28 + project_id: test-host + +counts: + google_cloud_run_v2_service: 1 + google_vpc_access_connector: 1 + modules: 4 + resources: 40 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-vpc-access-connector-create.yaml b/tests/modules/cloud_run_v2/examples/service-vpc-access-connector-create.yaml new file mode 100644 index 0000000000..0a396a0634 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-vpc-access-connector-create.yaml @@ -0,0 +1,49 @@ +# 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_v2_service.service[0]: + binary_authorization: [] + location: europe-west8 + name: hello + project: project-id + template: + - containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + volumes: [] + timeouts: null + module.cloud_run.google_vpc_access_connector.connector[0]: + ip_cidr_range: 10.10.10.0/28 + machine_type: e2-micro + max_throughput: 1000 + name: hello + network: projects/xxx/global/networks/aaa + project: project-id + region: europe-west8 + subnet: [] + +counts: + google_cloud_run_v2_service: 1 + google_vpc_access_connector: 1 + modules: 1 + resources: 2 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-vpc-access-connector.yaml b/tests/modules/cloud_run_v2/examples/service-vpc-access-connector.yaml new file mode 100644 index 0000000000..4c94468c70 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-vpc-access-connector.yaml @@ -0,0 +1,45 @@ +# 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_v2_service.service[0]: + location: europe-west8 + name: hello + project: project-id + template: + - annotations: null + containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + volumes: [] +# Depends on values known after apply, so empty in the plan +# vpc_access: +# - connector: connector-id +# egress: ALL_TRAFFIC +# network_interfaces: [] + +counts: + google_cloud_run_v2_service: 1 + modules: 1 + resources: 2 + +outputs: {} + diff --git a/tools/create_e2e_sandbox.sh b/tools/create_e2e_sandbox.sh index b49a14c0ad..206a274a74 100755 --- a/tools/create_e2e_sandbox.sh +++ b/tools/create_e2e_sandbox.sh @@ -28,7 +28,7 @@ # set -e -DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && cd .. && pwd ) DEST=$1 INFRA="${DEST}/infra" TIMESTAMP=$(date +%s)