diff --git a/README.md b/README.md index 5840a8f852..4caa7e224f 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Currently available modules: - **data** - [BigQuery dataset](./modules/bigquery-dataset), [Bigtable instance](./modules/bigtable-instance), [Dataplex](./modules/dataplex), [Dataplex DataScan](./modules/dataplex-datascan/), [Cloud SQL instance](./modules/cloudsql-instance), [Data Catalog Policy Tag](./modules/data-catalog-policy-tag), [Datafusion](./modules/datafusion), [Dataproc](./modules/dataproc), [GCS](./modules/gcs), [Pub/Sub](./modules/pubsub) - **development** - [API Gateway](./modules/api-gateway), [Apigee](./modules/apigee), [Artifact Registry](./modules/artifact-registry), [Container Registry](./modules/container-registry), [Cloud Source Repository](./modules/source-repository), [Workstation cluster](./modules/workstation-cluster) - **security** - [Binauthz](./modules/binauthz/), [KMS](./modules/kms), [SecretManager](./modules/secret-manager), [VPC Service Control](./modules/vpc-sc) -- **serverless** - [Cloud Function v1](./modules/cloud-function-v1), [Cloud Function v2](./modules/cloud-function-v2), [Cloud Run](./modules/cloud-run) +- **serverless** - [Cloud Function v1](./modules/cloud-function-v1), [Cloud Function v2](./modules/cloud-function-v2), [Cloud Run](./modules/cloud-run), [Cloud Run v2](./modules/cloud-run-v2) For more information and usage examples see each module's README file. diff --git a/modules/README.md b/modules/README.md index fa54a68c46..b4740f8e68 100644 --- a/modules/README.md +++ b/modules/README.md @@ -107,3 +107,4 @@ These modules are used in the examples included in this repository. If you are u - [Cloud Functions v1](./cloud-function-v1) - [Cloud Functions v2](./cloud-function-v2) - [Cloud Run](./cloud-run) +- [Cloud Run v2](./cloud-run-v2) diff --git a/modules/cloud-run-v2/README.md b/modules/cloud-run-v2/README.md new file mode 100644 index 0000000000..7fa4258b79 --- /dev/null +++ b/modules/cloud-run-v2/README.md @@ -0,0 +1,353 @@ +# Cloud Run Module + +Cloud Run management, with support for IAM roles and Eventarc trigger creation. + +## Examples + + +- [Examples](#examples) + - [IAM and environment variables](#iam-and-environment-variables) + - [Mounting secrets as volumes](#mounting-secrets-as-volumes) + - [Beta features](#beta-features) + - [VPC Access Connector](#vpc-access-connector) + - [Eventarc triggers](#eventarc-triggers) + - [PubSub](#pubsub) + - [Audit logs](#audit-logs) + - [Using custom service accounts for triggers](#using-custom-service-accounts-for-triggers) + - [Cloud Run Service Account](#cloud-run-service-account) +- [Variables](#variables) +- [Outputs](#outputs) + + +### 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: + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "hello" + region = var.region + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + env = { + VAR1 = "VALUE1" + VAR2 = "VALUE2" + } + env_from_key = { + SECRET1 = { + secret = "credentials" + version = "1" + } + } + } + } + iam = { + "roles/run.invoker" = ["allUsers"] + } +} +# tftest modules=1 resources=2 +``` + +### Mounting secrets as volumes + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "hello" + region = var.region + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + volume_mounts = { + "credentials" = "/credentials" + } + } + } + volumes = { + credentials = { + secret = { + name = "secret-manager-id" + path = "my-secret" + } + } + } +} +# tftest modules=1 resources=1 +``` + +### Beta features + +To use beta features like Direct VPC Egress, set the launch stage to a preview stage. + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "hello" + region = var.region + launch_stage = "BETA" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + revision = { + gen2_execution_environment = true + max_instance_count = 20 + vpc_access = { + egress = "ALL_TRAFFIC" + subnet = "default" + tags = ["tag1", "tag2", "tag3"] + } + } +} +# tftest modules=1 resources=1 +``` + +### VPC Access Connector + +You can use an existing [VPC Access Connector](https://cloud.google.com/vpc/docs/serverless-vpc-access) to connect to a VPC from Cloud Run. + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "hello" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + revision = { + vpc_access = { + connector = "connector-id" + egress = "ALL_TRAFFIC" + } + } +} +# tftest modules=1 resources=1 +``` + +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. + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "hello" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + vpc_connector_create = { + ip_cidr_range = "10.10.10.0/24" + vpc_self_link = "projects/example/global/networks/vpc" + instances = { + max = 10 + min = 2 + } + } +} +# tftest modules=1 resources=2 +``` + +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. + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "hello" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + vpc_connector_create = { + machine_type = "e2-standard-4" + subnet = { + name = "subnet-name" + project_id = "host-project" + } + } +} +# tftest modules=1 resources=2 +``` + +### Eventarc triggers + +#### PubSub + +This deploys a Cloud Run service that will be triggered when messages are published to Pub/Sub topics. + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "hello" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + eventarc_triggers = { + pubsub = { + topic-1 = "topic1" + topic-2 = "topic2" + } + } +} +# tftest modules=1 resources=3 +``` + +#### Audit logs + +This deploys a Cloud Run service that will be triggered when specific log events are written to Google Cloud audit logs. + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "hello" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + eventarc_triggers = { + audit_log = { + setiampolicy = { + method = "SetIamPolicy" + service = "cloudresourcemanager.googleapis.com" + } + } + } +} +# tftest modules=1 resources=2 +``` + +#### 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 Accounts 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-v2" + project_id = var.project_id + 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 +``` + +Example using automatically created service account: + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "hello" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + eventarc_triggers = { + pubsub = { + topic-1 = "topic1" + topic-2 = "topic2" + } + service_account_create = true + } +} +# tftest modules=1 resources=5 +``` + +### Cloud Run Service Account + +To use a custom service account managed by the module, set `service_account_create` to `true` and leave `service_account` set to `null` (default). + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "hello" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + service_account_create = true +} +# tftest modules=1 resources=2 +``` + +To use an externally managed service account, use its email in `service_account` and leave `service_account_create` to `false` (default). + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + 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" +} +# tftest modules=1 resources=1 +``` + +## 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 | ✓ | | +| [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 | +| [region](variables.tf#L157) | Region used for all resources. | string | | "europe-west1" | +| [revision](variables.tf#L163) | Revision template configurations. | object({…}) | | {} | +| [service_account](variables.tf#L190) | Service account email. Unused if service account is auto-created. | string | | null | +| [service_account_create](variables.tf#L196) | Auto-create service account. | bool | | false | +| [volumes](variables.tf#L202) | 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. | | + diff --git a/modules/cloud-run-v2/main.tf b/modules/cloud-run-v2/main.tf new file mode 100644 index 0000000000..b0492d45bb --- /dev/null +++ b/modules/cloud-run-v2/main.tf @@ -0,0 +1,328 @@ +/** + * 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. + */ + +locals { + connector = ( + var.vpc_connector_create != null + ? google_vpc_access_connector.connector.0.id + : try(var.revision.vpc_access.connector, null) + ) + prefix = var.prefix == null ? "" : "${var.prefix}-" + revision_name = ( + var.revision.name == null ? null : "${var.name}-${var.revision.name}" + ) + service_account_email = ( + var.service_account_create + ? ( + length(google_service_account.service_account) > 0 + ? google_service_account.service_account[0].email + : null + ) + : var.service_account + ) + trigger_sa_create = try( + var.eventarc_triggers.service_account_create, false + ) + trigger_sa_email = try( + google_service_account.trigger_service_account[0].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" { + # 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 + role = "roles/run.invoker" + member = "serviceAccount:${local.trigger_sa_email}" +} + +resource "google_service_account" "service_account" { + count = var.service_account_create ? 1 : 0 + project = var.project_id + account_id = "tf-cr-${var.name}" + display_name = "Terraform Cloud Run ${var.name}." +} + +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 + matching_criteria { + attribute = "type" + value = "google.cloud.audit.log.v1.written" + } + matching_criteria { + attribute = "serviceName" + value = each.value.service + } + matching_criteria { + attribute = "methodName" + value = each.value.method + } + destination { + cloud_run_service { + service = google_cloud_run_v2_service.service.name + region = google_cloud_run_v2_service.service.location + } + } + service_account = local.trigger_sa_email +} + +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 + matching_criteria { + attribute = "type" + value = "google.cloud.pubsub.topic.v1.messagePublished" + } + transport { + pubsub { + topic = each.value + } + } + destination { + cloud_run_service { + service = google_cloud_run_v2_service.service.name + region = google_cloud_run_v2_service.service.location + } + } + service_account = local.trigger_sa_email +} + +resource "google_service_account" "trigger_service_account" { + count = local.trigger_sa_create ? 1 : 0 + project = var.project_id + account_id = "tf-cr-trigger-${var.name}" + display_name = "Terraform trigger for Cloud Run ${var.name}." +} diff --git a/modules/cloud-run-v2/outputs.tf b/modules/cloud-run-v2/outputs.tf new file mode 100644 index 0000000000..d3c61784c9 --- /dev/null +++ b/modules/cloud-run-v2/outputs.tf @@ -0,0 +1,53 @@ +/** + * 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. + */ + +output "id" { + description = "Fully qualified service id." + value = google_cloud_run_v2_service.service.id +} + +output "service" { + description = "Cloud Run service." + value = google_cloud_run_v2_service.service +} + +output "service_account" { + description = "Service account resource." + value = try(google_service_account.service_account[0], null) +} + +output "service_account_email" { + description = "Service account email." + value = local.service_account_email +} + +output "service_account_iam_email" { + description = "Service account email." + value = join("", [ + "serviceAccount:", + local.service_account_email == null ? "" : local.service_account_email + ]) +} + +output "service_name" { + description = "Cloud Run service name." + value = google_cloud_run_v2_service.service.name +} + +output "vpc_connector" { + description = "VPC connector resource if created." + value = try(google_vpc_access_connector.connector.0.id, null) +} diff --git a/modules/cloud-run-v2/variables-vpcconnector.tf b/modules/cloud-run-v2/variables-vpcconnector.tf new file mode 100644 index 0000000000..53dbdc5361 --- /dev/null +++ b/modules/cloud-run-v2/variables-vpcconnector.tf @@ -0,0 +1,38 @@ +/** + * 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. + */ + +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) + instances = optional(object({ + max = optional(number) + min = optional(number) + }), {}) + throughput = optional(object({ + max = optional(number) + min = optional(number) + }), {}) + subnet = optional(object({ + name = optional(string) + project_id = optional(string) + }), {}) + }) + default = null +} diff --git a/modules/cloud-run-v2/variables.tf b/modules/cloud-run-v2/variables.tf new file mode 100644 index 0000000000..cae50a0b8b --- /dev/null +++ b/modules/cloud-run-v2/variables.tf @@ -0,0 +1,217 @@ +/** + * 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. + */ + +variable "containers" { + description = "Containers in name => attributes format." + type = map(object({ + image = string + command = optional(list(string)) + args = optional(list(string)) + env = optional(map(string)) + env_from_key = optional(map(object({ + secret = string + version = string + }))) + liveness_probe = optional(object({ + grpc = optional(object({ + port = optional(number) + service = optional(string) + })) + http_get = optional(object({ + http_headers = optional(map(string)) + path = optional(string) + })) + failure_threshold = optional(number) + initial_delay_seconds = optional(number) + period_seconds = optional(number) + timeout_seconds = optional(number) + })) + ports = optional(map(object({ + container_port = optional(number) + name = optional(string) + }))) + resources = optional(object({ + limits = optional(object({ + cpu = string + memory = string + })) + cpu_idle = optional(bool) + startup_cpu_boost = optional(bool) + })) + startup_probe = optional(object({ + grpc = optional(object({ + port = optional(number) + service = optional(string) + })) + http_get = optional(object({ + http_headers = optional(map(string)) + path = optional(string) + })) + tcp_socket = optional(object({ + port = optional(number) + })) + failure_threshold = optional(number) + initial_delay_seconds = optional(number) + period_seconds = optional(number) + timeout_seconds = optional(number) + })) + volume_mounts = optional(map(string)) + })) + default = {} + nullable = false +} + +variable "eventarc_triggers" { + description = "Event arc triggers for different sources." + type = object({ + audit_log = optional(map(object({ + method = string + service = string + }))) + pubsub = optional(map(string)) + service_account_email = optional(string) + service_account_create = optional(bool, false) + }) + default = {} +} + +variable "iam" { + description = "IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format." + type = map(list(string)) + default = {} +} + +variable "ingress" { + description = "Ingress settings." + type = string + default = null + validation { + condition = ( + var.ingress == null ? true : contains( + ["INGRESS_TRAFFIC_ALL", "INGRESS_TRAFFIC_INTERNAL_ONLY", + "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER"], var.ingress) + ) + error_message = <