voffice1 is a working VR1 site headend. MAAS 3.7.2 (region+rack, PostgreSQL 16.14) and LXD 5.21.5 are installed on it, that LXD is registered back into MAAS as an LXD VM host, and MAAS has composed, PXE-booted and COMMISSIONED its first service VM. D-114's model is proven.
New: scripts/site-headend-install.sh + tests/site-headend-install/run-tests.sh (18/18 PASS). The script is the install sequence we actually executed, codified -- not written from docs. Its --check mode was run against the live voffice1 and reports every item OK.
vcloud (L1 -- itself a KVM guest, measured)
|- voffice1 (L2) MAAS 3.7.2 region+rack + LXD 5.21.5, 10.10.0.20 (Kea reservation)
|- office1-netbox (L3) LXD VIRTUAL-MACHINE, composed by MAAS, PXE-booted by MAAS
office1-netbox: composed via maas admin vm-host compose, leased 10.10.1.100 from MAAS's own DHCP on lxdbr0, PXE-booted, ran commissioning, and reached status Ready with MAAS correctly detecting 2 cores / 4096 MiB. It then powered off -- correct for a commissioned machine./dev/kvm + svm). Now a guest has actually booted, PXE'd, commissioned and reported its hardware three levels deep. D-114's Office1 gate is CLEARED.lxd + tailscale pattern exactly: MAAS's unit of visibility is the machine; Juju's LXD containers (the OpenStack API services) remain invisible to MAAS, as in VR0.| network | authority | MAAS dhcp_on |
|---|---|---|
10.10.0.0/24 (office1-local, the site LAN) |
Kea, on the OPNsense edge | False |
10.10.1.0/24 (lxdbr0, the compose network) |
MAAS | True |
Two DHCP servers, two physically separate L2s -- lxdbr0 is never bridged onto the site LAN, so they cannot see each other. The script asserts this after configuring DHCP and FAILS if MAAS DHCP is on for any subnet other than the one it was told about.
10.10.1.0/24 is a NEW allocation that NetBox has not blessed. It was chosen deliberately (DC1 is 10.12.x, DC2 10.13.0.0/19, the tenant pool is 10.20.0.0/16 per D-016 -- the obvious-looking 10.20.x would have collided with tenant space). It must be registered in NetBox once NetBox exists. This is the known chicken-and-egg: NetBox is one of the VMs this headend composes.
lxd init --auto FAILS on a host that also runs MAAS. It creates lxdbr0 with LXD's own DHCP+DNS on, which starts a dnsmasq; dnsmasq binds the wildcard 0.0.0.0:53, and MAAS's bind9 (named) already holds :53. Verbatim: Failed starting network: The DNS and DHCP service exited prematurely: exit status 2 ("dnsmasq: failed to create listening socket for 10.10.1.1: Address already in use") The message names the BRIDGE address, which sends you hunting the wrong thing -- the real conflict is the wildcard bind. ipv4.dhcp=false + dns.mode=none are NOT sufficient: LXD still spawns dnsmasq for a managed bridge and it still tries to bind :53. The fix that works is raw.dnsmasq="port=0". Verified after the fact: dnsmasq runs but holds zero sockets on :53 and zero on :67.lxc reads its config from STDIN. Pipe this script to bash -s over ssh and the first lxc call without a redirect eats the rest of the script as YAML (Error: yaml: unmarshal errors: line 1: cannot unmarshal !!str 'echo "...' into api.StoragePoolPut) and everything after it silently vanishes. Every lxc call now ends in </dev/null. Same class as the OPNsense tcsh trap.5.21/stable and never allowed to land on latest first, because MAAS 3.6/3.7 is incompatible with LXD >= 6.7 (pinned pylxd 2.3.5 vs LXD 6.7's consolidated endpoints). Bonus discovered in research: core.trust_password still exists in 5.21 and is GONE in 6.x, so the pin also preserves the scriptable registration path. https://discourse.maas.io/t/maas-incompatibility-with-lxd-6-7/15749--compose-cidr is REQUIRED and has no default, precisely so it can never be picked by accident, and the script hard-fails if MAAS DHCP ends up enabled on any other subnet.Also encoded: systemd-timesyncd must be disabled (MAAS manages time via chrony); a dynamic iprange must exist before dhcp_on=True leases anything; dir storage driver chosen over zfs deliberately (no zfs loop file inside an already-nested guest).
--help on the box before use (maas init --help, maas createadmin --help, maas vm-host compose --help), rather than trusted from documentation. --password on createadmin and storage=label:size on compose were confirmed this way.0600 under /root/maas-secrets/, and were never printed into the session.tests/site-headend-install/run-tests.sh: 18/18 PASS. Includes a self-check that the harness actually catches a regression (removing the 5.21 pin makes it fail).scripts/site-headend-install.sh --check against the LIVE voffice1: every item OK.repo-lint: 0 fail. Full gauntlet: ALL GREEN.ssh voffice1 'sudo snap remove maas postgresql lxd' # or destroy voffice1 entirely: tofu -chdir=opentofu destroy -target=module.voffice1 git revert <this commit>
Reverting the commit removes the script + harness. The OPNsense edge is untouched. Note the Kea reservation for voffice1 lives on the edge, not in this commit -- remove it via the REST API (kea/dhcpv4/del_reservation) if voffice1 is destroyed for good.