diff --git a/modules/net-vlan-attachment/README.md b/modules/net-vlan-attachment/README.md index 0ba2ed816..85a17c125 100644 --- a/modules/net-vlan-attachment/README.md +++ b/modules/net-vlan-attachment/README.md @@ -646,19 +646,20 @@ module "example-va-b" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [description](variables.tf#L36) | VLAN attachment description. | string | ✓ | | -| [name](variables.tf#L53) | The common resources name, used after resource type prefix and suffix. | string | ✓ | | -| [network](variables.tf#L58) | The VPC name to which resources are associated to. | string | ✓ | | -| [peer_asn](variables.tf#L75) | The on-premises underlay router ASN. | string | ✓ | | -| [project_id](variables.tf#L80) | The project id where resources are created. | string | ✓ | | -| [region](variables.tf#L85) | The region where resources are created. | string | ✓ | | -| [router_config](variables.tf#L90) | Cloud Router configuration for the VPN. If you want to reuse an existing router, set create to false and use name to specify the desired router. | object({…}) | ✓ | | +| [description](variables.tf#L52) | VLAN attachment description. | string | ✓ | | +| [name](variables.tf#L69) | The common resources name, used after resource type prefix and suffix. | string | ✓ | | +| [network](variables.tf#L74) | The VPC name to which resources are associated to. | string | ✓ | | +| [peer_asn](variables.tf#L91) | The on-premises underlay router ASN. | string | ✓ | | +| [project_id](variables.tf#L96) | The project id where resources are created. | string | ✓ | | +| [region](variables.tf#L101) | The region where resources are created. | string | ✓ | | +| [router_config](variables.tf#L106) | Cloud Router configuration for the VPN. If you want to reuse an existing router, set create to false and use name to specify the desired router. | object({…}) | ✓ | | | [admin_enabled](variables.tf#L17) | Whether the VLAN attachment is enabled. | bool | | true | -| [dedicated_interconnect_config](variables.tf#L23) | Dedicated interconnect configuration. | object({…}) | | null | -| [ipsec_gateway_ip_ranges](variables.tf#L41) | IPSec Gateway IP Ranges. | map(string) | | {} | -| [mtu](variables.tf#L47) | The MTU associated to the VLAN attachment (1440 / 1500). | number | | 1500 | -| [partner_interconnect_config](variables.tf#L63) | Partner interconnect configuration. | object({…}) | | null | -| [vpn_gateways_ip_range](variables.tf#L115) | The IP range (cidr notation) to be used for the GCP VPN gateways. If null IPSec over Interconnect is not enabled. | string | | null | +| [context](variables.tf#L23) | Context-specific interpolations. | object({…}) | | {} | +| [dedicated_interconnect_config](variables.tf#L35) | Dedicated interconnect configuration. | object({…}) | | null | +| [ipsec_gateway_ip_ranges](variables.tf#L57) | IPSec Gateway IP Ranges. | map(string) | | {} | +| [mtu](variables.tf#L63) | The MTU associated to the VLAN attachment (1440 / 1500). | number | | 1500 | +| [partner_interconnect_config](variables.tf#L79) | Partner interconnect configuration. | object({…}) | | null | +| [vpn_gateways_ip_range](variables.tf#L131) | The IP range (cidr notation) to be used for the GCP VPN gateways. If null IPSec over Interconnect is not enabled. | string | | null | ## Outputs diff --git a/modules/net-vlan-attachment/main.tf b/modules/net-vlan-attachment/main.tf index 40b2c81f6..ab2680c00 100644 --- a/modules/net-vlan-attachment/main.tf +++ b/modules/net-vlan-attachment/main.tf @@ -15,20 +15,30 @@ */ locals { + ctx_p = "$" + ctx = { + for k, v in var.context : k => { + for kk, vv in v : "${local.ctx_p}${k}:${kk}" => vv + } + } ipsec_enabled = var.vpn_gateways_ip_range == null ? false : true + network = lookup(local.ctx.networks, var.network, var.network) + project_id = lookup(local.ctx.project_ids, var.project_id, var.project_id) + region = lookup(local.ctx.locations, var.region, var.region) + router_name = lookup(local.ctx.routers, try(var.router_config.name, ""), try(var.router_config.name, "")) router = ( var.router_config.create ? local.ipsec_enabled ? try(google_compute_router.encrypted[0].name, null) : try(google_compute_router.unencrypted[0].name, null) - : var.router_config.name + : local.router_name ) secret = random_id.secret.b64_url } resource "google_compute_address" "default" { count = local.ipsec_enabled ? 1 : 0 - project = var.project_id - network = var.network - region = var.region + project = local.project_id + network = local.network + region = local.region name = "pool-${var.name}" address_type = "INTERNAL" purpose = "IPSEC_INTERCONNECT" @@ -37,15 +47,15 @@ resource "google_compute_address" "default" { } resource "google_compute_interconnect_attachment" "default" { - project = var.project_id - region = var.region + project = local.project_id + region = local.region router = local.router name = var.name description = var.description interconnect = try(var.dedicated_interconnect_config.interconnect, null) bandwidth = try(var.dedicated_interconnect_config.bandwidth, null) mtu = local.ipsec_enabled ? null : var.mtu - candidate_subnets = var.dedicated_interconnect_config != null ? [var.dedicated_interconnect_config.bgp_range] : null + candidate_subnets = try(var.dedicated_interconnect_config.bgp_range, null) != null ? [var.dedicated_interconnect_config.bgp_range] : null vlan_tag8021q = try(var.dedicated_interconnect_config.vlan_tag, null) admin_enabled = var.admin_enabled encryption = local.ipsec_enabled ? "IPSEC" : null @@ -57,9 +67,9 @@ resource "google_compute_interconnect_attachment" "default" { resource "google_compute_router" "encrypted" { count = var.router_config.create && local.ipsec_enabled ? 1 : 0 name = "${var.name}-underlay" - network = var.network - project = var.project_id - region = var.region + network = local.network + project = local.project_id + region = local.region encrypted_interconnect_router = true bgp { asn = var.router_config.asn @@ -76,10 +86,10 @@ resource "google_compute_router" "encrypted" { resource "google_compute_router" "unencrypted" { count = var.router_config.create && !local.ipsec_enabled ? 1 : 0 - name = coalesce(var.router_config.name, "underlay-${var.name}") - project = var.project_id - region = var.region - network = var.network + name = coalesce(local.router_name, "underlay-${var.name}") + project = local.project_id + region = local.region + network = local.network bgp { advertise_mode = ( var.router_config.custom_advertise != null @@ -106,8 +116,8 @@ resource "google_compute_router" "unencrypted" { resource "google_compute_router_interface" "default" { count = var.dedicated_interconnect_config != null ? 1 : 0 - project = var.project_id - region = var.region + project = local.project_id + region = local.region name = "${var.name}-intf" router = local.router ip_range = google_compute_interconnect_attachment.default.cloud_router_ip_address @@ -117,9 +127,9 @@ resource "google_compute_router_interface" "default" { resource "google_compute_router_peer" "default" { count = var.dedicated_interconnect_config != null ? 1 : 0 name = "${var.name}-peer" - project = var.project_id + project = local.project_id router = local.router - region = var.region + region = local.region peer_ip_address = split("/", google_compute_interconnect_attachment.default.customer_router_ip_address)[0] peer_asn = var.peer_asn interface = google_compute_router_interface.default[0].name diff --git a/modules/net-vlan-attachment/variables.tf b/modules/net-vlan-attachment/variables.tf index cd87b39c9..b4b317424 100644 --- a/modules/net-vlan-attachment/variables.tf +++ b/modules/net-vlan-attachment/variables.tf @@ -20,6 +20,18 @@ variable "admin_enabled" { default = true } +variable "context" { + description = "Context-specific interpolations." + type = object({ + locations = optional(map(string), {}) + networks = optional(map(string), {}) + project_ids = optional(map(string), {}) + routers = optional(map(string), {}) + }) + default = {} + nullable = false +} + variable "dedicated_interconnect_config" { description = "Dedicated interconnect configuration." type = object({ @@ -30,6 +42,10 @@ variable "dedicated_interconnect_config" { interconnect = string vlan_tag = string }) + validation { + condition = var.dedicated_interconnect_config == null ? true : contains(["BPS_50M", "BPS_100M", "BPS_200M", "BPS_300M", "BPS_400M", "BPS_500M", "BPS_1G", "BPS_2G", "BPS_5G", "BPS_10G", "BPS_20G", "BPS_50G", "BPS_100G", "BPS_400G"], var.dedicated_interconnect_config.bandwidth) + error_message = "The bandwidth must be one of BPS_50M, BPS_100M, BPS_200M, BPS_300M, BPS_400M, BPS_500M, BPS_1G, BPS_2G, BPS_5G, BPS_10G, BPS_20G, BPS_50G, BPS_100G, BPS_400G." + } default = null } diff --git a/tests/modules/net-vlan-attachment/context.tfvars b/tests/modules/net-vlan-attachment/context.tfvars new file mode 100644 index 000000000..59e8bfed9 --- /dev/null +++ b/tests/modules/net-vlan-attachment/context.tfvars @@ -0,0 +1,35 @@ +context = { + locations = { + my_region = "europe-west1" + } + networks = { + my_network = "projects/my-project/global/networks/my-network" + } + project_ids = { + my_project = "my-project" + } + routers = { + my_router = "my-router" + } +} + +dedicated_interconnect_config = { + bandwidth = "BPS_100G" + bgp_range = "169.254.1.0/29" + bgp_priority = 100 + interconnect = "projects/my-project/global/interconnects/my-interconnect" + vlan_tag = 100 +} + +description = "test attachment" +name = "test-attachment" +peer_asn = "65534" + +network = "$networks:my_network" +project_id = "$project_ids:my_project" +region = "$locations:my_region" + +router_config = { + create = false + name = "$routers:my_router" +} diff --git a/tests/modules/net-vlan-attachment/context.yaml b/tests/modules/net-vlan-attachment/context.yaml new file mode 100644 index 000000000..e7ae61e7e --- /dev/null +++ b/tests/modules/net-vlan-attachment/context.yaml @@ -0,0 +1,85 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + google_compute_interconnect_attachment.default: + admin_enabled: true + bandwidth: BPS_100G + candidate_cloud_router_ip_address: null + candidate_cloud_router_ipv6_address: null + candidate_customer_router_ip_address: null + candidate_customer_router_ipv6_address: null + candidate_subnets: + - 169.254.1.0/29 + description: test attachment + effective_labels: + goog-terraform-provisioned: 'true' + encryption: NONE + interconnect: projects/my-project/global/interconnects/my-interconnect + ipsec_internal_addresses: null + l2_forwarding: [] + labels: null + mtu: '1500' + name: test-attachment + project: my-project + region: europe-west1 + router: my-router + subnet_length: null + terraform_labels: + goog-terraform-provisioned: 'true' + timeouts: null + type: DEDICATED + vlan_tag8021q: 100 + google_compute_router_interface.default[0]: + name: test-attachment-intf + private_ip_address: null + project: my-project + region: europe-west1 + router: my-router + subnetwork: null + timeouts: null + vpn_tunnel: null + google_compute_router_peer.default[0]: + advertise_mode: CUSTOM + advertised_groups: null + advertised_ip_ranges: [] + advertised_route_priority: 100 + custom_learned_ip_ranges: [] + custom_learned_route_priority: null + enable: true + enable_ipv6: false + export_policies: null + import_policies: null + interface: test-attachment-intf + md5_authentication_key: [] + name: test-attachment-peer + peer_asn: 65534 + project: my-project + region: europe-west1 + router: my-router + router_appliance_instance: null + timeouts: null + zero_advertised_route_priority: null + zero_custom_learned_route_priority: false + random_id.secret: + byte_length: 12 + keepers: null + prefix: null + +counts: + google_compute_interconnect_attachment: 1 + google_compute_router_interface: 1 + google_compute_router_peer: 1 + modules: 0 + random_id: 1 diff --git a/tests/modules/net-vlan-attachment/tftest.yaml b/tests/modules/net-vlan-attachment/tftest.yaml new file mode 100644 index 000000000..b38fadbc3 --- /dev/null +++ b/tests/modules/net-vlan-attachment/tftest.yaml @@ -0,0 +1,17 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module: modules/net-vlan-attachment +tests: + context: