READ-ONLY planning finding. Repo HEAD at time of read: branch dc-dc-stage5-preconditions, 2026-08-09. This is worker W0.3 of Phase 0 (docs/audit/container-elim-pass/SCOPE-AND- EXECUTION-PLAN.md, phase-prompts.md). No command was executed; every row cites path:line.
Model B (D-122/D-123): vcloud (outer libvirt) -> vvr1-dcN (containment VM = inner libvirt, ALSO the DC rack: MAAS rack/region + Juju/openstack client host) -> node VMs. Eliminating the containment VM collapses this to vcloud (libvirt) -> node VMs directly. vvr1-dcN (the containment VM) is NOT the LXD API-charm containers that run on deployed OpenStack nodes -- those are untouched by this pass.
The load-bearing fact this dimension surfaces: vvr1-dcN is not only a nesting boundary, it is also the NAMED EXECUTION HOST for three separate ruled roles: (1) the D-123 nested-libvirt node host, (2) the D-132-amendment per-DC MAAS region+rack, and (3) the D-138 cloud-facing client host (juju/openstack run FROM vvr1-dcN, reached ssh -J voffice1 jessea123@<dc- rack-transit-ip> -- runbooks/dc-dc-phase3-maas-enlist-deploy.md:424,430, runbooks/dc-dc-phase4-juju-bundle-per-dc.md:165,357,1108). Flattening removes the host that carries all three roles simultaneously -- each must be re-homed, and they need not all land on the same place.
vvr1-dcCanonical tree (excludes the stale .claude/worktrees/skill-repackage-20260727/ git-worktree snapshot, which mirrors ~384 additional hits from an unrelated 2026-07-27 skill-repackage task and is not part of the live repo surface):
grep -rn "vvr1-dc" --include="*.sh" --include="*.py" --include="*.md" --include="*.yaml" \
--include="*.tf" . (from repo root, worktree copy excluded)
424 occurrences across 78 files.
Heaviest files (occurrence count): | File | Count | Nature | |---|---|---| | docs/design-decisions.md | 66 | D-122/123/124/125/126/128/138 rulings, amendments | | opentofu/main.tf | 34 | outer root: creates the vvr1_dc0/vvr1_dc1 containment VM modules | | scripts/site-headend-install.sh | 18 | --role rack = installs on vvr1-dcN | | docs/CURRENT-STATE.md | 17 | living status references | | opentofu/variables.tf | 16 | vvr1_dc0/vvr1_dc1 module var blocks ("Model B: holds the inner libvirt pool") | | opentofu/vr1-dc0-substrate/main.tf | 13 | inner root: qemu+ssh provider targets vvr1-dc0 | | runbooks/dc-dc-phase2-tofu-dc-substrate.md | 13 | outer/inner apply runbook | | docs/dc0-deploy-readiness.md | 12 | readiness record | | opentofu/vr1-dc1-substrate/main.tf | 9 | inner root, dc1 | | docs/dc-dc-deployment-workflow.md | 9 | workflow doc, plane-split doctrine | | runbooks/dc-dc-teardown-rollback.md | 8 | Paths A/B/C/M name vvr1-dcN as the teardown target | | opentofu/vr1-dc0-substrate/variables.tf | 6 | | | docs/audit/record-inventory.md | 6 | | | netbox/dc-rack-mgmt-import.py | 5 | imports vvr1-dcN as a NetBox rack-mgmt device | | tests/dc-rack-mgmt-import/test_logic.py | 5 | harness for the above | | ... | | remaining 64 files carry 1-4 hits each (changelogs, security-ledger, archive) |
scripts/*.sh + scripts/*.py combined: 26 occurrences across site-headend-install.sh, dc-rack-net.sh, site-baseleg.sh, dc-mirror.sh, dc-egress-check.sh, maas-profile-assert.sh, dc-dc-whole-host-budget.py. opentofu/: 17 files. Most of the remainder is docs/ (design-decisions, CURRENT-STATE, changelogs, security-ledger, archive) and runbooks/ -- i.e. DECISION RECORD, not live tooling; those do not need code changes on flattening, only a superseding note (GA-R1/R2 append-only discipline -- do not edit history).
| Consumer (file:line) | What it keys to the containment layer | What breaks / changes on flattening | Severity |
|---|---|---|---|
scripts/lib-hosts.sh:52,157-168,212-214,246-251 VIRSH_POWER_ADDRESS, VIRSH_POWER_ADDRESS_FROM_OFFICE1, VIRSH_POWER_ADDRESS_FROM_DCREGION |
Both forms are qemu+ssh:// URIs that dial the containment VM's libvirtd (172.31.0.2/10.12.8.2 for dc0, 172.31.0.6/10.12.68.2 for dc1) -- this is how MAAS powers on/off node VMs, because the node VMs live INSIDE vvr1-dcN's libvirt, not vcloud's. |
If node VMs move to vcloud's own libvirt, the power address becomes vcloud's own libvirt (qemu:///system locally, or a qemu+ssh back to vcloud from wherever MAAS's region runs). The FROM_OFFICE1/FROM_DCREGION split (which exists because "the reachable rack address differs by region", lib-hosts.sh:159-167) may collapse entirely if there is no separate inner libvirt host to be reachable FROM. Every value in both DC arms (vr1-dc0/vr1-dc1 cases, lines 212-214, 246-251) needs re-derivation, not a rename. |
HIGH -- this is the mechanism MAAS uses to power every node; wrong here = "MAAS unreachable" masquerading as a network fault (a failure mode this repo has already hit once, maas-role-tags.sh:48-51). |
scripts/lib-hosts.sh:69-72 NIC_PLANE_ORDER, BREX_PARENT_NIC |
Describes the NIC-to-plane mapping the INNER tofu root pins per node (main.tf macs[0..5] order) -- a property of how opentofu/vr1-dcN-substrate/main.tf (the inner root, applied via qemu+ssh to vvr1-dcN) attaches MACs to node VM NICs. |
If nodes are created directly by the (now single) tofu root against vcloud libvirt, the NIC/MAC-to-plane pinning logic must be re-authored in that root, but the ORDER CONVENTION itself (metal-admin first, not PLANE_CIDRS order) is a fact about how MAAS/libvirt XML enumerates interfaces, independent of nesting -- it likely CARRIES FORWARD unchanged. Confirm at Phase 2 (tooling), not a Phase-0 blocker. |
LOW-MEDIUM -- convention likely survives; the FILE that encodes it (inner substrate root) is what changes. |
scripts/lib-hosts.sh:29-34 CARVE_AUX_HOSTS |
Declares the aux (non-Juju) -tailscale-01/-maas-01 VMs as --host-only carve targets; these ALSO live inside vvr1-dcN's inner libvirt today. |
No conceptual change on flattening -- these become ordinary flat-libvirt VMs alongside the 9 role nodes + juju controller. Their power address inherits the same VIRSH_POWER_ADDRESS fix above. |
LOW -- mechanical, rides the same fix as the row above. |
scripts/lib-net.sh (whole file) |
No vvr1-dc string appears here (verified: grep vvr1-dc scripts/lib-net.sh = 0 hits). PLANE_CIDRS/PLANE_GW/VIP prefixes are IP-plan facts, not containment-topology facts. |
UNCHANGED by container elimination as such. It WILL change under the concurrent D-143 re-IP (10.12->10.13), but that is a SEPARATE, already-ruled axis this pass must keep distinguishable (SCOPE-AND-EXECUTION-PLAN.md Section 7 says exactly this). | NONE for this dimension -- flag as a non-consumer so Phase 4's change-set does not double-count it. |
scripts/maas-node-power.sh:2-46 (usage, POWER_ADDRESS arg, VIRSH_URI) |
Takes a qemu+ssh:// power address as an argument (not hardcoded) and virsh-lists domains AT THAT URI to MAC-match them to MAAS machines. Every worked example in the header (qemu+ssh://jessea123@172.31.0.2/system vr1-dc0) targets the containment VM. |
The script itself is topology-agnostic (it takes the URI as input) -- it needs NO code change. But every CALLER that supplies 172.31.0.2/10.12.8.2-class addresses must supply the new (flat) address instead, which is exactly the lib-hosts.sh fix above. Also note: the header's D-103 rationale for per-machine (not pod) power was ALREADY about avoiding MAAS-virsh-pod storage incompatibilities (domblkinfo on volume-ref disks) -- that reasoning is unrelated to nesting and stays valid post-flatten. |
MEDIUM -- no code change, but every invocation site needs the new address; a stale hardcoded address in a runbook/changelog would silently power the WRONG (or a nonexistent) host. |
scripts/site-headend-install.sh:6-20,82-129,204-343,371-409 --role rack, --host-nodes, node_host_check(), node_host_setup() |
This is THE script that turns vvr1-dcN into a nested-libvirt node host: installs qemu-kvm/libvirtd, turns on nested KVM, creates the inner pool dir, the SEC-010 FORWARD-drop keyed on $TRANSIT_IF ("mgmt"), and verifies the D-125 WAN bridge/uplink. --role rack (no --host-nodes) is the narrower "just a MAAS rack enrolling to Office1's region" case, ALSO run on vvr1-dcN today. |
If nodes run directly on vcloud, --host-nodes (node_host_setup/node_host_check, ~140 lines) becomes DEAD CODE for VR1 -- there is no separate "rack that also hosts nested KVM" anymore; vcloud itself already IS the outer libvirt host and does not need this bootstrap. The rack role itself (MAAS enrollment) may still be needed if D-132's "MAAS region controller per DC" is KEPT as a normal flat VM (see D-132 row below) -- but it would no longer carry --host-nodes. The SEC-010 FORWARD-drop (TRANSIT_IF="mgmt") is keyed to a transit LEG that exists BECAUSE of the containment VM's two-leg (transit + inner-plane) design; a flat topology may not have a "transit" interface to drop-FORWARD on at all, or the DC-LOCAL boundary the drop enforces may need to move to a different device (a vcloud-host-level nftables rule, or a per-VM firewall) -- this is a design question for Phase 0's target-topology worker (W0.4), flagged here as a dependency. |
HIGH -- largest single file by consumer surface (18 vvr1-dc hits, ~140 lines of --host-nodes logic); also the SEC-010 enforcement point (a security control, not just wiring) lives here. |
scripts/dc-rack-net.sh:2-14,55-85 (whole script; site table for dc0/dc1) |
RUNS ON THE DC RACK HOST (i.e. vvr1-dcN) per its own header; persists rack bridge-leg IPs (vr1-dc0-metal-admin=10.12.8.2/22 etc.) and the D-131 node-facing DNS forwarder, both keyed to addresses the CONTAINMENT VM itself holds on its own inner bridges. |
If there is no containment VM, "the rack's own inner bridges" do not exist in the same shape -- these addresses (.2, .3 on metal-admin) were the containment VM's identity on its OWN nested networks. Under a flat topology this functionality (rack-leg persistence + node DNS forwarder) needs a new HOME: either the per-DC MAAS region VM (if D-132's region-per-DC survives as a flat VM) or is retired if the forwarder's reason (rack-only resolver SERVFAILs, dc-rack-net.sh:27-30) no longer applies once "the rack" is gone. Cannot be resolved without W0.4's target topology. |
HIGH -- a security/DNS-availability control (D-131), not cosmetic; silently losing it would reintroduce the SERVFAIL bug this script was built to fix. |
scripts/site-baseleg.sh:40-48 LEGS["office1"], the commented-out [vr1-dc0] row |
The office1 row is UNRELATED to the containment VM (it's the vcloud<->voffice1 base leg). The DC rows are explicitly DEFERRED with the comment "the DCs nest inside vvr1-dc0 and are reached by qemu+ssh ... add a row ONLY if/when a DC needs one" -- and D-138 (design-decisions.md:7126-7131) already closed this deferral: "the DC rows stay DEFERRED and their MEASURE-first note is now ANSWERED: ... no host-side leg is wanted." |
If nodes are flat on vcloud, the "DC rows deferred because reached by qemu+ssh through vvr1-dc0" premise disappears -- vcloud already has an L3 view of its own libvirt guests without an SSH hop. Whether a NEW base-leg row is needed depends entirely on whether the flat node VMs get bridged IPs vcloud itself must route to, which again is W0.4's call. | LOW -- currently an explicit no-op; only becomes live work if the target topology needs a new leg. |
scripts/maas-role-tags.sh:37,48-51 |
The comment "Run this where maas lives (the D-128 Plane-2 headend)" and the REFUSE message both assume the operator KNOWS which host that is -- today, resolvable to voffice1 (region) OR vvr1-dcN (rack), a distinction this pass changes. No vvr1-dc LITERAL string appears in this script's logic (it is genuinely site/host-agnostic, driven by lib-hosts.sh/MAAS_PROFILE). |
No code change required. Purely a DOC/comment currency issue once the execution-host question (Section 3 below) is answered -- the "headend" language should be corrected to match whatever host actually runs maas post-flatten. |
LOW -- comment-only. |
opentofu/main.tf:25-33,187,234,309-422 (outer root, module "vvr1_dc0"/"vvr1_dc1") |
This IS the resource that creates the containment VM (vm_name = "vvr1-dc0", line 412) -- the single biggest and most literal consumer. Line 405: "Site-down = a single virsh destroy vvr1-dc0 (the D-122 intent)" -- i.e. the outer root's entire per-DC unit of work today IS this one VM. |
The ENTIRE outer-root module for a DC either (a) is deleted and replaced by direct node-VM resources targeting vcloud libvirt (the flattened design), or (b) is repurposed to create something smaller (e.g. just a MAAS-region VM, if that role is kept). This is squarely Phase-0-W0.1's (substrate/tofu map) territory, cross-referenced here because it is also the top literal-reference file in the census. | HIGH (cross-referenced to W0.1, not re-owned here). |
opentofu/vr1-dc0-substrate/main.tf, vr1-dc1-substrate/main.tf (inner roots) |
Provider block targets qemu+ssh INTO vvr1-dc0/vvr1-dc1 (per main.tf:25-33 comment on the outer root, and the inner root's own versions.tf/provider config) -- this is THE apply that creates the 9+1(+2 aux) node VMs, currently nested. |
If flattened, there is no longer an "inner root run via qemu+ssh into the containment VM" -- either this root's provider target becomes qemu:///system on vcloud directly (merging outer+inner into one tofu apply), or it becomes qemu+ssh FROM wherever the new execution host is, straight to vcloud. Either way this is a provider-config + apply-ordering change, not a pure rename. Cross-referenced to W0.1. |
HIGH (cross-referenced to W0.1). |
netbox/dc-rack-mgmt-import.py, tests/dc-rack-mgmt-import/* |
Imports vvr1-dcN into NetBox as a rack-management device record (a physical/virtual asset in the DCIM model representing the containment VM as "the rack"). |
If there is no containment VM, this NetBox device either needs to be retired (with a NetBox-side decommission, not silent deletion -- NetBox is the IPAM/DCIM system of record) or repointed to represent something else (e.g., vcloud itself, or nothing, if "the rack" concept is retired outright). This is a DATA-migration consumer, distinct from a code consumer -- flag for Phase 2/W2.4 (which tools become which modules) since it touches an external system of record, not just repo files. | MEDIUM -- external-system consumer, easy to miss because it is not a runbook or script that gets "read" in the normal grep sweep for tooling. |
scripts/dc-egress-check.sh:63,72 |
Comments citing MEASURED ip route output taken directly ON vvr1-dc0/vvr1-dc1 (the default-route-via-provider-public fact). Historical/measurement citations, not live logic keyed to the containment layer. |
No functional change -- the DEFAULT ROUTE FACT itself (default via .4.1/.64.1) is a plane-gateway fact (lib-net.sh PLANE_GW), not a containment fact, and would still hold once nodes are flat as long as the same plane/gateway design is kept. Re-verify empirically post-flatten rather than assume; the citation just needs a currency note. |
LOW. |
scripts/dc-mirror.sh:6 |
Doc-comment: "RUNS ON THE DC RACK HOST (e.g. vvr1-dc0), not on vcloud/voffice1." | Same class as dc-rack-net.sh above but for the apt mirror service -- if "the rack host" no longer exists as a distinct entity, this script's stated execution host must be re-pointed to wherever the mirror service actually runs post-flatten (likely still a dedicated per-DC utility VM at the .4 octet, per lib-hosts.sh:96-100 REGION_HOST_SUFFIX/utility-band convention -- that utility VM is unaffected by containment removal, it just stops being INSIDE a nested host). |
LOW-MEDIUM -- doc-currency + confirm the utility VM's own libvirt parent changes from "inner" to "vcloud direct", nothing else. |
scripts/maas-profile-assert.sh:39 |
Usage example lists voffice1,vvr1-dc0,vvr1-dc1 as the three MAAS-profile-bearing hosts whose region identity this script proves ("a machine count is NOT proof"). |
If the per-DC MAAS region (D-132 amendment) no longer lives ON the containment VM (because there is no containment VM) but instead on a flat per-DC utility VM, the usage example needs updating but the SCRIPT'S JOB (prove which region a profile resolves to, by rack identity) is unchanged and arguably MORE necessary post-flatten (more hosts look alike without the containment boundary as a visual/structural cue). | LOW -- doc-currency; the script's function is robust to the topology change. |
| D-128/D-138 execution-host assumption (see Section 3, its own severity call-out below) | vvr1-dcN is the D-138-RULED host for the Juju client + openstack CLI, and (per D-132 amendment, design-decisions.md:7161-7168) the per-DC MAAS region controller. Both rulings say "in the DC" / "on the rack" and CITE vvr1-dc0 transit-IP SSH as the concrete mechanism (runbooks/dc-dc-phase3-maas-enlist-deploy.md:424,430; phase4-juju-bundle-per-dc.md:165). |
THE OWED QUESTION THIS PASS MUST ANSWER, NOT ASSUME: with no containment VM, where do juju/openstack/the MAAS region run from? See Section 3. |
CRITICAL / BLOCKING -- this is not a mechanical rename; it is an unresolved architecture question that D-128/D-132/D-138 do not answer on their own once their named host disappears. |
runbooks/dc-dc-teardown-rollback.md (8 hits; Paths A/B/C/M) |
Teardown paths name vvr1-dcN as the target of tofu destroy / virsh destroy / juju-controller-down recovery. |
Once the containment VM does not exist, these paths must be re-authored around whatever the new substrate shape is (destroying flat node VMs individually or via a module, not "destroy one containment VM = destroy the site"). The D-122 intent quoted in opentofu/main.tf:405 ("site-down = a single virsh destroy vvr1-dc0") is a SIMPLICITY PROPERTY that flattening explicitly TRADES AWAY -- teardown of N+1 individual VMs is inherently more steps than one. Flag as a design tradeoff for W0.4/W4.2 (module design should re-earn this simplicity via a tofu-module-scoped destroy, not lose it). |
MEDIUM-HIGH -- teardown is a frequently-exercised, high-consequence path (see D-061 register / docs/tool-index.md's own origin story) and losing "one command tears down a DC" without a replacement is a real regression. |
Today: vvr1-dcN simultaneously serves three ruled roles:
jujud's continuous MAAS-API dependency never crosses the Office1 fiber (SEC-010 preserved unamended by removing the cross-fiber requirement rather than exempting it).juju/openstack run FROM vvr1-dcN, reached via ssh -J voffice1 jessea123@<dc-rack-transit-ip>, because SEC-010 + D-052 make the node planes unreachable at L3 from voffice1, and D-138's own reasoning is explicit: "a MAAS rack proxies at the application layer and needs no kernel forwarding... that is TRUE of every Plane-2 tool then in use and FALSE of Juju, which dials the MACHINE at L3."If vvr1-dcN is eliminated, all three roles lose their named host simultaneously, and they do NOT have to be re-homed together -- each has a different constraint:
jujud's L3 MAAS dependency stays local -- this could be a flat per-DC utility VM (the existing .6/REGION_HOST_SUFFIX convention already assumes a VM distinct from the role nodes, so it may not even need a new design, just a new libvirt parent).design-decisions.md:7107). If node VMs are flat on vcloud and reachable from vcloud's own network without SEC-010's transit-drop boundary in the way, the client could plausibly run FROM VCLOUD ITSELF (collapsing D-128's Plane-1/Plane-2 split for this specific tool-class) -- but this is only true if the flattened topology does NOT recreate an equivalent transit/forwarding boundary between vcloud and the flat node VMs. If it DOES (e.g., to keep simulating the Roosevelt fiber-boundary realism the whole VR1 exercise exists to rehearse), then a replacement "DC-local client host" is still needed, and D-138's reasoning (why the client cannot live at the far side of that boundary) still applies verbatim to whatever plays the transit-boundary role post-flatten.This is the single largest open question this dimension surfaces, and W0.3 cannot close it alone -- it is jointly a W0.2 (network/wiring: does a transit/SEC-010-equivalent boundary still exist post-flatten?) and W0.4 (target-topology: what replaces vvr1-dcN as a named host) question. Recorded here as the explicit hand-off the SCOPE doc's Section 4 instructs: "if there is no containment VM, where do juju/openstack run from?" has NO answer in the current repo -- D-128/D-132/D-138 all name vvr1-dcN as the concrete host, and none of them anticipates its removal. Whatever Phase 0 / W0.4 proposes as the target topology MUST include an explicit answer to this, stated as plainly as D-138's own ruling was stated, because it carries the same SEC-010/D-052 security-boundary weight D-138 was ruled to resolve -- getting it wrong reopens exactly the "narrow SEC-010 exception vs. re-plan the control-plane topology" choice D-132's amendment closed.
scripts/lib-net.sh -- no containment-layer coupling; only D-143 (re-IP) touches it. Keep the two axes distinguishable per SCOPE-AND-EXECUTION-PLAN.md Section 7.scripts/maas-role-tags.sh, scripts/dc-egress-check.sh, scripts/maas-profile-assert.sh logic (not comments) -- host-agnostic by construction (driven by lib-hosts.sh/env), so they need NO code change, only doc-comment currency once Section 3's question is answered.design-decisions.md hits and ~17 CURRENT-STATE.md hits are the DECISION RECORD -- per GA-R1/append-only discipline these are not edited; the container-elim [ARCH] decision (owed, per SCOPE doc Section 7) will AMEND or SUPERSEDE the relevant entries (D-122/123 most directly), not rewrite them in place. Not a "consumer" in the code sense; flagged so Phase 4 does not propose editing history.vvr1-dcN in that role.scripts/lib-hosts.sh power-address maps (every DC arm), scripts/site-headend-install.sh --host-nodes machinery (~140 lines becomes dead code for VR1), scripts/dc-rack-net.sh (rack-leg + D-131 DNS forwarder needs a new home), the outer/inner OpenTofu roots (cross-referenced to W0.1), and runbooks/dc-dc-teardown-rollback.md (loses the "one virsh destroy" simplicity D-122 intended, needs a re-earned equivalent).