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
82 lines
2.3 KiB
Go
82 lines
2.3 KiB
Go
// Command backfill queries pdbmux (the PuppetDB multiplexer) for already-
|
|
// provisioned hosts and emits their hardware reality — serial, model, UUID,
|
|
// every recordable interface's MAC/IPs (including overlay/loopback/kube-lb
|
|
// addresses) and CPU/RAM/disk inventory — as reviewable per-host YAML for the
|
|
// NetBox reality side (modules/infra variable "reality").
|
|
//
|
|
// It is a generator, not a live data source: it writes committed config that
|
|
// terraform later reconciles into NetBox. Intent (config/.../devices/*.yaml)
|
|
// stays human-authored; this fills reality only.
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
defaultURL = "https://pdbmux.k8s.syd1.au.unkin.net/pdb/query/v4/facts"
|
|
defaultDomain = "main.unkin.net"
|
|
)
|
|
|
|
func main() {
|
|
url := flag.String("url", envOr("PDBMUX_URL", defaultURL), "pdbmux PuppetDB v4 facts endpoint")
|
|
out := flag.String("out", "", "directory to write <host>.yaml into (default: stdout)")
|
|
domain := flag.String("domain", defaultDomain, "domain appended to short hostnames to form certnames")
|
|
flag.Parse()
|
|
|
|
hosts := flag.Args()
|
|
if len(hosts) == 0 {
|
|
fmt.Fprintln(os.Stderr, "usage: backfill [--url URL] [--out DIR] [--domain D] host...")
|
|
os.Exit(2)
|
|
}
|
|
|
|
client := newFactsClient(*url)
|
|
rc := 0
|
|
for _, h := range hosts {
|
|
certname := h
|
|
if !strings.Contains(h, ".") {
|
|
certname = h + "." + *domain
|
|
}
|
|
facts, err := client.facts(certname)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "%s: query failed: %v\n", certname, err)
|
|
rc = 1
|
|
continue
|
|
}
|
|
if len(facts) == 0 {
|
|
fmt.Fprintf(os.Stderr, "%s: no facts (not in pdbmux)\n", certname)
|
|
continue
|
|
}
|
|
|
|
text := emitYAML(factsToReality(certname, facts), fmt.Sprintf("source: %s certname=%s", *url, certname))
|
|
if *out == "" {
|
|
fmt.Print(text)
|
|
continue
|
|
}
|
|
if err := os.MkdirAll(*out, 0o755); err != nil {
|
|
fmt.Fprintf(os.Stderr, "%s: %v\n", certname, err)
|
|
rc = 1
|
|
continue
|
|
}
|
|
path := filepath.Join(*out, shortName(certname)+".yaml")
|
|
if err := os.WriteFile(path, []byte(text), 0o644); err != nil {
|
|
fmt.Fprintf(os.Stderr, "%s: %v\n", certname, err)
|
|
rc = 1
|
|
continue
|
|
}
|
|
fmt.Fprintf(os.Stderr, "wrote %s\n", path)
|
|
}
|
|
os.Exit(rc)
|
|
}
|
|
|
|
func envOr(key, def string) string {
|
|
if v := os.Getenv(key); v != "" {
|
|
return v
|
|
}
|
|
return def
|
|
}
|