Refactor net-glb module for Terraform 1.3 (#1044)

* wip

* urlmaps

* wip

* tested

* fix managed certificate names

* simple HTTP and HTTPS examples

* gce and hybrid neg examples

* internet NEG example

* serverless NEG and backend bucket examples

* certificate example

* fix example tests

* remove stale test module

* module test

* adfs blueprint

* add support for non-classic GLB and PSC NEGs

* apigee blueprint

* glb and cloud armor blueprint

* deprecate non-working nginx reverse cluster

* api gateway blueprint

* tfdoc

* fix top-level READMEs

* switch to new tests

* only/at most
This commit is contained in:
Ludovico Magnocavallo 2022-12-08 17:35:44 +01:00 committed by GitHub
parent e57e00de6c
commit 46f694be08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 3438 additions and 4563 deletions

View File

@ -8,7 +8,7 @@ Currently available blueprints:
- **data solutions** - [GCE and GCS CMEK via centralized Cloud KMS](./data-solutions/cmek-via-centralized-kms), [Cloud Composer version 2 private instance, supporting Shared VPC and external CMEK key](./data-solutions/composer-2), [Cloud SQL instance with multi-region read replicas](./data-solutions/cloudsql-multiregion), [Data Platform](./data-solutions/data-platform-foundations), [Spinning up a foundation data pipeline on Google Cloud using Cloud Storage, Dataflow and BigQuery](./data-solutions/gcs-to-bq-with-least-privileges), [#SQL Server Always On Groups blueprint](./data-solutions/sqlserver-alwayson), [Data Playground](./data-solutions/data-playground)
- **factories** - [The why and the how of Resource Factories](./factories), [Google Cloud Identity Group Factory](./factories/cloud-identity-group-factory), [Google Cloud BQ Factory](./factories/bigquery-factory), [Google Cloud VPC Firewall Factory](./factories/net-vpc-firewall-yaml), [Minimal Project Factory](./factories/project-factory)
- **GKE** - [Binary Authorization Pipeline Blueprint](./gke/binauthz), [Storage API](./gke/binauthz/image), [Multi-cluster mesh on GKE (fleet API)](./gke/multi-cluster-mesh-gke-fleet-api), [GKE Multitenant Blueprint](./gke/multitenant-fleet), [Shared VPC with GKE support](./networking/shared-vpc-gke/)
- **networking** - [Decentralized firewall management](./networking/decentralized-firewall), [Decentralized firewall validator](./networking/decentralized-firewall/validator), [Network filtering with Squid](./networking/filtering-proxy), [Network filtering with Squid with isolated VPCs using Private Service Connect](./networking/filtering-proxy-psc), [HTTP Load Balancer with Cloud Armor](./networking/glb-and-armor), [Hub and Spoke via VPN](./networking/hub-and-spoke-vpn), [Hub and Spoke via VPC Peering](./networking/hub-and-spoke-peering), [Internal Load Balancer as Next Hop](./networking/ilb-next-hop), [Nginx-based reverse proxy cluster](./networking/nginx-reverse-proxy-cluster), [On-prem DNS and Google Private Access](./networking/onprem-google-access-dns), [Calling a private Cloud Function from On-premises](./networking/private-cloud-function-from-onprem), [Hybrid connectivity to on-premise services through PSC](./networking/psc-hybrid), [PSC Producer](./networking/psc-hybrid/psc-producer), [PSC Consumer](./networking/psc-hybrid/psc-consumer), [Shared VPC with optional GKE cluster](./networking/shared-vpc-gke)
- **networking** - [Decentralized firewall management](./networking/decentralized-firewall), [Decentralized firewall validator](./networking/decentralized-firewall/validator), [Network filtering with Squid](./networking/filtering-proxy), [Network filtering with Squid with isolated VPCs using Private Service Connect](./networking/filtering-proxy-psc), [HTTP Load Balancer with Cloud Armor](./networking/glb-and-armor), [Hub and Spoke via VPN](./networking/hub-and-spoke-vpn), [Hub and Spoke via VPC Peering](./networking/hub-and-spoke-peering), [Internal Load Balancer as Next Hop](./networking/ilb-next-hop), [On-prem DNS and Google Private Access](./networking/onprem-google-access-dns), [Calling a private Cloud Function from On-premises](./networking/private-cloud-function-from-onprem), [Hybrid connectivity to on-premise services through PSC](./networking/psc-hybrid), [PSC Producer](./networking/psc-hybrid/psc-producer), [PSC Consumer](./networking/psc-hybrid/psc-consumer), [Shared VPC with optional GKE cluster](./networking/shared-vpc-gke)
- **serverless** - [Creating multi-region deployments for API Gateway](./serverless/api-gateway)
- **third party solutions** - [OpenShift on GCP user-provisioned infrastructure](./third-party-solutions/openshift), [Wordpress deployment on Cloud Run](./third-party-solutions/wordpress/cloudrun)

View File

@ -87,7 +87,7 @@ module "server" {
}
group = {
named_ports = {
http = 443
https = 443
}
}
tags = ["https-server"]
@ -97,69 +97,25 @@ module "glb" {
source = "../../../modules/net-glb"
name = "${var.prefix}-glb"
project_id = module.project.project_id
https = true
reserve_ip_address = true
ssl_certificates_config = {
adfs-domain = {
domains = [
"${var.adfs_dns_domain_name}"
],
unmanaged_config = null
protocol = "HTTPS"
backend_service_configs = {
default = {
backends = [{ backend = module.server.group.id }]
log_sample_rate = 1
protocol = "HTTPS"
}
}
target_proxy_https_config = {
ssl_certificates = [
"adfs-domain"
]
}
backend_services_config = {
adfs-group-backend = {
bucket_config = null
enable_cdn = false
cdn_config = null
group_config = {
backends = [
{
group = module.server.group.id
options = null
}
],
health_checks = ["hc"]
log_config = {
enable = true
sample_rate = 1
}
options = {
affinity_cookie_ttl_sec = null
custom_request_headers = null
custom_response_headers = null
connection_draining_timeout_sec = null
load_balancing_scheme = null
locality_lb_policy = null
port_name = null
security_policy = null
session_affinity = null
timeout_sec = null
circuits_breakers = null
consistent_hash = null
iap = null
protocol = "HTTPS"
}
health_check_configs = {
default = {
https = {
port_specification = "USE_SERVING_PORT"
}
}
}
health_checks_config = {
hc = {
type = "tcp"
logging = true
options = null
check = {
port_name = "http"
port_specification = "USE_NAMED_PORT"
ssl_certificates = {
managed_configs = {
adfs-domain = {
domains = ["${var.adfs_dns_domain_name}"]
}
}
}

View File

@ -14,5 +14,5 @@
output "ip_address" {
description = "IP address."
value = module.glb.ip_address
}
value = module.glb.address
}

View File

@ -39,11 +39,21 @@ module "project" {
"storage.googleapis.com"
]
iam = {
"roles/bigquery.jobUser" = [module.function_gcs2bq.service_account_iam_email]
"roles/logging.logWriter" = [module.function_export.service_account_iam_email]
"roles/logging.logWriter" = [module.function_gcs2bq.service_account_iam_email]
"roles/apigee.admin" = [module.function_export.service_account_iam_email]
"roles/storage.admin" = ["serviceAccount:${module.project.service_accounts.robots.apigee}"]
"roles/bigquery.jobUser" = [
module.function_gcs2bq.service_account_iam_email
]
"roles/logging.logWriter" = [
module.function_export.service_account_iam_email
]
"roles/logging.logWriter" = [
module.function_gcs2bq.service_account_iam_email
]
"roles/apigee.admin" = [
module.function_export.service_account_iam_email
]
"roles/storage.admin" = [
"serviceAccount:${module.project.service_accounts.robots.apigee}"
]
}
}
@ -52,16 +62,14 @@ module "vpc" {
project_id = module.project.project_id
name = var.organization.authorized_network
vpc_create = var.vpc_create
subnets_psc = [for k, v in var.psc_config :
{
ip_cidr_range = v
name = "subnet-psc-${k}"
region = k
}
]
subnets_psc = [for k, v in var.psc_config : {
ip_cidr_range = v
name = "subnet-psc-${k}"
region = k
}]
psa_config = {
ranges = { for k, v in var.instances :
"apigee-${k}" => v.psa_ip_cidr_range
ranges = {
for k, v in var.instances : "apigee-${k}" => v.psa_ip_cidr_range
}
}
}
@ -78,76 +86,39 @@ module "apigee" {
]
}
resource "google_compute_region_network_endpoint_group" "neg" {
for_each = var.instances
name = "apigee-neg-${each.key}"
project = module.project.project_id
region = each.value.region
network_endpoint_type = "PRIVATE_SERVICE_CONNECT"
psc_target_service = module.apigee.instances[each.key].service_attachment
network = module.vpc.network.self_link
subnetwork = module.vpc.subnets_psc["${each.value.region}/subnet-psc-${each.value.region}"].self_link
}
module "glb" {
source = "../../../modules/net-glb"
name = "glb"
project_id = module.project.project_id
https = true
reserve_ip_address = true
ssl_certificates_config = { for k, v in var.envgroups :
"${k}-domain" => {
domains = v,
unmanaged_config = null
source = "../../../modules/net-glb"
name = "glb"
project_id = module.project.project_id
protocol = "HTTPS"
use_classic_version = false
backend_service_configs = {
default = {
backends = [for k, v in var.instances : { backend = k }]
protocol = "HTTPS"
}
}
target_proxy_https_config = {
ssl_certificates = [for k, v in var.envgroups : "${k}-domain"]
health_check_configs = {
default = {
https = { port_specification = "USE_SERVING_PORT" }
}
}
health_checks_config_defaults = null
backend_services_config = {
apigee = {
bucket_config = null
enable_cdn = false
cdn_config = null
group_config = {
backends = [for k, v in google_compute_region_network_endpoint_group.neg :
{
group = v.id
options = null
}
],
health_checks = []
log_config = null
options = {
affinity_cookie_ttl_sec = null
custom_request_headers = null
custom_response_headers = null
connection_draining_timeout_sec = null
load_balancing_scheme = "EXTERNAL_MANAGED"
locality_lb_policy = null
port_name = null
security_policy = null
session_affinity = null
timeout_sec = null
circuits_breakers = null
consistent_hash = null
iap = null
protocol = "HTTPS"
}
neg_configs = {
for k, v in var.instances : k => {
psc = {
region = v.region
target_service = module.apigee.instances[k].service_attachment
network = module.vpc.network.self_link
subnetwork = (
module.vpc.subnets_psc["${v.region}/subnet-psc-${v.region}"].self_link
)
}
}
}
global_forwarding_rule_config = {
load_balancing_scheme = "EXTERNAL_MANAGED"
ip_protocol = "TCP"
ip_version = "IPV4"
port_range = null
ssl_certificates = {
managed_config = {
for k, v in var.envgroups : k => { domains = [v] }
}
}
}
@ -162,7 +133,9 @@ module "bucket_export" {
project_id = module.project.project_id
name = "${module.project.project_id}-export"
iam = {
"roles/storage.objectViewer" = [module.function_gcs2bq.service_account_iam_email]
"roles/storage.objectViewer" = [
module.function_gcs2bq.service_account_iam_email
]
}
notification_config = {
enabled = true
@ -266,15 +239,24 @@ module "bigquery_dataset" {
}
}
iam = {
"roles/bigquery.dataEditor" = [module.function_gcs2bq.service_account_iam_email]
"roles/bigquery.dataEditor" = [
module.function_gcs2bq.service_account_iam_email
]
}
}
resource "google_app_engine_application" "app" {
project = module.project.project_id
location_id = ((var.organization.analytics_region == "europe-west1" || var.organization.analytics_region == "us-central1") ?
substr(var.organization.analytics_region, 0, length(var.organization.analytics_region) - 1) :
var.organization.analytics_region)
location_id = (
(
var.organization.analytics_region == "europe-west1" ||
var.organization.analytics_region == "us-central1"
)
? substr(
var.organization.analytics_region, 0, length(var.organization.analytics_region) - 1
)
: var.organization.analytics_region
)
}
resource "google_cloud_scheduler_job" "job" {

View File

@ -16,5 +16,5 @@
output "ip_address" {
description = "IP address."
value = module.glb.ip_address
value = module.glb.address
}

View File

@ -46,11 +46,13 @@ The blueprint shows how to implement spoke transitivity via BGP advertisements,
<br clear="left">
<!--
### Nginx-based reverse proxy cluster
<a href="./nginx-reverse-proxy-cluster/" title="Nginx-based reverse proxy cluster"><img src="./nginx-reverse-proxy-cluster/reverse-proxy.png" align="left" width="280px"></a> This [blueprint](./nginx-reverse-proxy-cluster/) how to deploy an autoscaling reverse proxy cluster using Nginx, based on regional Managed Instance Groups. The autoscaling is driven by Nginx current connections metric, sent by Cloud Ops Agent.
<a href="./_deprecated/nginx-reverse-proxy-cluster/" title="Nginx-based reverse proxy cluster"><img src="./_deprecated/nginx-reverse-proxy-cluster/reverse-proxy.png" align="left" width="280px"></a> This [blueprint](./nginx-reverse-proxy-cluster/) how to deploy an autoscaling reverse proxy cluster using Nginx, based on regional Managed Instance Groups. The autoscaling is driven by Nginx current connections metric, sent by Cloud Ops Agent.
<br clear="left">
-->
### DNS and Private Access for On-premises

View File

@ -0,0 +1,5 @@
# Deprecated or unsupported blueprints
The blueprints in this folder are either deprecated or need work on them.
- nginx reverse proxy cluster needs tests and resolving a cycle

View File

@ -71,7 +71,7 @@ locals {
error_log stderr;
access_log /dev/stdout combined;
set_real_ip_from ${module.xlb.ip_address}/32;
set_real_ip_from ${module.glb.address}/32;
set_real_ip_from 35.191.0.0/16;
set_real_ip_from 130.211.0.0/22;
real_ip_header X-Forwarded-For;
@ -121,7 +121,8 @@ locals {
module "project" {
source = "../../../modules/project"
billing_account = (var.project_create != null
billing_account = (
var.project_create != null
? var.project_create.billing_account_id
: null
)
@ -130,7 +131,7 @@ module "project" {
? var.project_create.parent
: null
)
project_create = var.project_create != null
services = [
"cloudresourcemanager.googleapis.com",
"compute.googleapis.com",
@ -138,21 +139,17 @@ module "project" {
"logging.googleapis.com",
"monitoring.googleapis.com",
]
project_create = var.project_create != null
}
module "vpc" {
source = "../../../modules/net-vpc"
project_id = module.project.project_id
name = var.network
subnets = [
{
name = var.subnetwork
ip_cidr_range = var.cidrs[var.subnetwork]
region = var.region
},
]
subnets = [{
name = var.subnetwork
ip_cidr_range = var.cidrs[var.subnetwork]
region = var.region
}]
vpc_create = var.network_create
}
@ -181,23 +178,21 @@ module "firewall" {
}
module "nat" {
source = "../../../modules/net-cloudnat"
project_id = module.project.project_id
region = var.region
name = "${var.prefix}-nat"
router_network = module.vpc.name
config_source_subnets = "LIST_OF_SUBNETWORKS"
logging_filter = "ALL"
source = "../../../modules/net-cloudnat"
project_id = module.project.project_id
region = var.region
name = "${var.prefix}-nat"
config_min_ports_per_vm = 4000
subnetworks = [
{
self_link = module.vpc.subnet_self_links[format("%s/%s", var.region, var.subnetwork)]
config_source_ranges = ["ALL_IP_RANGES"]
secondary_ranges = null
}
]
config_source_subnets = "LIST_OF_SUBNETWORKS"
logging_filter = "ALL"
router_network = module.vpc.name
subnetworks = [{
self_link = (
module.vpc.subnet_self_links[format("%s/%s", var.region, var.subnetwork)]
)
config_source_ranges = ["ALL_IP_RANGES"]
secondary_ranges = null
}]
}
###############################################################################
@ -240,7 +235,6 @@ module "mig-proxy" {
source = "../../../modules/compute-mig"
project_id = module.project.project_id
location = var.region
regional = true
name = "${var.prefix}-proxy-cluster"
named_ports = {
http = "80"
@ -255,19 +249,14 @@ module "mig-proxy" {
metric = var.autoscaling_metric
}
update_policy = {
instance_redistribution_type = "PROACTIVE"
max_surge_type = "fixed"
max_surge = 3
max_unavailable_type = null
max_unavailable = null
minimal_action = "REPLACE"
min_ready_sec = 60
type = "PROACTIVE"
}
default_version = {
instance_template = module.proxy-vm.template.self_link
name = "proxy-vm"
minimal_action = "REPLACE"
type = "PROACTIVE"
min_ready_sec = 30
max_surge = {
fixed = 1
}
}
instance_template = module.proxy-vm.template.self_link
health_check_config = {
type = "http"
check = {
@ -311,59 +300,28 @@ module "proxy-vm" {
service_account_create = false
}
module "xlb" {
source = "../../../modules/net-glb"
name = "${var.prefix}-reverse-proxy-xlb"
project_id = module.project.project_id
reserve_ip_address = true
health_checks_config = {
"${var.prefix}-reverse-proxy-hc" = {
type = "http"
logging = false
options = {
check_interval_sec = 10
healthy_threshold = 1
unhealthy_threshold = 1
timeout_sec = 10
}
check = {
module "glb" {
source = "../../../modules/net-glb"
project_id = module.project.project_id
name = "${var.prefix}-reverse-proxy-glb"
health_check_configs = {
default = {
check_interval_sec = 10
healthy_threshold = 1
unhealthy_threshold = 1
timeout_sec = 10
http = {
port_specification = "USE_NAMED_PORT"
port_name = "http"
request_path = "/healthz"
}
}
}
backend_services_config = {
"${var.prefix}-reverse-proxy-backend" = {
bucket_config = null
enable_cdn = false
cdn_config = null
group_config = {
backends = [
{
group = module.mig-proxy.group_manager.instance_group
options = null
}
]
health_checks = ["${var.prefix}-reverse-proxy-hc"]
log_config = null
options = {
affinity_cookie_ttl_sec = null
custom_request_headers = null
custom_response_headers = null
connection_draining_timeout_sec = null
load_balancing_scheme = null
locality_lb_policy = null
port_name = !var.tls ? "http" : "https"
protocol = !var.tls ? "HTTP" : "HTTPS"
security_policy = null
session_affinity = null
timeout_sec = null
circuits_breakers = null
consistent_hash = null
iap = null
}
}
backend_service_configs = {
default = {
backends = [{ backend = module.mig-proxy.group_manager.instance_group }]
port_name = !var.tls ? "http" : "https"
protocol = !var.tls ? "HTTP" : "HTTPS"
}
}
}

View File

@ -16,5 +16,5 @@
output "load_balancer_url" {
description = "Load balancer for the reverse proxy instance group."
value = !var.tls ? format("http://%s/", module.xlb.ip_address) : format("https://%s/", module.xlb.ip_address)
value = format("http%s://%s/", var.tls ? "s" : "", module.glb.address)
}

View File

@ -204,55 +204,14 @@ module "glb" {
source = "../../../modules/net-glb"
name = "${var.prefix}-http-lb"
project_id = module.project.project_id
backend_services_config = {
http-backend = {
bucket_config = null
enable_cdn = false
cdn_config = null
group_config = {
backends = [
{
group = module.mig_ew1.group_manager.instance_group
options = null
},
{
group = module.mig_ue1.group_manager.instance_group
options = null
}
],
health_checks = ["hc"]
log_config = {
enable = true
sample_rate = 1
}
options = {
affinity_cookie_ttl_sec = null
custom_request_headers = null
custom_response_headers = null
connection_draining_timeout_sec = null
load_balancing_scheme = null
locality_lb_policy = null
port_name = "http"
security_policy = try(google_compute_security_policy.policy[0].name, null)
session_affinity = null
timeout_sec = null
circuits_breakers = null
consistent_hash = null
iap = null
protocol = "HTTP"
}
}
}
}
health_checks_config = {
hc = {
type = "http"
logging = true
options = null
check = {
port_name = "http"
port_specification = "USE_NAMED_PORT"
}
backend_service_configs = {
default = {
backends = [
{ backend = module.mig_ew1.group_manager.instance_group },
{ backend = module.mig_ue1.group_manager.instance_group }
]
log_sample_rate = 1
security_policy = try(google_compute_security_policy.policy[0].name, null)
}
}
}

View File

@ -17,7 +17,7 @@
output "glb_ip_address" {
description = "Load balancer IP address."
value = module.glb.global_forwarding_rule.ip_address
value = module.glb.address
}
output "vm_siege_external_ip" {

View File

@ -103,26 +103,16 @@ module "gateways" {
module "glb" {
source = "../../../modules/net-glb"
name = "glb"
project_id = module.project.project_id
# This is important as serverless backends require no HCs
health_checks_config_defaults = null
reserve_ip_address = true
backend_services_config = {
serverless-backend = {
bucket_config = null
enable_cdn = false
cdn_config = null
group_config = {
backends = [for region in var.regions : {
group = google_compute_region_network_endpoint_group.serverless-negs[region].id
options = null
}
],
health_checks = []
log_config = null
options = null
}
name = "glb"
backend_service_configs = {
default = {
backends = [
for region in var.regions : {
backend = google_compute_region_network_endpoint_group.serverless-negs[region].id
}
]
health_checks = []
}
}
}

View File

@ -16,5 +16,5 @@
output "ip_address" {
description = "The reserved global IP address."
value = module.glb.ip_address
value = module.glb.address
}

3
modules/net-glb/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*backup
*tfstate
tfvars

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,262 @@
/**
* Copyright 2022 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_global_network_endpoint_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
},
{
for k, v in google_compute_region_network_endpoint_group.serverless : k => v.id
}
)
hc_ids = {
for k, v in google_compute_health_check.default : k => v.id
}
}
# google_compute_backend_bucket
resource "google_compute_backend_service" "default" {
provider = google-beta
for_each = var.backend_service_configs
project = (
each.value.project_id == null
? var.project_id
: each.value.project_id
)
name = "${var.name}-${each.key}"
description = var.description
affinity_cookie_ttl_sec = each.value.affinity_cookie_ttl_sec
compression_mode = each.value.compression_mode
connection_draining_timeout_sec = each.value.connection_draining_timeout_sec
custom_request_headers = each.value.custom_request_headers
custom_response_headers = each.value.custom_response_headers
enable_cdn = each.value.enable_cdn
health_checks = length(each.value.health_checks) == 0 ? null : [
for k in each.value.health_checks : lookup(local.hc_ids, k, k)
]
load_balancing_scheme = "EXTERNAL"
port_name = (
each.value.port_name == null
? lower(each.value.protocol == null ? var.protocol : each.value.protocol)
: each.value.port_name
)
protocol = (
each.value.protocol == null ? var.protocol : each.value.protocol
)
security_policy = each.value.security_policy
session_affinity = each.value.session_affinity
timeout_sec = each.value.timeout_sec
dynamic "backend" {
for_each = { for b in coalesce(each.value.backends, []) : b.backend => b }
content {
group = lookup(local.group_ids, backend.key, backend.key)
balancing_mode = backend.value.balancing_mode # UTILIZATION, RATE
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_rate = try(
backend.value.max_rate.per_group, null
)
max_rate_per_endpoint = try(
backend.value.max_rate.per_endpoint, null
)
max_rate_per_instance = try(
backend.value.max_rate.per_instance, null
)
max_utilization = backend.value.max_utilization
}
}
dynamic "cdn_policy" {
for_each = (
each.value.cdn_policy == null ? [] : [each.value.cdn_policy]
)
iterator = cdn
content {
cache_mode = cdn.value.cache_mode
client_ttl = cdn.value.client_ttl
default_ttl = cdn.value.default_ttl
max_ttl = cdn.value.max_ttl
negative_caching = cdn.value.negative_caching
serve_while_stale = cdn.value.serve_while_stale
signed_url_cache_max_age_sec = cdn.value.signed_url_cache_max_age_sec
dynamic "cache_key_policy" {
for_each = (
cdn.value.cache_key_policy == null
? []
: [cdn.value.cache_key_policy]
)
iterator = ck
content {
include_host = ck.value.include_host
include_named_cookies = ck.value.include_named_cookies
include_protocol = ck.value.include_protocol
include_query_string = ck.value.include_query_string
query_string_blacklist = ck.value.query_string_blacklist
query_string_whitelist = ck.value.query_string_whitelist
}
}
dynamic "negative_caching_policy" {
for_each = (
cdn.value.negative_caching_policy == null
? []
: [cdn.value.negative_caching_policy]
)
iterator = nc
content {
code = nc.value.code
ttl = nc.value.ttl
}
}
}
}
dynamic "circuit_breakers" {
for_each = (
each.value.circuit_breakers == null ? [] : [each.value.circuit_breakers]
)
iterator = cb
content {
max_connections = cb.value.max_connections
max_pending_requests = cb.value.max_pending_requests
max_requests = cb.value.max_requests
max_requests_per_connection = cb.value.max_requests_per_connection
max_retries = cb.value.max_retries
dynamic "connect_timeout" {
for_each = (
cb.value.connect_timeout == null ? [] : [cb.value.connect_timeout]
)
content {
seconds = connect_timeout.value.seconds
nanos = connect_timeout.value.nanos
}
}
}
}
dynamic "consistent_hash" {
for_each = (
each.value.consistent_hash == null ? [] : [each.value.consistent_hash]
)
iterator = ch
content {
http_header_name = ch.value.http_header_name
minimum_ring_size = ch.value.minimum_ring_size
dynamic "http_cookie" {
for_each = ch.value.http_cookie == null ? [] : [ch.value.http_cookie]
content {
name = http_cookie.value.name
path = http_cookie.value.path
dynamic "ttl" {
for_each = (
http_cookie.value.ttl == null ? [] : [http_cookie.value.ttl]
)
content {
seconds = ttl.value.seconds
nanos = ttl.value.nanos
}
}
}
}
}
}
dynamic "iap" {
for_each = each.value.iap_config == null ? [] : [each.value.iap_config]
content {
oauth2_client_id = iap.value.oauth2_client_id
oauth2_client_secret = iap.value.oauth2_client_secret
oauth2_client_secret_sha256 = iap.value.oauth2_client_secret_sha256
}
}
dynamic "log_config" {
for_each = each.value.log_sample_rate == null ? [] : [""]
content {
enable = true
sample_rate = each.value.log_sample_rate
}
}
dynamic "outlier_detection" {
for_each = (
each.value.outlier_detection == null ? [] : [each.value.outlier_detection]
)
iterator = od
content {
consecutive_errors = od.value.consecutive_errors
consecutive_gateway_failure = od.value.consecutive_gateway_failure
enforcing_consecutive_errors = od.value.enforcing_consecutive_errors
enforcing_consecutive_gateway_failure = od.value.enforcing_consecutive_gateway_failure
enforcing_success_rate = od.value.enforcing_success_rate
max_ejection_percent = od.value.max_ejection_percent
success_rate_minimum_hosts = od.value.success_rate_minimum_hosts
success_rate_request_volume = od.value.success_rate_request_volume
success_rate_stdev_factor = od.value.success_rate_stdev_factor
dynamic "base_ejection_time" {
for_each = (
od.value.base_ejection_time == null ? [] : [od.value.base_ejection_time]
)
content {
seconds = base_ejection_time.value.seconds
nanos = base_ejection_time.value.nanos
}
}
dynamic "interval" {
for_each = (
od.value.interval == null ? [] : [od.value.interval]
)
content {
seconds = interval.value.seconds
nanos = interval.value.nanos
}
}
}
}
dynamic "security_settings" {
for_each = (
each.value.security_settings == null ? [] : [each.value.security_settings]
)
iterator = ss
content {
client_tls_policy = ss.value.client_tls_policy
subject_alt_names = ss.value.subject_alt_names
}
}
}

View File

@ -1,211 +0,0 @@
/**
* Copyright 2022 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 Bucket and group backend services.
locals {
backend_services_bucket = {
for k, v in coalesce(var.backend_services_config, {}) :
k => v if v.bucket_config != null
}
backend_services_group = {
for k, v in coalesce(var.backend_services_config, {}) :
k => v if v.group_config != null
}
}
resource "google_compute_backend_bucket" "bucket" {
for_each = local.backend_services_bucket
name = "${var.name}-${each.key}"
description = "Terraform managed."
project = var.project_id
bucket_name = try(each.value.bucket_config.bucket_name, null)
custom_response_headers = try(each.value.bucket_config.options.custom_response_headers, null)
enable_cdn = try(each.value.enable_cdn, null)
dynamic "cdn_policy" {
for_each = try(each.value.cdn_policy, null) == null ? [] : [each.value.cdn_policy]
content {
cache_mode = try(cdn_policy.value.cache_mode, null)
client_ttl = try(cdn_policy.value.client_ttl, null)
default_ttl = try(cdn_policy.value.default_ttl, null)
max_ttl = try(cdn_policy.value.max_ttl, null)
negative_caching = try(cdn_policy.value.negative_caching, null)
serve_while_stale = try(cdn_policy.value.serve_while_stale, null)
signed_url_cache_max_age_sec = try(cdn_policy.value.signed_url_cache_max_age_sec, null)
dynamic "negative_caching_policy" {
for_each = try(cdn_policy.value.negative_caching_policy, null) == null ? [] : [cdn_policy.value.negative_caching_policy]
iterator = ncp
content {
code = ncp.value.code
ttl = ncp.value.ttl
}
}
}
}
}
resource "google_compute_backend_service" "group" {
for_each = var.region == null ? local.backend_services_group : {}
name = "${var.name}-${each.key}"
project = var.project_id
description = "Terraform managed."
affinity_cookie_ttl_sec = try(each.value.group_config.options.affinity_cookie_ttl_sec, null)
enable_cdn = try(each.value.enable_cdn, null)
custom_request_headers = try(each.value.group_config.options.custom_request_headers, null)
custom_response_headers = try(each.value.group_config.options.custom_response_headers, null)
connection_draining_timeout_sec = try(each.value.group_config.options.connection_draining_timeout_sec, null)
load_balancing_scheme = try(each.value.group_config.options.load_balancing_scheme, null)
locality_lb_policy = try(each.value.group_config.options.locality_lb_policy, null)
port_name = try(each.value.group_config.options.port_name, null)
protocol = try(each.value.group_config.options.protocol, null)
security_policy = try(each.value.group_config.options.security_policy, null)
session_affinity = try(each.value.group_config.options.session_affinity, null)
timeout_sec = try(each.value.group_config.options.timeout_sec, null)
# If no health checks are defined, use the default one.
# Otherwise, look in the health_checks_config map.
# Otherwise, use the health_check id as is (already existing).
health_checks = (
try(length(each.value.group_config.health_checks), 0) == 0
? try(
[google_compute_health_check.health_check["default"].id],
null
)
: [
for hc in each.value.group_config.health_checks :
try(google_compute_health_check.health_check[hc].id, hc)
]
)
dynamic "backend" {
for_each = try(each.value.group_config.backends, [])
content {
balancing_mode = try(backend.value.options.balancing_mode, null)
capacity_scaler = try(backend.value.options.capacity_scaler, null)
group = try(backend.value.group, null)
max_connections = try(backend.value.options.max_connections, null)
max_connections_per_instance = try(backend.value.options.max_connections_per_instance, null)
max_connections_per_endpoint = try(backend.value.options.max_connections_per_endpoint, null)
max_rate = try(backend.value.options.max_rate, null)
max_rate_per_instance = try(backend.value.options.max_rate_per_instance, null)
max_rate_per_endpoint = try(backend.value.options.max_rate_per_endpoint, null)
max_utilization = try(backend.value.options.max_utilization, null)
}
}
dynamic "circuit_breakers" {
for_each = (
try(each.value.group_config.options.circuit_breakers, null) == null
? []
: [each.value.group_config.options.circuit_breakers]
)
iterator = cb
content {
max_requests_per_connection = try(cb.value.max_requests_per_connection, null)
max_connections = try(cb.value.max_connections, null)
max_pending_requests = try(cb.value.max_pending_requests, null)
max_requests = try(cb.value.max_requests, null)
max_retries = try(cb.value.max_retries, null)
}
}
dynamic "consistent_hash" {
for_each = (
try(each.value.group_config.options.consistent_hash, null) == null
? []
: [each.value.group_config.options.consistent_hash]
)
content {
http_header_name = try(consistent_hash.value.http_header_name, null)
minimum_ring_size = try(consistent_hash.value.minimum_ring_size, null)
dynamic "http_cookie" {
for_each = try(consistent_hash.value.http_cookie, null) == null ? [] : [consistent_hash.value.http_cookie]
content {
name = try(http_cookie.value.name, null)
path = try(http_cookie.value.path, null)
dynamic "ttl" {
for_each = try(consistent_hash.value.ttl, null) == null ? [] : [consistent_hash.value.ttl]
content {
seconds = try(ttl.value.seconds, null) # Must be from 0 to 315,576,000,000 inclusive
nanos = try(ttl.value.nanos, null) # Must be from 0 to 999,999,999 inclusive
}
}
}
}
}
}
dynamic "cdn_policy" {
for_each = (
try(each.value.cdn_policy, null) == null
? []
: [each.value.cdn_policy]
)
iterator = cdn_policy
content {
signed_url_cache_max_age_sec = try(cdn_policy.value.signed_url_cache_max_age_sec, null)
default_ttl = try(cdn_policy.value.default_ttl, null)
max_ttl = try(cdn_policy.value.max_ttl, null)
client_ttl = try(cdn_policy.value.client_ttl, null)
negative_caching = try(cdn_policy.value.negative_caching, null)
cache_mode = try(cdn_policy.value.cache_mode, null)
serve_while_stale = try(cdn_policy.value.serve_while_stale, null)
dynamic "negative_caching_policy" {
for_each = (
try(cdn_policy.value.negative_caching_policy, null) == null
? []
: [cdn_policy.value.negative_caching_policy]
)
iterator = ncp
content {
code = try(ncp.value.code, null)
ttl = try(ncp.value.ttl, null)
}
}
}
}
dynamic "iap" {
for_each = (
try(each.value.group_config.options.iap, null) == null
? []
: [each.value.group_config.options.iap]
)
content {
oauth2_client_id = try(iap.value.oauth2_client_id, null)
oauth2_client_secret = try(iap.value.oauth2_client_secret, null) # sensitive
oauth2_client_secret_sha256 = try(iap.value.oauth2_client_secret_sha256, null) # sensitive
}
}
dynamic "log_config" {
for_each = (
try(each.value.group_config.log_config, null) == null
? []
: [each.value.group_config.log_config]
)
content {
enable = try(log_config.value.enable, null)
sample_rate = try(log_config.value.sample_rate, null)
}
}
}

View File

@ -0,0 +1,98 @@
/**
* Copyright 2022 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 groups and backend buckets resources.
resource "google_compute_backend_bucket" "default" {
for_each = var.backend_buckets_config
project = var.project_id
name = "${var.name}-${each.key}"
bucket_name = each.value.bucket_name
compression_mode = each.value.compression_mode
custom_response_headers = each.value.custom_response_headers
description = each.value.description
edge_security_policy = each.value.edge_security_policy
enable_cdn = each.value.enable_cdn
dynamic "cdn_policy" {
for_each = each.value.cdn_policy == null ? [] : [each.value.cdn_policy]
iterator = p
content {
cache_mode = p.value.cache_mode
client_ttl = p.value.client_ttl
default_ttl = p.value.default_ttl
max_ttl = p.value.max_ttl
negative_caching = p.value.negative_caching
request_coalescing = p.value.request_coalescing
serve_while_stale = p.value.serve_while_stale
signed_url_cache_max_age_sec = p.value.signed_url_cache_max_age_sec
dynamic "bypass_cache_on_request_headers" {
for_each = (
p.value.bypass_cache_on_request_headers == null
? []
: [p.value.bypass_cache_on_request_headers]
)
iterator = h
content {
header_name = h.value
}
}
dynamic "cache_key_policy" {
for_each = (
p.value.cache_key_policy == null ? [] : [p.value.cache_key_policy]
)
iterator = ckp
content {
include_http_headers = ckp.value.include_http_headers
query_string_whitelist = ckp.value.query_string_whitelist
}
}
dynamic "negative_caching_policy" {
for_each = (
p.value.negative_caching_policy == null
? []
: [p.value.negative_caching_policy]
)
iterator = ncp
content {
code = ncp.value.code
ttl = ncp.value.ttl
}
}
}
}
}
resource "google_compute_instance_group" "default" {
for_each = var.group_configs
project = (
each.value.project_id == null
? var.project_id
: each.value.project_id
)
zone = each.value.zone
name = "${var.name}-${each.key}"
description = var.description
instances = each.value.instances
dynamic "named_port" {
for_each = each.value.named_ports
content {
name = named_port.key
port = named_port.value
}
}
}

View File

@ -1,57 +0,0 @@
/**
* Copyright 2022 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 Global address and forwarding rule.
locals {
ip_address = var.region == null ? (
var.region == null && var.reserve_ip_address
? google_compute_global_address.static_ip.0.id
: null
) : null
port_range = coalesce(
var.global_forwarding_rule_config.port_range,
var.https ? "443" : "80"
)
target = var.region == null ? (
var.https
? google_compute_target_https_proxy.https.0.id
: google_compute_target_http_proxy.http.0.id
) : null
}
resource "google_compute_global_address" "static_ip" {
count = var.region == null && var.reserve_ip_address ? 1 : 0
provider = google-beta
name = var.name
project = var.project_id
description = "Terraform managed."
}
resource "google_compute_global_forwarding_rule" "forwarding_rule" {
count = var.region == null ? 1 : 0
provider = google-beta
name = var.name
project = var.project_id
description = "Terraform managed."
ip_protocol = var.global_forwarding_rule_config.ip_protocol
load_balancing_scheme = var.global_forwarding_rule_config.load_balancing_scheme
port_range = local.port_range
target = local.target
ip_address = local.ip_address
}

View File

@ -0,0 +1,113 @@
/**
* Copyright 2022 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.
resource "google_compute_health_check" "default" {
provider = google-beta
for_each = var.health_check_configs
project = (
each.value.project_id == null
? var.project_id
: each.value.project_id
)
name = "${var.name}-${each.key}"
description = each.value.description
check_interval_sec = each.value.check_interval_sec
healthy_threshold = each.value.healthy_threshold
timeout_sec = each.value.timeout_sec
unhealthy_threshold = each.value.unhealthy_threshold
dynamic "grpc_health_check" {
for_each = try(each.value.grpc, null) != null ? [""] : []
content {
port = each.value.grpc.port
port_name = each.value.grpc.port_name
port_specification = each.value.grpc.port_specification
grpc_service_name = each.value.grpc.service_name
}
}
dynamic "http_health_check" {
for_each = try(each.value.http, null) != null ? [""] : []
content {
host = each.value.http.host
port = each.value.http.port
port_name = each.value.http.port_name
port_specification = each.value.http.port_specification
proxy_header = each.value.http.proxy_header
request_path = each.value.http.request_path
response = each.value.http.response
}
}
dynamic "http2_health_check" {
for_each = try(each.value.http2, null) != null ? [""] : []
content {
host = each.value.http2.host
port = each.value.http2.port
port_name = each.value.http2.port_name
port_specification = each.value.http2.port_specification
proxy_header = each.value.http2.proxy_header
request_path = each.value.http2.request_path
response = each.value.http2.response
}
}
dynamic "https_health_check" {
for_each = try(each.value.https, null) != null ? [""] : []
content {
host = each.value.https.host
port = each.value.https.port
port_name = each.value.https.port_name
port_specification = each.value.https.port_specification
proxy_header = each.value.https.proxy_header
request_path = each.value.https.request_path
response = each.value.https.response
}
}
dynamic "ssl_health_check" {
for_each = try(each.value.ssl, null) != null ? [""] : []
content {
port = each.value.ssl.port
port_name = each.value.ssl.port_name
port_specification = each.value.ssl.port_specification
proxy_header = each.value.ssl.proxy_header
request = each.value.ssl.request
response = each.value.ssl.response
}
}
dynamic "tcp_health_check" {
for_each = try(each.value.tcp, null) != null ? [""] : []
content {
port = each.value.tcp.port
port_name = each.value.tcp.port_name
port_specification = each.value.tcp.port_specification
proxy_header = each.value.tcp.proxy_header
request = each.value.tcp.request
response = each.value.tcp.response
}
}
dynamic "log_config" {
for_each = try(each.value.enable_logging, null) == true ? [""] : []
content {
enable = true
}
}
}

View File

@ -1,253 +0,0 @@
/**
* Copyright 2022 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 checks.
locals {
# Get group backend services without health checks defined
_backends_without_hcs = [
for k, v in coalesce(var.backend_services_config, {}) :
v if(
v.group_config != null
&& (
try(v.group_config.health_checks, null) == null
|| length(try(v.group_config.health_checks, [])) == 0
)
)
]
health_checks_config_defaults = (
try(var.health_checks_config_defaults, null) == null
? null
: { default = var.health_checks_config_defaults }
)
# If at least one group backend service without HC is defined,
# create also a default HC (if default HC is not null)
health_checks_config = (
length(local._backends_without_hcs) > 0
? merge(
coalesce(local.health_checks_config_defaults, {}),
coalesce(var.health_checks_config, {})
)
: coalesce(var.health_checks_config, {})
)
}
resource "google_compute_health_check" "health_check" {
for_each = var.region == null ? local.health_checks_config : {}
provider = google-beta
name = "${var.name}-${each.key}"
project = var.project_id
description = "Terraform managed."
check_interval_sec = try(each.value.options.check_interval_sec, null)
healthy_threshold = try(each.value.options.healthy_threshold, null)
timeout_sec = try(each.value.options.timeout_sec, null)
unhealthy_threshold = try(each.value.options.unhealthy_threshold, null)
dynamic "http_health_check" {
for_each = (
try(each.value.type, null) == "http" || try(each.value.type, null) == null
? { 1 = 1 }
: {}
)
content {
host = try(each.value.check.host, null)
port = try(each.value.check.port, null)
port_name = try(each.value.check.port_name, null)
port_specification = try(each.value.check.port_specification, null)
proxy_header = try(each.value.check.proxy_header, null)
request_path = try(each.value.check.request_path, null)
response = try(each.value.check.response, null)
}
}
dynamic "https_health_check" {
for_each = (
try(each.value.type, null) == "https" || try(each.value.type, null) == null
? { 1 = 1 }
: {}
)
content {
host = try(each.value.check.host, null)
port = try(each.value.check.port, null)
port_name = try(each.value.check.port_name, null)
port_specification = try(each.value.check.port_specification, null)
proxy_header = try(each.value.check.proxy_header, null)
request_path = try(each.value.check.request_path, null)
response = try(each.value.check.response, null)
}
}
dynamic "tcp_health_check" {
for_each = (
try(each.value.type, null) == "tcp" || try(each.value.type, null) == null
? { 1 = 1 }
: {}
)
content {
port = try(each.value.check.port, null)
port_name = try(each.value.check.port_name, null)
port_specification = try(each.value.check.port_specification, null)
proxy_header = try(each.value.check.proxy_header, null)
request = try(each.value.check.request, null)
response = try(each.value.check.response, null)
}
}
dynamic "ssl_health_check" {
for_each = (
try(each.value.type, null) == "ssl" || try(each.value.type, null) == null
? { 1 = 1 }
: {}
)
content {
port = try(each.value.check.port, null)
port_name = try(each.value.check.port_name, null)
port_specification = try(each.value.check.port_specification, null)
proxy_header = try(each.value.check.proxy_header, null)
request = try(each.value.check.request, null)
response = try(each.value.check.response, null)
}
}
dynamic "http2_health_check" {
for_each = (
try(each.value.type, null) == "http2" || try(each.value.type, null) == null
? { 1 = 1 }
: {}
)
content {
host = try(each.value.check.host, null)
port = try(each.value.check.port, null)
port_name = try(each.value.check.port_name, null)
port_specification = try(each.value.check.port_specification, null)
proxy_header = try(each.value.check.proxy_header, null)
request_path = try(each.value.check.request_path, null)
response = try(each.value.check.response, null)
}
}
dynamic "log_config" {
for_each = try(each.value.logging, false) ? { 0 = 0 } : {}
content {
enable = true
}
}
}
resource "google_compute_region_health_check" "health_check" {
for_each = var.region != null ? local.health_checks_config : {}
provider = google-beta
name = "${var.name}-${each.key}"
project = var.project_id
region = var.region
description = "Terraform managed."
check_interval_sec = try(each.value.options.check_interval_sec, null)
healthy_threshold = try(each.value.options.healthy_threshold, null)
timeout_sec = try(each.value.options.timeout_sec, null)
unhealthy_threshold = try(each.value.options.unhealthy_threshold, null)
dynamic "http_health_check" {
for_each = (
try(each.value.type, null) == "http" || try(each.value.type, null) == null
? { 1 = 1 }
: {}
)
content {
host = try(each.value.check.host, null)
port = try(each.value.check.port, null)
port_name = try(each.value.check.port_name, null)
port_specification = try(each.value.check.port_specification, null)
proxy_header = try(each.value.check.proxy_header, null)
request_path = try(each.value.check.request_path, null)
response = try(each.value.check.response, null)
}
}
dynamic "https_health_check" {
for_each = (
try(each.value.type, null) == "https" || try(each.value.type, null) == null
? { 1 = 1 }
: {}
)
content {
host = try(each.value.check.host, null)
port = try(each.value.check.port, null)
port_name = try(each.value.check.port_name, null)
port_specification = try(each.value.check.port_specification, null)
proxy_header = try(each.value.check.proxy_header, null)
request_path = try(each.value.check.request_path, null)
response = try(each.value.check.response, null)
}
}
dynamic "tcp_health_check" {
for_each = (
try(each.value.type, null) == "tcp" || try(each.value.type, null) == null
? { 1 = 1 }
: {}
)
content {
port = try(each.value.check.port, null)
port_name = try(each.value.check.port_name, null)
port_specification = try(each.value.check.port_specification, null)
proxy_header = try(each.value.check.proxy_header, null)
request = try(each.value.check.request, null)
response = try(each.value.check.response, null)
}
}
dynamic "ssl_health_check" {
for_each = (
try(each.value.type, null) == "ssl" || try(each.value.type, null) == null
? { 1 = 1 }
: {}
)
content {
port = try(each.value.check.port, null)
port_name = try(each.value.check.port_name, null)
port_specification = try(each.value.check.port_specification, null)
proxy_header = try(each.value.check.proxy_header, null)
request = try(each.value.check.request, null)
response = try(each.value.check.response, null)
}
}
dynamic "http2_health_check" {
for_each = (
try(each.value.type, null) == "http2" || try(each.value.type, null) == null
? { 1 = 1 }
: {}
)
content {
host = try(each.value.check.host, null)
port = try(each.value.check.port, null)
port_name = try(each.value.check.port_name, null)
port_specification = try(each.value.check.port_specification, null)
proxy_header = try(each.value.check.proxy_header, null)
request_path = try(each.value.check.request_path, null)
response = try(each.value.check.response, null)
}
}
dynamic "log_config" {
for_each = try(each.value.logging, false) ? { 0 = 0 } : {}
content {
enable = true
}
}
}

91
modules/net-glb/main.tf Normal file
View File

@ -0,0 +1,91 @@
/**
* Copyright 2022 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 {
fwd_rule_ports = (
var.protocol == "HTTPS" ? [443] : coalesce(var.ports, [80])
)
fwd_rule_target = (
var.protocol == "HTTPS"
? google_compute_target_https_proxy.default.0.id
: google_compute_target_http_proxy.default.0.id
)
proxy_ssl_certificates = concat(
coalesce(var.ssl_certificates.certificate_ids, []),
[for k, v in google_compute_ssl_certificate.default : v.id],
[for k, v in google_compute_managed_ssl_certificate.default : v.id]
)
}
resource "google_compute_global_forwarding_rule" "default" {
provider = google-beta
project = var.project_id
name = var.name
description = var.description
ip_address = var.address
ip_protocol = "TCP"
load_balancing_scheme = (
var.use_classic_version ? "EXTERNAL" : "EXTERNAL_MANAGED"
)
port_range = join(",", local.fwd_rule_ports)
labels = var.labels
target = local.fwd_rule_target
}
# certificates
resource "google_compute_ssl_certificate" "default" {
for_each = var.ssl_certificates.create_configs
project = var.project_id
name = "${var.name}-${each.key}"
certificate = trimspace(each.value.certificate)
private_key = trimspace(each.value.private_key)
}
resource "google_compute_managed_ssl_certificate" "default" {
for_each = var.ssl_certificates.managed_configs
project = var.project_id
name = "${var.name}-${each.key}"
description = each.value.description
managed {
domains = each.value.domains
}
lifecycle {
create_before_destroy = true
}
}
# proxies
resource "google_compute_target_http_proxy" "default" {
count = var.protocol == "HTTPS" ? 0 : 1
project = var.project_id
name = var.name
description = var.description
url_map = google_compute_url_map.default.id
}
resource "google_compute_target_https_proxy" "default" {
count = var.protocol == "HTTPS" ? 1 : 0
project = var.project_id
name = var.name
description = var.description
certificate_map = var.https_proxy_config.certificate_map
quic_override = var.https_proxy_config.quic_override
ssl_certificates = local.proxy_ssl_certificates
ssl_policy = var.https_proxy_config.ssl_policy
url_map = google_compute_url_map.default.id
}

159
modules/net-glb/negs.tf Normal file
View File

@ -0,0 +1,159 @@
/**
* Copyright 2022 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 NEG resources.
locals {
_neg_endpoints_global = flatten([
for k, v in local.neg_global : [
for vv in v.internet.endpoints :
merge(vv, { neg = k, use_fqdn = v.internet.use_fqdn })
]
])
_neg_endpoints_zonal = flatten([
for k, v in local.neg_zonal : [
for vv in v.endpoints :
merge(vv, { neg = k, zone = v.zone })
]
])
neg_endpoints_global = {
for v in local._neg_endpoints_global :
"${v.neg}-${v.destination}-${coalesce(v.port, "none")}" => v
}
neg_endpoints_zonal = {
for v in local._neg_endpoints_zonal :
"${v.neg}-${v.ip_address}-${coalesce(v.port, "none")}" => v
}
neg_global = {
for k, v in var.neg_configs :
k => v if v.internet != null
}
neg_regional_psc = {
for k, v in var.neg_configs :
k => v if v.psc != null
}
neg_regional_serverless = {
for k, v in var.neg_configs :
k => v if v.cloudrun != null || v.cloudfunction != null
}
neg_zonal = {
# we need to rebuild new objects as we cannot merge different types
for k, v in var.neg_configs : k => {
description = v.description
endpoints = v.gce != null ? v.gce.endpoints : v.hybrid.endpoints
network = v.gce != null ? v.gce.network : v.hybrid.network
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
}
}
resource "google_compute_global_network_endpoint_group" "default" {
for_each = local.neg_global
project = var.project_id
name = "${var.name}-${each.key}"
# re-enable once provider properly supports this
# default_port = each.value.default_port
description = coalesce(each.value.description, var.description)
network_endpoint_type = (
each.value.internet.use_fqdn ? "INTERNET_FQDN_PORT" : "INTERNET_IP_PORT"
)
}
resource "google_compute_global_network_endpoint" "default" {
for_each = local.neg_endpoints_global
project = (
google_compute_global_network_endpoint_group.default[each.value.neg].project
)
global_network_endpoint_group = (
google_compute_global_network_endpoint_group.default[each.value.neg].name
)
fqdn = each.value.use_fqdn ? each.value.destination : null
ip_address = each.value.use_fqdn ? null : each.value.destination
port = each.value.port
}
resource "google_compute_network_endpoint_group" "default" {
for_each = local.neg_zonal
project = var.project_id
zone = each.value.zone
name = "${var.name}-${each.key}"
# re-enable once provider properly supports this
# default_port = each.value.default_port
description = coalesce(each.value.description, var.description)
network_endpoint_type = each.value.type
network = each.value.network
subnetwork = (
each.value.type == "NON_GCP_PRIVATE_IP_PORT"
? null
: each.value.subnetwork
)
}
resource "google_compute_network_endpoint" "default" {
for_each = local.neg_endpoints_zonal
project = (
google_compute_network_endpoint_group.default[each.value.neg].project
)
network_endpoint_group = (
google_compute_network_endpoint_group.default[each.value.neg].name
)
instance = try(each.value.instance, null)
ip_address = each.value.ip_address
port = each.value.port
zone = each.value.zone
}
resource "google_compute_region_network_endpoint_group" "psc" {
for_each = local.neg_regional_psc
project = var.project_id
region = each.value.psc.region
name = "${var.name}-${each.key}"
description = coalesce(each.value.description, var.description)
network_endpoint_type = "PRIVATE_SERVICE_CONNECT"
psc_target_service = each.value.psc.target_service
network = each.value.psc.network
subnetwork = each.value.psc.subnetwork
}
resource "google_compute_region_network_endpoint_group" "serverless" {
for_each = local.neg_regional_serverless
project = var.project_id
region = try(
each.value.cloudrun.region, each.value.cloudfunction.region, null
)
name = "${var.name}-${each.key}"
description = coalesce(each.value.description, var.description)
network_endpoint_type = "SERVERLESS"
dynamic "cloud_function" {
for_each = each.value.cloudfunction == null ? [] : [""]
content {
function = each.value.cloudfunction.target_function
url_mask = each.value.cloudfunction.target_urlmask
}
}
dynamic "cloud_run" {
for_each = each.value.cloudrun == null ? [] : [""]
content {
service = try(each.value.cloudrun.target_service.name, null)
tag = try(each.value.cloudrun.target_service.tag, null)
url_mask = each.value.cloudrun.target_urlmask
}
}
}

View File

@ -14,57 +14,40 @@
* limitations under the License.
*/
output "backend_services" {
output "address" {
description = "Forwarding rule address."
value = google_compute_global_forwarding_rule.default.ip_address
}
output "backend_service_ids" {
description = "Backend service resources."
value = {
bucket = try(google_compute_backend_bucket.bucket, [])
group = try(google_compute_backend_service.group, [])
for k, v in google_compute_backend_service.default : k => v.id
}
}
output "forwarding_rule" {
description = "The regional forwarding rule."
value = var.region == null ? google_compute_global_forwarding_rule.forwarding_rule.0 : google_compute_forwarding_rule.forwarding_rule.0
description = "Forwarding rule resource."
value = google_compute_global_forwarding_rule.default
}
output "global_forwarding_rule" {
description = "The global forwarding rule."
value = var.region == null ? google_compute_global_forwarding_rule.forwarding_rule.0 : null
output "group_ids" {
description = "Autogenerated instance group ids."
value = {
for k, v in google_compute_instance_group.default : k => v.id
}
}
output "health_checks" {
description = "Health-check resources."
value = try(google_compute_health_check.health_check, [])
output "health_check_ids" {
description = "Autogenerated health check ids."
value = {
for k, v in google_compute_health_check.default : k => v.id
}
}
output "ip_address" {
description = "The reserved global IP address."
value = var.region == null ? try(google_compute_global_address.static_ip.0.address, null) : try(google_compute_address.static_ip.0.address, null)
}
output "ip_address_self_link" {
description = "The URI of the reserved global IP address."
value = var.region == null ? google_compute_global_forwarding_rule.forwarding_rule.0.ip_address : google_compute_forwarding_rule.forwarding_rule.0.ip_address
}
output "ssl_certificates" {
description = "The SSL certificate."
value = try(
google_compute_managed_ssl_certificate.managed,
google_compute_ssl_certificate.unmanaged,
null
)
}
output "target_proxy" {
description = "The target proxy."
value = try(
google_compute_target_http_proxy.http,
google_compute_target_https_proxy.https
)
}
output "url_map" {
description = "The url-map."
value = google_compute_url_map.url_map
output "neg_ids" {
description = "Autogenerated network endpoint group ids."
value = {
for k, v in google_compute_network_endpoint_group.default : k => v.id
}
}

View File

@ -1,164 +0,0 @@
/**
* Copyright 2022 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 Bucket and group backend services for regional load balancers.
resource "google_compute_region_backend_service" "group" {
for_each = var.region != null ? local.backend_services_group : {}
name = "${var.name}-${each.key}"
project = var.project_id
region = var.region
description = "Terraform managed."
affinity_cookie_ttl_sec = try(each.value.group_config.options.affinity_cookie_ttl_sec, null)
enable_cdn = try(each.value.enable_cdn, null)
connection_draining_timeout_sec = try(each.value.group_config.options.connection_draining_timeout_sec, null)
load_balancing_scheme = try(each.value.group_config.options.load_balancing_scheme, null)
locality_lb_policy = try(each.value.group_config.options.locality_lb_policy, null)
port_name = try(each.value.group_config.options.port_name, null)
protocol = try(each.value.group_config.options.protocol, null)
session_affinity = try(each.value.group_config.options.session_affinity, null)
timeout_sec = try(each.value.group_config.options.timeout_sec, null)
# If no health checks are defined, use the default one.
# Otherwise, look in the health_checks_config map.
# Otherwise, use the health_check id as is (already existing).
health_checks = (
try(length(each.value.group_config.health_checks), 0) == 0
? try(
[google_compute_region_health_check.health_check["default"].id],
null
)
: [
for hc in each.value.group_config.health_checks :
try(google_compute_region_health_check.health_check[hc].id, hc)
]
)
dynamic "backend" {
for_each = try(each.value.group_config.backends, [])
content {
balancing_mode = try(backend.value.options.balancing_mode, null)
capacity_scaler = try(backend.value.options.capacity_scaler, null)
group = try(backend.value.group, null)
max_connections = try(backend.value.options.max_connections, null)
max_connections_per_instance = try(backend.value.options.max_connections_per_instance, null)
max_connections_per_endpoint = try(backend.value.options.max_connections_per_endpoint, null)
max_rate = try(backend.value.options.max_rate, null)
max_rate_per_instance = try(backend.value.options.max_rate_per_instance, null)
max_rate_per_endpoint = try(backend.value.options.max_rate_per_endpoint, null)
max_utilization = try(backend.value.options.max_utilization, null)
}
}
dynamic "circuit_breakers" {
for_each = (
try(each.value.group_config.options.circuit_breakers, null) == null
? []
: [each.value.group_config.options.circuit_breakers]
)
iterator = cb
content {
max_requests_per_connection = try(cb.value.max_requests_per_connection, null)
max_connections = try(cb.value.max_connections, null)
max_pending_requests = try(cb.value.max_pending_requests, null)
max_requests = try(cb.value.max_requests, null)
max_retries = try(cb.value.max_retries, null)
}
}
dynamic "consistent_hash" {
for_each = (
try(each.value.group_config.options.consistent_hash, null) == null
? []
: [each.value.group_config.options.consistent_hash]
)
content {
http_header_name = try(consistent_hash.value.http_header_name, null)
minimum_ring_size = try(consistent_hash.value.minimum_ring_size, null)
dynamic "http_cookie" {
for_each = try(consistent_hash.value.http_cookie, null) == null ? [] : [consistent_hash.value.http_cookie]
content {
name = try(http_cookie.value.name, null)
path = try(http_cookie.value.path, null)
dynamic "ttl" {
for_each = try(consistent_hash.value.ttl, null) == null ? [] : [consistent_hash.value.ttl]
content {
seconds = try(ttl.value.seconds, null) # Must be from 0 to 315,576,000,000 inclusive
nanos = try(ttl.value.nanos, null) # Must be from 0 to 999,999,999 inclusive
}
}
}
}
}
}
dynamic "cdn_policy" {
for_each = (
try(each.value.cdn_policy, null) == null
? []
: [each.value.cdn_policy]
)
iterator = cdn_policy
content {
signed_url_cache_max_age_sec = try(cdn_policy.value.signed_url_cache_max_age_sec, null)
default_ttl = try(cdn_policy.value.default_ttl, null)
max_ttl = try(cdn_policy.value.max_ttl, null)
client_ttl = try(cdn_policy.value.client_ttl, null)
negative_caching = try(cdn_policy.value.negative_caching, null)
cache_mode = try(cdn_policy.value.cache_mode, null)
serve_while_stale = try(cdn_policy.value.serve_while_stale, null)
dynamic "negative_caching_policy" {
for_each = (
try(cdn_policy.value.negative_caching_policy, null) == null
? []
: [cdn_policy.value.negative_caching_policy]
)
iterator = ncp
content {
code = try(ncp.value.code, null)
}
}
}
}
dynamic "iap" {
for_each = (
try(each.value.group_config.options.iap, null) == null
? []
: [each.value.group_config.options.iap]
)
content {
oauth2_client_id = try(iap.value.oauth2_client_id, null)
oauth2_client_secret = try(iap.value.oauth2_client_secret, null) # sensitive
oauth2_client_secret_sha256 = try(iap.value.oauth2_client_secret_sha256, null) # sensitive
}
}
dynamic "log_config" {
for_each = (
try(each.value.group_config.log_config, null) == null
? []
: [each.value.group_config.log_config]
)
content {
enable = try(log_config.value.enable, null)
sample_rate = try(log_config.value.sample_rate, null)
}
}
}

View File

@ -1,62 +0,0 @@
/**
* Copyright 2022 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 Global address and forwarding rule.
locals {
regional_ip_address = var.region != null ? (
var.reserve_ip_address
? google_compute_address.static_ip.0.id
: null
) : null
regional_port_range = coalesce(
var.forwarding_rule_config.port_range,
var.https ? "443" : "80"
)
regional_target = var.region != null ? (
var.https
? google_compute_region_target_https_proxy.https.0.id
: google_compute_region_target_http_proxy.http.0.id
) : null
}
resource "google_compute_address" "static_ip" {
count = var.region != null && var.reserve_ip_address ? 1 : 0
provider = google-beta
name = var.name
project = var.project_id
region = var.region
description = "Terraform managed."
address_type = "EXTERNAL"
}
resource "google_compute_forwarding_rule" "forwarding_rule" {
count = var.region != null ? 1 : 0
provider = google-beta
name = var.name
project = var.project_id
region = var.region
description = "Terraform managed."
ip_protocol = var.forwarding_rule_config.ip_protocol
load_balancing_scheme = var.forwarding_rule_config.load_balancing_scheme
port_range = local.regional_port_range
target = local.regional_target
ip_address = local.regional_ip_address
network_tier = var.forwarding_rule_config.network_tier
network = var.forwarding_rule_config.network
}

View File

@ -1,717 +0,0 @@
/**
* Copyright 2022 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 regional URL maps.
locals {
# Look for a backend services in the config whose id is
# the default_service given in the url-map.
# If not found, use the default_service id as given
# (assuming it's already existing).
# If the variable is null, will be set to null.
_regional_default_service = try(
google_compute_backend_bucket.bucket[var.url_map_config.default_service].id,
google_compute_region_backend_service.group[var.url_map_config.default_service].id,
var.url_map_config.default_service,
null
)
# If no backend services are specified,
# the first backend service defined is associated
regional_default_service = (
try(local._regional_default_service, null) == null
&& try(var.url_map_config.default_route_action.weighted_backend_services, null) == null
&& try(var.url_map_config.default_url_redirect, null) == null
? try(
google_compute_backend_bucket.bucket[keys(google_compute_backend_bucket.bucket)[0]].id,
google_compute_region_backend_service.group[keys(google_compute_region_backend_service.group)[0]].id,
null
)
: null
)
}
resource "google_compute_region_url_map" "url_map" {
count = var.region != null ? 1 : 0
name = var.name
description = "Terraform managed."
project = var.project_id
region = var.region
default_service = local.regional_default_service
dynamic "host_rule" {
for_each = (
try(var.url_map_config.host_rules, null) == null
? []
: var.url_map_config.host_rules
)
content {
description = try(host_rule.value.description, null)
hosts = try(host_rule.value.hosts, null)
path_matcher = try(host_rule.value.path_matcher, null)
}
}
dynamic "path_matcher" {
for_each = (
try(var.url_map_config.path_matchers, null) == null
? []
: var.url_map_config.path_matchers
)
content {
name = try(path_matcher.value.name, null)
description = try(path_matcher.value.description, null)
default_service = try(
google_compute_backend_bucket.bucket[var.url_map_config.default_service].id,
google_compute_region_backend_service.group[var.url_map_config.default_service].id,
path_matcher.value.default_service,
null
)
dynamic "path_rule" {
for_each = (
try(path_matcher.value.path_rules, null) == null
? []
: path_matcher.value.path_rules
)
content {
paths = try(path_rule.value.paths, null)
service = try(
google_compute_backend_bucket.bucket[path_rule.value.service].id,
google_compute_region_backend_service.group[path_rule.value.service].id,
path_rule.value.service,
null
)
dynamic "route_action" {
for_each = (
try(path_rule.value.route_action, null) == null
? []
: [path_rule.value.route_action]
)
content {
dynamic "cors_policy" {
for_each = (
try(route_action.value.cors_policy, null) == null
? []
: [route_action.value.cors_policy]
)
content {
allow_credentials = try(cors_policy.value.allow_credentials, null)
allow_headers = try(cors_policy.value.allow_headers, null)
allow_methods = try(cors_policy.value.allow_methods, null)
allow_origin_regexes = try(cors_policy.value.allow_origin_regexes, null)
allow_origins = try(cors_policy.value.allow_origins, null)
disabled = try(cors_policy.value.disabled, null)
expose_headers = try(cors_policy.value.expose_headers, null)
max_age = try(cors_policy.value.max_age, null)
}
}
dynamic "fault_injection_policy" {
for_each = (
try(route_action.value.fault_injection_policy, null) == null
? []
: [route_action.value.fault_injection_policy]
)
iterator = policy
content {
dynamic "abort" {
for_each = (
try(policy.value.abort, null) == null
? []
: [policy.value.abort]
)
content {
http_status = try(abort.value.http_status, null) # Must be between 200 and 599 inclusive
percentage = try(abort.value.percentage, null) # Must be between 0.0 and 100.0 inclusive
}
}
dynamic "delay" {
for_each = (
try(policy.value.delay, null) == null
? []
: [policy.value.delay]
)
content {
percentage = try(delay.value.percentage, null) # Must be between 0.0 and 100.0 inclusive
dynamic "fixed_delay" {
for_each = (
try(delay.value.fixed_delay, null) == null
? []
: [delay.value.fixed_delay]
)
content {
nanos = try(fixed_delay.value.nanos, null) # Must be from 0 to 999,999,999 inclusive
seconds = try(fixed_delay.value.seconds, null) # Must be from 0 to 315,576,000,000 inclusive
}
}
}
}
}
}
dynamic "request_mirror_policy" {
for_each = (
try(route_action.value.request_mirror_policy, null) == null
? []
: [route_action.value.request_mirror_policy]
)
iterator = policy
content {
backend_service = try(
google_compute_backend_bucket.bucket[policy.value.backend_service].id,
google_compute_region_backend_service.group[policy.value.backend_service].id,
policy.value.backend_service,
null
)
}
}
dynamic "retry_policy" {
for_each = (
try(route_action.value.retry_policy, null) == null
? []
: [route_action.value.retry_policy]
)
iterator = policy
content {
num_retries = try(policy.num_retries, null) # Must be > 0
# Valid values at https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_url_map#retry_conditions
retry_conditions = try(policy.retry_conditions, null)
dynamic "per_try_timeout" {
for_each = (
try(policy.value.per_try_timeout, null) == null
? []
: [policy.value.per_try_timeout]
)
iterator = timeout
content {
nanos = try(timeout.value.nanos, null) # Must be from 0 to 999,999,999 inclusive
seconds = try(timeout.value.seconds, null) # Must be from 0 to 315,576,000,000 inclusive
}
}
}
}
dynamic "timeout" {
for_each = (
try(route_action.value.timeout, null) == null
? []
: [route_action.value.timeout]
)
content {
nanos = try(timeout.value.nanos, null) # Must be from 0 to 999,999,999 inclusive
seconds = try(timeout.value.seconds, null) # Must be from 0 to 315,576,000,000 inclusive
}
}
dynamic "url_rewrite" {
for_each = (
try(route_action.value.url_rewrite, null) == null
? []
: [route_action.value.url_rewrite]
)
content {
host_rewrite = try(url_rewrite.value.host_rewrite, null) # Must be between 1 and 255 characters
path_prefix_rewrite = try(url_rewrite.value.path_prefix_rewrite, null) # Must be between 1 and 1024 characters
}
}
dynamic "weighted_backend_services" {
for_each = (
try(route_action.value.weighted_backend_services, null) == null
? []
: route_action.value.weighted_backend_services
)
iterator = weighted
content {
weight = try(weighted.value.weigth, null)
backend_service = try(
google_compute_backend_bucket.bucket[weighted.value.backend_service].id,
google_compute_backend_service.group[weighted.value.backend_service].id,
policy.value.backend_service,
null
)
dynamic "header_action" {
for_each = (
try(path_matcher.value.header_action, null) == null
? []
: [path_matcher.value.header_action]
)
content {
request_headers_to_remove = try(header_action.value.request_headers_to_remove, null)
response_headers_to_remove = try(header_action.value.response_headers_to_remove, null)
dynamic "request_headers_to_add" {
for_each = (
try(header_action.value.request_headers_to_add, null) == null
? [] :
[header_action.value.request_headers_to_add]
)
content {
header_name = try(request_headers_to_add.value.header_name, null)
header_value = try(request_headers_to_add.value.header_value, null)
replace = try(request_headers_to_add.value.replace, null)
}
}
dynamic "response_headers_to_add" {
for_each = (
try(header_action.response_headers_to_add, null) == null
? []
: [header_action.response_headers_to_add]
)
content {
header_name = try(response_headers_to_add.value.header_name, null)
header_value = try(response_headers_to_add.value.header_value, null)
replace = try(response_headers_to_add.value.replace, null)
}
}
}
}
}
}
}
}
dynamic "url_redirect" {
for_each = (
try(path_rule.value.url_redirect, null) == null
? []
: path_rule.value.url_redirect
)
content {
host_redirect = try(url_redirect.value.host_redirect, null) # Must be between 1 and 255 characters
https_redirect = try(url_redirect.value.https_redirect, null)
path_redirect = try(url_redirect.value.path_redirect, null)
prefix_redirect = try(url_redirect.value.prefix_redirect, null) # Must be between 1 and 1024 characters
# Valid valus at https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_url_map#redirect_response_code
redirect_response_code = try(url_redirect.value.redirect_response_code, null)
strip_query = try(url_redirect.value.strip_query, null)
}
}
}
}
dynamic "route_rules" {
for_each = (
try(path_matcher.value.route_rules, null) == null
? []
: path_matcher.value.route_rules
)
content {
priority = try(route_rules.value.priority, null)
service = try(
google_compute_backend_bucket.bucket[route_rules.value.service].id,
google_compute_backend_service.group[route_rules.value.service].id,
route_rules.value.service,
null
)
dynamic "header_action" {
for_each = (
try(path_matcher.value.header_action, null) == null
? []
: [path_matcher.value.header_action]
)
content {
request_headers_to_remove = try(header_action.value.request_headers_to_remove, null)
response_headers_to_remove = try(header_action.value.response_headers_to_remove, null)
dynamic "request_headers_to_add" {
for_each = (
try(header_action.value.request_headers_to_add, null) == null
? []
: [header_action.value.request_headers_to_add]
)
content {
header_name = try(request_headers_to_add.value.header_name, null)
header_value = try(request_headers_to_add.value.header_value, null)
replace = try(request_headers_to_add.value.replace, null)
}
}
dynamic "response_headers_to_add" {
for_each = (
try(header_action.response_headers_to_add, null) == null
? []
: [header_action.response_headers_to_add]
)
content {
header_name = try(response_headers_to_add.value.header_name, null)
header_value = try(response_headers_to_add.value.header_value, null)
replace = try(response_headers_to_add.value.replace, null)
}
}
}
}
dynamic "match_rules" {
for_each = (
try(path_matcher.value.match_rules, null) == null
? []
: path_matcher.value.match_rules
)
content {
full_path_match = try(match_rules.value.full_path_match, null) # Must be between 1 and 1024 characters
ignore_case = try(match_rules.value.ignore_case, null)
prefix_match = try(match_rules.value.prefix_match, null)
regex_match = try(match_rules.value.regex_match, null)
dynamic "header_matches" {
for_each = (
try(match_rules.value.header_matches, null) == null
? []
: [match_rules.value.header_matches]
)
content {
exact_match = try(header_matches.value.exact_match, null)
header_name = try(header_matches.value.header_name, null)
invert_match = try(header_matches.value.invert_match, null)
prefix_match = try(header_matches.value.prefix_match, null)
present_match = try(header_matches.value.present_match, null)
regex_match = try(header_matches.value.regex_match, null)
suffix_match = try(header_matches.value, null)
dynamic "range_match" {
for_each = try(header_matches.value.range_match, null) == null ? [] : [header_matches.value.range_match]
content {
range_end = try(range_match.value.range_end, null)
range_start = try(range_match.value.range_start, null)
}
}
}
}
dynamic "metadata_filters" {
for_each = (
try(match_rules.value.metadata_filters, null) == null
? []
: [match_rules.value.metadata_filters]
)
content {
# Valid values at https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_url_map#filter_match_criteria
filter_match_criteria = try(metadata_filters.value.filter_match_criteria, null)
dynamic "filter_labels" {
for_each = (
try(metadata_filters.value.filter_labels, null) == null
? []
: metadata_filters.value.filter_labels
)
content {
name = try(filter_labels.value.name, null) # Must be between 1 and 1024 characters
value = try(filter_labels.value.value, null) # Must be between 1 and 1024 characters
}
}
}
}
dynamic "query_parameter_matches" {
for_each = (
try(match_rules.value.query_parameter_matches, null) == null
? []
: [match_rules.value.query_parameter_matches]
)
iterator = query
content {
exact_match = try(query.value.exact_match, null)
name = try(query.value.name, null)
present_match = try(query.value.present_match, null)
regex_match = try(query.value.regex_match, null)
}
}
}
}
dynamic "route_action" {
for_each = (
try(route_rules.value.route_action, null) == null
? []
: [route_rules.value.route_action]
)
content {
dynamic "cors_policy" {
for_each = (
try(route_action.value.cors_policy, null) == null
? []
: [route_action.value.cors_policy]
)
content {
allow_credentials = try(cors_policy.value.allow_credentials, null)
allow_headers = try(cors_policy.value.allow_headers, null)
allow_methods = try(cors_policy.value.allow_methods, null)
allow_origin_regexes = try(cors_policy.value.allow_origin_regexes, null)
allow_origins = try(cors_policy.value.allow_origins, null)
disabled = try(cors_policy.value.disabled, null)
expose_headers = try(cors_policy.value.expose_headers, null)
max_age = try(cors_policy.value.max_age, null)
}
}
dynamic "fault_injection_policy" {
for_each = (
try(route_action.value.fault_injection_policy, null) == null
? []
: [route_action.value.fault_injection_policy]
)
iterator = policy
content {
dynamic "abort" {
for_each = (
try(policy.value.abort, null) == null
? []
: [policy.value.abort]
)
content {
http_status = try(abort.value.http_status, null) # Must be between 200 and 599 inclusive
percentage = try(abort.value.percentage, null) # Must be between 0.0 and 100.0 inclusive
}
}
dynamic "delay" {
for_each = (
try(policy.value.delay, null) == null
? []
: [policy.value.delay]
)
content {
percentage = try(delay.value.percentage, null) # Must be between 0.0 and 100.0 inclusive
dynamic "fixed_delay" {
for_each = (
try(delay.value.fixed_delay, null) == null
? []
: [delay.value.fixed_delay]
)
content {
nanos = try(fixed_delay.value.nanos, null) # Must be from 0 to 999,999,999 inclusive
seconds = try(fixed_delay.value.seconds, null) # Must be from 0 to 315,576,000,000 inclusive
}
}
}
}
}
}
dynamic "request_mirror_policy" {
for_each = (
try(route_action.value.request_mirror_policy, null) == null
? []
: [route_action.value.request_mirror_policy]
)
iterator = policy
content {
backend_service = try(
google_compute_backend_bucket.bucket[policy.value.backend_service].id,
google_compute_backend_service.group[policy.value.backend_service].id,
policy.value.backend_service,
null
)
}
}
dynamic "retry_policy" {
for_each = (
try(route_action.value.retry_policy, null) == null
? []
: [route_action.value.retry_policy]
)
iterator = policy
content {
num_retries = try(policy.num_retries, null) # Must be > 0
# Valid values at https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_url_map#retry_conditions
retry_conditions = try(policy.retry_conditions, null)
dynamic "per_try_timeout" {
for_each = (
try(policy.value.per_try_timeout, null) == null
? []
: [policy.value.per_try_timeout]
)
iterator = timeout
content {
nanos = try(timeout.value.nanos, null) # Must be from 0 to 999,999,999 inclusive
seconds = try(timeout.value.seconds, null) # Must be from 0 to 315,576,000,000 inclusive
}
}
}
}
dynamic "timeout" {
for_each = (
try(route_action.value.timeout, null) == null
? []
: [route_action.value.timeout]
)
content {
nanos = try(timeout.value.nanos, null) # Must be from 0 to 999,999,999 inclusive
seconds = try(timeout.value.seconds, null) # Must be from 0 to 315,576,000,000 inclusive
}
}
dynamic "url_rewrite" {
for_each = (
try(route_action.value.url_rewrite, null) == null
? []
: [route_action.value.url_rewrite]
)
content {
host_rewrite = try(url_rewrite.value.host_rewrite, null) # Must be between 1 and 255 characters
path_prefix_rewrite = try(url_rewrite.value.path_prefix_rewrite, null) # Must be between 1 and 1024 characters
}
}
dynamic "weighted_backend_services" {
for_each = (
try(route_action.value.weighted_backend_services, null) == null
? []
: [route_action.value.url_rewrite]
)
iterator = weighted
content {
weight = try(weighted.value.weigth, null)
backend_service = try(
google_compute_backend_bucket.bucket[weighted.value.backend_service].id,
google_compute_backend_service.group[weighted.value.backend_service].id,
weighted.value.backend_service,
null
)
dynamic "header_action" {
for_each = (
try(path_matcher.value.header_action, null) == null
? [] :
[path_matcher.value.header_action]
)
content {
request_headers_to_remove = try(header_action.value.request_headers_to_remove, null)
response_headers_to_remove = try(header_action.value.response_headers_to_remove, null)
dynamic "request_headers_to_add" {
for_each = (
try(header_action.value.request_headers_to_add, null) == null
? []
: [header_action.value.request_headers_to_add]
)
content {
header_name = try(request_headers_to_add.value.header_name, null)
header_value = try(request_headers_to_add.value.header_value, null)
replace = try(request_headers_to_add.value.replace, null)
}
}
dynamic "response_headers_to_add" {
for_each = (
try(header_action.response_headers_to_add, null) == null
? []
: [header_action.response_headers_to_add]
)
content {
header_name = try(response_headers_to_add.value.header_name, null)
header_value = try(response_headers_to_add.value.header_value, null)
replace = try(response_headers_to_add.value.replace, null)
}
}
}
}
}
}
}
}
dynamic "url_redirect" {
for_each = (
try(route_rules.value.url_redirect, null) == null
? []
: route_rules.value.url_redirect
)
content {
host_redirect = try(url_redirect.value.host_redirect, null) # Must be between 1 and 255 characters
https_redirect = try(url_redirect.value.https_redirect, null)
path_redirect = try(url_redirect.value.path_redirect, null)
prefix_redirect = try(url_redirect.value.prefix_redirect, null) # Must be between 1 and 1024 characters
# Valid valus at https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_url_map#redirect_response_code
redirect_response_code = try(url_redirect.value.redirect_response_code, null)
strip_query = try(url_redirect.value.strip_query, null)
}
}
}
}
dynamic "default_url_redirect" {
for_each = (
try(path_matcher.value.default_url_redirect, null) == null
? []
: path_matcher.value.default_url_redirect
)
content {
host_redirect = try(default_url_redirect.value.host_redirect, null) # Must be between 1 and 255 characters
https_redirect = try(default_url_redirect.value.https_redirect, null)
path_redirect = try(default_url_redirect.value.path_redirect, null) # Must be between 1 and 1024 characters
prefix_redirect = try(default_url_redirect.value.prefix_redirect, null) # Must be between 1 and 1024 characters
# Valid values at https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_url_map#redirect_response_code
redirect_response_code = try(default_url_redirect.value.redirect_response_code, null)
strip_query = try(default_url_redirect.value.strip_query, null)
}
}
}
}
# Up to 100 tests per url_map
dynamic "test" {
for_each = (
try(var.url_map_config.tests, null) == null
? []
: var.url_map_config.tests
)
content {
description = try(test.value.description, null)
host = try(test.value.host, null)
path = try(test.value.path, null)
service = try(
google_compute_backend_bucket.bucket[test.value.service].id,
google_compute_backend_service.group[test.value.service].id,
test.value.service,
null
)
}
}
dynamic "default_url_redirect" {
for_each = (
try(var.url_map_config.default_url_redirect, null) == null
? []
: [var.url_map_config.default_url_redirect]
)
content {
host_redirect = try(default_url_redirect.value.host_redirect, null) # Must be between 1 and 255 characters
https_redirect = try(default_url_redirect.value.https_redirect, null)
path_redirect = try(default_url_redirect.value.path_redirect, null) # Must be between 1 and 1024 characters
prefix_redirect = try(default_url_redirect.value.prefix_redirect, null) # Must be between 1 and 1024 characters
# Valid values at https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_url_map#redirect_response_code
redirect_response_code = try(default_url_redirect.value.redirect_response_code, null)
strip_query = try(default_url_redirect.value.strip_query, null)
}
}
}

View File

@ -1,62 +0,0 @@
/**
* Copyright 2022 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 SSL certificates.
locals {
# If the HTTPS target proxy has no SSL certs
# set, create also a default managed SSL cert
ssl_certificates_config = merge(
coalesce(var.ssl_certificates_config, {}),
try(length(var.target_proxy_https_config.ssl_certificates), 0) == 0
? { default = var.ssl_certificates_config_defaults }
: {}
)
ssl_certs_managed = (
var.https
? {
for k, v in coalesce(local.ssl_certificates_config, {}) :
k => v if v.unmanaged_config == null
}
: {}
)
ssl_certs_unmanaged = (
var.https
? {
for k, v in coalesce(local.ssl_certificates_config, {}) :
k => v if v.unmanaged_config != null
}
: {}
)
}
resource "google_compute_managed_ssl_certificate" "managed" {
for_each = local.ssl_certs_managed
project = var.project_id
name = "${var.name}-${each.key}"
managed {
domains = try(each.value.domains, null)
}
}
resource "google_compute_ssl_certificate" "unmanaged" {
for_each = local.ssl_certs_unmanaged
project = var.project_id
name = "${var.name}-${each.key}"
certificate = try(each.value.unmanaged_config.tls_self_signed_cert, null)
private_key = try(each.value.unmanaged_config.tls_private_key, null)
}

View File

@ -1,76 +0,0 @@
/**
* Copyright 2022 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 HTTP and HTTPS target proxies.
locals {
# If no SSL certificates are defined, use the default one.
# Otherwise, look in the ssl_certificates_config map.
# Otherwise, use the SSL certificate id as is (already existing).
ssl_certificates = (
try(var.target_proxy_https_config.ssl_certificates, null) == null
|| length(coalesce(try(var.target_proxy_https_config.ssl_certificates, null), [])) == 0
? try(
[google_compute_managed_ssl_certificate.managed["default"].id],
[google_compute_ssl_certificate.unmanaged["default"].id],
null
)
: [
for cert in try(var.target_proxy_https_config.ssl_certificates, []) :
try(
google_compute_managed_ssl_certificate.managed[cert].id,
google_compute_ssl_certificate.unmanaged[cert].id,
cert
)
]
)
}
resource "google_compute_target_http_proxy" "http" {
count = var.https ? 0 : (var.region == null ? 1 : 0)
name = var.name
project = var.project_id
description = "Terraform managed."
url_map = google_compute_url_map.url_map.0.id
}
resource "google_compute_target_https_proxy" "https" {
count = var.https ? (var.region == null ? 1 : 0) : 0
name = var.name
project = var.project_id
description = "Terraform managed."
url_map = google_compute_url_map.url_map.0.id
ssl_certificates = local.ssl_certificates
}
resource "google_compute_region_target_http_proxy" "http" {
count = var.https ? 0 : (var.region != null ? 1 : 0)
name = var.name
project = var.project_id
region = var.region
description = "Terraform managed."
url_map = google_compute_region_url_map.url_map.0.id
}
resource "google_compute_region_target_https_proxy" "https" {
count = var.https ? (var.region != null ? 1 : 0) : 0
name = var.name
project = var.project_id
region = var.region
description = "Terraform managed."
url_map = google_compute_region_url_map.url_map.0.id
ssl_certificates = local.ssl_certificates
}

File diff suppressed because it is too large Load Diff

952
modules/net-glb/urlmap.tf Normal file
View File

@ -0,0 +1,952 @@
/**
* Copyright 2022 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 URL map resources.
locals {
backend_ids = merge(
{ for k, v in google_compute_backend_service.default : k => v.id },
{ for k, v in google_compute_backend_bucket.default : k => v.id }
)
}
resource "google_compute_url_map" "default" {
provider = google-beta
project = var.project_id
name = var.name
description = var.description
default_service = (
var.urlmap_config.default_service == null ? null : lookup(
local.backend_ids,
var.urlmap_config.default_service,
var.urlmap_config.default_service
)
)
dynamic "default_route_action" {
for_each = (
var.urlmap_config.default_route_action == null
? []
: [var.urlmap_config.default_route_action]
)
iterator = route_action
content {
dynamic "cors_policy" {
for_each = (
route_action.value.cors_policy == null
? []
: [route_action.value.cors_policy]
)
content {
allow_credentials = cors_policy.value.allow_credentials
allow_headers = cors_policy.value.allow_headers
allow_methods = cors_policy.value.allow_methods
allow_origin_regexes = cors_policy.value.allow_origin_regexes
allow_origins = cors_policy.value.allow_origins
disabled = cors_policy.value.disabled
expose_headers = cors_policy.value.expose_headers
max_age = cors_policy.value.max_age
}
}
dynamic "fault_injection_policy" {
for_each = (
route_action.value.fault_injection_policy == null
? []
: [route_action.value.fault_injection_policy]
)
content {
dynamic "abort" {
for_each = (
fault_injection_policy.value.abort == null
? []
: [fault_injection_policy.value.abort]
)
content {
http_status = abort.value.status
percentage = abort.value.percentage
}
}
dynamic "delay" {
for_each = (
fault_injection_policy.value.delay == null
? []
: [fault_injection_policy.value.delay]
)
content {
percentage = delay.value.percentage
fixed_delay {
nanos = delay.value.fixed.nanos
seconds = delay.value.fixed.seconds
}
}
}
}
}
dynamic "request_mirror_policy" {
for_each = (
route_action.value.request_mirror_backend == null
? []
: [""]
)
content {
backend_service = lookup(
local.backend_ids,
route_action.value.request_mirror_backend,
route_action.value.request_mirror_backend
)
}
}
dynamic "retry_policy" {
for_each = (
route_action.value.retry_policy == null
? []
: [route_action.value.retry_policy]
)
content {
num_retries = retry_policy.value.num_retries
retry_conditions = retry_policy.value.retry_conditions
dynamic "per_try_timeout" {
for_each = (
retry_policy.value.per_try_timeout == null
? []
: [retry_policy.value.per_try_timeout]
)
content {
nanos = per_try_timeout.value.nanos
seconds = per_try_timeout.value.seconds
}
}
}
}
dynamic "timeout" {
for_each = (
route_action.value.timeout == null
? []
: [route_action.value.timeout]
)
content {
nanos = timeout.value.nanos
seconds = timeout.value.seconds
}
}
dynamic "url_rewrite" {
for_each = (
route_action.value.url_rewrite == null
? []
: [route_action.value.url_rewrite]
)
content {
host_rewrite = url_rewrite.value.host
path_prefix_rewrite = url_rewrite.value.path_prefix
}
}
dynamic "weighted_backend_services" {
for_each = coalesce(
route_action.value.weighted_backend_services, {}
)
iterator = service
content {
backend_service = lookup(
local.backend_ids, service.key, service.key
)
weight = service.value.weight
dynamic "header_action" {
for_each = (
service.value.header_action == null
? []
: [service.value.header_action]
)
iterator = h
content {
request_headers_to_remove = h.value.request_remove
response_headers_to_remove = h.value.response_remove
dynamic "request_headers_to_add" {
for_each = coalesce(h.value.request_add, {})
content {
header_name = request_headers_to_add.key
header_value = request_headers_to_add.value.value
replace = request_headers_to_add.value.replace
}
}
dynamic "response_headers_to_add" {
for_each = coalesce(h.value.response_add, {})
content {
header_name = response_headers_to_add.key
header_value = response_headers_to_add.value.value
replace = response_headers_to_add.value.replace
}
}
}
}
}
}
}
}
dynamic "default_url_redirect" {
for_each = (
var.urlmap_config.default_url_redirect == null
? []
: [var.urlmap_config.default_url_redirect]
)
iterator = r
content {
host_redirect = r.value.host
https_redirect = r.value.https
path_redirect = r.value.path
prefix_redirect = r.value.prefix
redirect_response_code = r.value.response_code
strip_query = r.value.strip_query
}
}
dynamic "header_action" {
for_each = (
var.urlmap_config.header_action == null
? []
: [var.urlmap_config.header_action]
)
iterator = h
content {
request_headers_to_remove = h.value.request_remove
response_headers_to_remove = h.value.response_remove
dynamic "request_headers_to_add" {
for_each = coalesce(h.value.request_add, {})
content {
header_name = request_headers_to_add.key
header_value = request_headers_to_add.value.value
replace = request_headers_to_add.value.replace
}
}
dynamic "response_headers_to_add" {
for_each = coalesce(h.value.response_add, {})
content {
header_name = response_headers_to_add.key
header_value = response_headers_to_add.value.value
replace = response_headers_to_add.value.replace
}
}
}
}
dynamic "host_rule" {
for_each = coalesce(var.urlmap_config.host_rules, [])
iterator = r
content {
hosts = r.value.hosts
path_matcher = r.value.path_matcher
description = r.value.description
}
}
dynamic "path_matcher" {
for_each = coalesce(var.urlmap_config.path_matchers, {})
iterator = m
content {
default_service = m.value.default_service == null ? null : lookup(
local.backend_ids, m.value.default_service, m.value.default_service
)
description = m.value.description
name = m.key
dynamic "default_route_action" {
for_each = (
m.value.default_route_action == null
? []
: [m.value.default_route_action]
)
iterator = route_action
content {
dynamic "cors_policy" {
for_each = (
route_action.value.cors_policy == null
? []
: [route_action.value.cors_policy]
)
content {
allow_credentials = cors_policy.value.allow_credentials
allow_headers = cors_policy.value.allow_headers
allow_methods = cors_policy.value.allow_methods
allow_origin_regexes = cors_policy.value.allow_origin_regexes
allow_origins = cors_policy.value.allow_origins
disabled = cors_policy.value.disabled
expose_headers = cors_policy.value.expose_headers
max_age = cors_policy.value.max_age
}
}
dynamic "fault_injection_policy" {
for_each = (
route_action.value.fault_injection_policy == null
? []
: [route_action.value.fault_injection_policy]
)
content {
dynamic "abort" {
for_each = (
fault_injection_policy.value.abort == null
? []
: [fault_injection_policy.value.abort]
)
content {
http_status = abort.value.status
percentage = abort.value.percentage
}
}
dynamic "delay" {
for_each = (
fault_injection_policy.value.delay == null
? []
: [fault_injection_policy.value.delay]
)
content {
percentage = delay.value.percentage
fixed_delay {
nanos = delay.value.fixed.nanos
seconds = delay.value.fixed.seconds
}
}
}
}
}
dynamic "request_mirror_policy" {
for_each = (
route_action.value.request_mirror_backend == null
? []
: [""]
)
content {
backend_service = lookup(
local.backend_ids,
route_action.value.request_mirror_backend,
route_action.value.request_mirror_backend
)
}
}
dynamic "retry_policy" {
for_each = (
route_action.value.retry_policy == null
? []
: [route_action.value.retry_policy]
)
content {
num_retries = retry_policy.value.num_retries
retry_conditions = retry_policy.value.retry_conditions
dynamic "per_try_timeout" {
for_each = (
retry_policy.value.per_try_timeout == null
? []
: [retry_policy.value.per_try_timeout]
)
content {
nanos = per_try_timeout.value.nanos
seconds = per_try_timeout.value.seconds
}
}
}
}
dynamic "timeout" {
for_each = (
route_action.value.timeout == null
? []
: [route_action.value.timeout]
)
content {
nanos = timeout.value.nanos
seconds = timeout.value.seconds
}
}
dynamic "url_rewrite" {
for_each = (
route_action.value.url_rewrite == null
? []
: [route_action.value.url_rewrite]
)
content {
host_rewrite = url_rewrite.value.host
path_prefix_rewrite = url_rewrite.value.path_prefix
}
}
dynamic "weighted_backend_services" {
for_each = coalesce(
route_action.value.weighted_backend_services, {}
)
iterator = service
content {
backend_service = lookup(
local.backend_ids, service.key, service.key
)
weight = service.value.weight
dynamic "header_action" {
for_each = (
service.value.header_action == null
? []
: [service.value.header_action]
)
iterator = h
content {
request_headers_to_remove = h.value.request_remove
response_headers_to_remove = h.value.response_remove
dynamic "request_headers_to_add" {
for_each = coalesce(h.value.request_add, {})
content {
header_name = request_headers_to_add.key
header_value = request_headers_to_add.value.value
replace = request_headers_to_add.value.replace
}
}
dynamic "response_headers_to_add" {
for_each = coalesce(h.value.response_add, {})
content {
header_name = response_headers_to_add.key
header_value = response_headers_to_add.value.value
replace = response_headers_to_add.value.replace
}
}
}
}
}
}
}
}
dynamic "default_url_redirect" {
for_each = (
m.value.default_url_redirect == null
? []
: [m.value.default_url_redirect]
)
content {
host_redirect = default_url_redirect.value.host
https_redirect = default_url_redirect.value.https
path_redirect = default_url_redirect.value.path
prefix_redirect = default_url_redirect.value.prefix
redirect_response_code = default_url_redirect.value.response_code
strip_query = default_url_redirect.value.strip_query
}
}
dynamic "header_action" {
for_each = (
m.value.header_action == null
? []
: [m.value.header_action]
)
iterator = h
content {
request_headers_to_remove = h.value.request_remove
response_headers_to_remove = h.value.response_remove
dynamic "request_headers_to_add" {
for_each = coalesce(h.value.request_add, {})
content {
header_name = request_headers_to_add.key
header_value = request_headers_to_add.value.value
replace = request_headers_to_add.value.replace
}
}
dynamic "response_headers_to_add" {
for_each = coalesce(h.value.response_add, {})
content {
header_name = response_headers_to_add.key
header_value = response_headers_to_add.value.value
replace = response_headers_to_add.value.replace
}
}
}
}
dynamic "path_rule" {
for_each = toset(coalesce(m.value.path_rules, []))
content {
paths = path_rule.value.paths
service = path_rule.value.service == null ? null : lookup(
local.backend_ids,
path_rule.value.service,
path_rule.value.service
)
dynamic "route_action" {
for_each = (
path_rule.value.route_action == null
? []
: [path_rule.value.route_action]
)
content {
dynamic "cors_policy" {
for_each = (
route_action.value.cors_policy == null
? []
: [route_action.value.cors_policy]
)
content {
allow_credentials = cors_policy.value.allow_credentials
allow_headers = cors_policy.value.allow_headers
allow_methods = cors_policy.value.allow_methods
allow_origin_regexes = cors_policy.value.allow_origin_regexes
allow_origins = cors_policy.value.allow_origins
disabled = cors_policy.value.disabled
expose_headers = cors_policy.value.expose_headers
max_age = cors_policy.value.max_age
}
}
dynamic "fault_injection_policy" {
for_each = (
route_action.value.fault_injection_policy == null
? []
: [route_action.value.fault_injection_policy]
)
content {
dynamic "abort" {
for_each = (
fault_injection_policy.value.abort == null
? []
: [fault_injection_policy.value.abort]
)
content {
http_status = abort.value.status
percentage = abort.value.percentage
}
}
dynamic "delay" {
for_each = (
fault_injection_policy.value.delay == null
? []
: [fault_injection_policy.value.delay]
)
content {
percentage = delay.value.percentage
fixed_delay {
nanos = delay.value.fixed.nanos
seconds = delay.value.fixed.seconds
}
}
}
}
}
dynamic "request_mirror_policy" {
for_each = (
route_action.value.request_mirror_backend == null
? []
: [""]
)
content {
backend_service = lookup(
local.backend_ids,
route_action.value.request_mirror_backend,
route_action.value.request_mirror_backend
)
}
}
dynamic "retry_policy" {
for_each = (
route_action.value.retry_policy == null
? []
: [route_action.value.retry_policy]
)
content {
num_retries = retry_policy.value.num_retries
retry_conditions = retry_policy.value.retry_conditions
dynamic "per_try_timeout" {
for_each = (
retry_policy.value.per_try_timeout == null
? []
: [retry_policy.value.per_try_timeout]
)
content {
nanos = per_try_timeout.value.nanos
seconds = per_try_timeout.value.seconds
}
}
}
}
dynamic "timeout" {
for_each = (
route_action.value.timeout == null
? []
: [route_action.value.timeout]
)
content {
nanos = timeout.value.nanos
seconds = timeout.value.seconds
}
}
dynamic "url_rewrite" {
for_each = (
route_action.value.url_rewrite == null
? []
: [route_action.value.url_rewrite]
)
content {
host_rewrite = url_rewrite.value.host
path_prefix_rewrite = url_rewrite.value.path_prefix
}
}
dynamic "weighted_backend_services" {
for_each = coalesce(
route_action.value.weighted_backend_services, {}
)
iterator = service
content {
backend_service = lookup(
local.backend_ids, service.key, service.key
)
weight = service.value.weight
dynamic "header_action" {
for_each = (
service.value.header_action == null
? []
: [service.value.header_action]
)
iterator = h
content {
request_headers_to_remove = h.value.request_remove
response_headers_to_remove = h.value.response_remove
dynamic "request_headers_to_add" {
for_each = coalesce(h.value.request_add, {})
content {
header_name = request_headers_to_add.key
header_value = request_headers_to_add.value.value
replace = request_headers_to_add.value.replace
}
}
dynamic "response_headers_to_add" {
for_each = coalesce(h.value.response_add, {})
content {
header_name = response_headers_to_add.key
header_value = response_headers_to_add.value.value
replace = response_headers_to_add.value.replace
}
}
}
}
}
}
}
}
dynamic "url_redirect" {
for_each = (
path_rule.value.url_redirect == null
? []
: [path_rule.value.url_redirect]
)
content {
host_redirect = url_redirect.value.host
https_redirect = url_redirect.value.https
path_redirect = url_redirect.value.path
prefix_redirect = url_redirect.value.prefix
redirect_response_code = url_redirect.value.response_code
strip_query = url_redirect.value.strip_query
}
}
}
}
dynamic "route_rules" {
for_each = toset(coalesce(m.value.route_rules, []))
content {
priority = route_rules.value.priority
service = route_rules.value.service == null ? null : lookup(
local.backend_ids,
route_rules.value.service,
route_rules.value.service
)
dynamic "header_action" {
for_each = (
route_rules.value.header_action == null
? []
: [route_rules.value.header_action]
)
iterator = h
content {
request_headers_to_remove = h.value.request_remove
response_headers_to_remove = h.value.response_remove
dynamic "request_headers_to_add" {
for_each = coalesce(h.value.request_add, {})
content {
header_name = request_headers_to_add.key
header_value = request_headers_to_add.value.value
replace = request_headers_to_add.value.replace
}
}
dynamic "response_headers_to_add" {
for_each = coalesce(h.value.response_add, {})
content {
header_name = response_headers_to_add.key
header_value = response_headers_to_add.value.value
replace = response_headers_to_add.value.replace
}
}
}
}
dynamic "match_rules" {
for_each = toset(coalesce(route_rules.value.match_rules, []))
content {
ignore_case = match_rules.value.ignore_case
full_path_match = (
try(match_rules.value.path.type, null) == "full"
? match_rules.value.path.value
: null
)
prefix_match = (
try(match_rules.value.path.type, null) == "prefix"
? match_rules.value.path.value
: null
)
regex_match = (
try(match_rules.value.path.type, null) == "regex"
? match_rules.value.path.value
: null
)
dynamic "header_matches" {
for_each = toset(coalesce(match_rules.value.headers, []))
iterator = h
content {
header_name = h.value.name
exact_match = h.value.type == "exact" ? h.value.value : null
invert_match = h.value.invert_match
prefix_match = h.value.type == "prefix" ? h.value.value : null
present_match = h.value.type == "present" ? h.value.value : null
regex_match = h.value.type == "regex" ? h.value.value : null
suffix_match = h.value.type == "suffix" ? h.value.value : null
dynamic "range_match" {
for_each = (
h.value.type != "range" || h.value.range_value == null
? []
: [""]
)
content {
range_end = h.value.range_value.end
range_start = h.value.range_value.start
}
}
}
}
dynamic "metadata_filters" {
for_each = toset(coalesce(match_rules.value.metadata_filters, []))
iterator = m
content {
filter_match_criteria = (
m.value.match_all ? "MATCH_ALL" : "MATCH_ANY"
)
dynamic "filter_labels" {
for_each = m.value.labels
content {
name = filter_labels.key
value = filter_labels.value
}
}
}
}
dynamic "query_parameter_matches" {
for_each = toset(coalesce(match_rules.value.query_params, []))
iterator = q
content {
name = q.value.name
exact_match = (
q.value.type == "exact" ? q.value.value : null
)
present_match = (
q.value.type == "present" ? q.value.value : null
)
regex_match = (
q.value.type == "regex" ? q.value.value : null
)
}
}
}
}
dynamic "route_action" {
for_each = (
route_rules.value.route_action == null
? []
: [route_rules.value.route_action]
)
content {
dynamic "cors_policy" {
for_each = (
route_action.value.cors_policy == null
? []
: [route_action.value.cors_policy]
)
content {
allow_credentials = cors_policy.value.allow_credentials
allow_headers = cors_policy.value.allow_headers
allow_methods = cors_policy.value.allow_methods
allow_origin_regexes = cors_policy.value.allow_origin_regexes
allow_origins = cors_policy.value.allow_origins
disabled = cors_policy.value.disabled
expose_headers = cors_policy.value.expose_headers
max_age = cors_policy.value.max_age
}
}
dynamic "fault_injection_policy" {
for_each = (
route_action.value.fault_injection_policy == null
? []
: [route_action.value.fault_injection_policy]
)
content {
dynamic "abort" {
for_each = (
fault_injection_policy.value.abort == null
? []
: [fault_injection_policy.value.abort]
)
content {
http_status = abort.value.status
percentage = abort.value.percentage
}
}
dynamic "delay" {
for_each = (
fault_injection_policy.value.delay == null
? []
: [fault_injection_policy.value.delay]
)
content {
percentage = delay.value.percentage
fixed_delay {
nanos = delay.value.fixed.nanos
seconds = delay.value.fixed.seconds
}
}
}
}
}
dynamic "request_mirror_policy" {
for_each = (
route_action.value.request_mirror_backend == null
? []
: [""]
)
content {
backend_service = lookup(
local.backend_ids,
route_action.value.request_mirror_backend,
route_action.value.request_mirror_backend
)
}
}
dynamic "retry_policy" {
for_each = (
route_action.value.retry_policy == null
? []
: [route_action.value.retry_policy]
)
content {
num_retries = retry_policy.value.num_retries
retry_conditions = retry_policy.value.retry_conditions
dynamic "per_try_timeout" {
for_each = (
retry_policy.value.per_try_timeout == null
? []
: [retry_policy.value.per_try_timeout]
)
content {
nanos = per_try_timeout.value.nanos
seconds = per_try_timeout.value.seconds
}
}
}
}
dynamic "timeout" {
for_each = (
route_action.value.timeout == null
? []
: [route_action.value.timeout]
)
content {
nanos = timeout.value.nanos
seconds = timeout.value.seconds
}
}
dynamic "url_rewrite" {
for_each = (
route_action.value.url_rewrite == null
? []
: [route_action.value.url_rewrite]
)
content {
host_rewrite = url_rewrite.value.host
path_prefix_rewrite = url_rewrite.value.path_prefix
}
}
dynamic "weighted_backend_services" {
for_each = coalesce(
route_action.value.weighted_backend_services, {}
)
iterator = service
content {
backend_service = lookup(
local.backend_ids, service.key, service.key
)
weight = service.value.weight
dynamic "header_action" {
for_each = (
service.value.header_action == null
? []
: [service.value.header_action]
)
iterator = h
content {
request_headers_to_remove = h.value.request_remove
response_headers_to_remove = h.value.response_remove
dynamic "request_headers_to_add" {
for_each = coalesce(h.value.request_add, {})
content {
header_name = request_headers_to_add.key
header_value = request_headers_to_add.value.value
replace = request_headers_to_add.value.replace
}
}
dynamic "response_headers_to_add" {
for_each = coalesce(h.value.response_add, {})
content {
header_name = response_headers_to_add.key
header_value = response_headers_to_add.value.value
replace = response_headers_to_add.value.replace
}
}
}
}
}
}
}
}
dynamic "url_redirect" {
for_each = (
route_rules.value.default_url_redirect == null
? []
: [route_rules.value.default_url_redirect]
)
content {
host_redirect = url_redirect.value.host
https_redirect = url_redirect.value.https
path_redirect = url_redirect.value.path
prefix_redirect = url_redirect.value.prefix
redirect_response_code = url_redirect.value.response_code
strip_query = url_redirect.value.strip_query
}
}
}
}
}
}
dynamic "test" {
for_each = toset(coalesce(var.urlmap_config.test, []))
content {
host = test.value.host
path = test.value.path
service = test.value.service
description = test.value.description
}
}
}

View File

@ -0,0 +1,150 @@
/**
* Copyright 2022 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 services variables.
variable "backend_service_configs" {
description = "Backend service level configuration."
type = map(object({
affinity_cookie_ttl_sec = optional(number)
compression_mode = optional(string)
connection_draining_timeout_sec = optional(number)
custom_request_headers = optional(list(string))
custom_response_headers = optional(list(string))
enable_cdn = optional(bool)
health_checks = optional(list(string), ["default"])
log_sample_rate = optional(number)
port_name = optional(string)
project_id = optional(string)
protocol = optional(string)
security_policy = optional(string)
session_affinity = optional(string)
timeout_sec = optional(number)
backends = list(object({
# group renamed to backend
backend = string
balancing_mode = optional(string, "UTILIZATION")
capacity_scaler = optional(number, 1)
description = optional(string, "Terraform managed.")
failover = optional(bool, false)
max_connections = optional(object({
per_endpoint = optional(number)
per_group = optional(number)
per_instance = optional(number)
}))
max_rate = optional(object({
per_endpoint = optional(number)
per_group = optional(number)
per_instance = optional(number)
}))
max_utilization = optional(number)
}))
cdn_policy = optional(object({
cache_mode = optional(string)
client_ttl = optional(number)
default_ttl = optional(number)
max_ttl = optional(number)
negative_caching = optional(bool)
serve_while_stale = optional(bool)
signed_url_cache_max_age_sec = optional(number)
cache_key_policy = optional(object({
include_host = optional(bool)
include_named_cookies = optional(list(string))
include_protocol = optional(bool)
include_query_string = optional(bool)
query_string_blacklist = optional(list(string))
query_string_whitelist = optional(list(string))
}))
negative_caching_policy = optional(object({
code = optional(number)
ttl = optional(number)
}))
}))
circuit_breakers = optional(object({
max_connections = optional(number)
max_pending_requests = optional(number)
max_requests = optional(number)
max_requests_per_connection = optional(number)
max_retries = optional(number)
connect_timeout = optional(object({
seconds = number
nanos = optional(number)
}))
}))
consistent_hash = optional(object({
http_header_name = optional(string)
minimum_ring_size = optional(number)
http_cookie = optional(object({
name = optional(string)
path = optional(string)
ttl = optional(object({
seconds = number
nanos = optional(number)
}))
}))
}))
iap_config = optional(object({
oauth2_client_id = string
oauth2_client_secret = string
oauth2_client_secret_sha256 = optional(string)
}))
outlier_detection = optional(object({
consecutive_errors = optional(number)
consecutive_gateway_failure = optional(number)
enforcing_consecutive_errors = optional(number)
enforcing_consecutive_gateway_failure = optional(number)
enforcing_success_rate = optional(number)
max_ejection_percent = optional(number)
success_rate_minimum_hosts = optional(number)
success_rate_request_volume = optional(number)
success_rate_stdev_factor = optional(number)
base_ejection_time = optional(object({
seconds = number
nanos = optional(number)
}))
interval = optional(object({
seconds = number
nanos = optional(number)
}))
}))
security_settings = optional(object({
client_tls_policy = string
subject_alt_names = list(string)
}))
}))
default = {}
nullable = false
validation {
condition = contains(
[
"-", "ROUND_ROBIN", "LEAST_REQUEST", "RING_HASH",
"RANDOM", "ORIGINAL_DESTINATION", "MAGLEV"
],
try(var.backend_service_configs.locality_lb_policy, "-")
)
error_message = "Invalid locality lb policy value."
}
validation {
condition = contains(
[
"NONE", "CLIENT_IP", "CLIENT_IP_NO_DESTINATION",
"CLIENT_IP_PORT_PROTO", "CLIENT_IP_PROTO"
],
try(var.backend_service_configs.session_affinity, "NONE")
)
error_message = "Invalid session affinity value."
}
}

View File

@ -0,0 +1,106 @@
/**
* Copyright 2022 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 variable.
variable "health_check_configs" {
description = "Optional auto-created health check configurations, use the output self-link to set it in the auto healing policy. Refer to examples for usage."
type = map(object({
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) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT
service_name = optional(string)
}))
http = optional(object({
host = optional(string)
port = optional(number)
port_name = optional(string)
port_specification = optional(string) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT
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) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT
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) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT
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) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT
proxy_header = optional(string)
request = optional(string)
response = optional(string)
}))
ssl = optional(object({
port = optional(number)
port_name = optional(string)
port_specification = optional(string) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT
proxy_header = optional(string)
request = optional(string)
response = optional(string)
}))
}))
default = {
default = {
http = {
port_specification = "USE_SERVING_PORT"
}
}
}
validation {
condition = alltrue([
for k, v in var.health_check_configs : (
(try(v.grpc, null) == null ? 0 : 1) +
(try(v.http, null) == null ? 0 : 1) +
(try(v.tcp, null) == null ? 0 : 1) <= 1
)
])
error_message = "At most one health check type can be configured at a time."
}
validation {
condition = alltrue(flatten([
for k, v in var.health_check_configs : [
for kk, vv in v : contains([
"-", "USE_FIXED_PORT", "USE_NAMED_PORT", "USE_SERVING_PORT"
], coalesce(try(vv.port_specification, null), "-"))
]
]))
error_message = "Invalid 'port_specification' value. Supported values are 'USE_FIXED_PORT', 'USE_NAMED_PORT', 'USE_SERVING_PORT'."
}
}

View File

@ -0,0 +1,372 @@
/**
* Copyright 2022 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 URLmap variable.
variable "urlmap_config" {
description = "The URL map configuration."
type = object({
default_route_action = optional(object({
request_mirror_backend = optional(string)
cors_policy = optional(object({
allow_credentials = optional(bool)
allow_headers = optional(string)
allow_methods = optional(string)
allow_origin_regexes = list(string)
allow_origins = list(string)
disabled = optional(bool)
expose_headers = optional(string)
max_age = optional(string)
}))
fault_injection_policy = optional(object({
abort = optional(object({
percentage = number
status = number
}))
delay = optional(object({
fixed = object({
seconds = number
nanos = number
})
percentage = number
}))
}))
retry_policy = optional(object({
num_retries = number
retry_conditions = optional(list(string))
per_try_timeout = optional(object({
seconds = number
nanos = optional(number)
}))
}))
timeout = optional(object({
seconds = number
nanos = optional(number)
}))
url_rewrite = optional(object({
host = optional(string)
path_prefix = optional(string)
}))
weighted_backend_services = optional(map(object({
weight = number
header_action = optional(object({
request_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
request_remove = optional(list(string))
response_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
response_remove = optional(list(string))
}))
})))
}))
default_service = optional(string)
default_url_redirect = optional(object({
host = optional(string)
https = optional(bool)
path = optional(string)
prefix = optional(string)
response_code = optional(string)
strip_query = optional(bool)
}))
header_action = optional(object({
request_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
request_remove = optional(list(string))
response_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
response_remove = optional(list(string))
}))
host_rules = optional(list(object({
hosts = list(string)
path_matcher = string
description = optional(string)
})))
path_matchers = optional(map(object({
description = optional(string)
default_route_action = optional(object({
request_mirror_backend = optional(string)
cors_policy = optional(object({
allow_credentials = optional(bool)
allow_headers = optional(string)
allow_methods = optional(string)
allow_origin_regexes = list(string)
allow_origins = list(string)
disabled = optional(bool)
expose_headers = optional(string)
max_age = optional(string)
}))
fault_injection_policy = optional(object({
abort = optional(object({
percentage = number
status = number
}))
delay = optional(object({
fixed = object({
seconds = number
nanos = number
})
percentage = number
}))
}))
retry_policy = optional(object({
num_retries = number
retry_conditions = optional(list(string))
per_try_timeout = optional(object({
seconds = number
nanos = optional(number)
}))
}))
timeout = optional(object({
seconds = number
nanos = optional(number)
}))
url_rewrite = optional(object({
host = optional(string)
path_prefix = optional(string)
}))
weighted_backend_services = optional(map(object({
weight = number
header_action = optional(object({
request_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
request_remove = optional(list(string))
response_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
response_remove = optional(list(string))
}))
})))
}))
default_service = optional(string)
default_url_redirect = optional(object({
host = optional(string)
https = optional(bool)
path = optional(string)
prefix = optional(string)
response_code = optional(string)
strip_query = optional(bool)
}))
header_action = optional(object({
request_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
request_remove = optional(list(string))
response_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
response_remove = optional(list(string))
}))
path_rules = optional(list(object({
paths = list(string)
service = optional(string)
route_action = optional(object({
request_mirror_backend = optional(string)
cors_policy = optional(object({
allow_credentials = optional(bool)
allow_headers = optional(string)
allow_methods = optional(string)
allow_origin_regexes = list(string)
allow_origins = list(string)
disabled = optional(bool)
expose_headers = optional(string)
max_age = optional(string)
}))
fault_injection_policy = optional(object({
abort = optional(object({
percentage = number
status = number
}))
delay = optional(object({
fixed = object({
seconds = number
nanos = number
})
percentage = number
}))
}))
retry_policy = optional(object({
num_retries = number
retry_conditions = optional(list(string))
per_try_timeout = optional(object({
seconds = number
nanos = optional(number)
}))
}))
timeout = optional(object({
seconds = number
nanos = optional(number)
}))
url_rewrite = optional(object({
host = optional(string)
path_prefix = optional(string)
}))
weighted_backend_services = optional(map(object({
weight = number
header_action = optional(object({
request_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
request_remove = optional(list(string))
response_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
response_remove = optional(list(string))
}))
})))
}))
url_redirect = optional(object({
host = optional(string)
https = optional(bool)
path = optional(string)
prefix = optional(string)
response_code = optional(string)
strip_query = optional(bool)
}))
})))
route_rules = optional(list(object({
priority = number
service = optional(string)
header_action = optional(object({
request_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
request_remove = optional(list(string))
response_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
response_remove = optional(list(string))
}))
match_rules = optional(list(object({
ignore_case = optional(bool, false)
headers = optional(list(object({
name = string
invert_match = optional(bool, false)
type = optional(string, "present") # exact, prefix, suffix, regex, present, range
value = optional(string)
range_value = optional(object({
end = string
start = string
}))
})))
metadata_filters = optional(list(object({
labels = map(string)
match_all = bool # MATCH_ANY, MATCH_ALL
})))
path = optional(object({
value = string
type = optional(string, "prefix") # full, prefix, regex
}))
query_params = optional(list(object({
name = string
value = string
type = optional(string, "present") # exact, present, regex
})))
})))
route_action = optional(object({
request_mirror_backend = optional(string)
cors_policy = optional(object({
allow_credentials = optional(bool)
allow_headers = optional(string)
allow_methods = optional(string)
allow_origin_regexes = list(string)
allow_origins = list(string)
disabled = optional(bool)
expose_headers = optional(string)
max_age = optional(string)
}))
fault_injection_policy = optional(object({
abort = optional(object({
percentage = number
status = number
}))
delay = optional(object({
fixed = object({
seconds = number
nanos = number
})
percentage = number
}))
}))
retry_policy = optional(object({
num_retries = number
retry_conditions = optional(list(string))
per_try_timeout = optional(object({
seconds = number
nanos = optional(number)
}))
}))
timeout = optional(object({
seconds = number
nanos = optional(number)
}))
url_rewrite = optional(object({
host = optional(string)
path_prefix = optional(string)
}))
weighted_backend_services = optional(map(object({
weight = number
header_action = optional(object({
request_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
request_remove = optional(list(string))
response_add = optional(map(object({
value = string
replace = optional(bool, true)
})))
response_remove = optional(list(string))
}))
})))
}))
url_redirect = optional(object({
host = optional(string)
https = optional(bool)
path = optional(string)
prefix = optional(string)
response_code = optional(string)
strip_query = optional(bool)
}))
})))
})))
test = optional(list(object({
host = string
path = string
service = string
description = optional(string)
})))
})
default = {
default_service = "default"
}
}

View File

@ -14,173 +14,78 @@
* limitations under the License.
*/
variable "backend_services_config" {
description = "The backends services configuration."
variable "address" {
description = "Optional IP address used for the forwarding rule."
type = string
default = null
}
variable "backend_buckets_config" {
description = "Backend buckets configuration."
type = map(object({
enable_cdn = bool
cdn_config = object({
cache_mode = string
client_ttl = number
default_ttl = number
max_ttl = number
negative_caching = bool
negative_caching_policy = map(number)
serve_while_stale = bool
signed_url_cache_max_age_sec = string
})
bucket_config = object({
bucket_name = string
options = object({
custom_response_headers = list(string)
})
})
group_config = object({
backends = list(object({
group = string # IG or NEG FQDN address
options = object({
balancing_mode = string # Can be UTILIZATION, RATE, CONNECTION
capacity_scaler = number # Valid range is [0.0,1.0]
max_connections = number
max_connections_per_instance = number
max_connections_per_endpoint = number
max_rate = number
max_rate_per_instance = number
max_rate_per_endpoint = number
max_utilization = number
})
bucket_name = string
compression_mode = optional(string)
custom_response_headers = optional(list(string))
description = optional(string)
edge_security_policy = optional(string)
enable_cdn = optional(bool)
cdn_policy = optional(object({
bypass_cache_on_request_headers = optional(list(string))
cache_mode = optional(string)
client_ttl = optional(number)
default_ttl = optional(number)
max_ttl = optional(number)
negative_caching = optional(bool)
request_coalescing = optional(bool)
serve_while_stale = optional(bool)
signed_url_cache_max_age_sec = optional(number)
cache_key_policy = optional(object({
include_http_headers = optional(list(string))
query_string_whitelist = optional(list(string))
}))
# Optional health check ids for backend service groups.
# Will lookup for ids in health_chacks_config first,
# then will use the id as is. If no ids are defined
# at all (null, []) health_checks_config_defaults is used
health_checks = list(string)
log_config = object({
enable = bool
sample_rate = number # must be in [0, 1]
})
options = object({
affinity_cookie_ttl_sec = number
custom_request_headers = list(string)
custom_response_headers = list(string)
connection_draining_timeout_sec = number
load_balancing_scheme = string # only EXTERNAL (default) makes sense here
locality_lb_policy = string
port_name = string
protocol = string
security_policy = string
session_affinity = string
timeout_sec = number
circuits_breakers = object({
max_requests_per_connection = number # Set to 1 to disable keep-alive
max_connections = number # Defaults to 1024
max_pending_requests = number # Defaults to 1024
max_requests = number # Defaults to 1024
max_retries = number # Defaults to 3
})
consistent_hash = object({
http_header_name = string
minimum_ring_size = string
http_cookie = object({
name = string
path = string
ttl = object({
seconds = number
nanos = number
})
})
})
iap = object({
oauth2_client_id = string
oauth2_client_secret = string
oauth2_client_secret_sha256 = string
})
})
})
negative_caching_policy = optional(object({
code = optional(number)
ttl = optional(number)
}))
}))
}))
default = {}
default = {}
nullable = true
}
variable "forwarding_rule_config" {
description = "Regional forwarding rule configurations."
type = object({
ip_protocol = string
ip_version = string
load_balancing_scheme = string
port_range = string
network_tier = string
network = string
})
default = {
load_balancing_scheme = "EXTERNAL_MANAGED"
ip_protocol = "TCP"
ip_version = "IPV4"
network_tier = "STANDARD"
network = "default"
# If not specified, 80 for https = false, 443 otherwise
port_range = null
}
variable "description" {
description = "Optional description used for resources."
type = string
default = "Terraform managed."
}
variable "global_forwarding_rule_config" {
description = "Global forwarding rule configurations."
type = object({
ip_protocol = string
ip_version = string
load_balancing_scheme = string
port_range = string
})
default = {
load_balancing_scheme = "EXTERNAL"
ip_protocol = "TCP"
ip_version = "IPV4"
# If not specified, 80 for https = false, 443 otherwise
port_range = null
}
}
variable "health_checks_config" {
description = "Custom health checks configuration."
variable "group_configs" {
description = "Optional unmanaged groups to create. Can be referenced in backends via key or outputs."
type = map(object({
type = string # http https tcp ssl http2
check = map(any) # actual health check block attributes
options = map(number) # interval, thresholds, timeout
logging = bool
zone = string
instances = optional(list(string), [])
named_ports = optional(map(number), {})
project_id = optional(string)
}))
default = {}
default = {}
nullable = false
}
variable "health_checks_config_defaults" {
description = "Auto-created health check default configuration."
variable "https_proxy_config" {
description = "HTTPS proxy connfiguration."
type = object({
type = string # http https tcp ssl http2
check = map(any) # actual health check block attributes
options = map(number) # interval, thresholds, timeout
logging = bool
certificate_map = optional(string)
quic_override = optional(string)
ssl_policy = optional(string)
})
default = {
type = "http"
logging = false
options = {}
check = {
port_specification = "USE_SERVING_PORT"
}
}
default = {}
nullable = false
}
variable "https" {
description = "Whether to enable HTTPS."
type = bool
default = false
variable "labels" {
description = "Labels set on resources."
type = map(string)
default = {}
}
variable "name" {
@ -188,70 +93,140 @@ variable "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({
description = optional(string)
cloudfunction = optional(object({
region = string
target_function = optional(string)
target_urlmask = optional(string)
}))
cloudrun = optional(object({
region = string
target_service = optional(object({
name = string
tag = optional(string)
}))
target_urlmask = optional(string)
}))
gce = optional(object({
network = string
subnetwork = string
zone = string
# default_port = optional(number)
endpoints = optional(list(object({
instance = string
ip_address = string
port = number
})))
}))
hybrid = optional(object({
network = string
zone = string
# re-enable once provider properly support this
# default_port = optional(number)
endpoints = optional(list(object({
ip_address = string
port = number
})))
}))
internet = optional(object({
use_fqdn = optional(bool, true)
# re-enable once provider properly support this
# default_port = optional(number)
endpoints = optional(list(object({
destination = 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.cloudfunction, null) == null ? 0 : 1) +
(try(v.cloudrun, null) == null ? 0 : 1) +
(try(v.gce, null) == null ? 0 : 1) +
(try(v.hybrid, null) == null ? 0 : 1) +
(try(v.internet, 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."
}
validation {
condition = alltrue([
for k, v in var.neg_configs : (
v.cloudrun == null
? true
: v.cloudrun.target_urlmask != null || v.cloudrun.target_service != null
)
])
error_message = "Cloud Run NEGs need either target service or target urlmask defined."
}
validation {
condition = alltrue([
for k, v in var.neg_configs : (
v.cloudfunction == null
? true
: v.cloudfunction.target_urlmask != null || v.cloudfunction.target_function != null
)
])
error_message = "Cloud Function NEGs need either target function or target urlmask defined."
}
}
variable "ports" {
description = "Optional ports for HTTP load balancer, valid ports are 80 and 8080."
type = list(string)
default = null
}
variable "project_id" {
description = "Project id."
type = string
}
variable "region" {
description = "Create a regional load balancer in this region."
variable "protocol" {
description = "Protocol supported by this load balancer."
type = string
default = null
}
variable "reserve_ip_address" {
description = "Whether to reserve a static global IP address."
type = bool
default = false
}
variable "ssl_certificates_config" {
description = "The SSL certificate configuration."
type = map(object({
domains = list(string)
# If unmanaged_config is null, the certificate will be managed
unmanaged_config = object({
tls_private_key = string
tls_self_signed_cert = string
})
}))
default = {}
}
variable "ssl_certificates_config_defaults" {
description = "The SSL certificate default configuration."
type = object({
domains = list(string)
# If unmanaged_config is null, the certificate will be managed
unmanaged_config = object({
tls_private_key = string
tls_self_signed_cert = string
})
})
default = {
domains = ["example.com"],
unmanaged_config = null
default = "HTTP"
nullable = false
validation {
condition = (
var.protocol == null || var.protocol == "HTTP" || var.protocol == "HTTPS"
)
error_message = "Protocol must be HTTP or HTTPS"
}
}
variable "target_proxy_https_config" {
description = "The HTTPS target proxy configuration."
variable "ssl_certificates" {
description = "SSL target proxy certificates (only if protocol is HTTPS) for existing, custom, and managed certificates."
type = object({
ssl_certificates = list(string)
certificate_ids = optional(list(string), [])
create_configs = optional(map(object({
certificate = string
private_key = string
})), {})
managed_configs = optional(map(object({
domains = list(string)
description = optional(string)
})), {})
})
default = null
default = {}
nullable = false
}
variable "url_map_config" {
description = "The url-map configuration."
type = object({
default_service = string
default_route_action = any
default_url_redirect = map(any)
header_action = any
host_rules = list(any)
path_matchers = list(any)
tests = list(map(string))
})
default = null
variable "use_classic_version" {
description = "Use classic Global Load Balancer."
type = bool
default = true
}

View File

@ -16,4 +16,4 @@ def test_resources(e2e_plan_runner):
"Test that plan works and the numbers of resources is as expected."
modules, resources = e2e_plan_runner()
assert len(modules) == 4
assert len(resources) == 16
assert len(resources) == 15

View File

@ -18,4 +18,4 @@ def test_blueprint(recursive_e2e_plan_runner):
"Test that all blueprint resources are created."
count_modules, count_resources = recursive_e2e_plan_runner(tf_var_file='test.regular.tfvars')
assert count_modules == 10
assert count_resources == 60
assert count_resources == 59

View File

@ -1,34 +0,0 @@
/**
* Copyright 2022 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 "test" {
source = "../../../../modules/net-glb"
project_id = "my-project"
name = "glb-test"
region = var.region
health_checks_config_defaults = var.health_checks_config_defaults
health_checks_config = var.health_checks_config
backend_services_config = var.backend_services_config
url_map_config = var.url_map_config
https = var.https
ssl_certificates_config = var.ssl_certificates_config
ssl_certificates_config_defaults = var.ssl_certificates_config_defaults
target_proxy_https_config = var.target_proxy_https_config
reserve_ip_address = var.reserve_ip_address
global_forwarding_rule_config = var.global_forwarding_rule_config
forwarding_rule_config = var.forwarding_rule_config
}

View File

@ -1,247 +0,0 @@
/**
* Copyright 2022 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 "region" {
description = "Create a regional load balancer."
type = string
default = null
}
variable "health_checks_config_defaults" {
description = "Auto-created health check default configuration."
type = object({
type = string # http https tcp ssl http2
check = map(any) # actual health check block attributes
options = map(number) # interval, thresholds, timeout
logging = bool
})
default = {
type = "http"
logging = false
options = {}
check = {
port_specification = "USE_SERVING_PORT"
}
}
}
variable "health_checks_config" {
description = "Custom health checks configuration."
type = map(object({
type = string # http https tcp ssl http2
check = map(any) # actual health check block attributes
options = map(number) # interval, thresholds, timeout
logging = bool
}))
default = {}
}
variable "backend_services_config" {
description = "The backends services configuration."
type = map(object({
enable_cdn = bool
cdn_config = object({
cache_mode = string
client_ttl = number
default_ttl = number
max_ttl = number
negative_caching = bool
negative_caching_policy = map(number)
serve_while_stale = bool
signed_url_cache_max_age_sec = string
})
bucket_config = object({
bucket_name = string
options = object({
custom_response_headers = list(string)
})
})
group_config = object({
backends = list(object({
group = string # IG or NEG FQDN address
options = object({
balancing_mode = string # Can be UTILIZATION, RATE, CONNECTION
capacity_scaler = number # Valid range is [0.0,1.0]
max_connections = number
max_connections_per_instance = number
max_connections_per_endpoint = number
max_rate = number
max_rate_per_instance = number
max_rate_per_endpoint = number
max_utilization = number
})
}))
# Optional health check ids for backend service groups.
# Will lookup for ids in health_chacks_config first,
# then will use the id as is. If no ids are defined
# at all (null, []) health_checks_config_defaults is used
health_checks = list(string)
log_config = object({
enable = bool
sample_rate = number # must be in [0, 1]
})
options = object({
affinity_cookie_ttl_sec = number
custom_request_headers = list(string)
custom_response_headers = list(string)
connection_draining_timeout_sec = number
load_balancing_scheme = string # only EXTERNAL (default) makes sense here
locality_lb_policy = string
port_name = string
protocol = string
security_policy = string
session_affinity = string
timeout_sec = number
circuits_breakers = object({
max_requests_per_connection = number # Set to 1 to disable keep-alive
max_connections = number # Defaults to 1024
max_pending_requests = number # Defaults to 1024
max_requests = number # Defaults to 1024
max_retries = number # Defaults to 3
})
consistent_hash = object({
http_header_name = string
minimum_ring_size = string
http_cookie = object({
name = string
path = string
ttl = object({
seconds = number
nanos = number
})
})
})
iap = object({
oauth2_client_id = string
oauth2_client_secret = string
oauth2_client_secret_sha256 = string
})
})
})
}))
default = {}
}
variable "url_map_config" {
description = "The url-map configuration."
type = object({
default_service = string
default_route_action = any
default_url_redirect = map(any)
header_action = any
host_rules = list(any)
path_matchers = list(any)
tests = list(map(string))
})
default = null
}
variable "ssl_certificates_config" {
description = "The SSL certificate configuration."
type = map(object({
domains = list(string)
# If unmanaged_config is null, the certificate will be managed
unmanaged_config = object({
tls_private_key = string
tls_self_signed_cert = string
})
}))
default = {}
}
variable "ssl_certificates_config_defaults" {
description = "The SSL certificate default configuration."
type = object({
domains = list(string)
# If unmanaged_config is null, the certificate will be managed
unmanaged_config = object({
tls_private_key = string
tls_self_signed_cert = string
})
})
default = {
domains = ["example.com"],
unmanaged_config = null
}
}
variable "target_proxy_https_config" {
description = "The HTTPS target proxy configuration."
type = object({
ssl_certificates = list(string)
})
default = null
}
variable "global_forwarding_rule_config" {
description = "Global forwarding rule configurations."
type = object({
ip_protocol = string
ip_version = string
load_balancing_scheme = string
port_range = string
})
default = {
load_balancing_scheme = "EXTERNAL"
ip_protocol = "TCP"
ip_version = "IPV4"
# If not specified, 80 for https = false, 443 otherwise
port_range = null
}
}
variable "forwarding_rule_config" {
description = "Global forwarding rule configurations."
type = object({
ip_protocol = string
ip_version = string
load_balancing_scheme = string
port_range = string
network_tier = string
network = string
})
default = {
load_balancing_scheme = "EXTERNAL_MANAGED"
ip_protocol = "TCP"
ip_version = "IPV4"
# If not specified, 80 for https = false, 443 otherwise
port_range = null
network_tier = "STANDARD"
network = "default"
}
}
variable "https" {
description = "Whether to enable HTTPS."
type = bool
default = false
}
variable "reserve_ip_address" {
description = "Whether to reserve a static global IP address."
type = bool
default = false
}

View File

@ -0,0 +1,109 @@
name = "glb-test-0"
project_id = "my-project"
backend_buckets_config = {
default-gcs = {
bucket_name = "my-bucket"
}
}
backend_service_configs = {
default = {
backends = [
{ backend = "projects/my-project/zones/europe-west8-b/instanceGroups/ig-b" },
{ backend = "ig-c" }
]
}
neg-cloudrun = {
backends = [{ backend = "neg-cloudrun" }]
health_checks = []
}
neg-gce = {
backends = [{ backend = "neg-gce" }]
balancing_mode = "RATE"
max_rate = { per_endpoint = 10 }
}
neg-hybrid = {
backends = [{ backend = "neg-hybrid" }]
balancing_mode = "RATE"
max_rate = { per_endpoint = 10 }
}
neg-internet = {
backends = [{ backend = "neg-internet" }]
health_checks = []
}
}
group_configs = {
ig-c = {
zone = "europe-west8-c"
instances = [
"projects/my-project/zones/europe-west8-c/instances/vm-c"
]
named_ports = { http = 80 }
}
}
health_check_configs = {
default = {
http = {
host = "hello.example.org"
port_specification = "USE_SERVING_PORT"
}
}
}
neg_configs = {
neg-cloudrun = {
cloudrun = {
region = "europe-west8"
target_service = {
name = "hello"
}
}
}
neg-gce = {
gce = {
network = "projects/my-project/global/networks/shared-vpc"
subnetwork = "projects/my-project/regions/europe-west8/subnetworks/gce"
zone = "europe-west8-b"
endpoints = [{
instance = "nginx-ew8-b"
ip_address = "10.24.32.25"
port = 80
}]
}
}
neg-hybrid = {
hybrid = {
network = "projects/my-project/global/networks/shared-vpc"
zone = "europe-west8-b"
endpoints = [{
ip_address = "192.168.0.3"
port = 80
}]
}
}
neg-internet = {
internet = {
use_fqdn = true
endpoints = [{
destination = "hello.example.org"
port = 80
}]
}
}
}
urlmap_config = {
default_service = "default"
host_rules = [{
hosts = ["*"]
path_matcher = "pathmap"
}]
path_matchers = {
pathmap = {
default_service = "default"
path_rules = [
{ paths = ["/cloudrun", "/cloudrun/*"], service = "neg-cloudrun" },
{ paths = ["/gce", "/gce/*"], service = "neg-gce" },
{ paths = ["/hybrid", "/hybrid/*"], service = "neg-hybrid" },
{ paths = ["/internet", "/internet/*"], service = "neg-internet" },
]
}
}
}

View File

@ -0,0 +1,34 @@
# Copyright 2022 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.
counts:
google_compute_backend_bucket: 1
google_compute_backend_service: 5
google_compute_global_forwarding_rule: 1
google_compute_global_network_endpoint: 1
google_compute_global_network_endpoint_group: 1
google_compute_health_check: 1
google_compute_instance_group: 1
google_compute_network_endpoint: 2
google_compute_network_endpoint_group: 2
google_compute_region_network_endpoint_group: 1
google_compute_target_http_proxy: 1
google_compute_url_map: 1
outputs:
address: __missing__
backend_service_ids: __missing__
forwarding_rule: __missing__
group_ids: __missing__
health_check_ids: __missing__
neg_ids: __missing__

View File

@ -1,303 +0,0 @@
# Copyright 2022 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.
_BACKEND_BUCKET = '''{
my-bucket = {
bucket_config = {
bucket_name = "my_bucket"
options = null
}
group_config = null
enable_cdn = false
cdn_config = null
}
}'''
_BACKEND_GROUP = '''{
my-group = {
bucket_config = null,
enable_cdn = false,
cdn_config = null,
group_config = {
backends = [
{
group = "my_group",
options = null
}
],
health_checks = []
log_config = null
options = null
}
}
}'''
_BACKEND_GROUP_HC = '''{
my-group = {
bucket_config = null,
enable_cdn = false,
cdn_config = null,
group_config = {
backends = [
{
group = "my_group",
options = null
}
],
health_checks = ["hc_1"]
log_config = null
options = null
}
}
}'''
_NAME = 'glb-test'
_SSL_CERTIFICATES_CONFIG_MANAGED = '''{
my-domain = {
domains = [
"my-domain.com"
]
unmanaged_config = null
}
}'''
_SSL_CERTIFICATES_CONFIG_UNMANAGED = '''{
my-domain = {
domains = [
"my-domain.com"
],
unmanaged_config = {
tls_private_key = "my-key"
tls_self_signed_cert = "my-cert"
}
}
}'''
_TARGET_PROXY_HTTPS_CONFIG = '''{
ssl_certificates = [
"my-domain"
]
}'''
def test_bucket(plan_runner):
"Tests a bucket backend service."
_, resources = plan_runner(backend_services_config=_BACKEND_BUCKET)
assert len(resources) == 4
resources = dict((r['type'], r['values']) for r in resources)
fwd_rule = resources['google_compute_global_forwarding_rule']
assert fwd_rule['load_balancing_scheme'] == 'EXTERNAL'
assert fwd_rule['port_range'] == '80'
assert fwd_rule['ip_protocol'] == 'TCP'
bucket = resources['google_compute_backend_bucket']
assert bucket['name'] == _NAME + '-my-bucket'
assert bucket['enable_cdn'] is False
assert 'google_compute_health_check' not in resources
assert 'google_compute_target_http_proxy' in resources
assert 'google_compute_url_map' in resources
def test_group_default_hc(plan_runner):
"Tests a group backend service with no HC specified."
_, resources = plan_runner(backend_services_config=_BACKEND_GROUP)
assert len(resources) == 5
resources = dict((r['type'], r['values']) for r in resources)
fwd_rule = resources['google_compute_global_forwarding_rule']
assert fwd_rule['load_balancing_scheme'] == 'EXTERNAL'
assert fwd_rule['port_range'] == '80'
assert fwd_rule['ip_protocol'] == 'TCP'
group = resources['google_compute_backend_service']
assert len(group['backend']) == 1
assert group['backend'][0]['group'] == 'my_group'
health_check = resources['google_compute_health_check']
assert health_check['name'] == _NAME + '-default'
assert len(health_check['http_health_check']) > 0
assert len(health_check['https_health_check']) == 0
assert len(health_check['http2_health_check']) == 0
assert len(health_check['tcp_health_check']) == 0
assert health_check['http_health_check'][0][
'port_specification'] == 'USE_SERVING_PORT'
assert health_check['http_health_check'][0]['proxy_header'] == 'NONE'
assert health_check['http_health_check'][0]['request_path'] == '/'
assert 'google_compute_target_http_proxy' in resources
assert 'google_compute_target_https_proxy' not in resources
assert 'google_compute_url_map' in resources
def test_group_default_hc_regional(plan_runner):
"Tests a group backend service with no HC specified."
_, resources = plan_runner(backend_services_config=_BACKEND_GROUP,
region="europe-west4")
assert len(resources) == 5
resources = dict((r['type'], r['values']) for r in resources)
fwd_rule = resources['google_compute_forwarding_rule']
assert fwd_rule['load_balancing_scheme'] == 'EXTERNAL_MANAGED'
assert fwd_rule['port_range'] == '80'
assert fwd_rule['ip_protocol'] == 'TCP'
group = resources['google_compute_region_backend_service']
assert len(group['backend']) == 1
assert group['backend'][0]['group'] == 'my_group'
health_check = resources['google_compute_region_health_check']
assert health_check['name'] == _NAME + '-default'
assert len(health_check['http_health_check']) > 0
assert len(health_check['https_health_check']) == 0
assert len(health_check['http2_health_check']) == 0
assert len(health_check['tcp_health_check']) == 0
assert health_check['http_health_check'][0][
'port_specification'] == 'USE_SERVING_PORT'
assert health_check['http_health_check'][0]['proxy_header'] == 'NONE'
assert health_check['http_health_check'][0]['request_path'] == '/'
assert 'google_compute_region_target_http_proxy' in resources
assert 'google_compute_region_target_https_proxy' not in resources
assert 'google_compute_region_url_map' in resources
def test_group_no_hc(plan_runner):
"Tests a group backend service without HCs (including no default HC)."
_, resources = plan_runner(backend_services_config=_BACKEND_GROUP,
health_checks_config_defaults='null')
assert len(resources) == 4
resources = dict((r['type'], r['values']) for r in resources)
assert 'google_compute_backend_service' in resources
assert 'google_compute_global_forwarding_rule' in resources
assert 'google_compute_health_check' not in resources
assert 'google_compute_target_http_proxy' in resources
assert 'google_compute_target_https_proxy' not in resources
assert 'google_compute_url_map' in resources
def test_group_existing_hc(plan_runner):
"Tests a group backend service with referencing an existing HC."
_, resources = plan_runner(backend_services_config=_BACKEND_GROUP_HC)
assert len(resources) == 4
resources = dict((r['type'], r['values']) for r in resources)
assert 'google_compute_backend_service' in resources
assert 'google_compute_global_forwarding_rule' in resources
assert 'google_compute_health_check' not in resources
assert 'google_compute_target_http_proxy' in resources
assert 'google_compute_target_https_proxy' not in resources
assert 'google_compute_url_map' in resources
def test_group_existing_hc_regional(plan_runner):
"Tests a group backend service with referencing an existing HC."
_, resources = plan_runner(backend_services_config=_BACKEND_GROUP_HC,
region="europe-west4")
assert len(resources) == 4
resources = dict((r['type'], r['values']) for r in resources)
assert 'google_compute_region_backend_service' in resources
assert 'google_compute_forwarding_rule' in resources
assert 'google_compute_region_health_check' not in resources
assert 'google_compute_region_target_http_proxy' in resources
assert 'google_compute_region_target_https_proxy' not in resources
assert 'google_compute_region_url_map' in resources
def test_reserved_ip(plan_runner):
"Tests an IP reservation with a group backend service."
_, resources = plan_runner(backend_services_config=_BACKEND_GROUP,
reserve_ip_address="true")
assert len(resources) == 6
resources = dict((r['type'], r['values']) for r in resources)
assert 'google_compute_backend_service' in resources
assert 'google_compute_global_address' in resources
assert 'google_compute_global_forwarding_rule' in resources
assert 'google_compute_target_http_proxy' in resources
assert 'google_compute_target_https_proxy' not in resources
assert 'google_compute_url_map' in resources
def test_ssl_managed(plan_runner):
"Tests HTTPS and SSL managed certificates."
_, resources = plan_runner(
backend_services_config=_BACKEND_GROUP,
https='true',
ssl_certificates_config=_SSL_CERTIFICATES_CONFIG_MANAGED,
target_proxy_https_config=_TARGET_PROXY_HTTPS_CONFIG)
assert len(resources) == 6
resources = dict((r['type'], r['values']) for r in resources)
fwd_rule = resources['google_compute_global_forwarding_rule']
assert fwd_rule['port_range'] == '443'
ssl_cert = resources['google_compute_managed_ssl_certificate']
assert ssl_cert['type'] == "MANAGED"
assert ssl_cert['managed'][0]['domains'][0] == 'my-domain.com'
assert 'google_compute_backend_service' in resources
assert 'google_compute_global_forwarding_rule' in resources
assert 'google_compute_ssl_certificate' not in resources
assert 'google_compute_target_http_proxy' not in resources
assert 'google_compute_target_https_proxy' in resources
assert 'google_compute_url_map' in resources
def test_ssl_unmanaged(plan_runner):
"Tests HTTPS and SSL unmanaged certificates."
_, resources = plan_runner(
backend_services_config=_BACKEND_GROUP,
https="true",
ssl_certificates_config=_SSL_CERTIFICATES_CONFIG_UNMANAGED,
target_proxy_https_config=_TARGET_PROXY_HTTPS_CONFIG)
assert len(resources) == 6
resources = dict((r['type'], r['values']) for r in resources)
fwd_rule = resources['google_compute_global_forwarding_rule']
assert fwd_rule['port_range'] == '443'
assert 'google_compute_backend_service' in resources
assert 'google_compute_global_forwarding_rule' in resources
assert 'google_compute_managed_ssl_certificate' not in resources
assert 'google_compute_ssl_certificate' in resources
assert 'google_compute_target_http_proxy' not in resources
assert 'google_compute_target_https_proxy' in resources
assert 'google_compute_url_map' in resources
def test_ssl_existing_cert(plan_runner):
"Tests HTTPS and SSL existing certificate."
_, resources = plan_runner(
backend_services_config=_BACKEND_GROUP,
https="true",
target_proxy_https_config=_TARGET_PROXY_HTTPS_CONFIG)
assert len(resources) == 5
resources = dict((r['type'], r['values']) for r in resources)
fwd_rule = resources['google_compute_global_forwarding_rule']
assert fwd_rule['port_range'] == '443'
assert 'google_compute_backend_service' in resources
assert 'google_compute_global_forwarding_rule' in resources
assert 'google_compute_managed_ssl_certificate' not in resources
assert 'google_compute_ssl_certificate' not in resources
assert 'google_compute_target_http_proxy' not in resources
assert 'google_compute_target_https_proxy' in resources
assert 'google_compute_url_map' in resources

View File

@ -0,0 +1,17 @@
# Copyright 2022 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-glb
tests:
test-plan:

View File

@ -1,162 +0,0 @@
# Copyright 2022 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.
def validate_policy_boolean(resources):
assert len(resources) == 2
assert all(
r['values']['parent'] == 'organizations/1234567890' for r in resources)
policies = {
r['index']: r['values']['spec'][0]
for r in resources
if r['type'] == 'google_org_policy_policy'
}
assert len(policies) == 2
p1 = policies['iam.disableServiceAccountKeyCreation']
assert p1['inherit_from_parent'] is None
assert p1['reset'] is None
assert p1['rules'] == [{
'allow_all': None,
'condition': [],
'deny_all': None,
'enforce': 'TRUE',
'values': []
}]
p2 = policies['iam.disableServiceAccountKeyUpload']
assert p2['inherit_from_parent'] is None
assert p2['reset'] is None
assert len(p2['rules']) == 2
assert p2['rules'][0] == {
'allow_all': None,
'condition': [],
'deny_all': None,
'enforce': 'FALSE',
'values': []
}
assert p2['rules'][1] == {
'allow_all': None,
'condition': [{
'description': 'test condition',
'expression': 'resource.matchTagId(aa, bb)',
'location': 'xxx',
'title': 'condition'
}],
'deny_all': None,
'enforce': 'TRUE',
'values': []
}
def validate_policy_list(resources):
assert len(resources) == 3
assert all(
r['values']['parent'] == 'organizations/1234567890' for r in resources)
policies = {
r['index']: r['values']['spec'][0]
for r in resources
if r['type'] == 'google_org_policy_policy'
}
assert len(policies) == 3
p1 = policies['compute.vmExternalIpAccess']
assert p1['inherit_from_parent'] is None
assert p1['reset'] is None
assert p1['rules'] == [{
'allow_all': None,
'condition': [],
'deny_all': 'TRUE',
'enforce': None,
'values': []
}]
p2 = policies['iam.allowedPolicyMemberDomains']
assert p2['inherit_from_parent'] is None
assert p2['reset'] is None
assert p2['rules'] == [{
'allow_all':
None,
'condition': [],
'deny_all':
None,
'enforce':
None,
'values': [{
'allowed_values': [
'C0xxxxxxx',
'C0yyyyyyy',
],
'denied_values': None
}]
}]
p3 = policies['compute.restrictLoadBalancerCreationForTypes']
assert p3['inherit_from_parent'] is None
assert p3['reset'] is None
assert len(p3['rules']) == 3
assert p3['rules'][0] == {
'allow_all': None,
'condition': [],
'deny_all': None,
'enforce': None,
'values': [{
'allowed_values': None,
'denied_values': ['in:EXTERNAL']
}]
}
assert p3['rules'][1] == {
'allow_all': None,
'condition': [{
'description': 'test condition',
'expression': 'resource.matchTagId(aa, bb)',
'location': 'xxx',
'title': 'condition'
}],
'deny_all': None,
'enforce': None,
'values': [{
'allowed_values': ['EXTERNAL_1'],
'denied_values': None
}]
}
assert p3['rules'][2] == {
'allow_all': 'TRUE',
'condition': [{
'description': 'test condition2',
'expression': 'resource.matchTagId(cc, dd)',
'location': 'xxx',
'title': 'condition2'
}],
'deny_all': None,
'enforce': None,
'values': []
}
def validate_policy_custom_constraints(resources):
assert len(resources) == 2
assert all(
r['values']['parent'] == 'organizations/1234567890' for r in resources)
constraints = {
r['index']: r['values']
for r in resources
if r['type'] == 'google_org_policy_custom_constraint'
}
assert len(constraints) == 2
c1 = constraints['custom.gkeEnableAutoUpgrade']
assert c1['resource_types'][0] == 'container.googleapis.com/NodePool'
assert c1['method_types'] == ['CREATE']
assert c1['condition'] == 'resource.management.autoUpgrade == true'
assert c1['action_type'] == 'ALLOW'
c2 = constraints['custom.dataprocNoMoreThan10Workers']
assert c2['resource_types'][0] == 'dataproc.googleapis.com/Cluster'
assert c2['method_types'] == ['CREATE', 'UPDATE']
assert c2['condition'] == 'resource.config.workerConfig.numInstances + resource.config.secondaryWorkerConfig.numInstances > 10'
assert c2['action_type'] == 'DENY'