diff --git a/network.tf b/network.tf index 2d513cb..7048d7c 100644 --- a/network.tf +++ b/network.tf @@ -1,12 +1,12 @@ resource "openstack_networking_network_v2" "networks" { for_each = var.networks - name = 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", null) - tenant_id = lookup(each.value, "tenant_id", null) + tenant_id = (each.value.project != null ? openstack_identity_project_v3.project[each.value.project].id : each.value.tenant_id) mtu = lookup(each.value, "mtu", null) port_security_enabled = lookup(each.value, "port_security_enabled", true) tags = lookup(each.value, "tags", []) @@ -22,22 +22,30 @@ resource "openstack_networking_network_v2" "networks" { } resource "openstack_networking_subnet_v2" "subnets" { - for_each = var.subnets + for_each = merge([ + for network_key, network in var.networks : { + for subnet_key, subnet in lookup(network, "subnets", {}) : + subnet_key => { + network = network_key + subnet = subnet + } + } + ]...) - name = each.key - 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 - tenant_id = lookup(each.value, "tenant_id", null) - 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", []) + name = each.value.subnet.name + network_id = openstack_networking_network_v2.networks[each.value.network].id + region = lookup(each.value.subnet, "region", null) + cidr = lookup(each.value.subnet, "cidr", null) + ip_version = lookup(each.value.subnet, "ip_version", 4) #default can be 4 or 6 + tenant_id = openstack_networking_network_v2.networks[each.value.network].tenant_id + gateway_ip = lookup(each.value.subnet, "gateway_ip", null) + enable_dhcp = lookup(each.value.subnet, "enable_dhcp", true) + dns_nameservers = lookup(each.value.subnet, "dns_nameservers", []) + dns_publish_fixed_ip = lookup(each.value.subnet, "dns_publish_fixed_ip", false) + service_types = lookup(each.value.subnet, "service_types", []) + subnetpool_id = lookup(each.value.subnet, "subnetpool_id", null) + no_gateway = lookup(each.value.subnet, "no_gateway", null) + tags = lookup(each.value.subnet, "tags", []) dynamic "allocation_pool" { for_each = lookup(each.value, "allocation_pool", []) @@ -51,28 +59,37 @@ resource "openstack_networking_subnet_v2" "subnets" { resource "openstack_networking_router_v2" "routers" { for_each = var.routers - name = each.key + name = each.value.name region = lookup(each.value, "region", null) - external_network_id = lookup(each.value, "external_network_id", null) + external_network_id = (each.value.external_network != null ? openstack_networking_network_v2.networks[each.value.external_network].id : each.value.external_network_id) admin_state_up = lookup(each.value, "admin_state_up", null) - tenant_id = lookup(each.value, "tenant_id", null) + tenant_id = (each.value.project != null ? openstack_identity_project_v3.project[each.value.project].id : each.value.tenant_id ) 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) + subnet_id = (each.value.subnet != null ? openstack_networking_subnet_v2.subnets[each.value.subnet].id : each.value.subnet_id) + ip_address = lookup(external_fixed_ip.value, "ip_address", null) } } } -resource "openstack_networking_router_interface_v2" "router_interfaces" { - for_each = var.router_interfaces +resource "openstack_networking_router_interface_v2" "interfaces" { + for_each = merge([ + for router_key, router in var.routers : { + for iface in lookup(router, "interfaces", []) : + "interface-${router_key}-${coalesce(iface.subnet, iface.subnet_id, iface.port)}" => { + router = router_key + iface = iface + } + } + ]...) - 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) + router_id = openstack_networking_router_v2.routers[each.value.router].id + region = lookup(each.value.iface, "region", null) + subnet_id = (each.value.iface.subnet != null ? openstack_networking_subnet_v2.subnets[each.value.iface.subnet].id : each.value.iface.subnet_id) + port_id = lookup(each.value.iface, "port_id", null) + force_destroy = lookup(each.value.iface, "force_destroy", false) } + diff --git a/variables.tf b/variables.tf index cb3a618..51edd7e 100644 --- a/variables.tf +++ b/variables.tf @@ -118,13 +118,45 @@ variable "network_rbac" { } variable "networks" { + description = <<-EOT + Map of networks. Keys are unique tofu resource names. Elements are maps with keys/values: + name: Required string, openstack name of network + region: Optional string + shared: Optional bool, default false + external: Optional bool, default false + admin_state_up: Optional bool, default false + project: Optional string openstack project name, overrides tenant_id + tenant_id: Optional string, openstack project ID + mtu: Optional number + port_security_enabled: Optional bool, default false + tags: Optional list + segments: Optional list of maps. Keys are unique tofu resource names. Elements are maps with keys/values - + physical_network: Optional string + network_type: Optional string + segmentation_id: Optional number + subnets: Optional map - + key: Required string, tofu resource name + name: Require string, openstack name + region: Optional string + cidr: Optional string + ip_version: Optional number, default 4 + gateway_ip: Optional string + enable_dhcp: Optional bool, default true + dns_nameservers: Optional list + dns_publish_fixed_ip: Optional bool, default false + service_types: Optional list + no_gateway: Optional bool + tags: Optional list + EOT type = map( object({ + name = string region = optional(string) shared = optional(bool, false) external = optional(bool, false) admin_state_up = optional(bool) + project = optional(string) tenant_id = optional(string) mtu = optional(number) port_security_enabled = optional(bool, true) @@ -137,70 +169,97 @@ variable "networks" { segmentation_id = optional(number) })), [] ) - }) - ) - default = {} -} -variable "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 + subnets = optional (map(object({ + name = 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), []) - type = map( - object({ - network_id = string - region = optional(string) - cidr = optional(string) - ip_version = optional(number, 4) - tenant_id = optional(string) - 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 - })), [] - ) + allocation_pool = optional( + list(object({ + start = string + end = string + })), [] + ) + })), {} ) }) ) + + validation { + condition = alltrue(flatten([ + for network in values(var.networks) : [ + for subnet in values(lookup(network, "subnets", {})) : + subnet.cidr != null || subnet.subnetpool_id != null + ] + ])) + error_message = "Each subnet must specify either cidr or subnetpool_id." + } + default = {} } + variable "routers" { + description = <<-EOT + Map of routers. Keys are unique tofu resource names. Elements are maps with keys/values: + name: Required string, openstack name of router + region: Optional string + external_network: Optional string, key in var.networks, overrides external_network_id + external_network_id: Optional string, openstack network ID + admin_state_up: Optional bool + project: Optional string, tofu resource project name, overrides tenant_id + tenant_id: Optional string, openstack project ID + tags: Optional list + external_fixed_ip: Optional list of maps - + subnet: Optional string, tofu resource subnet name, overrides subnet_id + subnet_id: Optional string, openstack subnet ID + ip_address: Optional string + + interfaces: Optional list of maps - + region: Optional string + subnet: Optional string, key in var.network[network_key].subnets, overrides subnet_id + subnet_id: Optional string, openstack subnet ID + port_id: Optional string + force_destroy: Optional bool, default false + EOT + type = map( object({ + name = string region = optional(string) + external_network = optional(string) external_network_id = optional(string) admin_state_up = optional(bool) - tenant_id = optional(string) + project = optional(string) + tenant_id = optional(string) tags = optional(list(string), []) external_fixed_ip = optional( list(object({ + subnet = optional(string) subnet_id = optional(string) ip_address = optional(string) })), [] ) - }) - ) - default = {} -} -variable "router_interfaces"{ - type = map( - object({ - router_id = optional(string) - region = optional(string) - subnet_id = optional(string) - port_id = optional(string) - force_destroy = optional(bool, false) + interfaces = optional( + list(object({ + region = optional(string) + subnet = optional(string) + subnet_id = optional(string) + port_id = optional(string) + force_destroy = optional(bool, false) + })), [] + ) }) ) default = {}