585d32b15c
Automate the PuppetDB reality import (issue #1) by querying pdbmux — the PuppetDB multiplexer whose HTTPS gateway is reachable from CI/workstations, unlike raw PuppetDB — instead of PuppetDB directly, and shaping the result to the NetBox reality side the devices module reconciles. - Add tools/backfill (Go): query pdbmux /pdb/query/v4/facts for the 13 existing physicals and emit per-host reality YAML — serial/model/UUID, every recordable interface (real NICs plus overlay/loopback/kube-lb) with MAC and CIDR IPs, and CPU/RAM/disk inventory. Filter ephemeral Calico veths and Ceph RBD volumes; take interface names from Facter, never assume them. - Emit deterministic, idempotent, yamllint-clean output into config/au/syd1/reality/<host>.yaml, generated for prodnxsr0001-0013. - Extend modules/infra with a reality variable and reality.tf creating netbox_device_interface/netbox_mac_address/netbox_ip_address/ netbox_inventory_item and device serial; wire reality only for hosts that also have an intent device. - Load reality/*.yaml in the terragrunt env; add `make backfill`; add a go vet/test woodpecker job; drop the in-cluster-only Python script. Closes #1 Claude-Session: https://claude.ai/code/session_01JUoARVdmhxKQHyyyp1pxeT
80 lines
2.2 KiB
Go
80 lines
2.2 KiB
Go
package main
|
|
|
|
import "testing"
|
|
|
|
func sampleReality() Reality {
|
|
return Reality{
|
|
Device: "prodnxsr0001",
|
|
Serial: "4RW6QM2",
|
|
Model: "OptiPlex 3050",
|
|
UUID: "4c4c4544-0052-5710-8036-b4c04f514d32",
|
|
Interfaces: []Interface{
|
|
{Name: "enp2s0", MAC: "d8:9e:f3:75:c3:60", MTU: 1500, Physical: true,
|
|
IPs: []string{"198.18.15.1/24", "198.18.19.1/32"}},
|
|
{Name: "loopback0", MAC: "f2:3d:ef:64:42:51", Physical: false,
|
|
IPs: []string{"198.18.19.1/32"}},
|
|
},
|
|
Inventory: &Inventory{
|
|
CPU: &CPU{Model: "Intel(R) Core(TM) i5-7500T CPU @ 2.70GHz", Cores: 4, Count: 4},
|
|
MemoryBytes: 33260900352,
|
|
Disks: []Disk{
|
|
{Name: "sda", Model: "SSDSC2BX012T4N", Serial: "BTHC651303WB1P2OGN", SizeBytes: 1200243695616},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
const wantYAML = `# Generated by tools/backfill from pdbmux - do not edit by hand.
|
|
# source: URL certname=prodnxsr0001.main.unkin.net
|
|
device: "prodnxsr0001"
|
|
serial: "4RW6QM2"
|
|
model: "OptiPlex 3050"
|
|
uuid: "4c4c4544-0052-5710-8036-b4c04f514d32"
|
|
interfaces:
|
|
- name: "enp2s0"
|
|
mac: "d8:9e:f3:75:c3:60"
|
|
mtu: 1500
|
|
physical: true
|
|
ips:
|
|
- "198.18.15.1/24"
|
|
- "198.18.19.1/32"
|
|
- name: "loopback0"
|
|
mac: "f2:3d:ef:64:42:51"
|
|
physical: false
|
|
ips:
|
|
- "198.18.19.1/32"
|
|
inventory:
|
|
cpu:
|
|
model: "Intel(R) Core(TM) i5-7500T CPU @ 2.70GHz"
|
|
cores: 4
|
|
count: 4
|
|
memory_bytes: 33260900352
|
|
disks:
|
|
- name: "sda"
|
|
model: "SSDSC2BX012T4N"
|
|
serial: "BTHC651303WB1P2OGN"
|
|
size_bytes: 1200243695616
|
|
`
|
|
|
|
func TestEmitYAMLGolden(t *testing.T) {
|
|
got := emitYAML(sampleReality(), "source: URL certname=prodnxsr0001.main.unkin.net")
|
|
if got != wantYAML {
|
|
t.Errorf("emit mismatch:\n--- got ---\n%s\n--- want ---\n%s", got, wantYAML)
|
|
}
|
|
}
|
|
|
|
func TestEmitYAMLDeterministic(t *testing.T) {
|
|
src := "source: URL certname=x"
|
|
if emitYAML(sampleReality(), src) != emitYAML(sampleReality(), src) {
|
|
t.Error("emit is not deterministic")
|
|
}
|
|
}
|
|
|
|
func TestEmitYAMLEmptyCollections(t *testing.T) {
|
|
got := emitYAML(Reality{Device: "d"}, "s")
|
|
want := "# Generated by tools/backfill from pdbmux - do not edit by hand.\n# s\ndevice: \"d\"\ninterfaces: []\n"
|
|
if got != want {
|
|
t.Errorf("empty emit = %q, want %q", got, want)
|
|
}
|
|
}
|