Add net-lb-proxy-int-cross-region module and tests (#4017)
* Add net-lb-proxy-int-cross-region module and tests * Add context support example and tests * Update copyright to 2026 and support instance group backends * docs: correct Instance Groups support note in README
This commit is contained in:
269
modules/net-lb-proxy-int-cross-region/README.md
Normal file
269
modules/net-lb-proxy-int-cross-region/README.md
Normal file
@@ -0,0 +1,269 @@
|
||||
# Cross-region Internal Proxy Network Load Balancer Module
|
||||
|
||||
This module allows managing Cross-region Internal Proxy Network Load Balancers (L4 proxy ILBs). It's designed to expose the full configuration of the underlying resources, and to facilitate common usage patterns by providing sensible defaults, and optionally managing prerequisite resources like health checks, network endpoint groups (NEGs), etc.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Cross-region internal proxy Network Load Balancers support Instance Groups (Managed or Unmanaged), zonal NEGs (`GCE_VM_IP_PORT`), and Hybrid NEGs as backends.
|
||||
>
|
||||
> Proxy-only subnets for cross-region load balancers must be created with the purpose set to `GLOBAL_MANAGED_PROXY` (in the VPC module, set `global = true` in the `subnets_proxy_only` configuration).
|
||||
|
||||
## Examples
|
||||
|
||||
<!-- BEGIN TOC -->
|
||||
- [Examples](#examples)
|
||||
- [Minimal Example](#minimal-example)
|
||||
- [Health Checks](#health-checks)
|
||||
- [Network Endpoint Groups (NEGs)](#network-endpoint-groups-negs)
|
||||
- [Zonal NEG creation](#zonal-neg-creation)
|
||||
- [Hybrid NEG creation](#hybrid-neg-creation)
|
||||
- [Variables](#variables)
|
||||
- [Outputs](#outputs)
|
||||
<!-- END TOC -->
|
||||
|
||||
### Minimal Example
|
||||
|
||||
An internal TCP proxy cross-region load balancer with a backend service pointing to auto-created zonal NEGs. This example demonstrates the use of the [context pattern](../../adrs/20251013-context-locals.md) for symbolic variable interpolation:
|
||||
|
||||
```hcl
|
||||
module "tcp-proxy-cross-region" {
|
||||
source = "./fabric/modules/net-lb-proxy-int-cross-region"
|
||||
name = "ilb-proxy-test"
|
||||
project_id = "$project_ids:my-project"
|
||||
port = 80
|
||||
|
||||
context = {
|
||||
project_ids = {
|
||||
my-project = var.project_id
|
||||
}
|
||||
networks = {
|
||||
my-vpc = var.vpc.self_link
|
||||
}
|
||||
subnets = {
|
||||
my-subnet-1 = var.subnet1.self_link
|
||||
my-subnet-2 = var.subnet2.self_link
|
||||
}
|
||||
}
|
||||
|
||||
vpc_config = {
|
||||
network = "$networks:my-vpc"
|
||||
subnetworks = {
|
||||
europe-west1 = "$subnets:my-subnet-1"
|
||||
europe-west4 = "$subnets:my-subnet-2"
|
||||
}
|
||||
}
|
||||
|
||||
neg_configs = {
|
||||
neg-a = {
|
||||
gce = {
|
||||
zone = "europe-west1-b"
|
||||
network = "$networks:my-vpc"
|
||||
subnetwork = "$subnets:my-subnet-1"
|
||||
endpoints = {
|
||||
vm-a = {
|
||||
instance = "my-vm-a"
|
||||
ip_address = "10.0.0.2"
|
||||
port = 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
neg-b = {
|
||||
gce = {
|
||||
zone = "europe-west4-a"
|
||||
network = "$networks:my-vpc"
|
||||
subnetwork = "$subnets:my-subnet-2"
|
||||
endpoints = {
|
||||
vm-b = {
|
||||
instance = "my-vm-b"
|
||||
ip_address = "10.0.1.2"
|
||||
port = 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backend_service_config = {
|
||||
backends = [
|
||||
{
|
||||
group = "neg-a"
|
||||
max_connections = {
|
||||
per_endpoint = 100
|
||||
}
|
||||
},
|
||||
{
|
||||
group = "neg-b"
|
||||
max_connections = {
|
||||
per_endpoint = 100
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=9
|
||||
```
|
||||
|
||||
### Health Checks
|
||||
|
||||
You can leverage externally defined health checks for backend services, or have the module create them for you. By default a simple TCP health check is created, and used in backend services.
|
||||
|
||||
Defining a custom health check:
|
||||
|
||||
```hcl
|
||||
module "tcp-proxy-cross-region" {
|
||||
source = "./fabric/modules/net-lb-proxy-int-cross-region"
|
||||
name = "ilb-proxy-test"
|
||||
project_id = var.project_id
|
||||
port = 80
|
||||
|
||||
vpc_config = {
|
||||
network = var.vpc.self_link
|
||||
subnetworks = {
|
||||
europe-west1 = var.subnet1.self_link
|
||||
}
|
||||
}
|
||||
|
||||
backend_service_config = {
|
||||
backends = [{
|
||||
group = "projects/my-project/zones/europe-west1-b/networkEndpointGroups/my-neg"
|
||||
max_connections = {
|
||||
per_endpoint = 100
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
health_check_config = {
|
||||
tcp = {
|
||||
port = 8080
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=4
|
||||
```
|
||||
|
||||
### Network Endpoint Groups (NEGs)
|
||||
|
||||
#### Zonal NEG creation
|
||||
|
||||
You can have the module create zonal NEGs for you by defining the `neg_configs` variable:
|
||||
|
||||
```hcl
|
||||
module "tcp-proxy-cross-region" {
|
||||
source = "./fabric/modules/net-lb-proxy-int-cross-region"
|
||||
name = "ilb-proxy-test"
|
||||
project_id = var.project_id
|
||||
port = 80
|
||||
|
||||
vpc_config = {
|
||||
network = var.vpc.self_link
|
||||
subnetworks = {
|
||||
europe-west1 = var.subnet1.self_link
|
||||
}
|
||||
}
|
||||
|
||||
neg_configs = {
|
||||
neg-a = {
|
||||
gce = {
|
||||
zone = "europe-west1-b"
|
||||
network = var.vpc.self_link
|
||||
subnetwork = var.subnet1.self_link
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backend_service_config = {
|
||||
backends = [{
|
||||
group = "neg-a"
|
||||
max_connections = {
|
||||
per_endpoint = 100
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=5
|
||||
```
|
||||
|
||||
#### Hybrid NEG creation
|
||||
|
||||
You can also configure hybrid NEGs:
|
||||
|
||||
```hcl
|
||||
module "tcp-proxy-cross-region" {
|
||||
source = "./fabric/modules/net-lb-proxy-int-cross-region"
|
||||
name = "ilb-proxy-test"
|
||||
project_id = var.project_id
|
||||
port = 80
|
||||
|
||||
vpc_config = {
|
||||
network = var.vpc.self_link
|
||||
subnetworks = {
|
||||
europe-west1 = var.subnet1.self_link
|
||||
}
|
||||
}
|
||||
|
||||
neg_configs = {
|
||||
hybrid-a = {
|
||||
hybrid = {
|
||||
network = var.vpc.self_link
|
||||
zone = "europe-west1-b"
|
||||
endpoints = {
|
||||
endpoint-1 = {
|
||||
ip_address = "10.10.10.1"
|
||||
port = 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backend_service_config = {
|
||||
backends = [{
|
||||
group = "hybrid-a"
|
||||
max_connections = {
|
||||
per_endpoint = 100
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=6
|
||||
```
|
||||
<!-- BEGIN TFDOC -->
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [name](variables.tf#L204) | Load balancer name. | <code>string</code> | ✓ | |
|
||||
| [project_id](variables.tf#L258) | Project id. | <code>string</code> | ✓ | |
|
||||
| [vpc_config](variables.tf#L274) | VPC-level configuration. | <code>object({…})</code> | ✓ | |
|
||||
| [addresses](variables.tf#L17) | Optional IP addresses used for the forwarding rules, mapped by subnetwork key. | <code>map(string)</code> | | <code>null</code> |
|
||||
| [backend_service_config](variables.tf#L23) | Backend service level configuration. | <code>object({…})</code> | | <code>{}</code> |
|
||||
| [context](variables.tf#L72) | Context-specific interpolations. | <code>object({…})</code> | | <code>{}</code> |
|
||||
| [description](variables.tf#L85) | Optional description used for resources. | <code>string</code> | | <code>"Terraform managed."</code> |
|
||||
| [group_configs](variables.tf#L91) | Optional unmanaged groups to create. Can be referenced in backends via key or outputs. | <code>map(object({…}))</code> | | <code>{}</code> |
|
||||
| [health_check](variables.tf#L105) | Name of existing health check to use, disables auto-created health check. | <code>string</code> | | <code>null</code> |
|
||||
| [health_check_config](variables.tf#L111) | Optional auto-created health check configurations. | <code>object({…})</code> | | <code>{…}</code> |
|
||||
| [labels](variables.tf#L198) | Labels set on resources. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [neg_configs](variables.tf#L209) | Optional network endpoint groups to create. Can be referenced in backends via key or outputs. | <code>map(object({…}))</code> | | <code>{}</code> |
|
||||
| [port](variables.tf#L252) | Forwarding rule port. Cross-region internal proxy load balancers support a single port. | <code>number</code> | | <code>80</code> |
|
||||
| [target_proxy_config](variables.tf#L263) | Target proxy configuration. | <code>object({…})</code> | | <code>{}</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
| name | description | sensitive |
|
||||
|---|---|:---:|
|
||||
| [addresses](outputs.tf#L17) | Forwarding rule addresses. | |
|
||||
| [backend_service](outputs.tf#L22) | Backend resource. | |
|
||||
| [backend_service_id](outputs.tf#L27) | Backend id. | |
|
||||
| [backend_service_self_link](outputs.tf#L32) | Backend self link. | |
|
||||
| [forwarding_rules](outputs.tf#L37) | Forwarding rule resources. | |
|
||||
| [group_self_links](outputs.tf#L42) | Optional unmanaged instance group self links. | |
|
||||
| [groups](outputs.tf#L49) | Optional unmanaged instance group resources. | |
|
||||
| [health_check](outputs.tf#L54) | Auto-created health-check resource. | |
|
||||
| [health_check_id](outputs.tf#L59) | Auto-created health-check id. | |
|
||||
| [health_check_self_link](outputs.tf#L64) | Auto-created health-check self link. | |
|
||||
| [ids](outputs.tf#L69) | Fully qualified forwarding rule ids. | |
|
||||
| [neg_ids](outputs.tf#L74) | Autogenerated network endpoint group ids. | |
|
||||
| [psc_neg_ids](outputs.tf#L81) | Autogenerated PSC network endpoint group ids. | |
|
||||
| [target_proxy](outputs.tf#L88) | Target proxy resource. | |
|
||||
| [target_proxy_id](outputs.tf#L93) | Target proxy id. | |
|
||||
<!-- END TFDOC -->
|
||||
76
modules/net-lb-proxy-int-cross-region/backend-service.tf
Normal file
76
modules/net-lb-proxy-int-cross-region/backend-service.tf
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright 2026 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.
|
||||
*/
|
||||
|
||||
# tfdoc:file:description Backend service resources.
|
||||
|
||||
locals {
|
||||
group_ids = merge(
|
||||
{
|
||||
for k, v in google_compute_instance_group.default : k => v.id
|
||||
},
|
||||
{
|
||||
for k, v in google_compute_network_endpoint_group.default : k => v.id
|
||||
},
|
||||
{
|
||||
for k, v in google_compute_region_network_endpoint_group.psc : k => v.id
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
resource "google_compute_backend_service" "default" {
|
||||
provider = google-beta
|
||||
project = local.project_id
|
||||
name = coalesce(var.backend_service_config.name, var.name)
|
||||
description = var.backend_service_config.description
|
||||
affinity_cookie_ttl_sec = var.backend_service_config.affinity_cookie_ttl_sec
|
||||
connection_draining_timeout_sec = var.backend_service_config.connection_draining_timeout_sec
|
||||
health_checks = [local.health_check]
|
||||
load_balancing_scheme = "INTERNAL_MANAGED"
|
||||
port_name = var.backend_service_config.port_name
|
||||
protocol = "TCP"
|
||||
session_affinity = var.backend_service_config.session_affinity
|
||||
timeout_sec = var.backend_service_config.timeout_sec
|
||||
|
||||
dynamic "backend" {
|
||||
for_each = { for b in coalesce(var.backend_service_config.backends, []) : b.group => b }
|
||||
content {
|
||||
group = lookup(local.group_ids, backend.key, backend.key)
|
||||
balancing_mode = backend.value.balancing_mode
|
||||
capacity_scaler = backend.value.capacity_scaler
|
||||
description = backend.value.description
|
||||
max_connections = try(
|
||||
backend.value.max_connections.per_group, null
|
||||
)
|
||||
max_connections_per_endpoint = try(
|
||||
backend.value.max_connections.per_endpoint, null
|
||||
)
|
||||
max_connections_per_instance = try(
|
||||
backend.value.max_connections.per_instance, null
|
||||
)
|
||||
max_utilization = backend.value.max_utilization
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "log_config" {
|
||||
for_each = var.backend_service_config.log_config == null ? [] : [""]
|
||||
content {
|
||||
enable = var.backend_service_config.log_config.enable
|
||||
sample_rate = var.backend_service_config.log_config.sample_rate
|
||||
optional_mode = var.backend_service_config.log_config.optional_mode
|
||||
optional_fields = var.backend_service_config.log_config.optional_fields
|
||||
}
|
||||
}
|
||||
}
|
||||
38
modules/net-lb-proxy-int-cross-region/groups.tf
Normal file
38
modules/net-lb-proxy-int-cross-region/groups.tf
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright 2026 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.
|
||||
*/
|
||||
|
||||
# tfdoc:file:description Instance group resources.
|
||||
|
||||
resource "google_compute_instance_group" "default" {
|
||||
for_each = var.group_configs
|
||||
project = (
|
||||
each.value.project_id == null
|
||||
? local.project_id
|
||||
: each.value.project_id
|
||||
)
|
||||
zone = try(local.ctx.locations[each.value.zone], each.value.zone)
|
||||
name = coalesce(each.value.name, "${var.name}-${each.key}")
|
||||
description = each.value.description
|
||||
instances = each.value.instances
|
||||
|
||||
dynamic "named_port" {
|
||||
for_each = each.value.named_ports
|
||||
content {
|
||||
name = named_port.key
|
||||
port = named_port.value
|
||||
}
|
||||
}
|
||||
}
|
||||
121
modules/net-lb-proxy-int-cross-region/health-check.tf
Normal file
121
modules/net-lb-proxy-int-cross-region/health-check.tf
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright 2026 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.
|
||||
*/
|
||||
|
||||
# tfdoc:file:description Health check resource.
|
||||
|
||||
locals {
|
||||
hc = (
|
||||
var.health_check != null ? null : var.health_check_config
|
||||
)
|
||||
hc_grpc = try(local.hc.grpc, null) != null
|
||||
hc_http = try(local.hc.http, null) != null
|
||||
hc_http2 = try(local.hc.http2, null) != null
|
||||
hc_https = try(local.hc.https, null) != null
|
||||
hc_ssl = try(local.hc.ssl, null) != null
|
||||
hc_tcp = try(local.hc.tcp, null) != null
|
||||
}
|
||||
|
||||
resource "google_compute_health_check" "default" {
|
||||
provider = google-beta
|
||||
count = local.hc != null ? 1 : 0
|
||||
project = local.project_id
|
||||
name = coalesce(local.hc.name, var.name)
|
||||
description = local.hc.description
|
||||
check_interval_sec = local.hc.check_interval_sec
|
||||
healthy_threshold = local.hc.healthy_threshold
|
||||
timeout_sec = local.hc.timeout_sec
|
||||
unhealthy_threshold = local.hc.unhealthy_threshold
|
||||
|
||||
dynamic "grpc_health_check" {
|
||||
for_each = local.hc_grpc ? [""] : []
|
||||
content {
|
||||
port = local.hc.grpc.port
|
||||
port_name = local.hc.grpc.port_name
|
||||
port_specification = local.hc.grpc.port_specification
|
||||
grpc_service_name = local.hc.grpc.service_name
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "http_health_check" {
|
||||
for_each = local.hc_http ? [""] : []
|
||||
content {
|
||||
host = local.hc.http.host
|
||||
port = local.hc.http.port
|
||||
port_name = local.hc.http.port_name
|
||||
port_specification = local.hc.http.port_specification
|
||||
proxy_header = local.hc.http.proxy_header
|
||||
request_path = local.hc.http.request_path
|
||||
response = local.hc.http.response
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "http2_health_check" {
|
||||
for_each = local.hc_http2 ? [""] : []
|
||||
content {
|
||||
host = local.hc.http2.host
|
||||
port = local.hc.http2.port
|
||||
port_name = local.hc.http2.port_name
|
||||
port_specification = local.hc.http2.port_specification
|
||||
proxy_header = local.hc.http2.proxy_header
|
||||
request_path = local.hc.http2.request_path
|
||||
response = local.hc.http2.response
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "https_health_check" {
|
||||
for_each = local.hc_https ? [""] : []
|
||||
content {
|
||||
host = local.hc.https.host
|
||||
port = local.hc.https.port
|
||||
port_name = local.hc.https.port_name
|
||||
port_specification = local.hc.https.port_specification
|
||||
proxy_header = local.hc.https.proxy_header
|
||||
request_path = local.hc.https.request_path
|
||||
response = local.hc.https.response
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "ssl_health_check" {
|
||||
for_each = local.hc_ssl ? [""] : []
|
||||
content {
|
||||
port = local.hc.ssl.port
|
||||
port_name = local.hc.ssl.port_name
|
||||
port_specification = local.hc.ssl.port_specification
|
||||
proxy_header = local.hc.ssl.proxy_header
|
||||
request = local.hc.ssl.request
|
||||
response = local.hc.ssl.response
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "tcp_health_check" {
|
||||
for_each = local.hc_tcp ? [""] : []
|
||||
content {
|
||||
port = local.hc.tcp.port
|
||||
port_name = local.hc.tcp.port_name
|
||||
port_specification = local.hc.tcp.port_specification
|
||||
proxy_header = local.hc.tcp.proxy_header
|
||||
request = local.hc.tcp.request
|
||||
response = local.hc.tcp.response
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "log_config" {
|
||||
for_each = try(local.hc.enable_logging, false) ? [""] : []
|
||||
content {
|
||||
enable = true
|
||||
}
|
||||
}
|
||||
}
|
||||
135
modules/net-lb-proxy-int-cross-region/main.tf
Normal file
135
modules/net-lb-proxy-int-cross-region/main.tf
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright 2026 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 {
|
||||
ctx = {
|
||||
for k, v in var.context : k => {
|
||||
for kk, vv in v : "${local.ctx_p}${k}:${kk}" => vv
|
||||
}
|
||||
}
|
||||
ctx_p = "$"
|
||||
network = lookup(local.ctx.networks, var.vpc_config.network, var.vpc_config.network)
|
||||
project_id = lookup(local.ctx.project_ids, var.project_id, var.project_id)
|
||||
}
|
||||
|
||||
locals {
|
||||
_neg_endpoints = flatten([
|
||||
for k, v in local.neg_zonal : [
|
||||
for kk, vv in v.endpoints : merge(vv, {
|
||||
key = "${k}-${kk}", neg = k, zone = v.zone
|
||||
})
|
||||
]
|
||||
])
|
||||
addresses = {
|
||||
for k, v in coalesce(var.addresses, {}) : k => lookup(local.ctx.addresses, v, v)
|
||||
}
|
||||
health_check = (
|
||||
var.health_check != null
|
||||
? var.health_check
|
||||
: google_compute_health_check.default[0].self_link
|
||||
)
|
||||
neg_endpoints = {
|
||||
for v in local._neg_endpoints : (v.key) => v
|
||||
}
|
||||
neg_zonal = {
|
||||
for k, v in var.neg_configs : k => {
|
||||
endpoints = v.gce != null ? v.gce.endpoints : v.hybrid.endpoints
|
||||
network = v.gce != null ? v.gce.network : v.hybrid.network
|
||||
project_id = v.project_id
|
||||
subnetwork = v.gce != null ? v.gce.subnetwork : null
|
||||
type = v.gce != null ? "GCE_VM_IP_PORT" : "NON_GCP_PRIVATE_IP_PORT"
|
||||
zone = v.gce != null ? v.gce.zone : v.hybrid.zone
|
||||
} if v.gce != null || v.hybrid != null
|
||||
}
|
||||
neg_regional_psc = {
|
||||
for k, v in var.neg_configs :
|
||||
k => v if v.psc != null
|
||||
}
|
||||
subnetworks = {
|
||||
for k, v in var.vpc_config.subnetworks : k => lookup(local.ctx.subnets, v, v)
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_global_forwarding_rule" "default" {
|
||||
for_each = local.subnetworks
|
||||
provider = google-beta
|
||||
project = local.project_id
|
||||
name = "${var.name}-${each.key}"
|
||||
description = var.description
|
||||
ip_address = try(local.addresses[each.key], null)
|
||||
ip_protocol = "TCP"
|
||||
load_balancing_scheme = "INTERNAL_MANAGED"
|
||||
network = local.network
|
||||
port_range = tostring(var.port)
|
||||
subnetwork = each.value
|
||||
labels = var.labels
|
||||
target = google_compute_target_tcp_proxy.default.id
|
||||
}
|
||||
|
||||
resource "google_compute_target_tcp_proxy" "default" {
|
||||
project = local.project_id
|
||||
name = coalesce(var.target_proxy_config.name, var.name)
|
||||
description = var.target_proxy_config.description
|
||||
backend_service = google_compute_backend_service.default.id
|
||||
proxy_header = var.target_proxy_config.proxy_header
|
||||
}
|
||||
|
||||
resource "google_compute_network_endpoint_group" "default" {
|
||||
for_each = local.neg_zonal
|
||||
project = (
|
||||
each.value.project_id == null
|
||||
? local.project_id
|
||||
: each.value.project_id
|
||||
)
|
||||
name = "${var.name}-${each.key}"
|
||||
network = (
|
||||
each.value.network == null
|
||||
? null
|
||||
: lookup(local.ctx.networks, each.value.network, each.value.network)
|
||||
)
|
||||
subnetwork = (
|
||||
each.value.subnetwork == null
|
||||
? null
|
||||
: lookup(local.ctx.subnets, each.value.subnetwork, each.value.subnetwork)
|
||||
)
|
||||
network_endpoint_type = each.value.type
|
||||
zone = lookup(local.ctx.locations, each.value.zone, each.value.zone)
|
||||
}
|
||||
|
||||
resource "google_compute_network_endpoint" "default" {
|
||||
for_each = local.neg_endpoints
|
||||
project = (
|
||||
local.neg_zonal[each.value.neg].project_id == null
|
||||
? local.project_id
|
||||
: local.neg_zonal[each.value.neg].project_id
|
||||
)
|
||||
network_endpoint_group = google_compute_network_endpoint_group.default[each.value.neg].name
|
||||
zone = lookup(local.ctx.locations, each.value.zone, each.value.zone)
|
||||
instance = try(each.value.instance, null)
|
||||
ip_address = each.value.ip_address
|
||||
port = each.value.port
|
||||
}
|
||||
|
||||
resource "google_compute_region_network_endpoint_group" "psc" {
|
||||
for_each = local.neg_regional_psc
|
||||
project = coalesce(each.value.project_id, local.project_id)
|
||||
name = "${var.name}-${each.key}"
|
||||
region = lookup(local.ctx.locations, each.value.psc.region, each.value.psc.region)
|
||||
network = lookup(local.ctx.networks, each.value.psc.network, each.value.psc.network)
|
||||
subnetwork = lookup(local.ctx.subnets, each.value.psc.subnetwork, each.value.psc.subnetwork)
|
||||
network_endpoint_type = "PRIVATE_SERVICE_CONNECT"
|
||||
psc_target_service = each.value.psc.target_service
|
||||
}
|
||||
96
modules/net-lb-proxy-int-cross-region/outputs.tf
Normal file
96
modules/net-lb-proxy-int-cross-region/outputs.tf
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright 2026 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 "addresses" {
|
||||
description = "Forwarding rule addresses."
|
||||
value = { for k, v in google_compute_global_forwarding_rule.default : k => v.ip_address }
|
||||
}
|
||||
|
||||
output "backend_service" {
|
||||
description = "Backend resource."
|
||||
value = google_compute_backend_service.default
|
||||
}
|
||||
|
||||
output "backend_service_id" {
|
||||
description = "Backend id."
|
||||
value = google_compute_backend_service.default.id
|
||||
}
|
||||
|
||||
output "backend_service_self_link" {
|
||||
description = "Backend self link."
|
||||
value = google_compute_backend_service.default.self_link
|
||||
}
|
||||
|
||||
output "forwarding_rules" {
|
||||
description = "Forwarding rule resources."
|
||||
value = google_compute_global_forwarding_rule.default
|
||||
}
|
||||
|
||||
output "group_self_links" {
|
||||
description = "Optional unmanaged instance group self links."
|
||||
value = {
|
||||
for k, v in google_compute_instance_group.default : k => v.self_link
|
||||
}
|
||||
}
|
||||
|
||||
output "groups" {
|
||||
description = "Optional unmanaged instance group resources."
|
||||
value = google_compute_instance_group.default
|
||||
}
|
||||
|
||||
output "health_check" {
|
||||
description = "Auto-created health-check resource."
|
||||
value = try(google_compute_health_check.default[0], null)
|
||||
}
|
||||
|
||||
output "health_check_id" {
|
||||
description = "Auto-created health-check id."
|
||||
value = try(google_compute_health_check.default[0].id, null)
|
||||
}
|
||||
|
||||
output "health_check_self_link" {
|
||||
description = "Auto-created health-check self link."
|
||||
value = try(google_compute_health_check.default[0].self_link, null)
|
||||
}
|
||||
|
||||
output "ids" {
|
||||
description = "Fully qualified forwarding rule ids."
|
||||
value = { for k, v in google_compute_global_forwarding_rule.default : k => v.id }
|
||||
}
|
||||
|
||||
output "neg_ids" {
|
||||
description = "Autogenerated network endpoint group ids."
|
||||
value = {
|
||||
for k, v in google_compute_network_endpoint_group.default : k => v.id
|
||||
}
|
||||
}
|
||||
|
||||
output "psc_neg_ids" {
|
||||
description = "Autogenerated PSC network endpoint group ids."
|
||||
value = {
|
||||
for k, v in google_compute_region_network_endpoint_group.psc : k => v.id
|
||||
}
|
||||
}
|
||||
|
||||
output "target_proxy" {
|
||||
description = "Target proxy resource."
|
||||
value = google_compute_target_tcp_proxy.default
|
||||
}
|
||||
|
||||
output "target_proxy_id" {
|
||||
description = "Target proxy id."
|
||||
value = google_compute_target_tcp_proxy.default.id
|
||||
}
|
||||
281
modules/net-lb-proxy-int-cross-region/variables.tf
Normal file
281
modules/net-lb-proxy-int-cross-region/variables.tf
Normal file
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* Copyright 2026 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 "addresses" {
|
||||
description = "Optional IP addresses used for the forwarding rules, mapped by subnetwork key."
|
||||
type = map(string)
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "backend_service_config" {
|
||||
description = "Backend service level configuration."
|
||||
type = object({
|
||||
name = optional(string)
|
||||
description = optional(string, "Terraform managed.")
|
||||
affinity_cookie_ttl_sec = optional(number)
|
||||
connection_draining_timeout_sec = optional(number)
|
||||
health_checks = optional(list(string), ["default"])
|
||||
log_config = optional(object({
|
||||
enable = optional(bool)
|
||||
sample_rate = optional(number)
|
||||
optional_mode = optional(string)
|
||||
optional_fields = optional(list(string))
|
||||
}))
|
||||
port_name = optional(string)
|
||||
project_id = optional(string)
|
||||
session_affinity = optional(string, "NONE")
|
||||
timeout_sec = optional(number)
|
||||
backends = optional(list(object({
|
||||
group = string
|
||||
balancing_mode = optional(string, "CONNECTION")
|
||||
capacity_scaler = optional(number, 1)
|
||||
description = optional(string, "Terraform managed.")
|
||||
max_connections = optional(object({
|
||||
per_endpoint = optional(number)
|
||||
per_group = optional(number)
|
||||
per_instance = optional(number)
|
||||
}))
|
||||
max_utilization = optional(number)
|
||||
})))
|
||||
})
|
||||
default = {}
|
||||
nullable = false
|
||||
validation {
|
||||
condition = (var.backend_service_config == null || contains(["NONE", "CLIENT_IP"],
|
||||
var.backend_service_config.session_affinity
|
||||
))
|
||||
error_message = "Invalid session affinity value."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for b in var.backend_service_config.backends : contains(
|
||||
["CONNECTION", "UTILIZATION"], coalesce(b.balancing_mode, "CONNECTION")
|
||||
)
|
||||
])
|
||||
error_message = "When specified, balancing mode needs to be 'CONNECTION' or 'UTILIZATION'."
|
||||
}
|
||||
}
|
||||
|
||||
variable "context" {
|
||||
description = "Context-specific interpolations."
|
||||
type = object({
|
||||
addresses = optional(map(string), {})
|
||||
locations = optional(map(string), {})
|
||||
networks = optional(map(string), {})
|
||||
project_ids = optional(map(string), {})
|
||||
subnets = optional(map(string), {})
|
||||
})
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "description" {
|
||||
description = "Optional description used for resources."
|
||||
type = string
|
||||
default = "Terraform managed."
|
||||
}
|
||||
|
||||
variable "group_configs" {
|
||||
description = "Optional unmanaged groups to create. Can be referenced in backends via key or outputs."
|
||||
type = map(object({
|
||||
name = optional(string)
|
||||
description = optional(string, "Terraform managed.")
|
||||
zone = string
|
||||
instances = optional(list(string))
|
||||
named_ports = optional(map(number), {})
|
||||
project_id = optional(string)
|
||||
}))
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "health_check" {
|
||||
description = "Name of existing health check to use, disables auto-created health check."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "health_check_config" {
|
||||
description = "Optional auto-created health check configurations."
|
||||
type = object({
|
||||
name = optional(string)
|
||||
check_interval_sec = optional(number)
|
||||
description = optional(string, "Terraform managed.")
|
||||
enable_logging = optional(bool, false)
|
||||
healthy_threshold = optional(number)
|
||||
project_id = optional(string)
|
||||
timeout_sec = optional(number)
|
||||
unhealthy_threshold = optional(number)
|
||||
grpc = optional(object({
|
||||
port = optional(number)
|
||||
port_name = optional(string)
|
||||
port_specification = optional(string)
|
||||
service_name = optional(string)
|
||||
}))
|
||||
http = optional(object({
|
||||
host = optional(string)
|
||||
port = optional(number)
|
||||
port_name = optional(string)
|
||||
port_specification = optional(string)
|
||||
proxy_header = optional(string)
|
||||
request_path = optional(string)
|
||||
response = optional(string)
|
||||
}))
|
||||
http2 = optional(object({
|
||||
host = optional(string)
|
||||
port = optional(number)
|
||||
port_name = optional(string)
|
||||
port_specification = optional(string)
|
||||
proxy_header = optional(string)
|
||||
request_path = optional(string)
|
||||
response = optional(string)
|
||||
}))
|
||||
https = optional(object({
|
||||
host = optional(string)
|
||||
port = optional(number)
|
||||
port_name = optional(string)
|
||||
port_specification = optional(string)
|
||||
proxy_header = optional(string)
|
||||
request_path = optional(string)
|
||||
response = optional(string)
|
||||
}))
|
||||
tcp = optional(object({
|
||||
port = optional(number)
|
||||
port_name = optional(string)
|
||||
port_specification = optional(string)
|
||||
proxy_header = optional(string)
|
||||
request = optional(string)
|
||||
response = optional(string)
|
||||
}))
|
||||
ssl = optional(object({
|
||||
port = optional(number)
|
||||
port_name = optional(string)
|
||||
port_specification = optional(string)
|
||||
proxy_header = optional(string)
|
||||
request = optional(string)
|
||||
response = optional(string)
|
||||
}))
|
||||
})
|
||||
default = {
|
||||
tcp = {
|
||||
port_specification = "USE_SERVING_PORT"
|
||||
}
|
||||
}
|
||||
validation {
|
||||
condition = (
|
||||
(try(var.health_check_config.grpc, null) == null ? 0 : 1) +
|
||||
(try(var.health_check_config.http, null) == null ? 0 : 1) +
|
||||
(try(var.health_check_config.http2, null) == null ? 0 : 1) +
|
||||
(try(var.health_check_config.https, null) == null ? 0 : 1) +
|
||||
(try(var.health_check_config.tcp, null) == null ? 0 : 1) +
|
||||
(try(var.health_check_config.ssl, null) == null ? 0 : 1) <= 1
|
||||
)
|
||||
error_message = "Only one health check type can be configured at a time."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in var.health_check_config : contains([
|
||||
"-", "USE_FIXED_PORT", "USE_NAMED_PORT", "USE_SERVING_PORT"
|
||||
], coalesce(try(v.port_specification, null), "-"))
|
||||
])
|
||||
error_message = "Invalid 'port_specification' value. Supported values are 'USE_FIXED_PORT', 'USE_NAMED_PORT', 'USE_SERVING_PORT'."
|
||||
}
|
||||
}
|
||||
|
||||
variable "labels" {
|
||||
description = "Labels set on resources."
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "name" {
|
||||
description = "Load balancer name."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "neg_configs" {
|
||||
description = "Optional network endpoint groups to create. Can be referenced in backends via key or outputs."
|
||||
type = map(object({
|
||||
project_id = optional(string)
|
||||
gce = optional(object({
|
||||
zone = string
|
||||
network = optional(string)
|
||||
subnetwork = optional(string)
|
||||
endpoints = optional(map(object({
|
||||
instance = string
|
||||
ip_address = string
|
||||
port = number
|
||||
})), {})
|
||||
}))
|
||||
hybrid = optional(object({
|
||||
zone = string
|
||||
network = optional(string)
|
||||
endpoints = optional(map(object({
|
||||
ip_address = string
|
||||
port = number
|
||||
})), {})
|
||||
}))
|
||||
psc = optional(object({
|
||||
region = string
|
||||
target_service = string
|
||||
network = optional(string)
|
||||
subnetwork = optional(string)
|
||||
}))
|
||||
}))
|
||||
default = {}
|
||||
nullable = false
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in var.neg_configs : (
|
||||
(try(v.gce, null) == null ? 0 : 1) +
|
||||
(try(v.hybrid, null) == null ? 0 : 1) +
|
||||
(try(v.psc, null) == null ? 0 : 1) == 1
|
||||
)
|
||||
])
|
||||
error_message = "Only one type of neg can be configured at a time."
|
||||
}
|
||||
}
|
||||
|
||||
variable "port" {
|
||||
description = "Forwarding rule port. Cross-region internal proxy load balancers support a single port."
|
||||
type = number
|
||||
default = 80
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "Project id."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "target_proxy_config" {
|
||||
description = "Target proxy configuration."
|
||||
type = object({
|
||||
description = optional(string, "Terraform managed.")
|
||||
name = optional(string)
|
||||
proxy_header = optional(string)
|
||||
})
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "vpc_config" {
|
||||
description = "VPC-level configuration."
|
||||
type = object({
|
||||
network = string
|
||||
subnetworks = map(string)
|
||||
})
|
||||
nullable = false
|
||||
}
|
||||
35
modules/net-lb-proxy-int-cross-region/versions.tf
generated
Normal file
35
modules/net-lb-proxy-int-cross-region/versions.tf
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
# Fabric release: v56.1.0
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.12.2"
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = ">= 7.33.0, < 8.0.0" # tftest
|
||||
}
|
||||
google-beta = {
|
||||
source = "hashicorp/google-beta"
|
||||
version = ">= 7.33.0, < 8.0.0" # tftest
|
||||
}
|
||||
}
|
||||
provider_meta "google" {
|
||||
module_name = "google-pso-tool/cloud-foundation-fabric/modules/net-lb-proxy-int-cross-region:v56.1.0-tf"
|
||||
}
|
||||
provider_meta "google-beta" {
|
||||
module_name = "google-pso-tool/cloud-foundation-fabric/modules/net-lb-proxy-int-cross-region:v56.1.0-tf"
|
||||
}
|
||||
}
|
||||
35
modules/net-lb-proxy-int-cross-region/versions.tofu
generated
Normal file
35
modules/net-lb-proxy-int-cross-region/versions.tofu
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
# Fabric release: v56.1.0
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.11.0"
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = ">= 7.33.0, < 8.0.0" # tftest
|
||||
}
|
||||
google-beta = {
|
||||
source = "hashicorp/google-beta"
|
||||
version = ">= 7.33.0, < 8.0.0" # tftest
|
||||
}
|
||||
}
|
||||
provider_meta "google" {
|
||||
module_name = "google-pso-tool/cloud-foundation-fabric/modules/net-lb-proxy-int-cross-region:v56.1.0-tofu"
|
||||
}
|
||||
provider_meta "google-beta" {
|
||||
module_name = "google-pso-tool/cloud-foundation-fabric/modules/net-lb-proxy-int-cross-region:v56.1.0-tofu"
|
||||
}
|
||||
}
|
||||
14
tests/modules/net_lb_proxy_int_cross_region/common.tfvars
Normal file
14
tests/modules/net_lb_proxy_int_cross_region/common.tfvars
Normal file
@@ -0,0 +1,14 @@
|
||||
name = "proxy-cr-test"
|
||||
project_id = "my-project"
|
||||
backend_service_config = {
|
||||
backends = [{
|
||||
group = "projects/myprj/zones/europe-west1-a/instanceGroups/my-ig"
|
||||
}]
|
||||
}
|
||||
vpc_config = {
|
||||
network = "network"
|
||||
subnetworks = {
|
||||
europe-west1 = "subnet-ew1"
|
||||
europe-west4 = "subnet-ew4"
|
||||
}
|
||||
}
|
||||
56
tests/modules/net_lb_proxy_int_cross_region/context.tfvars
Normal file
56
tests/modules/net_lb_proxy_int_cross_region/context.tfvars
Normal file
@@ -0,0 +1,56 @@
|
||||
name = "proxy-cr-ctx-test"
|
||||
project_id = "$project_ids:my-project"
|
||||
|
||||
context = {
|
||||
project_ids = {
|
||||
my-project = "concrete-project-id"
|
||||
}
|
||||
networks = {
|
||||
my-vpc = "projects/concrete-project-id/global/networks/concrete-vpc"
|
||||
}
|
||||
subnets = {
|
||||
my-subnet-1 = "projects/concrete-project-id/regions/europe-west1/subnetworks/concrete-subnet-1"
|
||||
my-subnet-2 = "projects/concrete-project-id/regions/europe-west4/subnetworks/concrete-subnet-2"
|
||||
}
|
||||
addresses = {
|
||||
my-addr-1 = "10.0.0.10"
|
||||
}
|
||||
}
|
||||
|
||||
vpc_config = {
|
||||
network = "$networks:my-vpc"
|
||||
subnetworks = {
|
||||
europe-west1 = "$subnets:my-subnet-1"
|
||||
europe-west4 = "$subnets:my-subnet-2"
|
||||
}
|
||||
}
|
||||
|
||||
addresses = {
|
||||
europe-west1 = "$addresses:my-addr-1"
|
||||
}
|
||||
|
||||
neg_configs = {
|
||||
neg-a = {
|
||||
gce = {
|
||||
zone = "europe-west1-b"
|
||||
network = "$networks:my-vpc"
|
||||
subnetwork = "$subnets:my-subnet-1"
|
||||
endpoints = {
|
||||
vm-a = {
|
||||
instance = "my-vm-a"
|
||||
ip_address = "10.0.0.2"
|
||||
port = 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backend_service_config = {
|
||||
backends = [{
|
||||
group = "neg-a"
|
||||
max_connections = {
|
||||
per_endpoint = 100
|
||||
}
|
||||
}]
|
||||
}
|
||||
174
tests/modules/net_lb_proxy_int_cross_region/context.yaml
Normal file
174
tests/modules/net_lb_proxy_int_cross_region/context.yaml
Normal file
@@ -0,0 +1,174 @@
|
||||
# Copyright 2026 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
|
||||
#
|
||||
# https://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_compute_backend_service.default:
|
||||
affinity_cookie_ttl_sec: null
|
||||
backend:
|
||||
- balancing_mode: CONNECTION
|
||||
capacity_scaler: 1
|
||||
custom_metrics: []
|
||||
description: Terraform managed.
|
||||
max_connections_per_endpoint: 100
|
||||
preference: ''
|
||||
traffic_duration: ''
|
||||
circuit_breakers: []
|
||||
compression_mode: null
|
||||
connection_draining_timeout_sec: 300
|
||||
consistent_hash: []
|
||||
custom_metrics: []
|
||||
custom_request_headers: null
|
||||
custom_response_headers: null
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
dynamic_forwarding: []
|
||||
edge_security_policy: null
|
||||
enable_cdn: null
|
||||
external_managed_migration_state: null
|
||||
external_managed_migration_testing_percentage: null
|
||||
ip_address_selection_policy: null
|
||||
load_balancing_scheme: INTERNAL_MANAGED
|
||||
locality_lb_policies: []
|
||||
locality_lb_policy: null
|
||||
max_stream_duration: []
|
||||
name: proxy-cr-ctx-test
|
||||
network_pass_through_lb_traffic_policy: []
|
||||
outlier_detection: []
|
||||
params: []
|
||||
project: concrete-project-id
|
||||
protocol: TCP
|
||||
security_policy: null
|
||||
security_settings: []
|
||||
service_lb_policy: null
|
||||
session_affinity: NONE
|
||||
strong_session_affinity_cookie: []
|
||||
timeouts: null
|
||||
tls_settings: []
|
||||
google_compute_global_forwarding_rule.default["europe-west1"]:
|
||||
allow_psc_global_access: null
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
external_managed_backend_bucket_migration_state: null
|
||||
external_managed_backend_bucket_migration_testing_percentage: null
|
||||
ip_address: 10.0.0.10
|
||||
ip_protocol: TCP
|
||||
ip_version: null
|
||||
labels: null
|
||||
load_balancing_scheme: INTERNAL_MANAGED
|
||||
metadata_filters: []
|
||||
name: proxy-cr-ctx-test-europe-west1
|
||||
network: projects/concrete-project-id/global/networks/concrete-vpc
|
||||
no_automate_dns_zone: null
|
||||
port_range: '80'
|
||||
project: concrete-project-id
|
||||
source_ip_ranges: null
|
||||
subnetwork: projects/concrete-project-id/regions/europe-west1/subnetworks/concrete-subnet-1
|
||||
timeouts: null
|
||||
google_compute_global_forwarding_rule.default["europe-west4"]:
|
||||
allow_psc_global_access: null
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
external_managed_backend_bucket_migration_state: null
|
||||
external_managed_backend_bucket_migration_testing_percentage: null
|
||||
ip_protocol: TCP
|
||||
ip_version: null
|
||||
labels: null
|
||||
load_balancing_scheme: INTERNAL_MANAGED
|
||||
metadata_filters: []
|
||||
name: proxy-cr-ctx-test-europe-west4
|
||||
network: projects/concrete-project-id/global/networks/concrete-vpc
|
||||
no_automate_dns_zone: null
|
||||
port_range: '80'
|
||||
project: concrete-project-id
|
||||
source_ip_ranges: null
|
||||
subnetwork: projects/concrete-project-id/regions/europe-west4/subnetworks/concrete-subnet-2
|
||||
timeouts: null
|
||||
google_compute_health_check.default[0]:
|
||||
check_interval_sec: 5
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
grpc_health_check: []
|
||||
grpc_tls_health_check: []
|
||||
healthy_threshold: 2
|
||||
http2_health_check: []
|
||||
http_health_check: []
|
||||
https_health_check: []
|
||||
name: proxy-cr-ctx-test
|
||||
project: concrete-project-id
|
||||
source_regions: null
|
||||
ssl_health_check: []
|
||||
tcp_health_check:
|
||||
- port: null
|
||||
port_name: null
|
||||
port_specification: USE_SERVING_PORT
|
||||
proxy_header: NONE
|
||||
request: null
|
||||
response: null
|
||||
timeout_sec: 5
|
||||
timeouts: null
|
||||
unhealthy_threshold: 2
|
||||
google_compute_network_endpoint.default["neg-a-vm-a"]:
|
||||
deletion_policy: DELETE
|
||||
instance: my-vm-a
|
||||
ip_address: 10.0.0.2
|
||||
network_endpoint_group: proxy-cr-ctx-test-neg-a
|
||||
port: 80
|
||||
project: concrete-project-id
|
||||
timeouts: null
|
||||
zone: europe-west1-b
|
||||
google_compute_network_endpoint_group.default["neg-a"]:
|
||||
default_port: null
|
||||
deletion_policy: DELETE
|
||||
description: null
|
||||
name: proxy-cr-ctx-test-neg-a
|
||||
network: projects/concrete-project-id/global/networks/concrete-vpc
|
||||
network_endpoint_type: GCE_VM_IP_PORT
|
||||
project: concrete-project-id
|
||||
subnetwork: projects/concrete-project-id/regions/europe-west1/subnetworks/concrete-subnet-1
|
||||
timeouts: null
|
||||
zone: europe-west1-b
|
||||
google_compute_target_tcp_proxy.default:
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
name: proxy-cr-ctx-test
|
||||
project: concrete-project-id
|
||||
proxy_header: NONE
|
||||
timeouts: null
|
||||
|
||||
counts:
|
||||
google_compute_backend_service: 1
|
||||
google_compute_global_forwarding_rule: 2
|
||||
google_compute_health_check: 1
|
||||
google_compute_network_endpoint: 1
|
||||
google_compute_network_endpoint_group: 1
|
||||
google_compute_target_tcp_proxy: 1
|
||||
modules: 0
|
||||
resources: 7
|
||||
|
||||
outputs:
|
||||
addresses: __missing__
|
||||
backend_service: __missing__
|
||||
backend_service_id: __missing__
|
||||
backend_service_self_link: __missing__
|
||||
forwarding_rules: __missing__
|
||||
group_self_links: {}
|
||||
groups: {}
|
||||
health_check: __missing__
|
||||
health_check_id: __missing__
|
||||
health_check_self_link: __missing__
|
||||
ids: __missing__
|
||||
neg_ids: __missing__
|
||||
psc_neg_ids: {}
|
||||
target_proxy: __missing__
|
||||
target_proxy_id: __missing__
|
||||
@@ -0,0 +1,10 @@
|
||||
health_check_config = {
|
||||
tcp = {
|
||||
port = 5123
|
||||
port_name = "tcp_port_name"
|
||||
port_specification = "USE_FIXED_PORT"
|
||||
proxy_header = "PROXY_V1"
|
||||
request = "tcp_request"
|
||||
response = "tcp_response"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
# Copyright 2026 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
|
||||
#
|
||||
# https://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_compute_backend_service.default:
|
||||
affinity_cookie_ttl_sec: null
|
||||
backend:
|
||||
- balancing_mode: CONNECTION
|
||||
capacity_scaler: 1
|
||||
custom_metrics: []
|
||||
description: Terraform managed.
|
||||
group: projects/myprj/zones/europe-west1-a/instanceGroups/my-ig
|
||||
preference: ''
|
||||
traffic_duration: ''
|
||||
circuit_breakers: []
|
||||
compression_mode: null
|
||||
connection_draining_timeout_sec: 300
|
||||
consistent_hash: []
|
||||
custom_metrics: []
|
||||
custom_request_headers: null
|
||||
custom_response_headers: null
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
dynamic_forwarding: []
|
||||
edge_security_policy: null
|
||||
enable_cdn: null
|
||||
external_managed_migration_state: null
|
||||
external_managed_migration_testing_percentage: null
|
||||
ip_address_selection_policy: null
|
||||
load_balancing_scheme: INTERNAL_MANAGED
|
||||
locality_lb_policies: []
|
||||
locality_lb_policy: null
|
||||
max_stream_duration: []
|
||||
name: proxy-cr-test
|
||||
network_pass_through_lb_traffic_policy: []
|
||||
outlier_detection: []
|
||||
params: []
|
||||
project: my-project
|
||||
protocol: TCP
|
||||
security_policy: null
|
||||
security_settings: []
|
||||
service_lb_policy: null
|
||||
session_affinity: NONE
|
||||
strong_session_affinity_cookie: []
|
||||
timeouts: null
|
||||
tls_settings: []
|
||||
google_compute_global_forwarding_rule.default["europe-west1"]:
|
||||
allow_psc_global_access: null
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
external_managed_backend_bucket_migration_state: null
|
||||
external_managed_backend_bucket_migration_testing_percentage: null
|
||||
ip_protocol: TCP
|
||||
ip_version: null
|
||||
labels: null
|
||||
load_balancing_scheme: INTERNAL_MANAGED
|
||||
metadata_filters: []
|
||||
name: proxy-cr-test-europe-west1
|
||||
network: network
|
||||
no_automate_dns_zone: null
|
||||
port_range: '80'
|
||||
project: my-project
|
||||
source_ip_ranges: null
|
||||
subnetwork: subnet-ew1
|
||||
timeouts: null
|
||||
google_compute_global_forwarding_rule.default["europe-west4"]:
|
||||
allow_psc_global_access: null
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
external_managed_backend_bucket_migration_state: null
|
||||
external_managed_backend_bucket_migration_testing_percentage: null
|
||||
ip_protocol: TCP
|
||||
ip_version: null
|
||||
labels: null
|
||||
load_balancing_scheme: INTERNAL_MANAGED
|
||||
metadata_filters: []
|
||||
name: proxy-cr-test-europe-west4
|
||||
network: network
|
||||
no_automate_dns_zone: null
|
||||
port_range: '80'
|
||||
project: my-project
|
||||
source_ip_ranges: null
|
||||
subnetwork: subnet-ew4
|
||||
timeouts: null
|
||||
google_compute_health_check.default[0]:
|
||||
check_interval_sec: 5
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
grpc_health_check: []
|
||||
grpc_tls_health_check: []
|
||||
healthy_threshold: 2
|
||||
http2_health_check: []
|
||||
http_health_check: []
|
||||
https_health_check: []
|
||||
name: proxy-cr-test
|
||||
project: my-project
|
||||
source_regions: null
|
||||
ssl_health_check: []
|
||||
tcp_health_check:
|
||||
- port: 5123
|
||||
port_name: tcp_port_name
|
||||
port_specification: USE_FIXED_PORT
|
||||
proxy_header: PROXY_V1
|
||||
request: tcp_request
|
||||
response: tcp_response
|
||||
timeout_sec: 5
|
||||
timeouts: null
|
||||
unhealthy_threshold: 2
|
||||
google_compute_target_tcp_proxy.default:
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
name: proxy-cr-test
|
||||
project: my-project
|
||||
proxy_header: NONE
|
||||
timeouts: null
|
||||
|
||||
counts:
|
||||
google_compute_backend_service: 1
|
||||
google_compute_global_forwarding_rule: 2
|
||||
google_compute_health_check: 1
|
||||
google_compute_target_tcp_proxy: 1
|
||||
modules: 0
|
||||
resources: 5
|
||||
|
||||
outputs:
|
||||
addresses: __missing__
|
||||
backend_service: __missing__
|
||||
backend_service_id: __missing__
|
||||
backend_service_self_link: __missing__
|
||||
forwarding_rules: __missing__
|
||||
group_self_links: {}
|
||||
groups: {}
|
||||
health_check: __missing__
|
||||
health_check_id: __missing__
|
||||
health_check_self_link: __missing__
|
||||
ids: __missing__
|
||||
neg_ids: {}
|
||||
psc_neg_ids: {}
|
||||
target_proxy: __missing__
|
||||
target_proxy_id: __missing__
|
||||
@@ -0,0 +1,26 @@
|
||||
name = "proxy-cr-ig-test"
|
||||
project_id = "my-project"
|
||||
|
||||
vpc_config = {
|
||||
network = "network"
|
||||
subnetworks = {
|
||||
europe-west1 = "subnet-ew1"
|
||||
europe-west4 = "subnet-ew4"
|
||||
}
|
||||
}
|
||||
|
||||
group_configs = {
|
||||
ig-a = {
|
||||
zone = "europe-west1-b"
|
||||
instances = [
|
||||
"projects/my-project/zones/europe-west1-b/instances/vm-a"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
backend_service_config = {
|
||||
backends = [{
|
||||
group = "ig-a"
|
||||
balancing_mode = "UTILIZATION"
|
||||
}]
|
||||
}
|
||||
161
tests/modules/net_lb_proxy_int_cross_region/instance-groups.yaml
Normal file
161
tests/modules/net_lb_proxy_int_cross_region/instance-groups.yaml
Normal file
@@ -0,0 +1,161 @@
|
||||
# Copyright 2026 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
|
||||
#
|
||||
# https://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_compute_backend_service.default:
|
||||
affinity_cookie_ttl_sec: null
|
||||
backend:
|
||||
- balancing_mode: UTILIZATION
|
||||
capacity_scaler: 1
|
||||
custom_metrics: []
|
||||
description: Terraform managed.
|
||||
preference: ''
|
||||
traffic_duration: ''
|
||||
circuit_breakers: []
|
||||
compression_mode: null
|
||||
connection_draining_timeout_sec: 300
|
||||
consistent_hash: []
|
||||
custom_metrics: []
|
||||
custom_request_headers: null
|
||||
custom_response_headers: null
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
dynamic_forwarding: []
|
||||
edge_security_policy: null
|
||||
enable_cdn: null
|
||||
external_managed_migration_state: null
|
||||
external_managed_migration_testing_percentage: null
|
||||
ip_address_selection_policy: null
|
||||
load_balancing_scheme: INTERNAL_MANAGED
|
||||
locality_lb_policies: []
|
||||
locality_lb_policy: null
|
||||
max_stream_duration: []
|
||||
name: proxy-cr-ig-test
|
||||
network_pass_through_lb_traffic_policy: []
|
||||
outlier_detection: []
|
||||
params: []
|
||||
project: my-project
|
||||
protocol: TCP
|
||||
security_policy: null
|
||||
security_settings: []
|
||||
service_lb_policy: null
|
||||
session_affinity: NONE
|
||||
strong_session_affinity_cookie: []
|
||||
timeouts: null
|
||||
tls_settings: []
|
||||
google_compute_global_forwarding_rule.default["europe-west1"]:
|
||||
allow_psc_global_access: null
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
external_managed_backend_bucket_migration_state: null
|
||||
external_managed_backend_bucket_migration_testing_percentage: null
|
||||
ip_protocol: TCP
|
||||
ip_version: null
|
||||
labels: null
|
||||
load_balancing_scheme: INTERNAL_MANAGED
|
||||
metadata_filters: []
|
||||
name: proxy-cr-ig-test-europe-west1
|
||||
network: network
|
||||
no_automate_dns_zone: null
|
||||
port_range: '80'
|
||||
project: my-project
|
||||
source_ip_ranges: null
|
||||
subnetwork: subnet-ew1
|
||||
timeouts: null
|
||||
google_compute_global_forwarding_rule.default["europe-west4"]:
|
||||
allow_psc_global_access: null
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
external_managed_backend_bucket_migration_state: null
|
||||
external_managed_backend_bucket_migration_testing_percentage: null
|
||||
ip_protocol: TCP
|
||||
ip_version: null
|
||||
labels: null
|
||||
load_balancing_scheme: INTERNAL_MANAGED
|
||||
metadata_filters: []
|
||||
name: proxy-cr-ig-test-europe-west4
|
||||
network: network
|
||||
no_automate_dns_zone: null
|
||||
port_range: '80'
|
||||
project: my-project
|
||||
source_ip_ranges: null
|
||||
subnetwork: subnet-ew4
|
||||
timeouts: null
|
||||
google_compute_health_check.default[0]:
|
||||
check_interval_sec: 5
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
grpc_health_check: []
|
||||
grpc_tls_health_check: []
|
||||
healthy_threshold: 2
|
||||
http2_health_check: []
|
||||
http_health_check: []
|
||||
https_health_check: []
|
||||
name: proxy-cr-ig-test
|
||||
project: my-project
|
||||
source_regions: null
|
||||
ssl_health_check: []
|
||||
tcp_health_check:
|
||||
- port: null
|
||||
port_name: null
|
||||
port_specification: USE_SERVING_PORT
|
||||
proxy_header: NONE
|
||||
request: null
|
||||
response: null
|
||||
timeout_sec: 5
|
||||
timeouts: null
|
||||
unhealthy_threshold: 2
|
||||
google_compute_instance_group.default["ig-a"]:
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
instances:
|
||||
- projects/my-project/zones/europe-west1-b/instances/vm-a
|
||||
name: proxy-cr-ig-test-ig-a
|
||||
named_port: []
|
||||
project: my-project
|
||||
timeouts: null
|
||||
zone: europe-west1-b
|
||||
google_compute_target_tcp_proxy.default:
|
||||
deletion_policy: DELETE
|
||||
description: Terraform managed.
|
||||
name: proxy-cr-ig-test
|
||||
project: my-project
|
||||
proxy_header: NONE
|
||||
timeouts: null
|
||||
|
||||
counts:
|
||||
google_compute_backend_service: 1
|
||||
google_compute_global_forwarding_rule: 2
|
||||
google_compute_health_check: 1
|
||||
google_compute_instance_group: 1
|
||||
google_compute_target_tcp_proxy: 1
|
||||
modules: 0
|
||||
resources: 6
|
||||
|
||||
outputs:
|
||||
addresses: __missing__
|
||||
backend_service: __missing__
|
||||
backend_service_id: __missing__
|
||||
backend_service_self_link: __missing__
|
||||
forwarding_rules: __missing__
|
||||
group_self_links: __missing__
|
||||
groups: __missing__
|
||||
health_check: __missing__
|
||||
health_check_id: __missing__
|
||||
health_check_self_link: __missing__
|
||||
ids: __missing__
|
||||
neg_ids: {}
|
||||
psc_neg_ids: {}
|
||||
target_proxy: __missing__
|
||||
target_proxy_id: __missing__
|
||||
21
tests/modules/net_lb_proxy_int_cross_region/tftest.yaml
Normal file
21
tests/modules/net_lb_proxy_int_cross_region/tftest.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
# Copyright 2026 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/net-lb-proxy-int-cross-region
|
||||
common_tfvars:
|
||||
- common.tfvars
|
||||
tests:
|
||||
health-checks-tcp:
|
||||
context:
|
||||
instance-groups:
|
||||
Reference in New Issue
Block a user