VPC Connector alignment to Cloud Run v2 + contexts

This commit is contained in:
Wiktor Niesiobędzki
2025-10-20 21:46:11 +00:00
parent b67b121a28
commit d9029e47a0
38 changed files with 1588 additions and 173 deletions

View File

@@ -15,6 +15,7 @@ Cloud Function management, with support for IAM roles, optional bucket creation
- [Multiple Cloud Functions within project](#multiple-cloud-functions-within-project)
- [Mounting secrets from Secret Manager](#mounting-secrets-from-secret-manager)
- [Using CMEK to encrypt function resources](#using-cmek-to-encrypt-function-resources)
- [VPC Access Connector](#vpc-access-connector)
- [Variables](#variables)
- [Outputs](#outputs)
- [Fixtures](#fixtures)
@@ -393,6 +394,85 @@ module "cf-http" {
}
# tftest inventory=cmek.yaml
```
## 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 "cf_http" {
source = "./fabric/modules/cloud-function-v1"
project_id = var.project_id
region = var.region
name = "test-cf-http"
bucket_name = var.bucket
bundle_config = {
path = "assets/sample-function/"
}
vpc_connector = {
name = google_vpc_access_connector.connector.id
egress_setting = "ALL_TRAFFIC"
}
}
# tftest 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` and `vpc_connector_create` variable which also supports optional attributes like number of instances, machine type, or throughput.
```hcl
module "cf_http" {
source = "./fabric/modules/cloud-function-v1"
project_id = var.project_id
region = var.region
name = "test-cf-http"
bucket_name = var.bucket
bundle_config = {
path = "assets/sample-function/"
}
vpc_connector = {
create = true
}
vpc_connector_create = {
ip_cidr_range = "10.10.10.0/28"
network = var.vpc.self_link
instances = {
max = 10
min = 3
}
}
}
# tftest 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.
```hcl
module "cf_http" {
source = "./fabric/modules/cloud-function-v1"
project_id = var.project_id
region = var.region
name = "test-cf-http"
bucket_name = var.bucket
bundle_config = {
path = "assets/sample-function/"
}
vpc_connector = {
create = true
}
vpc_connector_create = {
machine_type = "e2-standard-4"
subnet = {
name = module.net-vpc-host.subnets["${var.region}/fixture-subnet-28"].name
project_id = module.project-host.project_id
}
throughput = {
max = 300
min = 200
}
}
}
# tftest fixtures=fixtures/shared-vpc.tf inventory=service-vpc-access-connector-create-sharedvpc.yaml e2e
```
<!-- BEGIN TFDOC -->
## Variables
@@ -420,8 +500,8 @@ module "cf-http" {
| [secrets](variables.tf#L194) | Secret Manager secrets. Key is the variable name or mountpoint, volume versions are in version:path format. | <code title="map&#40;object&#40;&#123;&#10; is_volume &#61; bool&#10; project_id &#61; string&#10; secret &#61; string&#10; versions &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [service_account_config](variables-serviceaccount.tf#L17) | Service account configurations. | <code title="object&#40;&#123;&#10; create &#61; optional&#40;bool, true&#41;&#10; display_name &#61; optional&#40;string&#41;&#10; email &#61; optional&#40;string&#41;&#10; name &#61; optional&#40;string&#41;&#10; roles &#61; optional&#40;list&#40;string&#41;, &#91;&#10; &#34;roles&#47;logging.logWriter&#34;,&#10; &#34;roles&#47;monitoring.metricWriter&#34;&#10; &#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [trigger_config](variables.tf#L206) | Function trigger configuration. Leave null for HTTP trigger. | <code title="object&#40;&#123;&#10; event &#61; string&#10; resource &#61; string&#10; retry &#61; optional&#40;bool&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [vpc_connector](variables.tf#L216) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | <code title="object&#40;&#123;&#10; create &#61; optional&#40;bool, false&#41;&#10; name &#61; optional&#40;string&#41;&#10; egress_settings &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_connector_config](variables.tf#L227) | VPC connector network configuration. Must be provided if new VPC connector is being created. | <code title="object&#40;&#123;&#10; ip_cidr_range &#61; string&#10; network &#61; string&#10; instances &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number&#41;&#10; min &#61; optional&#40;number, 2&#41;&#10; &#125;&#41;&#41;&#10; throughput &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number, 300&#41;&#10; min &#61; optional&#40;number, 200&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [vpc_connector](variables-vpcconnector.tf#L17) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | <code title="object&#40;&#123;&#10; create &#61; optional&#40;bool, false&#41;&#10; name &#61; optional&#40;string&#41;&#10; egress_settings &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_connector_create](variables-vpcconnector.tf#L28) | VPC connector network configuration. Must be provided if new VPC connector is being created. | <code title="object&#40;&#123;&#10; ip_cidr_range &#61; optional&#40;string&#41;&#10; machine_type &#61; optional&#40;string&#41;&#10; name &#61; optional&#40;string&#41;&#10; network &#61; optional&#40;string&#41;&#10; instances &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number&#41;&#10; min &#61; optional&#40;number&#41;&#10; &#125;&#41;, &#123;&#125;&#10; &#41;&#10; throughput &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number&#41;&#10; min &#61; optional&#40;number&#41;&#10; &#125;&#41;, &#123;&#125;&#10; &#41;&#10; subnet &#61; optional&#40;object&#40;&#123;&#10; name &#61; optional&#40;string&#41;&#10; project_id &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
## Outputs
@@ -443,4 +523,6 @@ module "cf-http" {
- [cloudbuild-custom-pool.tf](../../tests/fixtures/cloudbuild-custom-pool.tf)
- [functions-default-sa-iam-grants.tf](../../tests/fixtures/functions-default-sa-iam-grants.tf)
- [pubsub.tf](../../tests/fixtures/pubsub.tf)
- [shared-vpc.tf](../../tests/fixtures/shared-vpc.tf)
- [vpc-connector.tf](../../tests/fixtures/vpc-connector.tf)
<!-- END TFDOC -->

View File

@@ -30,36 +30,10 @@ locals {
: null
)
)
location = lookup(local.ctx.locations, var.region, var.region)
prefix = var.prefix == null ? "" : "${var.prefix}-"
project_id = lookup(local.ctx.project_ids, var.project_id, var.project_id)
vpc_connector = (
var.vpc_connector.name == null
? null
: (
var.vpc_connector.create == false
? var.vpc_connector.name
: google_vpc_access_connector.connector[0].id
)
)
}
resource "google_vpc_access_connector" "connector" {
count = var.vpc_connector.create == true ? 1 : 0
project = local.project_id
name = var.vpc_connector.name
region = local.location
ip_cidr_range = lookup(local.ctx.cidr_ranges,
var.vpc_connector_config.ip_cidr_range,
var.vpc_connector_config.ip_cidr_range
)
network = lookup(local.ctx.networks,
var.vpc_connector_config.network, var.vpc_connector_config.network
)
max_instances = try(var.vpc_connector_config.instances.max, null)
min_instances = try(var.vpc_connector_config.instances.min, null)
max_throughput = try(var.vpc_connector_config.throughput.max, null)
min_throughput = try(var.vpc_connector_config.throughput.min, null)
location = lookup(local.ctx.locations, var.region, var.region)
prefix = var.prefix == null ? "" : "${var.prefix}-"
project_id = lookup(local.ctx.project_ids, var.project_id, var.project_id)
vpc_connector = var.vpc_connector.create ? google_vpc_access_connector.connector[0].id : var.vpc_connector.name
}
resource "google_cloudfunctions_function" "function" {
@@ -80,19 +54,17 @@ resource "google_cloudfunctions_function" "function" {
? replace(var.bundle_config.path, "/^gs:\\/\\/[^\\/]+\\//", "")
: google_storage_bucket_object.bundle[0].name
)
labels = var.labels
trigger_http = var.trigger_config == null ? true : null
https_trigger_security_level = var.https_security_level == null ? "SECURE_ALWAYS" : var.https_security_level
ingress_settings = var.ingress_settings
build_worker_pool = var.build_worker_pool
build_environment_variables = var.build_environment_variables
kms_key_name = var.kms_key == null ? null : lookup(local.ctx.kms_keys, var.kms_key, var.kms_key)
docker_registry = try(var.repository_settings.registry, "ARTIFACT_REGISTRY")
docker_repository = try(var.repository_settings.repository, null)
vpc_connector = local.vpc_connector
vpc_connector_egress_settings = try(
var.vpc_connector.egress_settings, null
)
labels = var.labels
trigger_http = var.trigger_config == null ? true : null
https_trigger_security_level = var.https_security_level == null ? "SECURE_ALWAYS" : var.https_security_level
ingress_settings = var.ingress_settings
build_worker_pool = var.build_worker_pool
build_environment_variables = var.build_environment_variables
kms_key_name = var.kms_key == null ? null : lookup(local.ctx.kms_keys, var.kms_key, var.kms_key)
docker_registry = try(var.repository_settings.registry, "ARTIFACT_REGISTRY")
docker_repository = try(var.repository_settings.repository, null)
vpc_connector = local.vpc_connector
vpc_connector_egress_settings = var.vpc_connector.egress_settings
dynamic "event_trigger" {
for_each = var.trigger_config == null ? [] : [""]
@@ -143,8 +115,8 @@ resource "google_cloudfunctions_function_iam_binding" "default" {
project = local.project_id
region = local.location
cloud_function = google_cloudfunctions_function.function.id
role = each.key
members = each.value
role = lookup(local.ctx.custom_roles, each.key, each.key)
members = [for member in each.value : lookup(local.ctx.iam_principals, member, member)]
lifecycle {
replace_triggered_by = [google_cloudfunctions_function.function]
}

View File

@@ -0,0 +1,59 @@
/**
* Copyright 2025 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" {
description = "VPC connector configuration. Set create to 'true' if a new connector needs to be created."
type = object({
create = optional(bool, false)
name = optional(string)
egress_settings = optional(string)
})
nullable = false
default = {}
}
variable "vpc_connector_create" {
description = "VPC connector network configuration. Must be provided if new VPC connector is being created."
type = object({
ip_cidr_range = 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)
min = optional(number)
}), {}
)
subnet = optional(object({
name = optional(string)
project_id = optional(string)
}), {})
})
default = null
validation {
condition = (
var.vpc_connector.create == false ||
try(var.vpc_connector_create.instances, null) != null ||
try(var.vpc_connector_create.throughput, null) != null
)
error_message = "VPC connector must specify either instances or throughput."
}
}

View File

@@ -212,39 +212,3 @@ variable "trigger_config" {
})
default = null
}
variable "vpc_connector" {
description = "VPC connector configuration. Set create to 'true' if a new connector needs to be created."
type = object({
create = optional(bool, false)
name = optional(string)
egress_settings = optional(string)
})
nullable = false
default = {}
}
variable "vpc_connector_config" {
description = "VPC connector network configuration. Must be provided if new VPC connector is being created."
type = object({
ip_cidr_range = string
network = string
instances = optional(object({
max = optional(number)
min = optional(number, 2)
}))
throughput = optional(object({
max = optional(number, 300)
min = optional(number, 200)
}))
})
default = null
validation {
condition = (
var.vpc_connector_config == null ||
try(var.vpc_connector_config.instances, null) != null ||
try(var.vpc_connector_config.throughput, null) != null
)
error_message = "VPC connector must specify either instances or throughput."
}
}

View File

@@ -0,0 +1,74 @@
/**
* Copyright 2025 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_subnet_name_ctx = (
try(var.vpc_connector_create.subnet.name, null) == null ? false :
contains(keys(local.ctx.subnets), var.vpc_connector_create.subnet.name)
)
# if you pass the subnet, you must pass only the name, not the whole id
_connector_subnet_name = (
local._connector_subnet_name_ctx
? provider::google::name_from_id(local.ctx.subnets[var.vpc_connector_create.subnet.name])
: try(var.vpc_connector_create.subnet.name, null)
)
# if project is not provided, but subnet is coming from context, use project from subnet id in context
# and avoid lookups using null project
_connector_subnet_project_input = try(var.vpc_connector_create.subnet.project_id, null)
_connector_subnet_project = (
local._connector_subnet_project_input == null
? (
local._connector_subnet_name_ctx
? provider::google::project_from_id(local.ctx.subnets[var.vpc_connector_create.subnet.name])
: null
)
: lookup(
local.ctx.project_ids, local._connector_subnet_project_input,
local._connector_subnet_project_input
)
)
}
resource "google_vpc_access_connector" "connector" {
count = var.vpc_connector_create != null ? 1 : 0
project = local.project_id
name = (
var.vpc_connector_create.name != null
? var.vpc_connector_create.name
: var.name
)
region = local.location
ip_cidr_range = var.vpc_connector_create.ip_cidr_range == null ? null : lookup(
local.ctx.cidr_ranges, var.vpc_connector_create.ip_cidr_range,
var.vpc_connector_create.ip_cidr_range
)
network = var.vpc_connector_create.network == null ? null : lookup(
local.ctx.networks, var.vpc_connector_create.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
dynamic "subnet" {
for_each = var.vpc_connector_create.subnet.name == null ? [] : [""]
content {
name = local._connector_subnet_name
project_id = local._connector_subnet_project
}
}
}

View File

@@ -14,6 +14,7 @@ Cloud Function management, with support for IAM roles, optional bucket creation
- [Private Cloud Build Pool](#private-cloud-build-pool)
- [Multiple Cloud Functions within project](#multiple-cloud-functions-within-project)
- [Mounting secrets from Secret Manager](#mounting-secrets-from-secret-manager)
- [VPC Access Connector](#vpc-access-connector)
- [Variables](#variables)
- [Outputs](#outputs)
- [Fixtures](#fixtures)
@@ -325,6 +326,85 @@ module "secret-manager" {
}
# tftest fixtures=fixtures/functions-default-sa-iam-grants.tf inventory=secrets.yaml e2e skip-tofu
```
## 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 "cf_http" {
source = "./fabric/modules/cloud-function-v2"
project_id = var.project_id
region = var.region
name = "test-cf-http"
bucket_name = var.bucket
bundle_config = {
path = "assets/sample-function/"
}
vpc_connector = {
name = google_vpc_access_connector.connector.id
egress_setting = "ALL_TRAFFIC"
}
}
# tftest 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` and `vpc_connector_create` variable which also supports optional attributes like number of instances, machine type, or throughput.
```hcl
module "cf_http" {
source = "./fabric/modules/cloud-function-v2"
project_id = var.project_id
region = var.region
name = "test-cf-http"
bucket_name = var.bucket
bundle_config = {
path = "assets/sample-function/"
}
vpc_connector = {
create = true
}
vpc_connector_create = {
ip_cidr_range = "10.10.10.0/28"
network = var.vpc.self_link
instances = {
max = 10
min = 3
}
}
}
# tftest 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.
```hcl
module "cf_http" {
source = "./fabric/modules/cloud-function-v2"
project_id = var.project_id
region = var.region
name = "test-cf-http"
bucket_name = var.bucket
bundle_config = {
path = "assets/sample-function/"
}
vpc_connector = {
create = true
}
vpc_connector_create = {
machine_type = "e2-standard-4"
subnet = {
name = module.net-vpc-host.subnets["${var.region}/fixture-subnet-28"].name
project_id = module.project-host.project_id
}
throughput = {
max = 300
min = 200
}
}
}
# tftest fixtures=fixtures/shared-vpc.tf inventory=service-vpc-access-connector-create-sharedvpc.yaml e2e
```
<!-- BEGIN TFDOC -->
## Variables
@@ -352,8 +432,8 @@ module "secret-manager" {
| [secrets](variables.tf#L192) | Secret Manager secrets. Key is the variable name or mountpoint, volume versions are in version:path format. | <code title="map&#40;object&#40;&#123;&#10; is_volume &#61; bool&#10; project_id &#61; string&#10; secret &#61; string&#10; versions &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [service_account_config](variables-serviceaccount.tf#L17) | Service account configurations. | <code title="object&#40;&#123;&#10; create &#61; optional&#40;bool, true&#41;&#10; display_name &#61; optional&#40;string&#41;&#10; email &#61; optional&#40;string&#41;&#10; name &#61; optional&#40;string&#41;&#10; roles &#61; optional&#40;list&#40;string&#41;, &#91;&#10; &#34;roles&#47;logging.logWriter&#34;,&#10; &#34;roles&#47;monitoring.metricWriter&#34;&#10; &#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [trigger_config](variables.tf#L204) | Function trigger configuration. Leave null for HTTP trigger. | <code title="object&#40;&#123;&#10; event_type &#61; string&#10; pubsub_topic &#61; optional&#40;string&#41;&#10; region &#61; optional&#40;string&#41;&#10; event_filters &#61; optional&#40;list&#40;object&#40;&#123;&#10; attribute &#61; string&#10; value &#61; string&#10; operator &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; service_account_email &#61; optional&#40;string&#41;&#10; service_account_create &#61; optional&#40;bool, false&#41;&#10; retry_policy &#61; optional&#40;string, &#34;RETRY_POLICY_DO_NOT_RETRY&#34;&#41; &#35; default to avoid permadiff&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [vpc_connector](variables.tf#L222) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | <code title="object&#40;&#123;&#10; create &#61; optional&#40;bool, false&#41;&#10; name &#61; optional&#40;string&#41;&#10; egress_settings &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_connector_config](variables.tf#L233) | VPC connector network configuration. Must be provided if new VPC connector is being created. | <code title="object&#40;&#123;&#10; ip_cidr_range &#61; string&#10; network &#61; string&#10; instances &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number&#41;&#10; min &#61; optional&#40;number, 2&#41;&#10; &#125;&#41;&#41;&#10; throughput &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number, 300&#41;&#10; min &#61; optional&#40;number, 200&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [vpc_connector](variables-vpcconnector.tf#L17) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | <code title="object&#40;&#123;&#10; create &#61; optional&#40;bool, false&#41;&#10; name &#61; optional&#40;string&#41;&#10; egress_settings &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_connector_create](variables-vpcconnector.tf#L28) | VPC connector network configuration. Must be provided if new VPC connector is being created. | <code title="object&#40;&#123;&#10; ip_cidr_range &#61; optional&#40;string&#41;&#10; machine_type &#61; optional&#40;string&#41;&#10; name &#61; optional&#40;string&#41;&#10; network &#61; optional&#40;string&#41;&#10; instances &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number&#41;&#10; min &#61; optional&#40;number&#41;&#10; &#125;&#41;, &#123;&#125;&#10; &#41;&#10; throughput &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number&#41;&#10; min &#61; optional&#40;number&#41;&#10; &#125;&#41;, &#123;&#125;&#10; &#41;&#10; subnet &#61; optional&#40;object&#40;&#123;&#10; name &#61; optional&#40;string&#41;&#10; project_id &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
## Outputs
@@ -379,4 +459,6 @@ module "secret-manager" {
- [cloudbuild-custom-pool.tf](../../tests/fixtures/cloudbuild-custom-pool.tf)
- [functions-default-sa-iam-grants.tf](../../tests/fixtures/functions-default-sa-iam-grants.tf)
- [pubsub.tf](../../tests/fixtures/pubsub.tf)
- [shared-vpc.tf](../../tests/fixtures/shared-vpc.tf)
- [vpc-connector.tf](../../tests/fixtures/vpc-connector.tf)
<!-- END TFDOC -->

View File

@@ -41,33 +41,7 @@ locals {
var.trigger_config.service_account_email,
null
)
vpc_connector = (
var.vpc_connector.name == null
? null
: (
var.vpc_connector.create == false
? var.vpc_connector.name
: google_vpc_access_connector.connector[0].id
)
)
}
resource "google_vpc_access_connector" "connector" {
count = var.vpc_connector.create == true ? 1 : 0
project = local.project_id
name = var.vpc_connector.name
region = local.location
ip_cidr_range = lookup(local.ctx.cidr_ranges,
var.vpc_connector_config.ip_cidr_range,
var.vpc_connector_config.ip_cidr_range
)
network = lookup(local.ctx.networks,
var.vpc_connector_config.network, var.vpc_connector_config.network
)
max_instances = try(var.vpc_connector_config.instances.max, null)
min_instances = try(var.vpc_connector_config.instances.min, null)
max_throughput = try(var.vpc_connector_config.throughput.max, null)
min_throughput = try(var.vpc_connector_config.throughput.min, null)
vpc_connector = var.vpc_connector.create ? google_vpc_access_connector.connector[0].id : var.vpc_connector.name
}
resource "google_cloudfunctions2_function" "function" {
@@ -168,33 +142,35 @@ resource "google_cloudfunctions2_function_iam_binding" "binding" {
for_each = {
for k, v in var.iam : k => v if k != "roles/run.invoker"
}
project = var.project_id
location = google_cloudfunctions2_function.function.location
project = local.project_id
location = local.location
cloud_function = google_cloudfunctions2_function.function.name
role = each.key
members = each.value
role = lookup(local.ctx.custom_roles, each.key, each.key)
members = [for member in each.value : lookup(local.ctx.iam_principals, member, member)]
lifecycle {
replace_triggered_by = [google_cloudfunctions2_function.function]
}
}
locals {
run_invoker_members = distinct(compact(concat(
!local.trigger_sa_create
? []
: ["serviceAccount:${local.trigger_sa_email}"],
lookup(var.iam, "roles/run.invoker", []),
)))
}
resource "google_cloud_run_service_iam_binding" "invoker" {
# cloud run resources are needed for invoker role to the underlying service
count = (
lookup(var.iam, "roles/run.invoker", null) != null
) ? 1 : 0
project = var.project_id
location = google_cloudfunctions2_function.function.location
project = local.project_id
location = local.location
service = google_cloudfunctions2_function.function.name
role = "roles/run.invoker"
members = distinct(compact(concat(
lookup(var.iam, "roles/run.invoker", []),
(
!local.trigger_sa_create
? []
: ["serviceAccount:${local.trigger_sa_email}"]
)
)))
members = [for member in local.run_invoker_members : lookup(local.ctx.iam_principals, member, member)]
lifecycle {
replace_triggered_by = [google_cloudfunctions2_function.function]
}
@@ -207,8 +183,8 @@ resource "google_cloud_run_service_iam_member" "invoker" {
lookup(var.iam, "roles/run.invoker", null) == null &&
local.trigger_sa_create
) ? 1 : 0
project = var.project_id
location = google_cloudfunctions2_function.function.location
project = local.project_id
location = local.location
service = google_cloudfunctions2_function.function.name
role = "roles/run.invoker"
member = "serviceAccount:${local.trigger_sa_email}"

View File

@@ -0,0 +1,59 @@
/**
* Copyright 2025 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" {
description = "VPC connector configuration. Set create to 'true' if a new connector needs to be created."
type = object({
create = optional(bool, false)
name = optional(string)
egress_settings = optional(string)
})
nullable = false
default = {}
}
variable "vpc_connector_create" {
description = "VPC connector network configuration. Must be provided if new VPC connector is being created."
type = object({
ip_cidr_range = 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)
min = optional(number)
}), {}
)
subnet = optional(object({
name = optional(string)
project_id = optional(string)
}), {})
})
default = null
validation {
condition = (
var.vpc_connector.create == false ||
try(var.vpc_connector_create.instances, null) != null ||
try(var.vpc_connector_create.throughput, null) != null
)
error_message = "VPC connector must specify either instances or throughput."
}
}

View File

@@ -218,39 +218,3 @@ variable "trigger_config" {
})
default = null
}
variable "vpc_connector" {
description = "VPC connector configuration. Set create to 'true' if a new connector needs to be created."
type = object({
create = optional(bool, false)
name = optional(string)
egress_settings = optional(string)
})
nullable = false
default = {}
}
variable "vpc_connector_config" {
description = "VPC connector network configuration. Must be provided if new VPC connector is being created."
type = object({
ip_cidr_range = string
network = string
instances = optional(object({
max = optional(number)
min = optional(number, 2)
}))
throughput = optional(object({
max = optional(number, 300)
min = optional(number, 200)
}))
})
default = null
validation {
condition = (
var.vpc_connector_config == null ||
try(var.vpc_connector_config.instances, null) != null ||
try(var.vpc_connector_config.throughput, null) != null
)
error_message = "VPC connector must specify either instances or throughput."
}
}

View File

@@ -0,0 +1,74 @@
/**
* Copyright 2025 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_subnet_name_ctx = (
try(var.vpc_connector_create.subnet.name, null) == null ? false :
contains(keys(local.ctx.subnets), var.vpc_connector_create.subnet.name)
)
# if you pass the subnet, you must pass only the name, not the whole id
_connector_subnet_name = (
local._connector_subnet_name_ctx
? provider::google::name_from_id(local.ctx.subnets[var.vpc_connector_create.subnet.name])
: try(var.vpc_connector_create.subnet.name, null)
)
# if project is not provided, but subnet is coming from context, use project from subnet id in context
# and avoid lookups using null project
_connector_subnet_project_input = try(var.vpc_connector_create.subnet.project_id, null)
_connector_subnet_project = (
local._connector_subnet_project_input == null
? (
local._connector_subnet_name_ctx
? provider::google::project_from_id(local.ctx.subnets[var.vpc_connector_create.subnet.name])
: null
)
: lookup(
local.ctx.project_ids, local._connector_subnet_project_input,
local._connector_subnet_project_input
)
)
}
resource "google_vpc_access_connector" "connector" {
count = var.vpc_connector_create != null ? 1 : 0
project = local.project_id
name = (
var.vpc_connector_create.name != null
? var.vpc_connector_create.name
: var.name
)
region = local.location
ip_cidr_range = var.vpc_connector_create.ip_cidr_range == null ? null : lookup(
local.ctx.cidr_ranges, var.vpc_connector_create.ip_cidr_range,
var.vpc_connector_create.ip_cidr_range
)
network = var.vpc_connector_create.network == null ? null : lookup(
local.ctx.networks, var.vpc_connector_create.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
dynamic "subnet" {
for_each = var.vpc_connector_create.subnet.name == null ? [] : [""]
content {
name = local._connector_subnet_name
project_id = local._connector_subnet_project
}
}
}

View File

@@ -189,7 +189,7 @@ You can use an existing [VPC Access Connector](https://cloud.google.com/vpc/docs
module "cloud_run" {
source = "./fabric/modules/cloud-run-v2"
project_id = var.project_id
region = var.region
region = var.regions.secondary
name = "hello"
containers = {
hello = {

View File

@@ -17,7 +17,7 @@
resource "google_vpc_access_connector" "connector" {
project = var.project_id
name = "vpc-connector"
region = var.region
region = var.regions.secondary
min_instances = 2
max_instances = 3
ip_cidr_range = "192.168.0.0/28"

View File

@@ -0,0 +1,58 @@
name = "test-cf-kms"
bucket_name = "bucket"
bundle_config = {
path = "gs://assets/sample-function.zip"
}
context = {
cidr_ranges = {
test = "10.10.20.0/28"
}
custom_roles = {
myrole_one = "organizations/366118655033/roles/myRoleOne"
}
iam_principals = {
mygroup = "group:test-group@example.com"
}
kms_keys = {
test = "projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute"
}
locations = {
ew8 = "europe-west8"
}
networks = {
test = "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
}
project_ids = {
test = "foo-test-0"
}
subnets = {
test = "projects/foo-dev-net-spoke-0/regions/europe-west1/subnetworks/gce"
}
}
kms_key = "$kms_keys:test"
iam = {
"$custom_roles:myrole_one" = [
"$iam_principals:mygroup"
]
}
project_id = "$project_ids:test"
region = "$locations:ew8"
service_account_config = {
roles = [
"$custom_roles:myrole_one"
]
}
vpc_connector = {
create = true
name = "connector_name"
}
vpc_connector_create = {
instances = {
max = 10
min = 3
}
subnet = {
name = "$subnets:test"
project_id = "$project_ids:test"
}
}

View File

@@ -0,0 +1,61 @@
# Copyright 2025 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:
google_cloudfunctions_function.function:
kms_key_name: projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute
project: foo-test-0
region: europe-west8
service_account_email: test-cf-kms@foo-test-0.iam.gserviceaccount.com
google_cloudfunctions_function_iam_binding.default["$custom_roles:myrole_one"]:
condition: []
members:
- group:test-group@example.com
project: foo-test-0
region: europe-west8
role: organizations/366118655033/roles/myRoleOne
google_project_iam_member.default["organizations/366118655033/roles/myRoleOne"]:
condition: []
member: serviceAccount:test-cf-kms@foo-test-0.iam.gserviceaccount.com
project: foo-test-0
role: organizations/366118655033/roles/myRoleOne
google_service_account.service_account[0]:
account_id: test-cf-kms
create_ignore_already_exists: null
description: null
disabled: false
display_name: test-cf-kms
email: test-cf-kms@foo-test-0.iam.gserviceaccount.com
member: serviceAccount:test-cf-kms@foo-test-0.iam.gserviceaccount.com
project: foo-test-0
timeouts: null
google_vpc_access_connector.connector[0]:
ip_cidr_range: null
machine_type: e2-micro
max_instances: 10
min_instances: 3
name: test-cf-kms
project: foo-test-0
region: europe-west8
subnet:
- name: gce
project_id: foo-test-0
timeouts: null
counts:
google_cloudfunctions_function: 1
google_cloudfunctions_function_iam_binding: 1
google_project_iam_member: 1
google_service_account: 1
google_vpc_access_connector: 1

View File

@@ -0,0 +1,57 @@
name = "test-cf-kms"
bucket_name = "bucket"
bundle_config = {
path = "gs://assets/sample-function.zip"
}
context = {
cidr_ranges = {
test = "10.10.20.0/28"
}
custom_roles = {
myrole_one = "organizations/366118655033/roles/myRoleOne"
}
iam_principals = {
mygroup = "group:test-group@example.com"
}
kms_keys = {
test = "projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute"
}
locations = {
ew8 = "europe-west8"
}
networks = {
test = "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
}
project_ids = {
test = "foo-test-0"
}
subnets = {
test = "projects/foo-dev-net-spoke-0/regions/europe-west1/subnetworks/gce"
}
}
kms_key = "$kms_keys:test"
iam = {
"$custom_roles:myrole_one" = [
"$iam_principals:mygroup"
]
}
project_id = "$project_ids:test"
region = "$locations:ew8"
service_account_config = {
roles = [
"$custom_roles:myrole_one"
]
}
vpc_connector = {
create = true
name = "connector_name"
}
vpc_connector_create = {
instances = {
max = 10
min = 3
}
subnet = {
name = "$subnets:test"
}
}

View File

@@ -0,0 +1,60 @@
# Copyright 2025 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:
google_cloudfunctions_function.function:
kms_key_name: projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute
project: foo-test-0
region: europe-west8
service_account_email: test-cf-kms@foo-test-0.iam.gserviceaccount.com
google_cloudfunctions_function_iam_binding.default["$custom_roles:myrole_one"]:
condition: []
members:
- group:test-group@example.com
project: foo-test-0
region: europe-west8
role: organizations/366118655033/roles/myRoleOne
google_project_iam_member.default["organizations/366118655033/roles/myRoleOne"]:
condition: []
member: serviceAccount:test-cf-kms@foo-test-0.iam.gserviceaccount.com
project: foo-test-0
role: organizations/366118655033/roles/myRoleOne
google_service_account.service_account[0]:
account_id: test-cf-kms
create_ignore_already_exists: null
description: null
disabled: false
display_name: test-cf-kms
email: test-cf-kms@foo-test-0.iam.gserviceaccount.com
member: serviceAccount:test-cf-kms@foo-test-0.iam.gserviceaccount.com
project: foo-test-0
timeouts: null
google_vpc_access_connector.connector[0]:
ip_cidr_range: null
machine_type: e2-micro
max_instances: 10
min_instances: 3
name: test-cf-kms
project: foo-test-0
region: europe-west8
subnet:
- name: gce
project_id: foo-dev-net-spoke-0
counts:
google_cloudfunctions_function: 1
google_cloudfunctions_function_iam_binding: 1
google_project_iam_member: 1
google_service_account: 1
google_vpc_access_connector: 1

View File

@@ -46,7 +46,7 @@ vpc_connector = {
create = true
name = "connector_name"
}
vpc_connector_config = {
vpc_connector_create = {
ip_cidr_range = "$cidr_ranges:test"
network = "$networks:test"
instances = {

View File

@@ -45,7 +45,7 @@ values:
machine_type: e2-micro
max_instances: 10
min_instances: 3
name: connector_name
name: test-cf-kms
network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
project: foo-test-0
region: europe-west8

View File

@@ -0,0 +1,68 @@
# Copyright 2025 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.cf_http.google_cloudfunctions_function.function:
available_memory_mb: 256
build_environment_variables: null
build_worker_pool: null
description: Terraform managed.
docker_registry: ARTIFACT_REGISTRY
docker_repository: null
effective_labels:
goog-terraform-provisioned: 'true'
entry_point: main
environment_variables: null
https_trigger_security_level: SECURE_ALWAYS
ingress_settings: ALLOW_ALL
kms_key_name: null
labels: null
max_instances: 1
min_instances: null
name: test-cf-http
on_deploy_update_policy: []
project: project-id
region: europe-west8
runtime: python310
secret_environment_variables: []
secret_volumes: []
service_account_email: test-cf-http@project-id.iam.gserviceaccount.com
source_archive_bucket: bucket
source_archive_object: bundle-95c1b0e5b92dae8333539b1e0ad5173b.zip
source_repository: []
terraform_labels:
goog-terraform-provisioned: 'true'
timeout: 180
timeouts: null
trigger_http: true
module.cf_http.google_vpc_access_connector.connector[0]:
ip_cidr_range: null
machine_type: e2-standard-4
max_throughput: 300
min_throughput: 200
name: test-cf-http
project: project-id
region: europe-west8
subnet:
- name: fixture-subnet-28
project_id: test-host
timeouts: null
counts:
google_cloudfunctions_function: 1
google_service_account: 1
google_storage_bucket_object: 1
outputs: {}

View File

@@ -0,0 +1,56 @@
# Copyright 2025 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.cf_http.google_cloudfunctions_function.function:
available_memory_mb: 256
build_environment_variables: null
build_worker_pool: null
description: Terraform managed.
docker_registry: ARTIFACT_REGISTRY
docker_repository: null
effective_labels:
goog-terraform-provisioned: 'true'
entry_point: main
environment_variables: null
https_trigger_security_level: SECURE_ALWAYS
ingress_settings: ALLOW_ALL
kms_key_name: null
labels: null
max_instances: 1
min_instances: null
name: test-cf-http
on_deploy_update_policy: []
project: project-id
region: europe-west8
runtime: python310
secret_environment_variables: []
secret_volumes: []
service_account_email: test-cf-http@project-id.iam.gserviceaccount.com
source_archive_bucket: bucket
source_repository: []
terraform_labels:
goog-terraform-provisioned: 'true'
timeout: 180
timeouts: null
trigger_http: true
counts:
google_cloudfunctions_function: 1
google_project_iam_member: 2
google_service_account: 1
google_storage_bucket_object: 1
outputs: {}

View File

@@ -0,0 +1,56 @@
# Copyright 2025 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.cf_http.google_cloudfunctions_function.function:
available_memory_mb: 256
build_environment_variables: null
build_worker_pool: null
description: Terraform managed.
docker_registry: ARTIFACT_REGISTRY
docker_repository: null
effective_labels:
goog-terraform-provisioned: 'true'
entry_point: main
environment_variables: null
https_trigger_security_level: SECURE_ALWAYS
ingress_settings: ALLOW_ALL
kms_key_name: null
labels: null
max_instances: 1
min_instances: null
name: test-cf-http
on_deploy_update_policy: []
project: project-id
region: europe-west8
runtime: python310
secret_environment_variables: []
secret_volumes: []
service_account_email: test-cf-http@project-id.iam.gserviceaccount.com
source_archive_bucket: bucket
source_repository: []
terraform_labels:
goog-terraform-provisioned: 'true'
timeout: 180
timeouts: null
trigger_http: true
counts:
google_cloudfunctions_function: 1
google_project_iam_member: 2
google_service_account: 1
google_storage_bucket_object: 1
outputs: {}

View File

@@ -15,4 +15,6 @@
module: modules/cloud-function-v1
tests:
context:
context-subnet:
context-subnet-project:
kms:

View File

@@ -0,0 +1,58 @@
name = "test-cf-kms"
bucket_name = "bucket"
bundle_config = {
path = "gs://assets/sample-function.zip"
}
context = {
cidr_ranges = {
test = "10.10.20.0/28"
}
custom_roles = {
myrole_one = "organizations/366118655033/roles/myRoleOne"
}
iam_principals = {
mygroup = "group:test-group@example.com"
}
kms_keys = {
test = "projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute"
}
locations = {
ew8 = "europe-west8"
}
networks = {
test = "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
}
project_ids = {
test = "foo-test-0"
}
subnets = {
test = "projects/foo-dev-net-spoke-0/regions/europe-west1/subnetworks/gce"
}
}
kms_key = "$kms_keys:test"
iam = {
"$custom_roles:myrole_one" = [
"$iam_principals:mygroup"
]
}
project_id = "$project_ids:test"
region = "$locations:ew8"
service_account_config = {
roles = [
"$custom_roles:myrole_one"
]
}
vpc_connector = {
create = true
name = "connector_name"
}
vpc_connector_create = {
instances = {
max = 10
min = 3
}
subnet = {
name = "$subnets:test"
project_id = "$project_ids:test"
}
}

View File

@@ -0,0 +1,64 @@
# Copyright 2025 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:
google_cloudfunctions2_function.function:
kms_key_name: projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute
location: europe-west8
name: test-cf-kms
project: foo-test-0
service_config:
- service_account_email: test-cf-kms@foo-test-0.iam.gserviceaccount.com
google_cloudfunctions2_function_iam_binding.binding["$custom_roles:myrole_one"]:
cloud_function: test-cf-kms
condition: []
members:
- group:test-group@example.com
project: foo-test-0
location: europe-west8
role: organizations/366118655033/roles/myRoleOne
google_project_iam_member.default["organizations/366118655033/roles/myRoleOne"]:
condition: []
member: serviceAccount:test-cf-kms@foo-test-0.iam.gserviceaccount.com
project: foo-test-0
role: organizations/366118655033/roles/myRoleOne
google_service_account.service_account[0]:
account_id: test-cf-kms
create_ignore_already_exists: null
description: null
disabled: false
display_name: test-cf-kms
email: test-cf-kms@foo-test-0.iam.gserviceaccount.com
member: serviceAccount:test-cf-kms@foo-test-0.iam.gserviceaccount.com
project: foo-test-0
timeouts: null
google_vpc_access_connector.connector[0]:
ip_cidr_range: null
machine_type: e2-micro
max_instances: 10
min_instances: 3
name: test-cf-kms
project: foo-test-0
region: europe-west8
subnet:
- name: gce
project_id: foo-test-0
timeouts: null
counts:
google_cloudfunctions2_function: 1
google_cloudfunctions2_function_iam_binding: 1
google_project_iam_member: 1
google_service_account: 1
google_vpc_access_connector: 1

View File

@@ -0,0 +1,57 @@
name = "test-cf-kms"
bucket_name = "bucket"
bundle_config = {
path = "gs://assets/sample-function.zip"
}
context = {
cidr_ranges = {
test = "10.10.20.0/28"
}
custom_roles = {
myrole_one = "organizations/366118655033/roles/myRoleOne"
}
iam_principals = {
mygroup = "group:test-group@example.com"
}
kms_keys = {
test = "projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute"
}
locations = {
ew8 = "europe-west8"
}
networks = {
test = "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
}
project_ids = {
test = "foo-test-0"
}
subnets = {
test = "projects/foo-dev-net-spoke-0/regions/europe-west1/subnetworks/gce"
}
}
kms_key = "$kms_keys:test"
iam = {
"$custom_roles:myrole_one" = [
"$iam_principals:mygroup"
]
}
project_id = "$project_ids:test"
region = "$locations:ew8"
service_account_config = {
roles = [
"$custom_roles:myrole_one"
]
}
vpc_connector = {
create = true
name = "connector_name"
}
vpc_connector_create = {
instances = {
max = 10
min = 3
}
subnet = {
name = "$subnets:test"
}
}

View File

@@ -0,0 +1,62 @@
# Copyright 2025 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:
google_cloudfunctions2_function.function:
kms_key_name: projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute
location: europe-west8
project: foo-test-0
service_config:
- service_account_email: test-cf-kms@foo-test-0.iam.gserviceaccount.com
google_cloudfunctions2_function_iam_binding.binding["$custom_roles:myrole_one"]:
cloud_function: test-cf-kms
condition: []
members:
- group:test-group@example.com
project: foo-test-0
location: europe-west8
role: organizations/366118655033/roles/myRoleOne
google_project_iam_member.default["organizations/366118655033/roles/myRoleOne"]:
condition: []
member: serviceAccount:test-cf-kms@foo-test-0.iam.gserviceaccount.com
project: foo-test-0
role: organizations/366118655033/roles/myRoleOne
google_service_account.service_account[0]:
account_id: test-cf-kms
create_ignore_already_exists: null
description: null
disabled: false
display_name: test-cf-kms
email: test-cf-kms@foo-test-0.iam.gserviceaccount.com
member: serviceAccount:test-cf-kms@foo-test-0.iam.gserviceaccount.com
project: foo-test-0
timeouts: null
google_vpc_access_connector.connector[0]:
ip_cidr_range: null
machine_type: e2-micro
max_instances: 10
min_instances: 3
name: test-cf-kms
project: foo-test-0
region: europe-west8
subnet:
- name: gce
project_id: foo-dev-net-spoke-0
counts:
google_cloudfunctions2_function: 1
google_cloudfunctions2_function_iam_binding: 1
google_project_iam_member: 1
google_service_account: 1
google_vpc_access_connector: 1

View File

@@ -0,0 +1,56 @@
name = "test-cf-kms"
bucket_name = "bucket"
bundle_config = {
path = "gs://assets/sample-function.zip"
}
context = {
cidr_ranges = {
test = "10.10.20.0/28"
}
custom_roles = {
myrole_one = "organizations/366118655033/roles/myRoleOne"
}
iam_principals = {
mygroup = "group:test-group@example.com"
}
kms_keys = {
test = "projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute"
}
locations = {
ew8 = "europe-west8"
}
networks = {
test = "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
}
project_ids = {
test = "foo-test-0"
}
subnets = {
test = "projects/foo-dev-net-spoke-0/regions/europe-west1/subnetworks/gce"
}
}
kms_key = "$kms_keys:test"
iam = {
"$custom_roles:myrole_one" = [
"$iam_principals:mygroup"
]
}
project_id = "$project_ids:test"
region = "$locations:ew8"
service_account_config = {
roles = [
"$custom_roles:myrole_one"
]
}
vpc_connector = {
create = true
name = "connector_name"
}
vpc_connector_create = {
ip_cidr_range = "$cidr_ranges:test"
network = "$networks:test"
instances = {
max = 10
min = 3
}
}

View File

@@ -0,0 +1,61 @@
# Copyright 2025 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:
google_cloudfunctions2_function.function:
kms_key_name: projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute
location: europe-west8
project: foo-test-0
service_config:
- service_account_email: test-cf-kms@foo-test-0.iam.gserviceaccount.com
google_cloudfunctions2_function_iam_binding.binding["$custom_roles:myrole_one"]:
condition: []
members:
- group:test-group@example.com
project: foo-test-0
location: europe-west8
role: organizations/366118655033/roles/myRoleOne
google_project_iam_member.default["organizations/366118655033/roles/myRoleOne"]:
condition: []
member: serviceAccount:test-cf-kms@foo-test-0.iam.gserviceaccount.com
project: foo-test-0
role: organizations/366118655033/roles/myRoleOne
google_service_account.service_account[0]:
account_id: test-cf-kms
create_ignore_already_exists: null
description: null
disabled: false
display_name: test-cf-kms
email: test-cf-kms@foo-test-0.iam.gserviceaccount.com
member: serviceAccount:test-cf-kms@foo-test-0.iam.gserviceaccount.com
project: foo-test-0
timeouts: null
google_vpc_access_connector.connector[0]:
ip_cidr_range: 10.10.20.0/28
machine_type: e2-micro
max_instances: 10
min_instances: 3
name: test-cf-kms
network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
project: foo-test-0
region: europe-west8
subnet: []
timeouts: null
counts:
google_cloudfunctions2_function: 1
google_cloudfunctions2_function_iam_binding: 1
google_project_iam_member: 1
google_service_account: 1
google_vpc_access_connector: 1

View File

@@ -0,0 +1,73 @@
# Copyright 2025 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.cf_http.google_cloudfunctions2_function.function:
build_config:
- entry_point: main
on_deploy_update_policy: []
runtime: python310
source:
- repo_source: []
storage_source:
- bucket: bucket
object: bundle-95c1b0e5b92dae8333539b1e0ad5173b.zip
worker_pool: null
description: Terraform managed.
effective_labels:
goog-terraform-provisioned: 'true'
event_trigger: []
kms_key_name: null
labels: null
location: europe-west8
name: test-cf-http
project: project-id
service_config:
- all_traffic_on_latest_revision: true
available_cpu: '0.166'
available_memory: 256M
binary_authorization_policy: null
environment_variables:
LOG_EXECUTION_ID: 'true'
ingress_settings: ALLOW_ALL
max_instance_count: 1
min_instance_count: 0
secret_environment_variables: []
secret_volumes: []
service_account_email: test-cf-http@project-id.iam.gserviceaccount.com
timeout_seconds: 180
vpc_connector_egress_settings: null
terraform_labels:
goog-terraform-provisioned: 'true'
timeouts: null
module.cf_http.google_vpc_access_connector.connector[0]:
ip_cidr_range: null
machine_type: e2-standard-4
max_throughput: 300
min_throughput: 200
name: test-cf-http
project: project-id
region: europe-west8
subnet:
- name: fixture-subnet-28
project_id: test-host
timeouts: null
counts:
google_cloudfunctions2_function: 1
google_service_account: 1
google_storage_bucket_object: 1
outputs: {}

View File

@@ -0,0 +1,62 @@
# Copyright 2025 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.cf_http.google_cloudfunctions2_function.function:
build_config:
- entry_point: main
on_deploy_update_policy: []
runtime: python310
source:
- repo_source: []
storage_source:
- bucket: bucket
object: bundle-95c1b0e5b92dae8333539b1e0ad5173b.zip
worker_pool: null
description: Terraform managed.
effective_labels:
goog-terraform-provisioned: 'true'
event_trigger: []
kms_key_name: null
labels: null
location: europe-west8
name: test-cf-http
project: project-id
service_config:
- all_traffic_on_latest_revision: true
available_cpu: '0.166'
available_memory: 256M
binary_authorization_policy: null
environment_variables:
LOG_EXECUTION_ID: 'true'
ingress_settings: ALLOW_ALL
max_instance_count: 1
min_instance_count: 0
secret_environment_variables: []
secret_volumes: []
service_account_email: test-cf-http@project-id.iam.gserviceaccount.com
timeout_seconds: 180
vpc_connector_egress_settings: null
terraform_labels:
goog-terraform-provisioned: 'true'
timeouts: null
counts:
google_cloudfunctions2_function: 1
google_project_iam_member: 2
google_service_account: 1
google_storage_bucket_object: 1
outputs: {}

View File

@@ -0,0 +1,62 @@
# Copyright 2025 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.cf_http.google_cloudfunctions2_function.function:
build_config:
- entry_point: main
on_deploy_update_policy: []
runtime: python310
source:
- repo_source: []
storage_source:
- bucket: bucket
object: bundle-95c1b0e5b92dae8333539b1e0ad5173b.zip
worker_pool: null
description: Terraform managed.
effective_labels:
goog-terraform-provisioned: 'true'
event_trigger: []
kms_key_name: null
labels: null
location: europe-west8
name: test-cf-http
project: project-id
service_config:
- all_traffic_on_latest_revision: true
available_cpu: '0.166'
available_memory: 256M
binary_authorization_policy: null
environment_variables:
LOG_EXECUTION_ID: 'true'
ingress_settings: ALLOW_ALL
max_instance_count: 1
min_instance_count: 0
secret_environment_variables: []
secret_volumes: []
service_account_email: test-cf-http@project-id.iam.gserviceaccount.com
timeout_seconds: 180
vpc_connector_egress_settings: null
terraform_labels:
goog-terraform-provisioned: 'true'
timeouts: null
counts:
google_cloudfunctions2_function: 1
google_project_iam_member: 2
google_service_account: 1
google_storage_bucket_object: 1
outputs: {}

View File

@@ -0,0 +1,9 @@
project_id = "project"
region = "region"
name = "test-cf-kms"
bucket_name = "bucket"
bundle_config = {
path = "gs://assets/sample-function.zip"
}
kms_key = "kms_key_id"
docker_repository_id = "artifact_registry_id"

View File

@@ -0,0 +1,44 @@
# Copyright 2025 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:
google_cloudfunctions2_function.function:
build_config:
- docker_repository: artifact_registry_id
source:
- repo_source: []
storage_source:
- bucket: bucket
object: sample-function.zip
kms_key_name: kms_key_id
name: test-cf-kms
project: project
location: region
service_config:
- service_account_email: test-cf-kms@project.iam.gserviceaccount.com
counts:
google_cloudfunctions2_function: 1
outputs:
bucket: null
bucket_name: bucket
function: __missing__
function_name: test-cf-kms
id: __missing__
invoke_command: __missing__
service_account: __missing__
service_account_email: test-cf-kms@project.iam.gserviceaccount.com
service_account_iam_email: serviceAccount:test-cf-kms@project.iam.gserviceaccount.com
vpc_connector: null

View File

@@ -0,0 +1,21 @@
# Copyright 2025 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: modules/cloud-function-v2
tests:
context:
context-subnet:
context-subnet-project:
kms:
vpcconnector:

View File

@@ -0,0 +1,11 @@
project_id = "test-project"
region = "region"
name = "test-cf-vpc"
bucket_name = "bucket"
bundle_config = {
path = "gs://assets/sample-function.zip"
}
vpc_connector = {
name = "projects/test-project/locations/region/connectors/vpc-connector"
egress_settings = "ALL_TRAFFIC"
}

View File

@@ -0,0 +1,44 @@
# Copyright 2025 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:
google_cloudfunctions2_function.function:
build_config:
- source:
- repo_source: []
storage_source:
- bucket: bucket
object: sample-function.zip
name: test-cf-vpc
project: test-project
location: region
service_config:
- service_account_email: test-cf-vpc@test-project.iam.gserviceaccount.com
vpc_connector: projects/test-project/locations/region/connectors/vpc-connector
vpc_connector_egress_settings: ALL_TRAFFIC
counts:
google_cloudfunctions2_function: 1
outputs:
bucket: null
bucket_name: bucket
function: __missing__
function_name: test-cf-vpc
id: __missing__
invoke_command: __missing__
service_account: __missing__
service_account_email: test-cf-vpc@test-project.iam.gserviceaccount.com
service_account_iam_email: serviceAccount:test-cf-vpc@test-project.iam.gserviceaccount.com
vpc_connector: null

View File

@@ -14,7 +14,7 @@
values:
module.cloud_run.google_cloud_run_v2_service.service[0]:
location: europe-west8
location: europe-west9
name: hello
project: project-id
template:
@@ -42,4 +42,3 @@ counts:
resources: 2
outputs: {}

View File

@@ -29,6 +29,10 @@ duplicates = [ #
"fast/stages/2-networking-b-nva/data/cidrs.yaml",
"fast/stages/2-networking-c-separate-envs/data/cidrs.yaml",
],
[
"modules/cloud-function-v1/bundle.tf",
"modules/cloud-function-v2/bundle.tf",
],
[
"modules/cloud-function-v1/serviceaccount.tf",
"modules/cloud-function-v2/serviceaccount.tf",
@@ -38,9 +42,13 @@ duplicates = [ #
"modules/cloud-function-v2/variables-serviceaccount.tf",
],
[
"modules/cloud-function-v1/bundle.tf",
"modules/cloud-function-v2/bundle.tf",
]
"modules/cloud-function-v1/variables-vpcconnector.tf",
"modules/cloud-function-v2/variables-vpcconnector.tf",
],
[
"modules/cloud-function-v1/vpcconnector.tf",
"modules/cloud-function-v2/vpcconnector.tf",
],
]