Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define service attachment interface for lb modules and implement in internal LBs #2122

Merged
merged 14 commits into from
Mar 2, 2024
Merged
40 changes: 36 additions & 4 deletions modules/net-lb-app-int/README.md

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions modules/net-lb-app-int/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,37 @@ resource "google_compute_region_target_https_proxy" "default" {
url_map = google_compute_region_url_map.default.id
}

resource "google_compute_service_attachment" "default" {
count = var.service_attachment == null ? 0 : 1
project = var.project_id
region = var.region
name = var.name
description = var.description
target_service = google_compute_forwarding_rule.default.id
nat_subnets = var.service_attachment.nat_subnets
connection_preference = (
var.service_attachment.automatic_connection
? "ACCEPT_AUTOMATIC"
: "ACCEPT_MANUAL"
)
consumer_reject_lists = var.service_attachment.consumer_reject_lists
domain_names = (
var.service_attachment.domain_name == null
? null
: [var.service_attachment.domain_name]
)
enable_proxy_protocol = var.service_attachment.enable_proxy_protocol
reconcile_connections = var.service_attachment.reconcile_connections
dynamic "consumer_accept_lists" {
for_each = var.service_attachment.consumer_accept_lists
iterator = accept
content {
project_id_or_num = each.key
connection_limit = each.value
ludoo marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

resource "google_compute_network_endpoint_group" "default" {
for_each = local.neg_zonal
project = (
Expand Down
7 changes: 7 additions & 0 deletions modules/net-lb-app-int/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,10 @@ output "regional_neg_ids" {
for k, v in google_compute_region_network_endpoint_group.default : k => v.id
}
}

output "service_attachment_id" {
description = "Id of the service attachment."
value = try(
google_compute_service_attachment.default.0.id, null
)
}
15 changes: 15 additions & 0 deletions modules/net-lb-app-int/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,21 @@ variable "region" {
type = string
}

variable "service_attachment" {
description = "PSC service attachment."
type = object({
nat_subnets = list(string)
automatic_connection = optional(bool, false)
consumer_accept_lists = optional(map(string), {})
consumer_reject_lists = optional(list(string))
description = optional(string)
domain_name = optional(string)
enable_proxy_protocol = optional(bool, false)
reconcile_connections = optional(bool)
})
default = null
}

variable "service_directory_registration" {
description = "Service directory namespace and service used to register this load balancer."
type = object({
Expand Down
7 changes: 6 additions & 1 deletion modules/net-lb-ext/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ locals {
)
}

resource "google_compute_forwarding_rule" "forwarding_rules" {
moved {
from = google_compute_forwarding_rule.forwarding_rules
to = google_compute_forwarding_rule.default
}

resource "google_compute_forwarding_rule" "default" {
for_each = var.forwarding_rules_config
provider = google-beta
project = var.project_id
Expand Down
8 changes: 4 additions & 4 deletions modules/net-lb-ext/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,22 @@ output "backend_service_self_link" {
output "forwarding_rule_addresses" {
description = "Forwarding rule addresses."
value = {
for k, v in google_compute_forwarding_rule.forwarding_rules
for k, v in google_compute_forwarding_rule.default
: k => v.ip_address
}
}

output "forwarding_rule_self_links" {
description = "Forwarding rule self links."
value = {
for k, v in google_compute_forwarding_rule.forwarding_rules
for k, v in google_compute_forwarding_rule.default
: k => v.self_link
}
}

output "forwarding_rules" {
description = "Forwarding rule resources."
value = google_compute_forwarding_rule.forwarding_rules
value = google_compute_forwarding_rule.default
}

output "group_self_links" {
Expand Down Expand Up @@ -80,7 +80,7 @@ output "health_check_self_link" {
output "id" {
description = "Fully qualified forwarding rule ids."
value = {
for k, v in google_compute_forwarding_rule.forwarding_rules
for k, v in google_compute_forwarding_rule.default
: k => v.id
}
}
89 changes: 74 additions & 15 deletions modules/net-lb-int/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@

This module allows managing a GCE Internal Load Balancer and integrates the forwarding rule, regional backend, and optional health check resources. It's designed to be a simple match for the [`compute-vm`](../compute-vm) module, which can be used to manage instance templates and instance groups.

## Issues

There are some corner cases where Terraform raises a cycle error on apply, for example when using the entire ILB module as a value in `for_each` counts used to create static routes in the VPC module. These are easily fixed by using forwarding rule ids instead of modules as values in the `for_each` loop.

<!--
One other issue is a `Provider produced inconsistent final plan` error which is sometimes raised when switching template version. This seems to be related to this [open provider issue](https://github.com/terraform-providers/terraform-provider-google/issues/3937), but it's relatively harmless since the resource is updated, and subsequent applies raise no errors.
-->
<!-- BEGIN TOC -->
- [Examples](#examples)
- [Referencing existing MIGs](#referencing-existing-migs)
- [Externally managed instances](#externally-managed-instances)
- [Passing multiple protocols through the load balancers](#passing-multiple-protocols-through-the-load-balancers)
- [Mutiple forwarding rules](#mutiple-forwarding-rules)
- [Dual stack (IPv4 and IPv6)](#dual-stack-ipv4-and-ipv6)
- [PSC service attachments](#psc-service-attachments)
- [End to end example](#end-to-end-example)
- [Issues](#issues)
- [Variables](#variables)
- [Outputs](#outputs)
<!-- END TOC -->

## Examples

- [Referencing existing MIGs](#referencing-existing-migs)
- [Externally managed instances](#externally-managed-instances)
- [Passing multiple protocols through the load balancers](#passing-multiple-protocols-through-the-load-balancers)
- [End to end example](#end-to-end-example)

### Referencing existing MIGs

This example shows how to reference existing Managed Infrastructure Groups (MIGs).
Expand Down Expand Up @@ -154,7 +155,6 @@ The example adds two forwarding rules:
- the first one, called `ilb-test-vip-one` exposes an IPv4 address, it listens on all ports, and allows connections from any region.
- the second one, called `ilb-test-vip-two` exposes an IPv4 address, it listens on port 80 and allows connections from the same region only.


```hcl
module "ilb" {
source = "./fabric/modules/net-lb-int"
Expand Down Expand Up @@ -229,6 +229,54 @@ module "ilb" {
# tftest modules=1 resources=5
```

### PSC service attachments

The optional `service_attachments` variable allows optional configuration of one service attachment for each of the forwarding rules.
ludoo marked this conversation as resolved.
Show resolved Hide resolved

```hcl
module "ilb" {
source = "./fabric/modules/net-lb-int"
project_id = var.project_id
region = "europe-west1"
name = "ilb-test"
service_label = "ilb-test"
vpc_config = {
network = var.vpc.self_link
subnetwork = var.subnet.self_link
}
forwarding_rules_config = {
vip-one = {}
vip-two = {
global_access = false
ports = [80]
}
}
group_configs = {
my-group = {
zone = "europe-west1-b"
instances = [
"instance-1-self-link",
"instance-2-self-link"
]
}
}
backends = [{
group = module.ilb.groups.my-group.self_link
}]
service_attachments = {
vip-one = {
nat_subnets = [var.subnet_psc_1.self_link]
automatic_connection = true
}
vip-two = {
nat_subnets = [var.subnet_psc_2.self_link]
automatic_connection = true
}
}
}
# tftest modules=1 resources=7
```

### End to end example

This example spins up a simple HTTP server and combines four modules:
Expand Down Expand Up @@ -298,6 +346,15 @@ module "ilb" {
}
# tftest modules=3 resources=7 e2e
```

## Issues

There are some corner cases where Terraform raises a cycle error on apply, for example when using the entire ILB module as a value in `for_each` counts used to create static routes in the VPC module. These are easily fixed by using forwarding rule ids instead of modules as values in the `for_each` loop.

<!--
One other issue is a `Provider produced inconsistent final plan` error which is sometimes raised when switching template version. This seems to be related to this [open provider issue](https://github.com/terraform-providers/terraform-provider-google/issues/3937), but it's relatively harmless since the resource is updated, and subsequent applies raise no errors.
-->

<!-- BEGIN TFDOC -->
## Variables

Expand All @@ -306,7 +363,7 @@ module "ilb" {
| [name](variables.tf#L184) | Name used for all resources. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L189) | Project id where resources will be created. | <code>string</code> | ✓ | |
| [region](variables.tf#L200) | GCP region. | <code>string</code> | ✓ | |
| [vpc_config](variables.tf#L211) | VPC-level configuration. | <code title="object&#40;&#123;&#10; network &#61; string&#10; subnetwork &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [vpc_config](variables.tf#L226) | VPC-level configuration. | <code title="object&#40;&#123;&#10; network &#61; string&#10; subnetwork &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [backend_service_config](variables.tf#L17) | Backend service level configuration. | <code title="object&#40;&#123;&#10; connection_draining_timeout_sec &#61; optional&#40;number&#41;&#10; connection_tracking &#61; optional&#40;object&#40;&#123;&#10; idle_timeout_sec &#61; optional&#40;number&#41;&#10; persist_conn_on_unhealthy &#61; optional&#40;string&#41;&#10; track_per_session &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10; enable_subsetting &#61; optional&#40;bool&#41;&#10; failover_config &#61; optional&#40;object&#40;&#123;&#10; disable_conn_drain &#61; optional&#40;bool&#41;&#10; drop_traffic_if_unhealthy &#61; optional&#40;bool&#41;&#10; ratio &#61; optional&#40;number&#41;&#10; &#125;&#41;&#41;&#10; log_sample_rate &#61; optional&#40;number&#41;&#10; protocol &#61; optional&#40;string, &#34;UNSPECIFIED&#34;&#41;&#10; session_affinity &#61; optional&#40;string&#41;&#10; timeout_sec &#61; optional&#40;number&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [backends](variables.tf#L51) | Load balancer backends. | <code title="list&#40;object&#40;&#123;&#10; group &#61; string&#10; description &#61; optional&#40;string, &#34;Terraform managed.&#34;&#41;&#10; failover &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [description](variables.tf#L62) | Optional description used for resources. | <code>string</code> | | <code>&#34;Terraform managed.&#34;</code> |
Expand All @@ -316,7 +373,8 @@ module "ilb" {
| [health_check_config](variables.tf#L101) | Optional auto-created health check configuration, use the output self-link to set it in the auto healing policy. Refer to examples for usage. | <code title="object&#40;&#123;&#10; check_interval_sec &#61; optional&#40;number&#41;&#10; description &#61; optional&#40;string, &#34;Terraform managed.&#34;&#41;&#10; enable_logging &#61; optional&#40;bool, false&#41;&#10; healthy_threshold &#61; optional&#40;number&#41;&#10; timeout_sec &#61; optional&#40;number&#41;&#10; unhealthy_threshold &#61; optional&#40;number&#41;&#10; grpc &#61; optional&#40;object&#40;&#123;&#10; port &#61; optional&#40;number&#41;&#10; port_name &#61; optional&#40;string&#41;&#10; port_specification &#61; optional&#40;string&#41; &#35; USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT&#10; service_name &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; http &#61; optional&#40;object&#40;&#123;&#10; host &#61; optional&#40;string&#41;&#10; port &#61; optional&#40;number&#41;&#10; port_name &#61; optional&#40;string&#41;&#10; port_specification &#61; optional&#40;string&#41; &#35; USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT&#10; proxy_header &#61; optional&#40;string&#41;&#10; request_path &#61; optional&#40;string&#41;&#10; response &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; http2 &#61; optional&#40;object&#40;&#123;&#10; host &#61; optional&#40;string&#41;&#10; port &#61; optional&#40;number&#41;&#10; port_name &#61; optional&#40;string&#41;&#10; port_specification &#61; optional&#40;string&#41; &#35; USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT&#10; proxy_header &#61; optional&#40;string&#41;&#10; request_path &#61; optional&#40;string&#41;&#10; response &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; https &#61; optional&#40;object&#40;&#123;&#10; host &#61; optional&#40;string&#41;&#10; port &#61; optional&#40;number&#41;&#10; port_name &#61; optional&#40;string&#41;&#10; port_specification &#61; optional&#40;string&#41; &#35; USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT&#10; proxy_header &#61; optional&#40;string&#41;&#10; request_path &#61; optional&#40;string&#41;&#10; response &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; tcp &#61; optional&#40;object&#40;&#123;&#10; port &#61; optional&#40;number&#41;&#10; port_name &#61; optional&#40;string&#41;&#10; port_specification &#61; optional&#40;string&#41; &#35; USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT&#10; proxy_header &#61; optional&#40;string&#41;&#10; request &#61; optional&#40;string&#41;&#10; response &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; ssl &#61; optional&#40;object&#40;&#123;&#10; port &#61; optional&#40;number&#41;&#10; port_name &#61; optional&#40;string&#41;&#10; port_specification &#61; optional&#40;string&#41; &#35; USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT&#10; proxy_header &#61; optional&#40;string&#41;&#10; request &#61; optional&#40;string&#41;&#10; response &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; tcp &#61; &#123;&#10; port_specification &#61; &#34;USE_SERVING_PORT&#34;&#10; &#125;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [labels](variables.tf#L178) | Labels set on resources. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [protocol](variables.tf#L194) | Forwarding rule protocol used, defaults to TCP. | <code>string</code> | | <code>&#34;TCP&#34;</code> |
| [service_label](variables.tf#L205) | Optional prefix of the fully qualified forwarding rule name. | <code>string</code> | | <code>null</code> |
| [service_attachments](variables.tf#L205) | PSC service attachments, keyed by forwarding rule. | <code title="map&#40;object&#40;&#123;&#10; nat_subnets &#61; list&#40;string&#41;&#10; automatic_connection &#61; optional&#40;bool, false&#41;&#10; consumer_accept_lists &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; consumer_reject_lists &#61; optional&#40;list&#40;string&#41;&#41;&#10; description &#61; optional&#40;string&#41;&#10; domain_name &#61; optional&#40;string&#41;&#10; enable_proxy_protocol &#61; optional&#40;bool, false&#41;&#10; reconcile_connections &#61; optional&#40;bool&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>null</code> |
| [service_label](variables.tf#L220) | Optional prefix of the fully qualified forwarding rule name. | <code>string</code> | | <code>null</code> |

## Outputs

Expand All @@ -334,4 +392,5 @@ module "ilb" {
| [health_check_id](outputs.tf#L73) | Auto-created health-check id. | |
| [health_check_self_link](outputs.tf#L78) | Auto-created health-check self link. | |
| [id](outputs.tf#L83) | Fully qualified forwarding rule ids. | |
| [service_attachment_ids](outputs.tf#L91) | Service attachment ids. | |
<!-- END TFDOC -->
60 changes: 52 additions & 8 deletions modules/net-lb-int/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,34 @@
locals {
bs_conntrack = var.backend_service_config.connection_tracking
bs_failover = var.backend_service_config.failover_config
forwarding_rule_names = {
for k, v in var.forwarding_rules_config :
k => k == "" ? var.name : "${var.name}-${k}"
}
health_check = (
var.health_check != null
? var.health_check
: google_compute_health_check.default.0.self_link
)
_service_attachments = (
var.service_attachments == null ? {} : var.service_attachments
)
service_attachments = {
for k, v in local._service_attachments :
k => v if lookup(var.forwarding_rules_config, k, null) != null
}
}

resource "google_compute_forwarding_rule" "forwarding_rules" {
for_each = var.forwarding_rules_config
provider = google-beta
project = var.project_id
name = (
each.key == "" ? var.name : "${var.name}-${each.key}"
)
moved {
from = google_compute_forwarding_rule.forwarding_rules
to = google_compute_forwarding_rule.default
}

resource "google_compute_forwarding_rule" "default" {
for_each = var.forwarding_rules_config
provider = google-beta
project = var.project_id
name = local.forwarding_rule_names[each.key]
region = var.region
description = each.value.description
ip_address = each.value.address
Expand Down Expand Up @@ -71,7 +85,10 @@ resource "google_compute_region_backend_service" "default" {
balancing_mode = "CONNECTION"
description = backend.value.description
failover = backend.value.failover
group = backend.key
group = try(
google_compute_instance_group.default[backend.key].id,
backend.key
)
}
}

Expand Down Expand Up @@ -113,3 +130,30 @@ resource "google_compute_region_backend_service" "default" {
}

}

resource "google_compute_service_attachment" "default" {
for_each = local.service_attachments
project = var.project_id
region = var.region
name = local.forwarding_rule_names[each.key]
description = var.description
target_service = google_compute_forwarding_rule.default[each.key].id
nat_subnets = each.value.nat_subnets
connection_preference = (
each.value.automatic_connection ? "ACCEPT_AUTOMATIC" : "ACCEPT_MANUAL"
)
consumer_reject_lists = each.value.consumer_reject_lists
domain_names = (
each.value.domain_name == null ? null : [each.value.domain_name]
)
enable_proxy_protocol = each.value.enable_proxy_protocol
reconcile_connections = each.value.reconcile_connections
dynamic "consumer_accept_lists" {
for_each = each.value.consumer_accept_lists
iterator = accept
content {
project_id_or_num = each.key
connection_limit = each.value
}
ludoo marked this conversation as resolved.
Show resolved Hide resolved
}
}
15 changes: 11 additions & 4 deletions modules/net-lb-int/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,23 @@ output "backend_service_self_link" {
output "forwarding_rule_addresses" {
description = "Forwarding rule address."
value = {
for k, v in google_compute_forwarding_rule.forwarding_rules
for k, v in google_compute_forwarding_rule.default
: k => v.ip_address
}
}

output "forwarding_rule_self_links" {
description = "Forwarding rule self links."
value = {
for k, v in google_compute_forwarding_rule.forwarding_rules
for k, v in google_compute_forwarding_rule.default
: k => v.self_link
}
}

output "forwarding_rules" {
description = "Forwarding rule resources."
value = {
for k, v in google_compute_forwarding_rule.forwarding_rules
for k, v in google_compute_forwarding_rule.default
: k => v
}
}
Expand Down Expand Up @@ -83,7 +83,14 @@ output "health_check_self_link" {
output "id" {
description = "Fully qualified forwarding rule ids."
value = {
for k, v in google_compute_forwarding_rule.forwarding_rules
for k, v in google_compute_forwarding_rule.default
: k => v.id
}
}

output "service_attachment_ids" {
description = "Service attachment ids."
value = {
for k, v in google_compute_service_attachment.default : k => v.id
}
}