No live infrastructure touched -- script + test-harness changes only (prep session; no jumphost/juju/MAAS access this session). Closes the CLI-wiring half of tooling gap register item #15 sub-item 2 in docs/dc-dc-deployment-workflow.md (full detail in runbooks/dc-dc-phase3-maas-enlist-deploy.md's "Known gaps" section, item 2), which blocked scripts/reenroll-hosts.sh, scripts/carve-host- interfaces.sh, and scripts/phase-00-maas-standup.sh from being invoked with a $DC argument at all -- DOCFIX-151 (2026-07-09) only gave the selector functions to lib-net.sh/lib-hosts.sh; no consumer script called them yet.
$DC env var wiring in the 3 MAAS scriptsFILES: scripts/reenroll-hosts.sh, scripts/carve-host-interfaces.sh, scripts/phase-00-maas-standup.sh, tests/carve-host-interfaces/run- tests.sh, tests/phase-00-maas-standup/run-tests.sh, new tests/reenroll- hosts/run-tests.sh.
WHAT: each script now reads an opt-in $DC env var immediately after sourcing lib-net.sh/lib-hosts.sh (the earliest possible point, matching the pattern runbooks/dc-dc-phase3-maas-enlist-deploy.md's Step 1 already documents) and, only if $DC is non-empty, calls lib_net_select_dc "$DC" (all three scripts) and lib_hosts_select_dc "$DC" (reenroll-hosts.sh and carve-host-interfaces.sh only -- phase-00-maas-standup.sh never sources lib-hosts.sh, it has no host-identity dependency to select). This matches the convention the selector functions and the Stage 4 runbook already established (an explicit $DC env var passed positionally into each function), rather than inventing a new --dc CLI-flag convention that does not exist anywhere else in this repo.
DC="${DC:-}"
if [ -n "$DC" ]; then
lib_net_select_dc "$DC"
lib_hosts_select_dc "$DC" # reenroll-hosts.sh / carve-host-interfaces.sh only
fi
Backward compatible by construction: unset $DC skips the if body entirely, so every existing invocation (bash scripts/reenroll-hosts.sh --check, bash scripts/carve-host-interfaces.sh openstack0 --apply, bash scripts/phase-00-maas-standup.sh) runs byte-for-byte as it did before this change -- confirmed by re-invoking each script with no $DC set and diffing against pre-change behavior descriptions in runbooks/phase-00-teardown- maas-reset.md (see VERIFIED below).
No second validation layer was added: because all three scripts already run under set -euo pipefail, a selector function returning non-zero (dc2 at the network layer; dc1 AND dc2 at the host layer) causes the script to exit immediately with that same exit code -- which happens to line up with each script's own "1 = fatal" convention, so the propagation is free.
VERIFIED (this workstation; no jq installed, no live jumphost/MAAS/juju access -- same environment gap DOCFIX-151's changelog documented):
need_jq/any MAAS call, so these do not need jq or a fake maas at all):
DC unset -> unaffected (rc identical to before this change in every script).DC=dc0 -> explicit no-op, byte-for-byte same as unset.DC=dc1 -> reenroll-hosts.sh and carve-host-interfaces.sh FAIL LOUD at lib_hosts_select_dc ("no enrolled hosts yet..."), before touching MAAS; phase-00-maas-standup.sh (network-selector only) no-ops (D-101: dc1 inherits dc0's plane literals) and proceeds to its own MAAS calls.DC=dc2 -> all three FAIL LOUD at lib_net_select_dc first ("no assigned network literals yet..."), before lib_hosts_select_dc is ever reached in the two scripts that also call it.DC=bogus -> all three FAIL LOUD ("unknown DC 'bogus'").bash scripts/repo-lint.sh: 0 fail, 1 documented legacy WARN (unchanged).bash scripts/run-tests-all.sh: new reenroll-hosts suite added (none existed before); it reports FAIL: jq required, identically to its sibling suites carve-host-interfaces and phase-00-maas-standup (both already jq-gated, unrelated to this change) and to roughly twenty other suites in the same gauntlet run that all fail for the same reason on this jq-less Windows workstation. Did NOT run a git stash A/B comparison this time (unlike DOCFIX-151's changelog) because the working tree currently carries OTHER in-flight, uncommitted changes from parallel agent sessions tonight (per the operator's own instruction that multiple agents are working concurrently) -- stashing would have touched their work, not just this delivery's. Instead, correctness was verified directly (the jq-independent invocation matrix above), and the only new gauntlet observation is the addition of the reenroll-hosts suite itself (previously absent, so it could not have been part of any prior baseline) failing for the same pre-existing, already-documented reason as its siblings -- not a regression this delivery introduced.$DC test cases to both existing harnesses (tests/carve-host-interfaces/run-tests.sh, tests/phase-00-maas-standup/run-tests.sh): a DC=dc0 explicit no-op case (must match the existing default-case assertions), and fail-loud cases for the blocked DC values, using a new run_dc() helper that skips fixture setup entirely (these calls exit at the selector, before the script ever reaches need_jq/a MAAS call, so they do not depend on the fixtures OR on jq being installed -- confirmed by invoking them directly, bypassing the harness's own jq gate, per the VERIFIED bullet above).tests/reenroll-hosts/run-tests.sh (no harness existed for this script before). Scoped narrowly to what this delivery actually changed: the $DC fail-loud/no-op matrix, plus a smoke test that --check's read-only reporting is unaffected when $DC is unset. Does not attempt to cover the create/poll/tag mutation paths (those need an interactive password prompt and a much heavier MAAS fixture set -- out of scope for a targeted parameterization change). Uses a minimal fake maas returning an empty machines list plus < /dev/null on stdin so a bug that ever reached the real interactive password prompt would fail loudly (EOF) instead of hanging the harness.REVERT: git checkout HEAD~ -- scripts/reenroll-hosts.sh scripts/carve- host-interfaces.sh scripts/phase-00-maas-standup.sh tests/carve-host-interfaces/run-tests.sh tests/phase-00-maas-standup/run-tests.sh && rm -rf tests/reenroll-hosts (safe -- purely additive/opt-in; unset $DC behavior is provably unchanged, so no other script or runbook step that does not set $DC depends on any of this).
Tooling gap register item #15 has SEVEN sub-findings (enumerated in runbooks/dc-dc-phase3-maas-enlist-deploy.md's "Known gaps" section). This delivery closes ONLY the CLI-invocation half of sub-item 2 (the three scripts not accepting $DC at all). It does NOT:
lib-hosts.sh. lib_hosts_select_dc still fails loud for both dc1 and dc2, exactly as DOCFIX-151 left it -- that data gap is a separate, later delivery item (the Stage 4 runbook's own delivery checklist), not something this change works around.phase-00-maas-standup.sh's PLANES table dc2-aware. That table is a hardcoded D-052/D-053 literal, not derived from lib-net.sh's flat vars -- selecting dc1 happens to be correct today only because D-101 makes dc1's real target identical to dc0's, not because the script reads dc1-specific data. Once dc2 gets real NetBox CIDRs (gap #3), this table will need its own parameterization pass.HOST_TAG/boot-fabric-name literals are DC0-specific). All six remain OPEN, unchanged by this delivery.docs/dc-dc-deployment-workflow.md item #15 and runbooks/dc-dc-phase3- maas-enlist-deploy.md's gap #2 / Steps 5 and 8 updated to reflect the partial closure (see those files' diffs). The next real dependency for sub-item 2's FULL closure is Stage 4's own execution: once it measures real per-DC hostnames/octets/boot MACs and a real per-DC PLANES table update gets authored, lib-hosts.sh and phase-00-maas-standup.sh's literal table go from "selector wired but fails loud" to "selector wired and populated" -- no further change to the three scripts themselves should be required for that.