Rax foundations: config, domain model, NetBox client, diff engine
Phases 1-3 of the Rax build plan (see the plan doc referenced in the session this was built from): repo scaffolding, the pure domain model, a NetBox read client, and the pure diff engine.
What's here
-
Scaffolding: fail-fast env-based config (NetBox tokens, Proxmox
environments, OIDC-vs-local-admin auth mode selection), a minimal
server exposing
/healthz, Dockerfile/Makefile/docker-compose following hop-site's stdlib-first, Docker-multi-stage conventions. -
Domain model + NetBox client:
DeviceSpec/VMState/Plantypes (no I/O), andBuildDeviceSpecwhich resolves a rackeddcim.deviceinto aDeviceSpec— rack-role-gated (onlyvm-rack-role racks are in scope), vid-vs-internal-VLAN-id resolved correctly, MAC read from theprimary_mac_addressobject, routed-prefix detection for the Ansible-static-route reminder. -
Diff engine:
diff.Compute(spec, state, opts) -> Plan, pure and I/O-free so it's reusable from the web UI, arax debug diffCLI, and apply's own pre-apply re-validation. Disk shrink is always a Blocker, never an Action. A NIC's MAC only diffs when explicitly pinned in NetBox. Every interface needs a description before a Plan is Applyable.
Not yet built
Proxmox client (BuildVMState), auth (OIDC/local-admin), the web UI,
internal/apply, and internal/store (rack bindings + audit log) —
these are later phases.
Note on branch history
This repo's trunk had no commits when work started, so it began with
an empty bootstrap commit (Initialize trunk) purely so a real branch
existed to target. The original feature/scaffold branch ended up as
GitLab's auto-selected default branch (an artifact of push order before
trunk existed) and is now orphaned/protected — safe to delete via the
web UI once this MR is in, it holds nothing this branch doesn't also
have.
Test plan
-
gofmt -l .clean -
go vet ./...clean -
go build ./...succeeds -
go test ./...— all tests pass (config: 13, netbox: 7, diff: 21) -
Manual smoke test: binary starts, /healthzreturns 200