[#593] Add HTTP ILB module (net-ilb-l7)
This commit is contained in:
@@ -27,7 +27,7 @@ The current list of modules supports most of the core foundational and networkin
|
||||
Currently available modules:
|
||||
|
||||
- **foundational** - [folder](./modules/folder), [organization](./modules/organization), [project](./modules/project), [service accounts](./modules/iam-service-account), [logging bucket](./modules/logging-bucket), [billing budget](./modules/billing-budget), [naming convention](./modules/naming-convention), [projects-data-source](./modules/projects-data-source)
|
||||
- **networking** - [VPC](./modules/net-vpc), [VPC firewall](./modules/net-vpc-firewall), [VPC peering](./modules/net-vpc-peering), [VPN static](./modules/net-vpn-static), [VPN dynamic](./modules/net-vpn-dynamic), [HA VPN](./modules/net-vpn-ha), [NAT](./modules/net-cloudnat), [address reservation](./modules/net-address), [DNS](./modules/dns), [L4 ILB](./modules/net-ilb), [Service Directory](./modules/service-directory), [Cloud Endpoints](./modules/endpoints)
|
||||
- **networking** - [VPC](./modules/net-vpc), [VPC firewall](./modules/net-vpc-firewall), [VPC peering](./modules/net-vpc-peering), [VPN static](./modules/net-vpn-static), [VPN dynamic](./modules/net-vpn-dynamic), [HA VPN](./modules/net-vpn-ha), [NAT](./modules/net-cloudnat), [address reservation](./modules/net-address), [DNS](./modules/dns), [L4 ILB](./modules/net-ilb), [L7 ILB](./modules/net-ilb-l7), [Service Directory](./modules/service-directory), [Cloud Endpoints](./modules/endpoints)
|
||||
- **compute** - [VM/VM group](./modules/compute-vm), [MIG](./modules/compute-mig), [GKE cluster](./modules/gke-cluster), [GKE nodepool](./modules/gke-nodepool), [GKE hub](./modules/gke-hub), [COS container](./modules/cloud-config-container/cos-generic-metadata/) (coredns, mysql, onprem, squid)
|
||||
- **data** - [GCS](./modules/gcs), [BigQuery dataset](./modules/bigquery-dataset), [Pub/Sub](./modules/pubsub), [Datafusion](./modules/datafusion), [Bigtable instance](./modules/bigtable-instance), [Cloud SQL instance](./modules/cloudsql-instance), [Data Catalog Policy Tag](./modules/data-catalog-policy-tag)
|
||||
- **development** - [Cloud Source Repository](./modules/source-repository), [Container Registry](./modules/container-registry), [Artifact Registry](./modules/artifact-registry), [Apigee Organization](./modules/apigee-organization), [Apigee X Instance](./modules/apigee-x-instance), [API Gateway](./modules/api-gateway)
|
||||
|
||||
432
modules/net-ilb-l7/README.md
Normal file
432
modules/net-ilb-l7/README.md
Normal file
@@ -0,0 +1,432 @@
|
||||
# Internal (HTTP/S) Load Balancer Module
|
||||
|
||||
The module allows managing Internal HTTP/HTTPS Load Balancers (HTTP(S) ILBs), integrating the forwarding rule, the url-map, the backends, optional health checks and SSL certificates.
|
||||
It's designed to be a simple match for the [`vpc`](../net-vpc) and the [`compute-mig`](../compute-mig) modules, which can be used to manage VPCs and instance groups.
|
||||
|
||||
## Examples
|
||||
|
||||
### Minimal Example
|
||||
|
||||
An HTTP ILB with a backend service pointing to a GCE instance group:
|
||||
|
||||
```hcl
|
||||
module "ilb" {
|
||||
source = "./modules/net-ilb-l7"
|
||||
name = "ilb-test"
|
||||
project_id = var.project_id
|
||||
region = "europe-west1"
|
||||
network = var.vpc.self_link
|
||||
subnetwork = var.subnet.self_link
|
||||
|
||||
backend_services_config = {
|
||||
my-backend-svc = {
|
||||
backends = [
|
||||
{
|
||||
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
||||
options = null
|
||||
}
|
||||
]
|
||||
health_checks = []
|
||||
log_config = null
|
||||
options = null
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=5
|
||||
```
|
||||
|
||||
Network and subnetwork can be entered using their name (if present in the same project) or leveraging their link id. The latter is mandatory if you're trying to deploy an ILB in a shared VPC environment.
|
||||
|
||||
```hcl
|
||||
module "ilb" {
|
||||
source = "./modules/net-ilb-l7"
|
||||
name = "ilb-test"
|
||||
project_id = var.project_id
|
||||
region = "europe-west1"
|
||||
network = "projects/my-host-project/global/networks/my-shared-vpc"
|
||||
subnetwork = "projects/my-host-project/regions/europe-west1/subnetworks/my-shared-subnet"
|
||||
|
||||
backend_services_config = {
|
||||
my-backend-svc = {
|
||||
backends = [
|
||||
{
|
||||
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
||||
options = null
|
||||
}
|
||||
]
|
||||
health_checks = []
|
||||
log_config = null
|
||||
options = null
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=5
|
||||
```
|
||||
|
||||
### Defining Health Checks
|
||||
|
||||
If no health checks are specified, a default health check is created and associated to each backend service without health checks already associated. The default health check configuration can be modified through the `health_checks_config_defaults` variable.
|
||||
|
||||
If the `health_checks_config_defaults` variable is set to null, no default health checks will be automatically associted to backend services.
|
||||
|
||||
Alternatively, one or more health checks can be either contextually created or attached, if existing. If the id of the health checks specified is equal to one of the keys of the `health_checks_config` variable, the health check is contextually created; otherwise, the health check id is used as is, assuming an health check with that id alredy exists.
|
||||
|
||||
For example, to contextually create a health check and attach it to the backend service:
|
||||
|
||||
```hcl
|
||||
module "ilb" {
|
||||
source = "./modules/net-ilb-l7"
|
||||
name = "ilb-test"
|
||||
project_id = var.project_id
|
||||
region = "europe-west1"
|
||||
network = var.vpc.self_link
|
||||
subnetwork = var.subnet.self_link
|
||||
|
||||
backend_services_config = {
|
||||
my-backend-svc = {
|
||||
backends = [
|
||||
{
|
||||
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
||||
options = null
|
||||
}
|
||||
],
|
||||
health_checks = ["hc-1"]
|
||||
log_config = null
|
||||
options = null
|
||||
}
|
||||
}
|
||||
|
||||
health_checks_config = {
|
||||
hc-1 = {
|
||||
type = "http"
|
||||
logging = true
|
||||
options = {
|
||||
timeout_sec = 5
|
||||
}
|
||||
check = {
|
||||
port_specification = "USE_SERVING_PORT"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=5
|
||||
```
|
||||
|
||||
### Network Endpoint Groups (NEGs)
|
||||
|
||||
Zonal Network Endpoint Groups (NEGs) can also be used, as shown in the example below.
|
||||
|
||||
```hcl
|
||||
module "ilb" {
|
||||
source = "./modules/net-ilb-l7"
|
||||
name = "ilb-test"
|
||||
project_id = var.project_id
|
||||
region = "europe-west1"
|
||||
network = var.vpc.self_link
|
||||
subnetwork = var.subnet.self_link
|
||||
|
||||
backend_services_config = {
|
||||
my-backend-svc = {
|
||||
backends = [
|
||||
{
|
||||
group = google_compute_network_endpoint_group.my-neg.id
|
||||
options = {
|
||||
balancing_mode = "RATE"
|
||||
capacity_scaler = 1.0
|
||||
max_connections = null
|
||||
max_connections_per_instance = null
|
||||
max_connections_per_endpoint = null
|
||||
max_rate = 100
|
||||
max_rate_per_endpoint = null
|
||||
max_rate_per_instance = null
|
||||
max_utilization = null
|
||||
}
|
||||
}
|
||||
],
|
||||
health_checks = []
|
||||
log_config = null
|
||||
options = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_network_endpoint_group" "my-neg" {
|
||||
name = "my-neg"
|
||||
project = var.project_id
|
||||
network = var.vpc.self_link
|
||||
subnetwork = var.subnet.self_link
|
||||
default_port = "90"
|
||||
zone = "europe-west1-b"
|
||||
}
|
||||
# tftest modules=1 resources=5
|
||||
```
|
||||
-->
|
||||
|
||||
### Url-map
|
||||
|
||||
The url-map can be customized with lots of different configurations. This includes leveraging multiple backends in different parts of the configuration.
|
||||
Given its complexity, it's left to the user passing the right data structure.
|
||||
|
||||
For simplicity, *if no configurations are given* the first backend service defined (in alphabetical order, with priority to bucket backend services, if any) is used as the *default_service*, thus answering to the root (*/*) path.
|
||||
|
||||
Backend services can be specified as needed in the url-map configuration, referencing the id used to declare them in the backend services map. If a corresponding backend service is found, their object id is automatically used; otherwise, it is assumed that the string passed is the id of an already existing backend and it is given to the provider as it was passed.
|
||||
|
||||
In this example, we're using a backend service as the default backend
|
||||
|
||||
```hcl
|
||||
module "ilb" {
|
||||
source = "./modules/net-ilb-l7"
|
||||
name = "ilb-test"
|
||||
project_id = var.project_id
|
||||
region = "europe-west1"
|
||||
network = var.vpc.self_link
|
||||
subnetwork = var.subnet.self_link
|
||||
|
||||
url_map_config = {
|
||||
default_service = "my-backend-svc"
|
||||
default_url_redirect = null
|
||||
tests = null
|
||||
host_rules = []
|
||||
path_matchers = [
|
||||
{
|
||||
name = "my-example-page"
|
||||
path_rules = [
|
||||
{
|
||||
paths = ["/my-example-page"]
|
||||
service = "another-group-backend"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
backend_services_config = {
|
||||
my-backend-svc = {
|
||||
backends = [
|
||||
{
|
||||
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
||||
options = null
|
||||
}
|
||||
],
|
||||
health_checks = []
|
||||
log_config = null
|
||||
options = null
|
||||
},
|
||||
my-example-page = {
|
||||
backends = [
|
||||
{
|
||||
group = "projects/my-project/zones/europe-west1-a/instanceGroups/another-ig"
|
||||
options = null
|
||||
}
|
||||
],
|
||||
health_checks = []
|
||||
log_config = null
|
||||
options = null
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=6
|
||||
```
|
||||
|
||||
### Reserve a static IP address
|
||||
|
||||
Optionally, a static IP address can be reserved:
|
||||
|
||||
```hcl
|
||||
module "ilb" {
|
||||
source = "./modules/net-ilb-l7"
|
||||
name = "ilb-test"
|
||||
project_id = var.project_id
|
||||
region = "europe-west1"
|
||||
network = var.vpc.self_link
|
||||
subnetwork = var.subnet.self_link
|
||||
|
||||
static_ip_config = {
|
||||
reserve = true
|
||||
options = null
|
||||
}
|
||||
|
||||
backend_services_config = {
|
||||
my-backend-svc = {
|
||||
backends = [
|
||||
{
|
||||
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
||||
options = null
|
||||
}
|
||||
],
|
||||
health_checks = []
|
||||
log_config = null
|
||||
options = null
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=6
|
||||
```
|
||||
|
||||
### HTTPS And SSL Certificates
|
||||
|
||||
HTTPS is disabled by default but it can be optionally enabled.
|
||||
|
||||
When HTTPS is enabled, if the ids specified in the `target_proxy_https_config` variable are not found in the `ssl_certificates_config` map, they are used as is, assuming the ssl certificates already exist:
|
||||
|
||||
```hcl
|
||||
module "ilb" {
|
||||
source = "./modules/net-ilb-l7"
|
||||
name = "ilb-test"
|
||||
project_id = var.project_id
|
||||
region = "europe-west1"
|
||||
network = var.vpc.self_link
|
||||
subnetwork = var.subnet.self_link
|
||||
|
||||
https = true
|
||||
|
||||
target_proxy_https_config = {
|
||||
ssl_certificates = [
|
||||
"an-existing-cert"
|
||||
]
|
||||
}
|
||||
|
||||
backend_services_config = {
|
||||
my-backend-svc = {
|
||||
backends = [
|
||||
{
|
||||
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
||||
options = null
|
||||
}
|
||||
]
|
||||
health_checks = []
|
||||
log_config = null
|
||||
options = null
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=5
|
||||
```
|
||||
|
||||
Otherwise, unmanaged certificates can also be contextually created:
|
||||
|
||||
```hcl
|
||||
module "ilb" {
|
||||
source = "./modules/net-ilb-l7"
|
||||
name = "ilb-test"
|
||||
project_id = var.project_id
|
||||
region = "europe-west1"
|
||||
network = var.vpc.self_link
|
||||
subnetwork = var.subnet.self_link
|
||||
|
||||
https = true
|
||||
|
||||
ssl_certificates_config = {
|
||||
my-domain = {
|
||||
domains = [
|
||||
"my-domain.com"
|
||||
],
|
||||
tls_private_key = tls_private_key.self_signed_key.private_key_pem
|
||||
tls_self_signed_cert = tls_self_signed_cert.self_signed_cert.cert_pem
|
||||
}
|
||||
}
|
||||
|
||||
target_proxy_https_config = {
|
||||
ssl_certificates = [
|
||||
"my-domain"
|
||||
]
|
||||
}
|
||||
|
||||
backend_services_config = {
|
||||
my-backend-svc = {
|
||||
backends = [
|
||||
{
|
||||
group = "projects/my-project/zones/europe-west1-a/instanceGroups/my-ig"
|
||||
options = null
|
||||
}
|
||||
],
|
||||
health_checks = []
|
||||
log_config = null
|
||||
options = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "tls_private_key" "self_signed_key" {
|
||||
algorithm = "RSA"
|
||||
rsa_bits = 2048
|
||||
}
|
||||
|
||||
resource "tls_self_signed_cert" "self_signed_cert" {
|
||||
key_algorithm = tls_private_key.self_signed_key.algorithm
|
||||
private_key_pem = tls_private_key.self_signed_key.private_key_pem
|
||||
validity_period_hours = 12
|
||||
early_renewal_hours = 3
|
||||
dns_names = ["example.com"]
|
||||
allowed_uses = [
|
||||
"key_encipherment",
|
||||
"digital_signature",
|
||||
"server_auth"
|
||||
]
|
||||
subject {
|
||||
common_name = "example.com"
|
||||
organization = "My Test Org"
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=6
|
||||
```
|
||||
|
||||
## Components And Files Mapping
|
||||
|
||||
An Internal HTTP Load Balancer is made of multiple components, that change depending on the configurations. Sometimes, it may be tricky to understand what they are, and how they relate to each other. Following, we provide a very brief overview to become more familiar with them.
|
||||
|
||||
- The global load balancer [forwarding rule](forwarding-rule.tf) binds a frontend public Virtual IP (VIP) to an HTTP(S) [target proxy](target-proxy.tf).
|
||||
- If the target proxy is HTTPS, it requires one or more unmanaged [SSL certificates](ssl-certificates.tf).
|
||||
- Target proxies leverage [url-maps](url-map.tf): a set of L7 rules that create a mapping between specific hostnames, URIs (and more) to one or more [backends services](backend-services.tf).
|
||||
- [Backend services](backend-services.tf) link to one or multiple infrastructure groups (GCE instance groups or NEGs). It is assumed in this module that groups have been previously created through other modules, and referenced in the input variables.
|
||||
- Backend services support one or more [health checks](health-checks.tf), used to verify that the backend is indeed healthy, so that traffic can be forwarded to it. Health checks currently supported in this module are HTTP, HTTPS, HTTP2, SSL, TCP.
|
||||
|
||||
<!-- TFDOC OPTS files:1 -->
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Files
|
||||
|
||||
| name | description | resources |
|
||||
|---|---|---|
|
||||
| [backend-services.tf](./backend-services.tf) | Bucket and group backend services. | <code>google_compute_region_backend_service</code> |
|
||||
| [forwarding-rule.tf](./forwarding-rule.tf) | IP Address and forwarding rule. | <code>google_compute_address</code> · <code>google_compute_forwarding_rule</code> |
|
||||
| [health-checks.tf](./health-checks.tf) | Health checks. | <code>google_compute_region_health_check</code> |
|
||||
| [outputs.tf](./outputs.tf) | Module outputs. | |
|
||||
| [ssl-certificates.tf](./ssl-certificates.tf) | SSL certificates. | <code>google_compute_region_ssl_certificate</code> |
|
||||
| [target-proxy.tf](./target-proxy.tf) | HTTP and HTTPS target proxies. | <code>google_compute_region_target_http_proxy</code> · <code>google_compute_region_target_https_proxy</code> |
|
||||
| [url-map.tf](./url-map.tf) | URL maps. | <code>google_compute_region_url_map</code> |
|
||||
| [variables.tf](./variables.tf) | Module variables. | |
|
||||
| [versions.tf](./versions.tf) | Version pins. | |
|
||||
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [name](variables.tf#L17) | Load balancer name. | <code>string</code> | ✓ | |
|
||||
| [project_id](variables.tf#L22) | Project id. | <code>string</code> | ✓ | |
|
||||
| [region](variables.tf#L157) | The region where to allocate the ILB resources. | <code>string</code> | ✓ | |
|
||||
| [subnetwork](variables.tf#L187) | The subnetwork where the ILB VIP is allocated. | <code>string</code> | ✓ | |
|
||||
| [backend_services_config](variables.tf#L27) | The backends services configuration. | <code title="map(object({ backends = list(object({ group = string # The instance group link id options = object({ balancing_mode = string # Can be UTILIZATION, RATE 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 }) })) 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 locality_lb_policy = string port_name = string protocol = 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 }) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [forwarding_rule_config](variables.tf#L98) | Forwarding rule configurations. | <code title="object({ ip_version = string labels = map(string) network_tier = string port_range = string })">object({…})</code> | | <code title="{ allow_global_access = true ip_version = "IPV4" labels = {} network_tier = "PREMIUM" port_range = null }">{…}</code> |
|
||||
| [health_checks_config](variables.tf#L116) | Custom health checks configuration. | <code title="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 }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [health_checks_config_defaults](variables.tf#L127) | Auto-created health check default configuration. | <code title="object({ check = map(any) # actual health check block attributes logging = bool options = map(number) # interval, thresholds, timeout type = string # http https tcp ssl http2 })">object({…})</code> | | <code title="{ type = "http" logging = false options = {} check = { port_specification = "USE_SERVING_PORT" } }">{…}</code> |
|
||||
| [https](variables.tf#L145) | Whether to enable HTTPS. | <code>bool</code> | | <code>false</code> |
|
||||
| [network](variables.tf#L151) | The network where the ILB is created. | <code>string</code> | | <code>"default"</code> |
|
||||
| [ssl_certificates_config](variables.tf#L162) | The SSL certificates configuration. | <code title="map(object({ domains = list(string) tls_private_key = string tls_self_signed_cert = string }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [static_ip_config](variables.tf#L172) | Static IP address configuration. | <code title="object({ reserve = bool options = object({ address = string subnetwork = string # The subnet id }) })">object({…})</code> | | <code title="{ reserve = false options = null }">{…}</code> |
|
||||
| [target_proxy_https_config](variables.tf#L192) | The HTTPS target proxy configuration. | <code title="object({ ssl_certificates = list(string) })">object({…})</code> | | <code>null</code> |
|
||||
| [url_map_config](variables.tf#L200) | The url-map configuration. | <code title="object({ default_service = string default_url_redirect = map(any) host_rules = list(any) path_matchers = list(any) tests = list(map(string)) })">object({…})</code> | | <code>null</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
| name | description | sensitive |
|
||||
|---|---|:---:|
|
||||
| [backend_services](outputs.tf#L22) | Backend service resources. | |
|
||||
| [forwarding_rule](outputs.tf#L55) | The forwarding rule. | |
|
||||
| [health_checks](outputs.tf#L17) | Health-check resources. | |
|
||||
| [ip_address](outputs.tf#L41) | The reserved IP address. | |
|
||||
| [ssl_certificate_link_ids](outputs.tf#L34) | The SSL certificate. | |
|
||||
| [target_proxy](outputs.tf#L46) | The target proxy. | |
|
||||
| [url_map](outputs.tf#L29) | The url-map. | |
|
||||
|
||||
<!-- END TFDOC -->
|
||||
133
modules/net-ilb-l7/backend-services.tf
Normal file
133
modules/net-ilb-l7/backend-services.tf
Normal file
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* 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.
|
||||
|
||||
resource "google_compute_region_backend_service" "backend_service" {
|
||||
for_each = var.backend_services_config
|
||||
name = "${var.name}-${each.key}"
|
||||
project = var.project_id
|
||||
description = "Terraform managed."
|
||||
affinity_cookie_ttl_sec = try(each.value.options.affinity_cookie_ttl_sec, null)
|
||||
connection_draining_timeout_sec = try(each.value.options.connection_draining_timeout_sec, null)
|
||||
load_balancing_scheme = "INTERNAL_MANAGED"
|
||||
locality_lb_policy = try(each.value.options.locality_lb_policy, null)
|
||||
port_name = try(each.value.options.port_name, null)
|
||||
protocol = try(each.value.options.protocol, null)
|
||||
region = var.region
|
||||
session_affinity = try(each.value.options.session_affinity, null)
|
||||
timeout_sec = try(each.value.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.health_checks), 0) == 0
|
||||
? try(
|
||||
[google_compute_region_health_check.health_check["default"].self_link],
|
||||
null
|
||||
)
|
||||
: [
|
||||
for hc in each.value.health_checks :
|
||||
try(google_compute_region_health_check.health_check[hc].self_link, hc)
|
||||
]
|
||||
)
|
||||
|
||||
dynamic "backend" {
|
||||
for_each = try(each.value.backends, [])
|
||||
content {
|
||||
balancing_mode = try(backend.value.options.balancing_mode, "UTILIZATION")
|
||||
capacity_scaler = try(backend.value.options.capacity_scaler, 1.0)
|
||||
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.options.circuit_breakers, null) == null
|
||||
? []
|
||||
: [each.value.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.options.consistent_hash, null) == null
|
||||
? []
|
||||
: [each.value.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 "iap" {
|
||||
for_each = (
|
||||
try(each.value.options.iap, null) == null
|
||||
? []
|
||||
: [each.value.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.log_config, null) == null
|
||||
? []
|
||||
: [each.value.log_config]
|
||||
)
|
||||
content {
|
||||
enable = try(log_config.value.enable, null)
|
||||
sample_rate = try(log_config.value.sample_rate, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
67
modules/net-ilb-l7/forwarding-rule.tf
Normal file
67
modules/net-ilb-l7/forwarding-rule.tf
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 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 IP Address and forwarding rule.
|
||||
|
||||
locals {
|
||||
ip_address = (
|
||||
var.static_ip_config.reserve
|
||||
? google_compute_address.static_ip.0.id
|
||||
: null
|
||||
)
|
||||
|
||||
port_range = coalesce(
|
||||
var.forwarding_rule_config.port_range,
|
||||
var.https ? "443" : "80"
|
||||
)
|
||||
|
||||
target = (
|
||||
var.https
|
||||
? google_compute_region_target_https_proxy.https.0.id
|
||||
: google_compute_region_target_http_proxy.http.0.id
|
||||
)
|
||||
}
|
||||
|
||||
resource "google_compute_address" "static_ip" {
|
||||
count = var.static_ip_config.reserve ? 1 : 0
|
||||
provider = google-beta
|
||||
name = var.name
|
||||
project = var.project_id
|
||||
description = "Terraform managed."
|
||||
address_type = "INTERNAL"
|
||||
address = try(var.static_ip_config.options.address, null)
|
||||
purpose = "GCE_ENDPOINT"
|
||||
region = try(var.region, null)
|
||||
subnetwork = try(var.static_ip_config.options.subnet, var.subnetwork, null)
|
||||
}
|
||||
|
||||
resource "google_compute_forwarding_rule" "forwarding_rule" {
|
||||
provider = google-beta
|
||||
name = var.name
|
||||
project = var.project_id
|
||||
description = "Terraform managed."
|
||||
ip_address = local.ip_address
|
||||
ip_protocol = "TCP"
|
||||
labels = try(var.forwarding_rule_config.labels, {})
|
||||
load_balancing_scheme = "INTERNAL_MANAGED"
|
||||
network = try(var.forwarding_rule_config.network, null)
|
||||
network_tier = var.forwarding_rule_config.network_tier
|
||||
port_range = local.port_range
|
||||
ports = []
|
||||
region = try(var.region, null)
|
||||
subnetwork = try(var.subnetwork, null)
|
||||
target = local.target
|
||||
}
|
||||
148
modules/net-ilb-l7/health-checks.tf
Normal file
148
modules/net-ilb-l7/health-checks.tf
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* 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 backend services without health checks defined
|
||||
_backends_without_hcs = [
|
||||
for k, v in coalesce(var.backend_services_config, {}) :
|
||||
v if(
|
||||
try(v.health_checks, null) == null
|
||||
|| length(try(v.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_region_health_check" "health_check" {
|
||||
for_each = 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)
|
||||
region = var.region
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
58
modules/net-ilb-l7/outputs.tf
Normal file
58
modules/net-ilb-l7/outputs.tf
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
output "health_checks" {
|
||||
description = "Health-check resources."
|
||||
value = try(google_compute_region_health_check.health_check, [])
|
||||
}
|
||||
|
||||
output "backend_services" {
|
||||
description = "Backend service resources."
|
||||
value = {
|
||||
group = try(google_compute_region_backend_service.backend_service, [])
|
||||
}
|
||||
}
|
||||
|
||||
output "url_map" {
|
||||
description = "The url-map."
|
||||
value = try(google_compute_region_url_map.url_map, null)
|
||||
}
|
||||
|
||||
output "ssl_certificate_link_ids" {
|
||||
description = "The SSL certificate."
|
||||
value = {
|
||||
for k, v in google_compute_region_ssl_certificate.certificates : k => v.self_link
|
||||
}
|
||||
}
|
||||
|
||||
output "ip_address" {
|
||||
description = "The reserved IP address."
|
||||
value = try(google_compute_forwarding_rule.forwarding_rule.ip_address, null)
|
||||
}
|
||||
|
||||
output "target_proxy" {
|
||||
description = "The target proxy."
|
||||
value = try(
|
||||
google_compute_region_target_https_proxy.https.0,
|
||||
google_compute_region_target_http_proxy.http.0,
|
||||
[]
|
||||
)
|
||||
}
|
||||
|
||||
output "forwarding_rule" {
|
||||
description = "The forwarding rule."
|
||||
value = try(google_compute_forwarding_rule.forwarding_rule, null)
|
||||
}
|
||||
26
modules/net-ilb-l7/ssl-certificates.tf
Normal file
26
modules/net-ilb-l7/ssl-certificates.tf
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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.
|
||||
|
||||
resource "google_compute_region_ssl_certificate" "certificates" {
|
||||
for_each = var.ssl_certificates_config
|
||||
project = var.project_id
|
||||
name = "${var.name}-${each.key}"
|
||||
certificate = try(each.value.tls_self_signed_cert, null)
|
||||
private_key = try(each.value.tls_private_key, null)
|
||||
region = var.region
|
||||
}
|
||||
48
modules/net-ilb-l7/target-proxy.tf
Normal file
48
modules/net-ilb-l7/target-proxy.tf
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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 {
|
||||
# Look for the cert in the the ssl_certificates_config map.
|
||||
# If not found, use the SSL certificate id as is (already existing).
|
||||
ssl_certificates = [
|
||||
for cert in try(var.target_proxy_https_config.ssl_certificates, []) :
|
||||
try(
|
||||
google_compute_region_ssl_certificate.certificates[cert].self_link,
|
||||
cert
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_compute_region_target_http_proxy" "http" {
|
||||
count = var.https ? 0 : 1
|
||||
name = var.name
|
||||
project = var.project_id
|
||||
description = "Terraform managed."
|
||||
region = var.region
|
||||
url_map = google_compute_region_url_map.url_map.id
|
||||
}
|
||||
|
||||
resource "google_compute_region_target_https_proxy" "https" {
|
||||
count = var.https ? 1 : 0
|
||||
name = var.name
|
||||
project = var.project_id
|
||||
description = "Terraform managed."
|
||||
region = var.region
|
||||
url_map = google_compute_region_url_map.url_map.id
|
||||
ssl_certificates = local.ssl_certificates
|
||||
}
|
||||
708
modules/net-ilb-l7/url-map.tf
Normal file
708
modules/net-ilb-l7/url-map.tf
Normal file
@@ -0,0 +1,708 @@
|
||||
/**
|
||||
* 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 maps.
|
||||
|
||||
locals {
|
||||
# Look for a backend service 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.
|
||||
_default_service = try(
|
||||
google_compute_region_backend_service.backend_service[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
|
||||
default_service = (
|
||||
try(local._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_region_backend_service.backend_service[keys(google_compute_region_backend_service.backend_service)[0]].id,
|
||||
null
|
||||
)
|
||||
: null
|
||||
)
|
||||
}
|
||||
|
||||
resource "google_compute_region_url_map" "url_map" {
|
||||
name = var.name
|
||||
description = "Terraform managed."
|
||||
project = var.project_id
|
||||
region = var.region
|
||||
default_service = local.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_region_backend_service.backend_service[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_region_backend_service.backend_service[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_region_backend_service.backend_service[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_region_backend_service.backend_service[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_region_backend_service.backend_service[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_region_backend_service.backend_service[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_region_backend_service.backend_service[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_region_backend_service.backend_service[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)
|
||||
}
|
||||
}
|
||||
}
|
||||
210
modules/net-ilb-l7/variables.tf
Normal file
210
modules/net-ilb-l7/variables.tf
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* 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 "name" {
|
||||
description = "Load balancer name."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "Project id."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "backend_services_config" {
|
||||
description = "The backends services configuration."
|
||||
type = map(object({
|
||||
backends = list(object({
|
||||
group = string # The instance group link id
|
||||
options = object({
|
||||
balancing_mode = string # Can be UTILIZATION, RATE
|
||||
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
|
||||
locality_lb_policy = string
|
||||
port_name = string
|
||||
protocol = 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 "forwarding_rule_config" {
|
||||
description = "Forwarding rule configurations."
|
||||
type = object({
|
||||
ip_version = string
|
||||
labels = map(string)
|
||||
network_tier = string
|
||||
port_range = string
|
||||
})
|
||||
default = {
|
||||
allow_global_access = true
|
||||
ip_version = "IPV4"
|
||||
labels = {}
|
||||
network_tier = "PREMIUM"
|
||||
# If not specified, 443 if var.https = true; 80 otherwise
|
||||
port_range = null
|
||||
}
|
||||
}
|
||||
|
||||
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 "health_checks_config_defaults" {
|
||||
description = "Auto-created health check default configuration."
|
||||
type = object({
|
||||
check = map(any) # actual health check block attributes
|
||||
logging = bool
|
||||
options = map(number) # interval, thresholds, timeout
|
||||
type = string # http https tcp ssl http2
|
||||
})
|
||||
default = {
|
||||
type = "http"
|
||||
logging = false
|
||||
options = {}
|
||||
check = {
|
||||
port_specification = "USE_SERVING_PORT"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "https" {
|
||||
description = "Whether to enable HTTPS."
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "network" {
|
||||
description = "The network where the ILB is created."
|
||||
type = string
|
||||
default = "default"
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "The region where to allocate the ILB resources."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "ssl_certificates_config" {
|
||||
description = "The SSL certificates configuration."
|
||||
type = map(object({
|
||||
domains = list(string)
|
||||
tls_private_key = string
|
||||
tls_self_signed_cert = string
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "static_ip_config" {
|
||||
description = "Static IP address configuration."
|
||||
type = object({
|
||||
reserve = bool
|
||||
options = object({
|
||||
address = string
|
||||
subnetwork = string # The subnet id
|
||||
})
|
||||
})
|
||||
default = {
|
||||
reserve = false
|
||||
options = null
|
||||
}
|
||||
}
|
||||
|
||||
variable "subnetwork" {
|
||||
description = "The subnetwork where the ILB VIP is allocated."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "target_proxy_https_config" {
|
||||
description = "The HTTPS target proxy configuration."
|
||||
type = object({
|
||||
ssl_certificates = list(string)
|
||||
})
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "url_map_config" {
|
||||
description = "The url-map configuration."
|
||||
type = object({
|
||||
default_service = string
|
||||
default_url_redirect = map(any)
|
||||
host_rules = list(any)
|
||||
path_matchers = list(any)
|
||||
tests = list(map(string))
|
||||
})
|
||||
default = null
|
||||
}
|
||||
27
modules/net-ilb-l7/versions.tf
Normal file
27
modules/net-ilb-l7/versions.tf
Normal file
@@ -0,0 +1,27 @@
|
||||
# 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
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.0.0"
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = ">= 4.0.0"
|
||||
}
|
||||
google-beta = {
|
||||
source = "hashicorp/google-beta"
|
||||
version = ">= 4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
13
tests/modules/net_ilb_l7/__init__.py
Normal file
13
tests/modules/net_ilb_l7/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# 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.
|
||||
33
tests/modules/net_ilb_l7/fixture/main.tf
Normal file
33
tests/modules/net_ilb_l7/fixture/main.tf
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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-ilb-l7"
|
||||
project_id = "my-project"
|
||||
name = "ilb-l7-test"
|
||||
region = "europe-west1"
|
||||
network = "projects/my-project/global/networks/default"
|
||||
subnetwork = "projects/my-project/regions/europe-west1/subnetworks/default"
|
||||
backend_services_config = var.backend_services_config
|
||||
forwarding_rule_config = var.forwarding_rule_config
|
||||
health_checks_config = var.health_checks_config
|
||||
health_checks_config_defaults = var.health_checks_config_defaults
|
||||
https = var.https
|
||||
ssl_certificates_config = var.ssl_certificates_config
|
||||
static_ip_config = var.static_ip_config
|
||||
target_proxy_https_config = var.target_proxy_https_config
|
||||
url_map_config = var.url_map_config
|
||||
}
|
||||
184
tests/modules/net_ilb_l7/fixture/variables.tf
Normal file
184
tests/modules/net_ilb_l7/fixture/variables.tf
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* 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 "backend_services_config" {
|
||||
description = "The backends services configuration."
|
||||
type = map(object({
|
||||
backends = list(object({
|
||||
group = string # IG FQDN address
|
||||
options = object({
|
||||
balancing_mode = string # Can be UTILIZATION, RATE
|
||||
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
|
||||
locality_lb_policy = string
|
||||
port_name = string
|
||||
protocol = 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 "forwarding_rule_config" {
|
||||
description = "Forwarding rule configurations."
|
||||
type = object({
|
||||
ip_version = string
|
||||
labels = map(string)
|
||||
network_tier = string
|
||||
port_range = string
|
||||
})
|
||||
default = {
|
||||
allow_global_access = true
|
||||
ip_version = "IPV4"
|
||||
labels = {}
|
||||
network_tier = "PREMIUM"
|
||||
# If not specified, 443 if var.https = true; 80 otherwise
|
||||
port_range = null
|
||||
}
|
||||
}
|
||||
|
||||
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 "health_checks_config_defaults" {
|
||||
description = "Auto-created health check default configuration."
|
||||
type = object({
|
||||
check = map(any) # actual health check block attributes
|
||||
logging = bool
|
||||
options = map(number) # interval, thresholds, timeout
|
||||
type = string # http https tcp ssl http2
|
||||
})
|
||||
default = {
|
||||
type = "http"
|
||||
logging = false
|
||||
options = {}
|
||||
check = {
|
||||
port_specification = "USE_SERVING_PORT"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "https" {
|
||||
description = "Whether to enable HTTPS."
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "ssl_certificates_config" {
|
||||
description = "The SSL certificate configuration."
|
||||
type = map(object({
|
||||
domains = list(string)
|
||||
tls_private_key = string
|
||||
tls_self_signed_cert = string
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "static_ip_config" {
|
||||
description = "Static IP address configuration."
|
||||
type = object({
|
||||
reserve = bool
|
||||
options = object({
|
||||
address = string
|
||||
subnetwork = string # The subnet id
|
||||
})
|
||||
})
|
||||
default = {
|
||||
reserve = false
|
||||
options = null
|
||||
}
|
||||
}
|
||||
|
||||
variable "target_proxy_https_config" {
|
||||
description = "The HTTPS target proxy configuration."
|
||||
type = object({
|
||||
ssl_certificates = list(string)
|
||||
})
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "url_map_config" {
|
||||
description = "The url-map configuration."
|
||||
type = object({
|
||||
default_service = string
|
||||
default_url_redirect = map(any)
|
||||
host_rules = list(any)
|
||||
path_matchers = list(any)
|
||||
tests = list(map(string))
|
||||
})
|
||||
default = null
|
||||
}
|
||||
184
tests/modules/net_ilb_l7/test_plan.py
Normal file
184
tests/modules/net_ilb_l7/test_plan.py
Normal file
@@ -0,0 +1,184 @@
|
||||
# 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_SVC_CONFIG = '''{
|
||||
my-group = {
|
||||
backends = [
|
||||
{
|
||||
group = "my_group",
|
||||
options = null
|
||||
}
|
||||
],
|
||||
health_checks = []
|
||||
log_config = null
|
||||
options = null
|
||||
}
|
||||
}'''
|
||||
|
||||
_BACKEND_SVC_CONFIG_HC = '''{
|
||||
my-group = {
|
||||
backends = [
|
||||
{
|
||||
group = "my_group",
|
||||
options = null
|
||||
}
|
||||
],
|
||||
health_checks = ["hc_1"]
|
||||
log_config = null
|
||||
options = null
|
||||
}
|
||||
}'''
|
||||
|
||||
_NAME = 'ilb-l7-test'
|
||||
|
||||
_RESERVED_IP_CONFIG = '''{
|
||||
reserve = true
|
||||
options = null
|
||||
}'''
|
||||
|
||||
_SSL_CERTIFICATES_CONFIG = '''{
|
||||
my-domain = {
|
||||
domains = [
|
||||
"my-domain.com"
|
||||
],
|
||||
tls_private_key = "my-key"
|
||||
tls_self_signed_cert = "my-cert"
|
||||
}
|
||||
}'''
|
||||
|
||||
_TARGET_PROXY_HTTPS_CONFIG = '''{
|
||||
ssl_certificates = [
|
||||
"my-domain"
|
||||
]
|
||||
}'''
|
||||
|
||||
|
||||
def test_group_default_hc(plan_runner):
|
||||
"Tests a group backend service with no HC specified."
|
||||
_, resources = plan_runner(backend_services_config=_BACKEND_SVC_CONFIG)
|
||||
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'] == 'INTERNAL_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_SVC_CONFIG,
|
||||
health_checks_config_defaults='null')
|
||||
|
||||
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_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
|
||||
assert 'google_compute_forwarding_rule' 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_SVC_CONFIG_HC)
|
||||
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_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
|
||||
assert 'google_compute_forwarding_rule' in resources
|
||||
|
||||
|
||||
def test_reserved_ip(plan_runner):
|
||||
"Tests an IP reservation with a group backend service."
|
||||
_, resources = plan_runner(
|
||||
backend_services_config=_BACKEND_SVC_CONFIG,
|
||||
static_ip_config=_RESERVED_IP_CONFIG
|
||||
)
|
||||
assert len(resources) == 6
|
||||
resources = dict((r['type'], r['values']) for r in resources)
|
||||
|
||||
assert 'google_compute_region_backend_service' 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
|
||||
assert 'google_compute_address' in resources
|
||||
assert 'google_compute_forwarding_rule' in resources
|
||||
|
||||
|
||||
def test_ssl(plan_runner):
|
||||
"Tests HTTPS and SSL certificates."
|
||||
_, resources = plan_runner(
|
||||
backend_services_config=_BACKEND_SVC_CONFIG,
|
||||
https="true",
|
||||
ssl_certificates_config=_SSL_CERTIFICATES_CONFIG,
|
||||
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_forwarding_rule']
|
||||
assert fwd_rule['port_range'] == '443'
|
||||
|
||||
assert 'google_compute_region_backend_service' in resources
|
||||
assert 'google_compute_region_ssl_certificate' in resources
|
||||
assert 'google_compute_region_target_http_proxy' not in resources
|
||||
assert 'google_compute_region_target_https_proxy' in resources
|
||||
assert 'google_compute_region_url_map' in resources
|
||||
assert 'google_compute_forwarding_rule' in resources
|
||||
|
||||
|
||||
def test_ssl_existing_cert(plan_runner):
|
||||
"Tests HTTPS and SSL existing certificate."
|
||||
_, resources = plan_runner(
|
||||
backend_services_config=_BACKEND_SVC_CONFIG,
|
||||
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_forwarding_rule']
|
||||
assert fwd_rule['port_range'] == '443'
|
||||
|
||||
assert 'google_compute_region_backend_service' in resources
|
||||
assert 'google_compute_region_ssl_certificate' not in resources
|
||||
assert 'google_compute_region_target_http_proxy' not in resources
|
||||
assert 'google_compute_region_target_https_proxy' in resources
|
||||
assert 'google_compute_region_url_map' in resources
|
||||
assert 'google_compute_forwarding_rule' in resources
|
||||
Reference in New Issue
Block a user