From 0714210320885b80666c13dd1de7a13a42fd97eb Mon Sep 17 00:00:00 2001 From: Claudia Watson Date: Thu, 30 Apr 2026 15:24:15 +0100 Subject: [PATCH 1/4] add test portal_internals resource --- network.tf | 23 +++++++++++++++++++++++ variables.tf | 25 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/network.tf b/network.tf index ba5a70e..11395f5 100644 --- a/network.tf +++ b/network.tf @@ -76,3 +76,26 @@ resource "openstack_networking_router_interface_v2" "router_interfaces" { port_id = lookup(each.value, "port_id", null) force_destroy = lookup(each.value, "force_destroy", false) } + +resource "openstack_networking_network_v2" "portal_internals" { + for_each = var.portal_internals + + tenant_id = each.key + name = each.value.name + region = lookup(each.value, "region", null) + shared = lookup(each.value, "shared", false) + external = lookup(each.value, "external", false) + admin_state_up = lookup(each.value, "admin_state_up", false) + mtu = lookup(each.value, "mtu", null) + port_security_enabled = lookup(each.value, "port_security_enabled", true) + tags = lookup(each.value, "tags", []) + + dynamic "segments" { + for_each = lookup(each.value, "segments", []) + content { + physical_network = lookup(segments.value, "physical_network", null) + network_type = lookup(segments.value, "network_type", null) + segmentation_id = lookup(segments.value, "segmentation_id", null) + } + } +} \ No newline at end of file diff --git a/variables.tf b/variables.tf index 8e0ba77..22fcd0a 100644 --- a/variables.tf +++ b/variables.tf @@ -206,6 +206,31 @@ variable "router_interfaces"{ default = {} } +variable "portal_internals" { + + type = map( + object({ + name = string + region = optional(string) + shared = optional(bool, false) + external = optional(bool, false) + admin_state_up = optional(bool, false) + mtu = optional(number) + port_security_enabled = optional(bool, true) + tags = optional(list(string), []) + + segments = optional( + list(object({ + physical_network = optional(string) + network_type = optional(string) + segmentation_id = optional(number) + })), [] + ) + }) + ) + default = {} +} + variable "flavors" { description = <<-EOT Mapping of flavor definitions. Key is flavor name, and must be quoted From 6b28ca6541e483cc1da233e2865e1284468fe994 Mon Sep 17 00:00:00 2001 From: Claudia Watson Date: Fri, 1 May 2026 09:23:32 +0100 Subject: [PATCH 2/4] add resource for portal internal subnets --- network.tf | 29 ++++++++++++++++++++++++++++- variables.tf | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/network.tf b/network.tf index 11395f5..a8dda60 100644 --- a/network.tf +++ b/network.tf @@ -77,7 +77,7 @@ resource "openstack_networking_router_interface_v2" "router_interfaces" { force_destroy = lookup(each.value, "force_destroy", false) } -resource "openstack_networking_network_v2" "portal_internals" { +resource "openstack_networking_network_v2" "portal_internal_networks" { for_each = var.portal_internals tenant_id = each.key @@ -98,4 +98,31 @@ resource "openstack_networking_network_v2" "portal_internals" { segmentation_id = lookup(segments.value, "segmentation_id", null) } } +} + +resource "openstack_networking_subnet_v2" "portal_internal_subnets" { + for_each = var.subnets + + tenant_id = each.key + name = each.value.name + network_id = each.value.network_id + region = lookup(each.value, "region", null) + cidr = lookup(each.value, "cidr", null) + ip_version = lookup(each.value, "ip_version", 4) #default can be 4 or 6 + gateway_ip = lookup(each.value, "gateway_ip", null) + enable_dhcp = lookup(each.value, "enable_dhcp", true) + dns_nameservers = lookup(each.value, "dns_nameservers", []) + dns_publish_fixed_ip = lookup(each.value, "dns_publish_fixed_ip", false) + service_types = lookup(each.value, "service_types", []) + subnetpool_id = lookup(each.value, "subnetpool_id", null) + no_gateway = lookup(each.value, "no_gateway", null) + tags = lookup(each.value, "tags", []) + + dynamic "allocation_pool" { + for_each = lookup(each.value, "allocation_pool", []) + content { + start = allocation_pool.value.start + end = allocation_pool.value.end + } + } } \ No newline at end of file diff --git a/variables.tf b/variables.tf index 22fcd0a..76b41f8 100644 --- a/variables.tf +++ b/variables.tf @@ -206,7 +206,7 @@ variable "router_interfaces"{ default = {} } -variable "portal_internals" { +variable "portal_internal_networks" { type = map( object({ @@ -231,6 +231,37 @@ variable "portal_internals" { default = {} } +variable "portal_internal_subnets" { + # TODO: make child of network, and automatically set network_id. See e.g. stuff in projects.tf + # TODO: make cidr or subnetpool_id required via validation + + type = map( + object({ + name = string + network_id = string + region = optional(string) + cidr = optional(string) + ip_version = optional(number, 4) + gateway_ip = optional(string) + enable_dhcp = optional(bool, true) + dns_nameservers = optional(list(string), []) + dns_publish_fixed_ip = optional(bool, false) + service_types = optional(list(string), []) + subnetpool_id = optional(string) + no_gateway = optional(bool) + tags = optional(list(string), []) + + allocation_pool = optional( + list(object({ + start = string + end = string + })), [] + ) + }) + ) + default = {} +} + variable "flavors" { description = <<-EOT Mapping of flavor definitions. Key is flavor name, and must be quoted From 0df4ed0269d4b500a32a425df612e5ce6518d933 Mon Sep 17 00:00:00 2001 From: Claudia Watson Date: Fri, 1 May 2026 14:34:04 +0100 Subject: [PATCH 3/4] add portal router and portal router interface resources --- network.tf | 40 ++++++++++++++++++++++++++++++++--- variables.tf | 59 +++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 93 insertions(+), 6 deletions(-) diff --git a/network.tf b/network.tf index a8dda60..7b2a7b1 100644 --- a/network.tf +++ b/network.tf @@ -54,6 +54,8 @@ resource "openstack_networking_router_v2" "routers" { name = each.key region = lookup(each.value, "region", null) external_network_id = lookup(each.value, "external_network_id", null) + external_subnet_ids = lookup(each.value, "external_subnet_id", []) + enable_snat = lookup(each.value, "enable_snat", null) admin_state_up = lookup(each.value, "admin_state_up", false) tenant_id = lookup(each.value, "tenant_id", null) tags = lookup(each.value, "tags", []) @@ -78,7 +80,7 @@ resource "openstack_networking_router_interface_v2" "router_interfaces" { } resource "openstack_networking_network_v2" "portal_internal_networks" { - for_each = var.portal_internals + for_each = var.portal_internal_networks tenant_id = each.key name = each.value.name @@ -101,7 +103,7 @@ resource "openstack_networking_network_v2" "portal_internal_networks" { } resource "openstack_networking_subnet_v2" "portal_internal_subnets" { - for_each = var.subnets + for_each = var.portal_internal_subnets tenant_id = each.key name = each.value.name @@ -112,7 +114,7 @@ resource "openstack_networking_subnet_v2" "portal_internal_subnets" { gateway_ip = lookup(each.value, "gateway_ip", null) enable_dhcp = lookup(each.value, "enable_dhcp", true) dns_nameservers = lookup(each.value, "dns_nameservers", []) - dns_publish_fixed_ip = lookup(each.value, "dns_publish_fixed_ip", false) + dns_publish_fixed_ip = lookup(each.value, "dns_publish_fixed_ip", null) service_types = lookup(each.value, "service_types", []) subnetpool_id = lookup(each.value, "subnetpool_id", null) no_gateway = lookup(each.value, "no_gateway", null) @@ -125,4 +127,36 @@ resource "openstack_networking_subnet_v2" "portal_internal_subnets" { end = allocation_pool.value.end } } +} + +resource "openstack_networking_router_v2" "portal_routers" { + for_each = var.portal_routers + + tenant_id = each.key + name = each.value.name + region = lookup(each.value, "region", null) + external_network_id = lookup(each.value, "external_network_id", null) + external_subnet_ids = lookup(each.value, "external_subnet_id", []) + enable_snat = lookup(each.value, "enable_snat", null) + admin_state_up = lookup(each.value, "admin_state_up", false) + + tags = lookup(each.value, "tags", []) + + dynamic "external_fixed_ip" { + for_each = lookup(each.value, "external_fixed_ip", []) + content { + subnet_id = lookup(external_fixed_ip.value, "subnet_id", null) + ip_address = lookup(external_fixed_ip.value, "ip_address", null) + } + } +} + +resource "openstack_networking_router_interface_v2" "portal_router_interfaces" { + for_each = var.portal_router_interfaces + + router_id = each.value.router_id + region = lookup(each.value, "region", null) + subnet_id = lookup(each.value, "subnet_id", null) + port_id = lookup(each.value, "port_id", null) + force_destroy = lookup(each.value, "force_destroy", false) } \ No newline at end of file diff --git a/variables.tf b/variables.tf index 76b41f8..b46aabb 100644 --- a/variables.tf +++ b/variables.tf @@ -178,6 +178,8 @@ variable "routers" { object({ region = optional(string) external_network_id = optional(string) + external_subnet_ids = optional(list(string), []) + enable_snat = optional(bool) admin_state_up = optional(bool, false) tentant_id = optional(string) tags = optional(list(string), []) @@ -196,7 +198,6 @@ variable "routers" { variable "router_interfaces"{ type = map( object({ - router_id = optional(string) region = optional(string) subnet_id = optional(string) port_id = optional(string) @@ -245,7 +246,7 @@ variable "portal_internal_subnets" { gateway_ip = optional(string) enable_dhcp = optional(bool, true) dns_nameservers = optional(list(string), []) - dns_publish_fixed_ip = optional(bool, false) + dns_publish_fixed_ip = optional(bool) service_types = optional(list(string), []) subnetpool_id = optional(string) no_gateway = optional(bool) @@ -262,6 +263,40 @@ variable "portal_internal_subnets" { default = {} } +variable "portal_routers" { + type = map( + object({ + name = string + region = optional(string) + external_network_id = optional(string) + external_subnet_ids = optional(list(string), []) + enable_snat = optional(bool) + admin_state_up = optional(bool, false) + tags = optional(list(string), []) + + external_fixed_ip = optional( + list(object({ + subnet_id = optional(string) + ip_address = optional(string) + })), [] + ) + }) + ) + default = {} +} + +variable "portal_router_interfaces"{ + type = map( + object({ + region = optional(string) + subnet_id = optional(string) + port_id = optional(string) + force_destroy = optional(bool, false) + }) + ) + default = {} +} + variable "flavors" { description = <<-EOT Mapping of flavor definitions. Key is flavor name, and must be quoted @@ -397,4 +432,22 @@ output "router" { id = v.id } } -} \ No newline at end of file +} + +output "portal_internal_network" { + value = { + for k, v in openstack_networking_network_v2.portal_internal_networks : + k => { + id = v.id + } + } +} + +output "portal_router" { + value = { + for k, v in openstack_networking_router_v2.portal_routers : + k => { + id = v.id + } + } +} From ffe3fab948a8ce2c4c0c980b57c115ab25bf123b Mon Sep 17 00:00:00 2001 From: Claudia Watson Date: Wed, 6 May 2026 15:43:59 +0100 Subject: [PATCH 4/4] portal router interface creation automatic when router interface defined --- network.tf | 11 ++++++----- variables.tf | 22 ++++++++++------------ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/network.tf b/network.tf index 7b2a7b1..c5a8edd 100644 --- a/network.tf +++ b/network.tf @@ -136,7 +136,7 @@ resource "openstack_networking_router_v2" "portal_routers" { name = each.value.name region = lookup(each.value, "region", null) external_network_id = lookup(each.value, "external_network_id", null) - external_subnet_ids = lookup(each.value, "external_subnet_id", []) + external_subnet_ids = lookup(each.value, "external_subnet_id", null) enable_snat = lookup(each.value, "enable_snat", null) admin_state_up = lookup(each.value, "admin_state_up", false) @@ -151,12 +151,13 @@ resource "openstack_networking_router_v2" "portal_routers" { } } -resource "openstack_networking_router_interface_v2" "portal_router_interfaces" { - for_each = var.portal_router_interfaces +resource "openstack_networking_router_interface_v2" "portal_routers" { + for_each = {for tenant_id, rou in var.portal_routers: tenant_id => rou.router_interface if rou.router_interface !=null} - router_id = each.value.router_id + + router_id = openstack_networking_router_v2.portal_routers[each.key].id region = lookup(each.value, "region", null) subnet_id = lookup(each.value, "subnet_id", null) port_id = lookup(each.value, "port_id", null) force_destroy = lookup(each.value, "force_destroy", false) -} \ No newline at end of file +} diff --git a/variables.tf b/variables.tf index b46aabb..4c1ae12 100644 --- a/variables.tf +++ b/variables.tf @@ -269,7 +269,7 @@ variable "portal_routers" { name = string region = optional(string) external_network_id = optional(string) - external_subnet_ids = optional(list(string), []) + external_subnet_ids = optional(list(string), null) enable_snat = optional(bool) admin_state_up = optional(bool, false) tags = optional(list(string), []) @@ -280,19 +280,17 @@ variable "portal_routers" { ip_address = optional(string) })), [] ) - }) - ) - default = {} -} -variable "portal_router_interfaces"{ - type = map( - object({ - region = optional(string) - subnet_id = optional(string) - port_id = optional(string) - force_destroy = optional(bool, false) + router_interface = optional( + object({ + region = optional(string) + subnet_id = optional(string) + port_id = optional(string) + force_destroy = optional(bool, false) + }) + ) }) + ) default = {} }