Add the chassis_mac custom field and drop the switch device type
Switches are created by hand in the NetBox UI, so the model and its port templates have no consumer.
This commit is contained in:
@@ -7,12 +7,14 @@ reference data a host is planned against. Device records are not here.
|
||||
|
||||
| Owner | Objects |
|
||||
|-------|---------|
|
||||
| **this repo** | sites, prefixes, DHCP pool ranges, gateways, managed IPs, VLAN groups + VLANs, device types (incl. switch models and their interface templates), manufacturers, device roles, platforms, custom-field definitions, network profiles |
|
||||
| **this repo** | sites, prefixes, DHCP pool ranges, gateways, managed IPs, VLAN groups + VLANs, device types, manufacturers, device roles, platforms, custom-field definitions, network profiles |
|
||||
| **autodiscovery agent** | device records, interfaces, MAC addresses, switch cabling |
|
||||
| **UI** | host names, role assignment, IP allocation (inventory -> planned) |
|
||||
|
||||
Writing a device from here would fight both of them, so the module declares no
|
||||
`netbox_device`.
|
||||
`netbox_device`. The handful of network switches are created by hand in the
|
||||
NetBox UI; this repo only defines the `chassis_mac` field discovery matches them
|
||||
on.
|
||||
|
||||
> Supersedes `terraform-infra`, which also drove Kea DHCP. Kea is managed by the
|
||||
> [kea-operator](https://git.unkin.net/unkin/kea-operator) CRs in argocd-apps
|
||||
@@ -23,7 +25,7 @@ Writing a device from here would fight both of them, so the module declares no
|
||||
```
|
||||
config/<region>/<dc>/sites.yaml # site slug -> name/description
|
||||
config/<region>/<dc>/subnets/net-<a>-<b>-<c>-<d>-<len>.yaml
|
||||
config/<region>/<dc>/device-types/<slug>.yaml # manufacturer, model, port templates
|
||||
config/<region>/<dc>/device-types/<slug>.yaml # manufacturer, model
|
||||
config/<region>/<dc>/device-roles.yaml
|
||||
config/<region>/<dc>/platforms.yaml # slug -> display name
|
||||
config/<region>/<dc>/vlans.yaml # keyed per site
|
||||
@@ -64,22 +66,10 @@ repo without re-deriving them.
|
||||
|
||||
## Device types (`device-types/<slug>.yaml`)
|
||||
|
||||
`ports` declares interface templates as ranges, not 28 hand-written entries.
|
||||
NetBox instantiates them on every device created from the type.
|
||||
|
||||
```yaml
|
||||
manufacturer: TP-Link
|
||||
model: Omada SG3429X
|
||||
manufacturer: Dell
|
||||
model: OptiPlex 3070
|
||||
u_height: 1
|
||||
ports:
|
||||
- name_format: two-gigabitEthernet 1/0/%d # single %d
|
||||
type: 2.5gbase-t
|
||||
first: 1
|
||||
count: 24
|
||||
- name_format: ten-gigabitEthernet 1/0/%d
|
||||
type: 10gbase-x-sfpp
|
||||
first: 25
|
||||
count: 4
|
||||
```
|
||||
|
||||
## VLANs (`vlans.yaml`)
|
||||
@@ -115,7 +105,8 @@ interfaces:
|
||||
## Custom fields (`custom-fields.yaml`)
|
||||
|
||||
Field **definitions** for what bootapi reads: `pxe_enabled`,
|
||||
`provision_template`, `domain`, `nameservers`, `gateway`. `content_types` are
|
||||
`provision_template`, `domain`, `nameservers`, `gateway`; plus `chassis_mac`,
|
||||
which autodiscovery matches an LLDP neighbour on. `content_types` are
|
||||
NetBox `app_label.model` strings. `pxe_enabled`'s *value* is deliberately not
|
||||
managed here — it is runtime state cleared by bootapi's `/provisioned` callback.
|
||||
|
||||
|
||||
@@ -36,3 +36,10 @@ gateway:
|
||||
content_types:
|
||||
- dcim.device
|
||||
- ipam.ipaddress
|
||||
|
||||
chassis_mac:
|
||||
type: text
|
||||
label: Chassis MAC
|
||||
description: LLDP advertises a neighbour's ChassisID MAC but not its serial, so the autodiscovery agent matches an LLDP neighbour to this device by chassis MAC rather than the mutable SysName.
|
||||
content_types:
|
||||
- dcim.device
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# TP-Link Omada SG3429X: 24x 2.5G copper + 4x 10G SFP+.
|
||||
# NetBox instantiates these interfaces on every device created from the type.
|
||||
manufacturer: TP-Link
|
||||
model: Omada SG3429X
|
||||
u_height: 1
|
||||
ports:
|
||||
- name_format: two-gigabitEthernet 1/0/%d
|
||||
type: 2.5gbase-t
|
||||
first: 1
|
||||
count: 24
|
||||
- name_format: ten-gigabitEthernet 1/0/%d
|
||||
type: 10gbase-x-sfpp
|
||||
first: 25
|
||||
count: 4
|
||||
@@ -1,20 +1,5 @@
|
||||
locals {
|
||||
manufacturers = toset([for t in var.device_types : t.manufacturer])
|
||||
|
||||
# One interface template per port, flattened to "<type slug>:<name>".
|
||||
interface_templates = merge([
|
||||
for slug, t in var.device_types : {
|
||||
for e in flatten([
|
||||
for p in t.ports : [
|
||||
for i in range(p.count) : {
|
||||
name = format(p.name_format, p.first + i)
|
||||
type = p.type
|
||||
mgmt_only = p.mgmt_only
|
||||
}
|
||||
]
|
||||
]) : "${slug}:${e.name}" => merge(e, { device_type = slug })
|
||||
}
|
||||
]...)
|
||||
}
|
||||
|
||||
resource "netbox_manufacturer" "this" {
|
||||
@@ -33,15 +18,6 @@ resource "netbox_device_type" "this" {
|
||||
u_height = each.value.u_height
|
||||
}
|
||||
|
||||
resource "netbox_interface_template" "this" {
|
||||
for_each = local.interface_templates
|
||||
|
||||
device_type_id = tonumber(netbox_device_type.this[each.value.device_type].id)
|
||||
name = each.value.name
|
||||
type = each.value.type
|
||||
mgmt_only = each.value.mgmt_only
|
||||
}
|
||||
|
||||
resource "netbox_device_role" "this" {
|
||||
for_each = var.device_roles
|
||||
|
||||
|
||||
@@ -35,23 +35,13 @@ variable "subnets" {
|
||||
|
||||
variable "device_types" {
|
||||
description = <<-EOT
|
||||
Device-type catalogue keyed by NetBox slug. `ports` declares interface
|
||||
templates as ranges: each block names `count` ports from `first`, formatted
|
||||
with `name_format` (a single %d). NetBox instantiates them on every device
|
||||
created from the type. Manufacturers are created from the distinct
|
||||
`manufacturer` values.
|
||||
Device-type catalogue keyed by NetBox slug. Manufacturers are created from
|
||||
the distinct `manufacturer` values.
|
||||
EOT
|
||||
type = map(object({
|
||||
manufacturer = string
|
||||
model = string
|
||||
u_height = optional(number, 1)
|
||||
ports = optional(list(object({
|
||||
name_format = string
|
||||
type = string
|
||||
first = optional(number, 1)
|
||||
count = number
|
||||
mgmt_only = optional(bool, false)
|
||||
})), [])
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user