Skip to content

Commit

Permalink
Manage core router tunnel interfaces (#23)
Browse files Browse the repository at this point in the history
Applied locally 🙈
  • Loading branch information
mraerino authored Aug 2, 2024
1 parent 09a9f75 commit 6bf5ca5
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 17 deletions.
33 changes: 29 additions & 4 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,35 @@ locals {
devices = {
for dev in data.netbox_devices.devices.devices : dev.name => dev
}
core_devices = concat(
[for dev in data.netbox_devices.core_routers.devices : {
id = dev.device_id
name = dev.name
device = dev
}],
[for vm in data.netbox_virtual_machines.core_routers.vms : {
id = vm.vm_id
name = vm.name
vm = vm
}],
)
}

resource "netbox_vpn_tunnel_group" "sites" {
name = "site-tunnels"
}

module "tunnel_interfaces" {
for_each = { for dev in local.core_devices : dev.name => dev }

source = "./modules/available_interfaces"

prefix = "tun"
device_id = each.value.id
device_type = can(each.value.vm) ? "vm" : "device"
targets = [for name, dev in local.devices : name]
}

module "device" {
for_each = local.devices

Expand All @@ -24,10 +47,12 @@ module "device" {
tunnel_prefix_v4_id = data.netbox_prefix.tunnels_prefix_v4.id
tunnel_prefix_v6_id = data.netbox_prefix.tunnels_prefix_v6.id

tunnel_peer_names = concat(
[for dev in data.netbox_devices.core_routers.devices : dev.name],
[for vm in data.netbox_virtual_machines.core_routers.vms : vm.name],
)
core_tunnels = [for dev in local.core_devices : {
name = dev.name
device_id = dev.id
device_type = can(dev.vm) ? "vm" : "device"
if_name = module.tunnel_interfaces[dev.name].interface_names[each.key]
}]

tunnel_prefix_role_id = data.netbox_ipam_role.transfer.id

Expand Down
86 changes: 86 additions & 0 deletions modules/available_interfaces/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
variable "device_id" {
type = number
description = "ID of the device to find interfaces for"
}

variable "device_type" {
type = string
description = "Whether to look for interfaces on a device or vm"
default = "device"
validation {
condition = contains(["device", "vm"], var.device_type)
error_message = "Must be one of 'device' or 'vm'"
}
}

variable "prefix" {
type = string
description = "interface prefix to find the next descendant for"
}

variable "targets" {
type = list(string)
description = "names of targets to create interfaces for"
}

data "netbox_device_interfaces" "existing" {
count = var.device_type == "device" ? 1 : 0

name_regex = "^${var.prefix}\\d+$"

filter {
name = "device_id"
value = var.device_id
}
}

data "netbox_interfaces" "existing" {
count = var.device_type == "vm" ? 1 : 0

name_regex = "^${var.prefix}\\d+$"

filter {
name = "vm_id"
value = var.device_id
}
}

locals {
if_names = concat(
[for dev in flatten(data.netbox_device_interfaces.existing[*].interfaces) : dev.name],
[for dev in flatten(data.netbox_interfaces.existing[*].interfaces) : dev.name],
)
if_nums = [for name in local.if_names : parseint(one(regex("^${var.prefix}(\\d+)$", name)), 10)]
max_if_num = max(local.if_nums...)
current_targets_hash = sha1(join("-", var.targets))
}

resource "terraform_data" "targets_hash" {
for_each = { for name in var.targets : name => {} }

input = local.current_targets_hash
lifecycle {
ignore_changes = [input]
}
}

locals {
# targets that have been added in the current apply
relevant_targets = [for name in var.targets : name if terraform_data.targets_hash[name].output == local.current_targets_hash]
target_offsets = { for i, name in local.relevant_targets : name => i }
}

resource "terraform_data" "ifnum" {
for_each = { for name in var.targets : name => {} }

input = local.max_if_num + 1 + try(local.target_offsets[each.key], 0)
lifecycle {
ignore_changes = [input]
}
}

output "interface_names" {
value = {
for name, data in terraform_data.ifnum : name => "${var.prefix}${coalesce(data.output, "-unknown")}"
}
}
8 changes: 8 additions & 0 deletions modules/available_interfaces/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
terraform {
required_providers {
netbox = {
source = "e-breuninger/netbox"
version = "~> 3.8.0"
}
}
}
52 changes: 42 additions & 10 deletions modules/device/tunnel.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
resource "netbox_device_interface" "tunnels" {
for_each = { for i, name in var.tunnel_peer_names : name => i }
for_each = { for i, peer in var.core_tunnels : peer.name => i }

type = "virtual"
name = "tun${each.value}"
Expand All @@ -8,25 +8,54 @@ resource "netbox_device_interface" "tunnels" {
device_id = var.device_id
}

resource "netbox_device_interface" "core" {
for_each = { for peer in var.core_tunnels : peer.name => peer if peer.device_type == "device" }

type = "virtual"
name = each.value.if_name
label = "Tunnel ${var.name}"
description = "Tunnel to ${var.name}"
device_id = each.value.device_id

mtu = 1476
}

resource "netbox_interface" "core" {
for_each = { for peer in var.core_tunnels : peer.name => peer if peer.device_type == "vm" }

name = each.value.if_name
description = "Tunnel to ${var.name}"
virtual_machine_id = each.value.device_id

mtu = 1476
}

locals {
core_interfaces = merge(netbox_device_interface.core, netbox_interface.core)
}

resource "netbox_available_prefix" "tunnels_v4" {
for_each = toset(var.tunnel_peer_names)
for_each = { for peer in var.core_tunnels : peer.name => {} }

parent_prefix_id = var.tunnel_prefix_v4_id
prefix_length = 31

status = "active"
description = "Tunnel from ${each.value} to ${var.name}"
description = "Tunnel from ${each.key} to ${var.name}"
role_id = var.tunnel_prefix_role_id
tenant_id = var.tenant_id
}

resource "netbox_ip_address" "remote_tunnel_address_v4" {
for_each = netbox_available_prefix.tunnels_v4
for_each = { for peer in var.core_tunnels : peer.name => peer }

ip_address = "${cidrhost(each.value.prefix, 0)}/${each.value.prefix_length}"
ip_address = "${cidrhost(netbox_available_prefix.tunnels_v4[each.key].prefix, 0)}/${netbox_available_prefix.tunnels_v4[each.key].prefix_length}"
status = "active"
description = "Peer address of ${each.key} for ${var.name}"
tenant_id = var.tenant_id

object_type = each.value.device_type == "vm" ? "virtualization.vminterface" : "dcim.interface"
interface_id = local.core_interfaces[each.key].id
}

resource "netbox_ip_address" "local_tunnel_address_v4" {
Expand All @@ -40,24 +69,27 @@ resource "netbox_ip_address" "local_tunnel_address_v4" {
}

resource "netbox_available_prefix" "tunnels_v6" {
for_each = toset(var.tunnel_peer_names)
for_each = { for peer in var.core_tunnels : peer.name => {} }

parent_prefix_id = var.tunnel_prefix_v6_id
prefix_length = 64

status = "active"
description = "Tunnel from ${each.value} to ${var.name}"
description = "Tunnel from ${each.key} to ${var.name}"
role_id = var.tunnel_prefix_role_id
tenant_id = var.tenant_id
}

resource "netbox_ip_address" "remote_tunnel_address_v6" {
for_each = netbox_available_prefix.tunnels_v6
for_each = { for peer in var.core_tunnels : peer.name => peer }

ip_address = "${cidrhost(each.value.prefix, 1)}/${each.value.prefix_length}"
ip_address = "${cidrhost(netbox_available_prefix.tunnels_v6[each.key].prefix, 1)}/${netbox_available_prefix.tunnels_v6[each.key].prefix_length}"
status = "active"
description = "Peer address of ${each.key} for ${var.name}"
tenant_id = var.tenant_id

object_type = each.value.device_type == "vm" ? "virtualization.vminterface" : "dcim.interface"
interface_id = local.core_interfaces[each.key].id
}

resource "netbox_ip_address" "local_tunnel_address_v6" {
Expand All @@ -71,7 +103,7 @@ resource "netbox_ip_address" "local_tunnel_address_v6" {
}

resource "netbox_vpn_tunnel" "core" {
for_each = { for i, name in var.tunnel_peer_names : name => i }
for_each = { for peer in var.core_tunnels : peer.name => {} }

name = "${each.key}-${var.name}"
encapsulation = "gre"
Expand Down
11 changes: 8 additions & 3 deletions modules/device/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ variable "sites_prefix_v6_id" {
description = "Netbox ID of prefix (v6) to create site prefix in"
}

variable "tunnel_peer_names" {
type = list(string)
description = "names of tunnel peers"
variable "core_tunnels" {
type = list(object({
name = string
device_id = string
device_type = string
if_name = string
}))
description = "info about tunnel peers"
}

variable "tunnel_group_id" {
Expand Down

0 comments on commit 6bf5ca5

Please sign in to comment.