Session changelog (GA-R2/D1: ONE per session). Logged window: dc0-deploy (same-day append, per the A/B-boundary handoff). Status lives ONLY in docs/CURRENT-STATE.md; this file is narrative + reverts.
module "voffice1" in the outer root; apply in a planned voffice1 restart window (graceful shutdown first; region/NetBox/Tailscale return via proven autostart).docs/design-decisions.md:3727); no new D-number (GA-R3, doubt resolves DOWN).<forward>/<ip>) with exactly ONE attached interface (vvr1-dc0 vnet3); voffice1 + office1-opnsense have NO mesh NIC; nothing holds 172.31.0.1; vvr1-dc0's applied transit leg = 172.31.0.2/30 with only route 10.10.0.0/22 via 172.31.0.1 (d124-rack.auto.tfvars, consumed by step A). Item-20 disposition: with voffice1 holding .1, vvr1-dc0 is reached by -J voffice1 (D-126 shape) -- NO vcloud host leg / site-baseleg DC row needed for this net.opentofu/main.tf module "voffice1": network_names gains module.mesh_vr1_dc0_office1.network_name SECOND (office1-local stays first -- PCI order preserves enp1s0); network_config rewritten from the single-NIC "en*" glob to per-NIC name matches (lan=enp1s0 dhcp4; transit=enp2s0 static ${vr1_dc0_rack_transit_peer_ip}/${prefix} -- same D-124 tfvars the rack consumes, no new literal). Naming-trap + no-cloud-init- re-run caveats documented in-block: the seed netplan is REBUILD correctness; the live transit config is an in-guest netplan drop-in at the gated attach step.network_names = [module.office1_network.network_name] and the previous "en*" glob network_config (git revert of this commit); if already applied, a follow-up plan shows the interface removal and the in-guest drop-in /etc/netplan/60-transit.yaml is deleted.docs/audit/outer-apply-20260719-voffice1-transit.txt) -> domain up with both NICs, office1-local index 0.52:54:00:6a:87:e5 -> new 52:54:00:89:e1:19). The Kea reservation (MAC-keyed) missed and voffice1 leased pool address .108 (measured via edge ARP). FIX: re-keyed reservation uuid b12621e6-63e9-4714-9726-2e130c84e069 to the new MAC via the D-113 API (kea/dhcpv4/set_reservation -> saved; kea/service/reconfigure -> ok), then a detached networkctl reconfigure enp1s0 -> voffice1 back on 10.10.0.20.modules/cloudinit-vm does not pin MACs, so ANY interface-list change re-rolls them and breaks MAC-keyed DHCP reservations. Roosevelt-relevant; candidate module mac var or a documented ops step. Also: live transit config landed as in-guest netplan drop-in /etc/netplan/60-transit.yaml (narrows the lan glob to enp1s0 + transit enp2s0 static) -- the drop-in must ALSO narrow lan, else the 50-cloud-init en* glob claims enp2s0 (measured: first drop-in attempt without it left enp2s0 addressless).kea/dhcpv4/set_reservation back to the old MAC (senseless unless the NIC change is also reverted); delete the drop-in.172.31.0.2 unreachable; MEASURED: both rack NICs emitted ZERO frames ever (host FDB virbr7/virbr4, voffice1 ARP FAILED); guest OS alive (ACPI-responsive; cloud-init completed per offline logs).modules/cloudinit-vm domains have NO serial console, NO qga channel, NO graphics; qga is NOT in the noble base image and its cloud-init install failed (no egress) -- so no console, no agent, no network. LOGGED FINDING: add opt-in serial console (+ the D-129-style qga channel var) to modules/cloudinit-vm -- observability gap bites every future DC VM. NOT executed mid-step.~/vvr1-dc0-offline-inspect{,2}.txt): NIC names enp1s0/enp2s0 CORRECT (naming trap closed); root cause = netplan match.name + set-name: boot 1 renames don't apply (.link written after udev add) so the rendered config matched nothing; after removing set-name, boot 2 STILL failed because the early-boot netplan generator ran against the OLD config and renamed the devices to mgmt/uplink before cloud-init wrote the new file (one-boot lag, measured in syslog). Boot 3 (current config, no renames) is the verification boot.network_config drops set-name, keeps MEASURED kernel names; instance-id bumped vvr1-dc0-d123 -> -d123-r2 (side effects noted in-block); seed replaced via explicit -replace=module.vvr1_dc0.libvirt_volume.seed (the sanctioned override of D-130 ignore_changes for INTENDED seed changes) -- plan/apply 2/0/2 exact (docs/audit/outer-{plan,apply}-20260719-vvr1dc0-netplan-fix.txt).--transit-if enp1s0 --uplink-if enp2s0 (script defaults mgmt/uplink no longer match reality); runbook prose naming "mgmt" needs a DOCFIX at stage close.-replace apply + reboot.enp1s0 UP 172.31.0.2/30, region route present, br-vr1-dc0-wan up.-i ~/vr1-dc0-creds/vr1-dc0_svc_ed25519 -J voffice1 jessea123@172.31.0.2 works (D-126 -J shape, per-env key); rack -> region ping 10.10.0.20 0% loss (the MAAS-enrollment path for the G10 bootstrap).docs/audit/outer-plan-20260720-postfix-converged.txt); CURRENT-STATE section 5 updated in the same commit.install -m600 /dev/stdin), verified by byte-count only (32), never in context.docs/audit/stepB-bootstrap-20260720.txt): maas snap 3.7/stable installed, rack ENROLLED to http://10.10.0.20:5240/MAAS; FAILED at qemu apt install on stale image package lists (404s via proxy). Fix: apt-get update (proxied), re-run.docs/audit/stepB-bootstrap-20260720-run2.txt): EXIT 0 -- libvirt/qemu + nested KVM on, inner pool + AppArmor, SEC-010 FORWARD-drop loaded on enp1s0 + sec010-fw.service enabled (boot-persistent), br-vr1-dc0-wan verified with enp2s0 enslaved.--check (docs/audit/stepB-check-20260720.txt): all items ok EXCEPT opnsense base (the remaining step-B item); rackd running, enrolled.maas ... rack-controllers delete; SEC-010: disable sec010-fw.service + rm /etc/nftables-sec010.nft; packages: apt/snap remove; snap proxy: snap unset system proxy.http proxy.https.opnsense-26.7-nano.qcow2; vr1-dc0-substrate opnsense_base_path default updated (no inner state exists; pre-apply edit); step-B --check passes --opnsense-base for the 26.7 path. LOGGED follow-items: site-headend-install.sh's 26.1 default + hint strings (script change + harness, stage close); the D-112/D-113 serial/API boot path is REVALIDATED on 26.7 at the step-C boot gate (office1 precedent: 26.1-proven, upgraded in place to 26.7).https://mirror.ams1.nl.leaseweb.net/opnsense -- MEASURED from the vendor's live download page this session (not memory), HEAD-verified serving the 26.7 nano (~468 MiB). LOGGED FINDING: opnsense-prep-image.sh performs no checksum verification of the downloaded image (same property as the original 26.1 prep; candidate hardening).docs/audit/stepB-opnsense-prep-20260720.txt). Inner-root opnsense_base_path default -> 26.7 (validate PASS).--check EXIT 0, ALL items ok (docs/audit/stepB-check-20260720-final.txt).systemctl disable sec010-fw on voffice1; nft delete table inet sec010; ledger row reopens citing this item.29cf7bf (branch); dc0 private key staged to ~/vr1-dc0-creds/ (0700/0600, piped -- SEC-009 convention now spans hosts); ssh config entry for 172.31.0.2; known_hosts seeded via ssh-keyscan with the ED25519 fingerprint cross-checked against the accept-new-trusted entry (MATCH).keyfile+sshauth=privkey URI params -- its Go ssh ignores ~/.ssh/config AND default identities; single-type known_hosts fails as "key mismatch" (multi-type scan required); (ii) modules/wan-bridge: <mtu> is ILLEGAL in bridge-mode networks -- removed (MTU belongs to the host bridge; DOCFIX-194 class: parsed, never applied); (iii) base-image location premise WRONG under remote provider -- content UPLOADS from the executing host; 26.7 qcow2 copied rack->voffice1 (~/vr1-dc0-images/), tfvar override + variables.tf description corrected; (iv) edge serial-log dir /var/lib/libvirt/vr1/staging/ is a HARDCODED vcloud literal in modules/opnsense-edge (:223) -- dir created on the rack (755); LOGGED findings: parameterize the path; fold staging-dir creation into site-headend-install --host-nodes; opentofu-validate.sh does not cover the inner root.docs/audit/inner-{plan,apply}-20260720-stepC*.txt): run 1 = 25/28 (nodes+planes+pool; wan-bridge mtu abort); run 2 = wan bridge (edge disk stat abort); run 3 = edge disk (staging-dir abort; provider self-cleaned the failed domain -- operator undefine found nothing); run 4 = edge domain, EXIT 0. CONVERGED: inner plan zero diff (docs/audit/inner-converge-20260720-stepC.txt).~/openstack-caracal-dc-dc/opentofu/vr1-dc0-substrate/terraform.tfstate) -- back it up with the site; follow-item for the backup set.tofu destroy in the inner root from voffice1 (site-down alternative: virsh destroy vvr1-dc0, D-122); module fixes revert by commit.~/vr1-dc0-creds/vr1-dc0-edge_ed25519, 0600/0644, SEC-009 convention), staged to the rack the same way.10.12.4.2/22 on the provider-public inner bridge (virbr5, MEASURED) + the D-124-ruled 10.12.8.2/22 on metal-admin (virbr2). INTERIM: ip addr add, not persistent. LOGGED FINDING (queued): site-headend-install.sh never implemented the rack legs despite main.tf's comment claiming it consumes vr1_dc0_rack_metal_admin_ip -- add rack-leg support + harness before step D closes. Also interim: 192.168.1.2/24 on virbr5 to reach the edge's FACTORY LAN; REMOVE once the edge is re-addressed.~/d112c-console.log on the rack). Driver evolved v1->v6 against MEASURED failures, each real and worth keeping for the runbook: (i) serial console wraps long lines -> ship payload as <=160-char base64 chunks (openssl base64 -d), never one long line; (ii) set-name in the edge netplan is irrelevant here but the same class bit the rack (item 4); (iii) tcsh on the edge (documented trap) breaks nested-quoted sed -- "Unmatched '"'"'" -- so NEVER patch files via quoted one-liners; re-ship the whole payload instead; (iv) write_config() needs an include beyond config.inc -- MEASURED (grep -l shell_safe /usr/local/etc/inc/*.inc -> auth/console/filter/ interfaces/rrd/system/util.inc), not guessed; (v) writing config.xml does NOT materialize /root/.ssh/authorized_keys -- must call the vendor's local_user_set() (auth.inc). This was the actual reason key auth failed after a "successful" config write.ssh -i vr1-dc0-edge_ed25519 root@192.168.1.1 -> key-only auth OK, uname -r = 15.1-RELEASE-p1, ifconfig -l = vtnet0/vtnet1. INTERFACE MAPPING MEASURED: vtnet0 = LAN = provider-public plane (it answered on virbr5), vtnet1 = WAN -- same order as the office1 edge.opnsense-bootstrap-apikey.sh
opnsense-mint-apikey.php, run ON the rack): key/secret 80 chars -> ~/vr1-dc0-creds/opnsense-api.txt (0600, secret never printed). SMOKE TEST PASS: GET core/firmware/status -> HTTP 200, CORE_ABI 26.7. This is the first proof the D-113(a2) API path works on 26.7 (the 26.7 revalidation the operator's base-version ruling called for). Script note: the bootstrap script requires the minter BESIDE it (its own dir), not in scripts/ -- worth a usage-line DOCFIX.POST auth/user/del_api_key/<id>, the proven negative-tested path) + creds file; ip addr del the three interim addresses; the console bootstrap reverts by re-imaging the edge (inner tofu destroy/re-apply of the edge module).br-vr1-dc0-wan, serial-log probe, then destroyed (leftover-domains=0 asserted). Script: scratchpad d125-egress-test.sh; capture docs/audit/d125-egress-gate-20260720.txt.vr1-dc0-uplink carries an <ip> but NO <dhcp> block -- there is no DHCP server on that /24 by design (the edge WAN takes a STATIC .2, D-113/D-125). DOCFIX QUEUED: the gate's wording "must GET a vcloud-ISP address" implies DHCP; it must say STATIC, or the /24 needs a range. Re-run used static 172.30.2.50/24.ping 1.1.1.1 FAILED (NET-PING-RC=1).10.10.0.0/22 via 172.31.0.1; the WAN bridge is IP-less by design), so traffic to 1.1.1.1 fails in the rack's own routing table before the NAT is ever consulted. Its ICMP+TCP failures say nothing about virbr4. The ONLY clean signal is the GUEST's (172.30.2.50) failed egress, and that guest tested ICMP only -- if the rule dump comes back identical for both bridges, re-run the guest probe with curl before concluding anything. (Recorded per GA-R1/C2: a wrong measurement is corrected in the record, not quietly dropped.)office1-wan NAT 0% loss. The two network definitions are byte-equivalent in substance (net-dumpxml: both forward mode=nat + <nat><port 1024-65535>; only netmask-vs- prefix notation differs) -- so the delta is in vcloud's LIVE firewall rules for virbr4, NOT in the design or the config.docs/audit/d125-egress-gate-20260720-matrix.txt). The "missing rule" hypothesis was DISPROVED by measurement first: the operator-run dumps show virbr4's rule set is structurally IDENTICAL to the WORKING virbr11 (only counters differ; virbr11's one extra rule is a DHCP checksum fixup it has because it carries a DHCP range). All three masquerade rules exist for 172.30.2.0/24 INCLUDING the generic (non-tcp/udp) one, and it had FIRED (1 packet/84 bytes = one ICMP conntrack entry), with FORWARD accept counting 136 packets. So net-destroy/net-start would have fixed nothing -- the pre-staged fix was correctly NOT run.curl http://1.1.1.1 -> 301, curl archive.ubuntu.com -> 200. Egress works for ICMP AND TCP to real hosts, so the D-125 bridge-in chain is PROVEN end to end and the double-NAT fallback is NOT needed.10.10.0.20:8000 -> 000) on all runs, while internet egress worked. That is the D-122/SEC-010 intent holding: the DC's WAN segment is an ISP uplink, not a path into Office1. Worth an explicit assertion in the hardening tests rather than leaving it an incidental observation.nft list ruleset and iptables-save (which backend is authoritative here is itself unmeasured -- do not assume), diffing virbr4 against the WORKING virbr11. Two rule families must both be checked, and a subnet-only grep would MISS the second: POSTROUTING masquerade (keyed on 172.30.2.0/24) and FORWARD accept (keyed on the INTERFACE virbr4). Pre-staged fix-forward IF the rules are absent or malformed vs virbr11: virsh net-destroy vr1-dc0-uplink && virsh net-start vr1-dc0-uplink reinstalls libvirt's rules from scratch -- cheap and safe (nothing rides that uplink yet but the probe). If instead the dump shows libvirt never installed them correctly, the restart will not help and the dig moves to the firewall backend / conntrack./tmp/noble.img on the rack (kept deliberately: it is the base for any future throwaway probe).interfaces/settings/get returns ONLY global offload flags, while interfaces/overview/list and interfaces/lan/get both return 404 "Endpoint not found". Base-interface addressing is still legacy /interfaces.php. The amendment now holds on TWO majors, measured.scripts/opnsense-set-iface-v4.php + scripts/opnsense-set-interface-v4.sh + tests/opnsense-set-interface-v4/ (53/53 PASS first run; gauntlet 70 -> 71 harnesses ALL GREEN; repo-lint 0 fail). Mirrors the proven v6 sibling exactly -- vendor Config singleton (never a config.xml push), dry-by-default, interface-count guard, fresh read-back verify, sh -s for the tcsh trap, KERNEL as ground truth. Two deliberate improvements over the v6 sibling: (i) the GATEWAY half (creates/updates at most ONE gateway_item, count-guarded exactly like the interface count, opt-in via a 5th arg); (ii) the interface's DEVICE is MEASURED from the edge's own config instead of the v6 sibling's hardcoded lan->vtnet0 / wan->vtnet1 sed -- that mapping is per-edge and hardcoding it is a hard-rule-2 violation waiting to happen. Harness pins BOTH (test 12 fails if the hardcode returns). LOGGED FINDING: backport the measured-device fix to the v6 sibling at stage close.172.30.2.2/24 + WAN_GW = 172.30.2.1 default. Note the edge had shipped with WAN on dhcp, which could NEVER have worked -- the uplink /24 has no DHCP server (same fact that broke probe run 1). Verified on the kernel: inet 172.30.2.2, default 172.30.2.1 UGS vtnet1, and the EDGE ITSELF pings 1.1.1.1 at 0% loss -- the D-125 chain now proven through the real OPNsense edge, not just a probe.192.168.1.1/24 -> 10.12.4.1/22 (the D-115/lib-net ruled provider-public gateway). Session dropped as designed; edge verified at the new address from the rack: inet 10.12.4.1 netmask 0xfffffc00.GET core/firmware/status -> 200 CORE_ABI 26.7; edge egress still 0% loss.192.168.1.2/24 on the rack's provider-public bridge is REMOVED (virbr5 now carries only the ruled 10.12.4.2/22).--commit <edge> lan 192.168.1.1 24, --commit <edge> wan ...); the gateway item is named WAN_GW and is the only one this tool created.modules/opnsense-edge (both MEASURED), so installing os-qemu-guest-agent alone yields a package that can never answer. Options presented: add channel var now / iperf only
expose_qga_channel (opt-in, DEFAULT OFF) in modules/opnsense-edge; vr1-dc0-substrate sets it true so NEW DC edges are BORN with the channel (the runbook's no-retrofit intent). Default OFF is load-bearing: a device change alters the domain, so defaulting ON would bounce every existing edge on the next plan. Shape taken from tofu providers schema -json (dmacvicar 0.9.8: devices.channels[].target.virt_io{name} + source.unix{mode}), NOT from a blog; source.unix carries no path, letting libvirt allocate the socket (same reasoning the serial block documents for pty).libvirt_volume.disk (holding the console + API bootstrap) was never at risk. Verified after: channel present (grep count 2), domain running, edge still reachable at 10.12.4.1.opnsense-plugins.sh apply had NEVER installed anything. api() used bash "$API" ${DRY_RUN:+--dry-run}: ${VAR:+word} expands when VAR is set and NON-EMPTY, and DRY_RUN=0 is non-empty -- so every apply silently dry-ran while printing "OK: profile 'vr1-edge' applied". A textbook false success, and the reason it survived review is that the harness drove ONLY --dry-run, leaving the live path with zero coverage. FIX tests the VALUE; harness gains two live-path tests against a stub api client, verified to FAIL 2/2 on the buggy version before restoring (a regression test that cannot fail is worthless). 20/20. This is exactly the class D-129's own "package present is not success" warning is about -- here the SCRIPT was the false reporter.{"status":"ok","msg_uuid":...} per plugin (not dry-run echoes), capture docs/audit/d129-plugins-20260720.txt (the earlier capture of the same name recorded the false dry-run and is REPLACED). Measured on the edge: os-qemu-guest-agent-1.3, qemu-guest-agent-11.0.1, os-iperf-1.0_2, iperf3-3.21.POST qemuguestagent/service/start -> {"response":"OK"}, status -> running) rather than by hand-editing rc.conf.virsh qemu-agent-command vr1-dc0-opnsense '{"execute":"guest-ping"}' -> {"return":{}}, and virsh domifaddr --source agent reports vtnet0 10.12.4.1/22 + vtnet1 172.30.2.2/24. The agent ANSWERS over the channel.DisabledRPCs, including guest-exec/guest-exec-status -- arbitrary command execution on the edge from the libvirt host. On a commercial multi-tenant cloud the DC edge should almost certainly disable the exec RPCs (we need guest-ping/fsfreeze/shutdown coordination, not remote exec). Not changed mid-step; propose with options at the review.POST qemuguestagent/service/stop; uninstall via core/firmware/remove/<pkg>; set expose_qga_channel = false and re-apply (in-place domain update again).Step-D work completed before the incident surfaced:
voffice1 (region, mtstwf) and vvr1-dc0 (rack, 7chphy, rackd running).10.12.8.0/22 = VLAN 5005/fabric-4, provider-public 10.12.4.0/22 = VLAN 5006/fabric-5. (Stale 192.168.1.0/24 also sits on fabric-5 -- the edge's old factory LAN, now vacated; cleanup queued.)dhcp_on=true primary_rack=7chphy, verified by read-back (10.12.8.0/22 dhcp=True primary=7chphy).INCIDENT (found by verification, not by a self-report):
virsh reset vr1-dc0-control-01 did NOT enlist. MEASURED cause chain: rack service_set shows dhcpd: off; no dhcpd process on the rack; no /var/snap/maas/common/maas/dhcpd.conf generated -- while MAAS's own API reports the VLAN as dhcp_on=True with the correct primary rack and the interface correctly linked (VLAN 5005, static 10.12.8.2). Config state and running state DISAGREE."Not enough hosts to serve the request", poll_workflow_task_queue retried 2807 times, task queue mtstwf@region:.... No worker is polling, so the workflow that pushes DHCP config to a rack can never run.voffice1 itself has NO dhcpd process (pgrep -c dhcpd -> 0) and reports no dhcpd service, while Office1's compose net 10.10.1.0/24 reads dhcp=True. So MAAS DHCP has been DOWN REGION-WIDE -- almost certainly since the 2026-07-17 host reboot -- and went unnoticed because office1-netbox/office1-tailscale were already Deployed and kept their addresses. This is NOT caused by the DC0 deploy; the deploy is what exposed it.cloud-assert.sh and the Office1 health checks did not catch a dead DHCP server, because MAAS's own service_set reported the region healthy. A behavioral DHCP assertion belongs in the health sweep -- this is precisely the "service's own verdict" principle the repo already applies elsewhere.sudo snap restart maas on voffice1 -> region back (HTTP 301 on localhost:5240). Recovery verified BEHAVIORALLY, not by service status: pgrep -c dhcpd on voffice1 0 -> 1, and on the DC rack 0 -> 1; MAAS then reported dhcpd: running on BOTH controllers (was off on the rack, absent entirely on the region). One restart fixed both sites, which confirms the single wedged-Temporal root cause rather than two faults.virsh reset vr1-dc0-control-01) enlisted immediately after.pgrep -c dhcpd on each controller and the region journal for Temporal "Not enough hosts to serve the request"; remedy snap restart maas; verify behaviorally on every controller, never by service_set.docs/audit/stepD-enlistment-20260720.txt): count 9, status 8 Commissioning + 1 New, shapes {16cpu/64GiB: 3, 12cpu/48GiB: 2, 8cpu/24GiB: 4} -- an EXACT match to the D-121 Option C / R-3 layout (3 control + 2 compute + 4 storage).vvr1-dc0 (itself a VM on vcloud) PXE-booted from the Office1 region across the D-124 transit and is running MAAS's ephemeral commissioning kernel -- i.e. real nested KVM at depth 4, proven by behavior rather than by inference from svm being present.maas-vm-host registration (module BUILT 2026-07-09, still UNVALIDATED) is the next piece, and it needs TF_VAR_maas_api_key.Revert: maas admin machines delete per machine (or delete the pod once registered); the VMs themselves are inner-root state.
PROPOSED REMEDY (superseded by the RESOLVED block above; kept for the audit trail): restart MAAS on the region (sudo snap restart maas on voffice1) to re-establish Temporal workers, then re-verify dhcpd on BOTH controllers behaviorally. Blast radius is low right now (no OpenStack workloads; both Office1 VMs already deployed and unaffected by a brief DHCP/API outage), which makes this the cheapest moment to fix it.
opentofu/vr1-dc0-maas/ -- a THIRD root holding the MAAS registration alone. Rationale is DOCFIX-179's own measured lesson applied rather than repeated: a provider "maas" block forces EVERY plan in its root to demand maas_api_url + the SENSITIVE key, even for plans creating zero MAAS resources (the DOCFIX-175 plaintext-secret surface). Putting it in the inner substrate root would make routine substrate work require MAAS creds. Substrate roots stay credential-free. Validated explicitly -- note opentofu-validate.sh covers only the outer root + modules, so neither extra root is gauntlet-covered; extending it stays QUEUED and is now more load-bearing (two uncovered roots).TF_VAR_maas_api_key from the operator-placed 0600 file; verified by FORMAT alone (71 bytes, 3 colon-separated parts), never printed. Caveat recorded in the root's header: the key DOES land in that root's tfstate (unavoidable with this provider), so that state inherits credential handling.ServerError: 503 ... Failed talking to pod: Failed to login to virsh console.virsh -c qemu:///system -> Failed to connect socket to '/var/run/libvirt/libvirt-sock': Permission denied. And snap connections maas lists NO libvirt interface at all -- there is nothing to snap connect. So a LOCAL qemu:///system VM host is ARCHITECTURALLY IMPOSSIBLE with snap-based MAAS.modules/maas-vm-host's header both state the DC pod is registered with power_address = qemu:///system LOCAL to the rack ("vvr1-dc0 is BOTH the MAAS rack AND the libvirt host, so no cross-fiber virsh dial"). The no-cross-fiber INTENT survives; the stated MECHANISM cannot work. Both surfaces need an amendment once the replacement is ruled. Roosevelt- relevant: the same constraint hits every DC pod and any snap-MAAS metal build, so this is not a VR1 quirk./snap/maas/41649/usr/bin/ssh), and jessea123 on the rack is in the libvirt group (113) -- so qemu+ssh://jessea123@172.31.0.2/system reaches libvirt through sshd (unconfined) instead of the blocked socket. It needs a key the snap's root can read (/var/snap/maas/current/root/.ssh/ does not exist yet) plus that pubkey in the rack user's authorized_keys.git rm -r opentofu/vr1-dc0-maas removes the root.Sequence, each step measured (operator ruled the DEDICATED key: "Dedicated MAAS->libvirt key (Recommended)"):
maas-virsh_ed25519 on the rack (0600, SEC-009 folder), pubkey into the rack user's authorized_keys, private half into the RACK's MAAS snap. Rack snap could then virsh -c qemu+ssh://... fine -- but the apply still failed the same way.Host key verification failed. Same key + keyscan installed there; region snap then listed the inner domains. (Worth keeping: for a virsh pod, the credential belongs wherever MAAS dials FROM, which is not necessarily the rack that owns the hardware.)Pod vr1-dc0-inner ... already exist -- the two earlier 503s had EACH created a pod server-side before erroring, so MAAS held two broken cores=0 pods outside tofu state. Deleted both (own residue), re-applied.Virsh command ['domblkinfo','vr1-dc0-compute-01','vda'] failed: internal error: missing storage backend for 'volume' storage.virsh domblkinfo vr1-dc0-compute-01 vda fails identically at the console with an ACTIVE, autostart pool. libvirtd cannot run domblkinfo against disks declared as pool+volume references -- which is exactly how modules/node-vm builds them. MAAS virsh pods are therefore incompatible with this repo's node-vm disk shape; making the pod work would mean converting node-vm to file-path disks and re-applying all nine domains.power_type=virsh + power_parameters_power_{address,id} on the canary (ace-oyster = vr1-dc0-control-01, matched by MAC) -> maas admin machine query-power-state returns {"state": "off"}. No pod, no domblkinfo, no module change, no touching nine live domains.scripts/maas-node-power.sh + tests/maas-node-power/ (24/24 PASS first run; gauntlet 71 -> 72 harnesses ALL GREEN; repo-lint 0 fail) -- delivered as TOOLING rather than nine hand-typed CLI calls so dc1 and any re-run are repeatable. Design points the harness pins: (i) matching is BY MAC, never by name -- MAAS assigns random hostnames at enlistment (ace-oyster, not vr1-dc0-control-01), so a name match would map nothing or, worse, the wrong node; (ii) dry by default; (iii) every write is verified by an actual query-power-state -- a stored power parameter proves nothing about whether MAAS can REACH the hypervisor; (iv) the measured pod-refutation reasoning travels in the script header.virsh (it is the MAAS/LXD host, not a libvirt host) -> installed libvirt-clients; and the maas CLI profile was root-only -> created a user profile with maas login ... - reading the key from STDIN (never printed, never in argv).docs/audit/stepD-power-20260720.txt): 10 domains found, 9 mapped and set, each confirmed power state: off by query. The 10th (the edge) is correctly unmapped -- it is not a MAAS machine.Ready means MAAS commissioned the node and it is deployable -- the whole point of step D. The remaining six finish unattended.maas admin machine update <id> power_type= (clears power) per machine; the script itself reverts by commit.Marking node failed - Node operation 'Commissioning' timed out after 30 minutes).Loading ephemeral for 20+ minutes with the rack at 385 GiB free and load 0.04. It is not contention and not memory.list-boot-images -> status: synced, 10 images), and DHCP itself (these same nodes enlisted fine over PXE earlier, which is what proved the depth-4 gate).modules/node-vm defines no serial console (confirmed in the module and in the live domain XML -- no serial/console devices), so a node stuck in Loading ephemeral is a sealed box: no console, no agent, no way to see the boot. This is the identical finding already logged against modules/cloudinit-vm (item 4), now proven to bite a second module and an actual live diagnosis. The fix is the same opt-in serial+log pattern modules/opnsense-edge already carries -- that module's console log is what made the 2026-07-12 boot bugs legible, and it is exactly what is missing here.noqueue). D-100 rules the parameters as a PLACEHOLDER for the rehearsal within a "same-metro dark-fiber, low single-digit ms" lean. Applying to the dc0<->dc1 leg is both the semantically correct link for D-100 and the SAFE one -- it carries no traffic (dc1 does not exist), unlike the transit, which is currently load-bearing for MAAS/PXE. modules/netem-link cannot run unattended from here: it shells out to ssh <host> 'sudo tc ...' and assumes PASSWORDLESS SUDO, which vcloud's operator account does not have -- a documented module assumption that this host violates.modules/node-vm now defines a serial console + boot log, with the log directory PARAMETERIZED (serial_log_dir) rather than opnsense-edge's hardcoded vcloud literal, which is wrong on any other libvirt host. Applied to all 9 domains: 0 add / 9 change / 0 destroy, in-place, nothing destroyed. validate PASS, repo-lint 0 fail.console=ttyS0. A serial console alone does not make a PXE-booting node observable -- seeing the firmware/ephemeral stage needs a graphics device + virsh screenshot (or a MAAS-side kernel cmdline change). Queue this as the correction to the node-vm console work; do not assume the console added today closes the observability gap.WHAT IS SOLIDLY ESTABLISHED (all measured):
Performing PXE boot 18:17:03 -> Loading ephemeral 18:17:45 -> silence -> timeout.counter, so drops cannot be read directly -- hypothesis UNCONFIRMED, not refuted.synced, 10 images), DHCP (leases work), and node SHAPE (Ready and Failed both span 16/64, 12/48 and 8/24).INVALID EXPERIMENTS -- MINE, RECORDED SO NOBODY TRUSTS THEM:
Commissioning already, so the new request did not restart the 30-minute timer (the failure at 19:24:51 belongs to the 18:54 attempt), and I then destroyed domains mid-commission, killing the in-flight run. STOPPED HERE rather than iterate again -- this is the reconciliation circuit-breaker: repeated cycles without convergence, and contaminated evidence is worse than none.CLEANEST NEXT EXPERIMENT (not run): with ALL node domains powered off and nothing else touching the fleet, commission EXACTLY ONE machine from a clean Ready/New state and leave it strictly untouched for 35+ minutes. Only that isolates contention from a genuine per-node failure. Candidate fixes to test after it: raise MAAS node_timeout (nested I/O is slow and 30 min may simply be too short), add a graphics device for virsh screenshot, add counter to the SEC-010 rules so the node->region hypothesis becomes readable, and check the kernel cmdline MAAS actually serves.
Failed commissioning state (so the commission restarts MAAS's 30-min timer), commission EXACTLY ONE, poll READ-ONLY only, touch nothing.Failed commissioning after 1770s (~29.5 min = the 30-min timeout), a SINGLE node entirely alone. Contention is refuted -- it is not I/O bandwidth, not memory, not the metadata service being swamped. The failure is systemic and per-node.Commissioning -> Performing PXE boot -> Loading ephemeral (~40s later) -> 30 min of silence -> timeout. The node gets the ephemeral image handoff and then never reports back.:5248 listening (2 sockets), rack->region 5240 = 301. A :5248 tcpdump returned 0 packets but its 220s window likely closed before the ephemeral OS reached the metadata-fetch stage -- INCONCLUSIVE (a timing race), not evidence.node_timeout (maas admin maas set-config name=node_timeout value=<min>, e.g. 60), commission ONE node, see if it completes. If it does, the fix is a config value (and a Roosevelt note: bare metal commissions faster, so this is a VR1-nested tuning, not a Roosevelt default). If it still fails well past 30 min, the timeout is exonerated and the next probe is the metadata-proxy access log / a console screenshot (needs the graphics-device correction to the node-vm console -- item 19).awk toupper(cell) ~ /OPEN|PENDING/) matched the substring OPEN inside "fail-open" in the closed row's disposition -- the row counted OPEN forever (same class as the GA-F15 wrap trap). Fix: strip FAIL-OPEN from the cell before matching (scripts/ledger-scan.sh); harness gains a CLOSED-row-with-fail-open fixture + nochk (45/45 PASS). Count re-verified: 7 open, SEC-010 absent.sudo apt-get install -y libguestfs-tools (1:1.52.0-5ubuntu3) -- enables offline guest inspection (virt-cat/virt-ls), used for items 4's captures. Standard KVM-host tooling; Roosevelt-transferable.sudo apt-get remove libguestfs-tools.