Purpose. The operator ruled Model B for D-123 (nodes nested inside vvr1-dc0, single-object virsh destroy site-down) -- the heavier, higher-risk path (depth-4 nested virt, supersedes D-103/D-114, ~416 GiB containment VM). This document preserves Model A as a fully-specified, already-implemented fallback so that if Model B fails to deploy, we revert WITHOUT re-engineering.
Revert anchor (git). Model A is not theoretical -- it is the CURRENTLY COMMITTED substrate. The last commit before any Model B reshape is tagged model-a-fallback (re-cut 2026-07-16 onto 114d392, the R-3-compliant Model A layout with 4 storage nodes/DC -- the prior anchor at 87a7a8a was R-3-stale, flagged by the Model B design cross-check). To restore Model A: git checkout model-a-fallback -- opentofu/ (or cherry-pick the substrate files), then re-run bash scripts/opentofu-validate.sh. No file needs to be re-authored -- Model A already validates (tofu validate Success; 11/11 modules).
Nodes are vcloud-level libvirt siblings of the headend -- NOT nested inside it. This is the VR0-proven shape and the ADOPTED D-103/D-114 seam.
vcloud (host, L0)
|-- vvr1-dc0 MAAS rack headend (cloudinit-vm; D-124: 4 vCPU / 8192 MiB / 80 GiB;
| expose_nested_virt = false; legs = metal-admin + office1<->dc0 transit)
|-- vr1-dc0-control-01..03 node VMs (16/65536/150) \
|-- vr1-dc0-compute-01..02 node VMs (12/49152/100) > vcloud-level siblings, on vr1_dc0_planes
|-- vr1-dc0-storage-01..04 node VMs (8/24576/550) / (4 storage/DC per R-3)
|-- vr1-dc0-edge opnsense (2/2048, 2-NIC: provider-public LAN + vr1-dc0-wan WAN)
|-- vr1-dc0-* planes 6 isolated-L2 libvirt networks (dc-planes) at vcloud level
|-- vr1-dc0-wan NAT /24 simulated ISP uplink (site-wan)
`-- mesh-vr1-dc0-office1 transit leg (office1 <-> dc0)
nesting depth = 2 (vcloud -> node VM -> nova KVM guest) <- VR0-PROVEN
site-down = destroy the vr1-dc0-* domain GROUP (scripted, gated)
MAAS model = region on Office1 + rack (vvr1-dc0); maas-vm-host registers VCLOUD's virsh so
MAAS discovers the OpenTofu-created node domains (D-103/D-114 as-built)
| Artifact | Model A content |
|---|---|
opentofu/main.tf module "vr1_dc0_node" |
for_each = local.vr1_dc0_nodes; created on the vcloud libvirt provider; attached to module.vr1_dc0_planes outputs (6 NICs, metal-admin first = PXE). |
opentofu/main.tf module "vvr1_dc0" |
cloudinit-vm, 4/8192/80 (D-124), expose_nested_virt = false, two legs (metal-admin + mesh transit). A small rack headend that holds NO nodes. |
opentofu/main.tf module "vr1_dc0_planes" / mesh_* / vr1_dc0_wan |
all created at vcloud level. |
Step-9 maas-vm-host (deferred, DOCFIX-179) |
registers vcloud's virsh to the DC's MAAS -> MAAS discovers the vcloud-level node domains. |
scripts/site-headend-install.sh --role rack |
installs the rack controller on vvr1-dc0 (no LXD/compose in rack mode). |
| Site-down | a scripted group-destroy of the vr1-dc0-* domains (owned by dc-dc-teardown-rollback.md); NOT a single virsh destroy. |
Reverting = undoing exactly these; nothing else moves.
module "vr1_dc0_node" (and the 6 planes + vr1-dc0-wan) from vcloud's libvirt to vvr1-dc0's inner libvirt. A restores them to vcloud level.vvr1-dc0 from 4/8192/80 to ~416 GiB (must hold one DC's full node fleet) and sets expose_nested_virt = true. A restores D-124's 4/8192/80.vvr1-dc0's inner virsh; A registers vcloud's virsh.virsh destroy vvr1-dc0; A = scripted group-destroy.opentofu/vr1-dc0-substrate/ (a new root dir + its own state) and a site-headend-install.sh --host-nodes node-host bootstrap; A has neither. Revert removes them.vr1-dc0-wan inside vvr1-dc0, B adds a vcloud-level ISP NAT (module "vr1_dc0_uplink", site-wan), a 2nd IP-less uplink NIC + the br-vr1-dc0-wan netplan bridge on vvr1-dc0, the new modules/wan-bridge, the bootstrap's --uplink-if/--wan-bridge verify, and re-addresses the OPNsense WAN into the vcloud ISP /24. In Model A none of this exists -- vr1-dc0-wan is a vcloud-level NAT the vcloud-level edge attaches to directly, egressing via vcloud with no uplink NIC, no bridge, no wan-bridge module. Revert removes all of it and restores the OPNsense WAN to 172.30.2.2 on the vr1-dc0-wan NAT. (New HELD gates that vanish on revert: vr1_dc0_uplink_cidr, the OPNsense WAN re-address.)git checkout model-a-fallback -- opentofu/main.tf opentofu/variables.tf opentofu/modules/ (restores the Model A substrate verbatim -- this also drops module "vr1_dc0_uplink" and the vr1_dc0_uplink_cidr var, since Model A has neither), then git rm -r opentofu/vr1-dc0-substrate (the inner root does not exist in Model A) and git rm -r opentofu/modules/wan-bridge (D-125, also absent in Model A), and revert the site-headend-install.sh node-host mode (incl. the D-125 --uplink-if/--wan-bridge WAN-bridge verify). Restore the OPNsense WAN address to 172.30.2.2.bash scripts/opentofu-validate.sh -> expect 11/11 PASS (Model A already validates).vr1-dc0-* group op) in place of the single-object destroy.repo-lint, run-tests-all, tofu validate) before proceeding.vvr1-dc0 cannot be allocated ~416 GiB on the host alongside the other layers.expose_nested_virt = true on vvr1-dc0 destabilises the headend/rack.Model A remains the recommended engineering choice on delta/risk grounds; Model B is the operator-ruled choice for its single-object site-down primitive. This plan makes the choice reversible at low cost. Kept in sync with the D-123 sweep; if Model B changes, update section 3.