Newer
Older
openstack-caracal-dc-dc / tests / dc-selector / run-tests.sh
#!/usr/bin/env bash
# tests/dc-selector/run-tests.sh -- unit tests for the $DC selector
# convention (2026-07-09, tooling gap register #1): lib_net_select_dc() in
# scripts/lib-net.sh and lib_hosts_select_dc() in scripts/lib-hosts.sh.
#
# Asserts:
#  - sourcing either file with no further action is unaffected (backward
#    compatible by construction -- the flat vars populate exactly as before).
#  - lib_net_select_dc: vr0-dc0/vr1-dc0 no-op (D-101 inheritance); vr1-dc1
#    OVERRIDES to the D-124-amendment literals (2026-07-21: contiguous /22s in
#    10.12.64.0/19) and UNSETS the not-yet-ruled OpenStack-layer values;
#    unknown/retired tokens fail loud; one selection per shell (the guard
#    added with the diverging dc1 arm).
#  - lib_hosts_select_dc: vr0-dc0 no-op, VR1 arms POPULATED 2026-07-23 (was: fail loud -- no real
#    per-DC host enrollment exists yet for either -- this is the documented
#    asymmetry vs. lib-net.sh).
#  - Neither function ever silently invents/reuses a value across DCs.
set -uo pipefail
SD="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
NET="$SD/../../scripts/lib-net.sh"
HOSTSLIB="$SD/../../scripts/lib-hosts.sh"
P=0; F=0
ok(){ echo "PASS: $1"; P=$((P+1)); }
no(){ echo "FAIL: $1"; F=$((F+1)); }
chk(){ [ "$2" = "$3" ] && ok "$1" || no "$1 (got '$2' want '$3')"; }

# guard: both libs still refuse direct execution (unchanged by this addition)
( bash "$NET" >/dev/null 2>&1 );      chk "lib-net direct-exec-refused"   "$?" 2
( bash "$HOSTSLIB" >/dev/null 2>&1 ); chk "lib-hosts direct-exec-refused" "$?" 2

# shellcheck source=/dev/null
. "$NET"
# shellcheck source=/dev/null
. "$HOSTSLIB"

# --- backward compatibility: sourcing alone still populates the flat vars ---
chk "PLANE_CIDRS unaffected"       "${PLANE_CIDRS[0]}"       "10.12.4.0/22"
chk "KEYSTONE_VIP_DEFAULT unaffected" "$KEYSTONE_VIP_DEFAULT" "10.12.4.50"
chk "HOSTS array unaffected"       "${HOSTS[0]}"             "openstack0"
chk "HOST_OCTET unaffected"        "${HOST_OCTET[openstack0]}" "40"

# --- lib_net_select_dc (D-119 region-qualified): vr0-dc0/vr1-dc0 no-op,
#     vr1-dc1 OVERRIDES (D-124 amendment 2026-07-21), RETIRED bare dcN fails
#     loud, unknown fails loud ---
( lib_net_select_dc vr0-dc0 ); chk "net vr0-dc0 no-op rc"    "$?" 0
( lib_net_select_dc vr1-dc0 ); chk "net vr1-dc0 no-op rc"    "$?" 0
( lib_net_select_dc vr1-dc1 ); chk "net vr1-dc1 selects rc"  "$?" 0
( lib_net_select_dc bogus 2>/dev/null ); chk "net unknown-token fails-loud rc" "$?" 1
( lib_net_select_dc 2>/dev/null ); chk "net missing-arg fails-loud rc" "$?" 1

# vr1-dc1 arm: the D-124-amendment literals land (apex-verified 2026-07-21).
DC1_P0="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${PLANE_CIDRS[0]}")"
chk "net vr1-dc1 provider-public is 10.12.64.0/22" "$DC1_P0" "10.12.64.0/22"
DC1_P5="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${PLANE_CIDRS[5]}")"
chk "net vr1-dc1 replication is 10.12.84.0/22" "$DC1_P5" "10.12.84.0/22"
DC1_MA="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${PLANE_NAME[10.12.68.0/22]}")"
chk "net vr1-dc1 10.12.68.0/22 is metal-admin" "$DC1_MA" "metal-admin"
DC1_GW="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${PLANE_GW[10.12.64.0/22]}")"
chk "net vr1-dc1 provider-public gw is 10.12.64.1 (ruled edge LAN gw)" "$DC1_GW" "10.12.64.1"
DC1_MI="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "$METAL_INTERNAL_CIDR")"
chk "net vr1-dc1 metal-internal CIDR is 10.12.72.0/22" "$DC1_MI" "10.12.72.0/22"
# --- R9 group: REPLACED 2026-07-29, not deleted -------------------------------------
# These two cases asserted that vr1-dc1 UNSETS KEYSTONE_VIP_DEFAULT and VIP_PREFIX_*.
# That state was correct only while the values were unruled. R9 (the D-119 AMENDMENT,
# RULED 2026-07-27) ruled them and named overlays/vr1-dc1-vips.yaml the single AUTHORED
# source, and the unset was actively costing: `lib_net_select_dc vr1-dc1` left
# KEYSTONE_VIP_DEFAULT unbound, so every selector-CALLER touching it died under `set -u`
# while the non-callers silently used dc0's address.
# The assertions are REPOINTED at the ruled values -- a strictly stronger check than the
# absence they replace -- and paired with the DRIFT cases below, which re-derive the same
# values from the overlay so the arm and the ratified artifact cannot diverge silently.
DC1_KV="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${KEYSTONE_VIP_DEFAULT:-}")"
chk "net vr1-dc1 sets KEYSTONE_VIP_DEFAULT (R9)" "$DC1_KV" "10.12.64.50"
DC1_VP="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${VIP_PREFIX_PROVIDER:-}")"
chk "net vr1-dc1 sets VIP_PREFIX_PROVIDER (R9)" "$DC1_VP" "10.12.64"
DC1_VA="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${VIP_PREFIX_ADMIN:-}")"
chk "net vr1-dc1 sets VIP_PREFIX_ADMIN (R9)" "$DC1_VA" "10.12.68"
DC1_VI="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${VIP_PREFIX_INTERNAL:-}")"
chk "net vr1-dc1 sets VIP_PREFIX_INTERNAL (R9)" "$DC1_VI" "10.12.72"
DC1_VC="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${VIP_COUNT_EXPECT:-}")"
chk "net vr1-dc1 sets VIP_COUNT_EXPECT 13 (R11)" "$DC1_VC" "13"

# --- R9's DRIFT half: the arm is checked against the artifact it was copied from ------
# R9's ruled shape is DERIVE + drift-check. Only the drift half exists today (the arm is
# hand-authored, see lib-net.sh's own note), and this is it: re-read the RATIFIED
# overlay and require the arm to agree, in both directions. Re-rendering the overlay
# without updating the arm, or editing the arm without the overlay, turns this red.
OVL="$SD/../../overlays/vr1-dc1-vips.yaml"
if [ ! -r "$OVL" ]; then
  no "R9 drift: overlays/vr1-dc1-vips.yaml is missing -- the arm's authored source is gone"
else
  # First v4 leg of each vip line = provider column; 2nd = admin; 3rd = internal.
  OVL_PP="$(awk -F'"' '/^[[:space:]]+vip:/{split($2,a," "); split(a[1],p,"."); print p[1]"."p[2]"."p[3]; exit}' "$OVL")"
  OVL_PA="$(awk -F'"' '/^[[:space:]]+vip:/{split($2,a," "); split(a[2],p,"."); print p[1]"."p[2]"."p[3]; exit}' "$OVL")"
  OVL_PI="$(awk -F'"' '/^[[:space:]]+vip:/{split($2,a," "); split(a[3],p,"."); print p[1]"."p[2]"."p[3]; exit}' "$OVL")"
  OVL_CNT="$(grep -cE '^[[:space:]]+vip:' "$OVL")"
  OVL_KS="$(awk -F'"' '/^  keystone:/{k=1} k&&/^[[:space:]]+vip:/{split($2,a," "); print a[1]; exit}' "$OVL")"
  chk "R9 drift: arm provider prefix == overlay" "$DC1_VP" "$OVL_PP"
  chk "R9 drift: arm admin prefix == overlay"    "$DC1_VA" "$OVL_PA"
  chk "R9 drift: arm internal prefix == overlay" "$DC1_VI" "$OVL_PI"
  chk "R9 drift: arm VIP_COUNT_EXPECT == overlay vip: line count" "$DC1_VC" "$OVL_CNT"
  chk "R9 drift: arm KEYSTONE_VIP_DEFAULT == overlay keystone provider leg" "$DC1_KV" "$OVL_KS"
fi
# REPLACED 2026-07-27, not deleted. This asserted that vr1-dc1 UNSETS FIP_POOL_START.
# The pool was RULED that day (GA-R5: "Rule dc1 FIP pool 10.12.65.0-10.12.67.254";
# recorded on the D-134 R4 amendment), so the old assertion encoded a state the ruling
# retired. Re-pointed at the ruled VALUE, which is a STRONGER check than the absence
# it replaces -- and paired with the guard below, so narrowing the unset list by one
# pair cannot silently narrow it further.
DC1_FP="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${FIP_POOL_START:-}")"
chk "net vr1-dc1 sets the RULED FIP_POOL_START" "$DC1_FP" "10.12.65.0"
DC1_FPE="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${FIP_POOL_END:-}")"
chk "net vr1-dc1 sets the RULED FIP_POOL_END" "$DC1_FPE" "10.12.67.254"
# GUARD, NON-NEGOTIABLE. The unset list shrank twice (the FIP pool in 2026-07-27's
# ruling, the R9 VIP group in 2026-07-29's delivery) and both times the same pair had to
# survive: METAL_INTERNAL_VID / METAL_INTERNAL_IFACE are not "unruled", they are
# ABOLISHED for VR1 by D-133 (flat per-NIC carve; metal-internal untagged on enp3s0).
# Anything that repopulates them silently reintroduces a retired VLAN stack, which is
# exactly what R9's own GUARD paragraph forbids. Both DCs, both variables -- the
# vr1-dc0 arm inherited them from VR0 until 2026-07-29 and now unsets them too.
DC1_MV="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${METAL_INTERNAL_VID+still-set}")"
chk "net vr1-dc1 STILL unsets METAL_INTERNAL_VID (D-133 retired that stack)" "$DC1_MV" ""
DC1_MIF="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${METAL_INTERNAL_IFACE+still-set}")"
chk "net vr1-dc1 STILL unsets METAL_INTERNAL_IFACE (D-133 retired br-internal)" "$DC1_MIF" ""
DC0_MV="$(lib_net_select_dc vr1-dc0 >/dev/null 2>&1; echo "${METAL_INTERNAL_VID+still-set}")"
chk "net vr1-dc0 unsets METAL_INTERNAL_VID (D-133 'affected surfaces', executed 2026-07-29)" "$DC0_MV" ""
DC0_MIF="$(lib_net_select_dc vr1-dc0 >/dev/null 2>&1; echo "${METAL_INTERNAL_IFACE+still-set}")"
chk "net vr1-dc0 unsets METAL_INTERNAL_IFACE (D-133)" "$DC0_MIF" ""
# VR0's own as-built is UNTOUCHED: D-133 supersedes Pattern A "FOR VR1 DC NODES ONLY".
VR0_MV="$(lib_net_select_dc vr0-dc0 >/dev/null 2>&1; echo "${METAL_INTERNAL_VID:-}")"
chk "net vr0-dc0 KEEPS METAL_INTERNAL_VID 103 (VR0 as-built untouched)" "$VR0_MV" "103"
VR0_MIF="$(lib_net_select_dc vr0-dc0 >/dev/null 2>&1; echo "${METAL_INTERNAL_IFACE:-}")"
chk "net vr0-dc0 KEEPS METAL_INTERNAL_IFACE br-internal" "$VR0_MIF" "br-internal"

# --- metal-admin carries NO gateway in either VR1 DC (retired VR0 inheritance) -------
# MEASURED 2026-07-27 (docs/audit/stage5-committee-raw-20260727.md:309, reconciled at
# docs/CURRENT-STATE.md:938-950): MAAS returns gateway `none` for 10.12.8.0/22 and
# 10.12.68.0/22, and both .1 addresses are held by NOTHING (100% loss, ARP never
# resolves) while both provider-public gateways answer and carry the rack default route.
# D-134's carve rules `.1` gateways for the PROVIDER subnets only. The pin was the
# defect, not MAAS -- it made scripts/pre-flight-checks.sh hard-fail on a correct cloud.
VR0_GWN="$(lib_net_select_dc vr0-dc0 >/dev/null 2>&1; echo "${#PLANE_GW[@]}")"
chk "net vr0-dc0 keeps BOTH gateways (VR0 real as-built)" "$VR0_GWN" "2"
DC0_GWN="$(lib_net_select_dc vr1-dc0 >/dev/null 2>&1; echo "${#PLANE_GW[@]}")"
chk "net vr1-dc0 has exactly ONE routed plane" "$DC0_GWN" "1"
DC0_GWK="$(lib_net_select_dc vr1-dc0 >/dev/null 2>&1; echo "${!PLANE_GW[*]}")"
chk "net vr1-dc0 routed plane is provider-public" "$DC0_GWK" "10.12.4.0/22"
DC0_GWA="$(lib_net_select_dc vr1-dc0 >/dev/null 2>&1; echo "${PLANE_GW[10.12.8.0/22]:-unset}")"
chk "net vr1-dc0 metal-admin has NO gateway (measured: 10.12.8.1 answers nothing)" "$DC0_GWA" "unset"
DC1_GWN="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${#PLANE_GW[@]}")"
chk "net vr1-dc1 has exactly ONE routed plane" "$DC1_GWN" "1"
DC1_GWA="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; echo "${PLANE_GW[10.12.68.0/22]:-unset}")"
chk "net vr1-dc1 metal-admin has NO gateway (measured: 10.12.68.1 answers nothing)" "$DC1_GWA" "unset"

# ONE SELECTION PER SHELL (guard added with the diverging dc1 arm): changing
# selection after dc1 is REFUSED; re-selecting the SAME DC stays a no-op.
( lib_net_select_dc vr1-dc1 >/dev/null 2>&1; lib_net_select_dc vr0-dc0 2>/dev/null ); \
  chk "net dc1->vr0-dc0 re-select REFUSED (stale cross-DC values)" "$?" 1
SWITCH_ERR="$(lib_net_select_dc vr1-dc1 >/dev/null 2>&1; lib_net_select_dc vr0-dc0 2>&1 1>/dev/null || true)"
grep -q "already selected" <<<"$SWITCH_ERR" && ok "net re-select error says already selected" || no "net re-select error says already selected"
( lib_net_select_dc vr1-dc0 >/dev/null 2>&1; lib_net_select_dc vr1-dc0 ); \
  chk "net same-DC re-select stays a no-op rc" "$?" 0

# D-119 REGRESSION GUARD: the bare dcN tokens are RETIRED and must be REJECTED.
# Accepting them "for compatibility" would preserve the exact cross-region
# ambiguity D-119 deletes -- 'dc0' meant VR0's LIVE cloud in lib-net.sh but VR1's
# FIRST DC in the NetBox importer. Silence here is how the off-by-one comes back.
for retired in dc0 dc1 dc2; do
  ( lib_net_select_dc "$retired" 2>/dev/null ); chk "net RETIRED '$retired' rejected (D-119)" "$?" 1
  R_ERR="$(lib_net_select_dc "$retired" 2>&1 1>/dev/null || true)"
  grep -q "RETIRED" <<<"$R_ERR" && ok "net '$retired' error says RETIRED" || no "net '$retired' error says RETIRED"
done

# no-op really means no-op: values identical after selecting vr0-dc0 or vr1-dc0.
# They match by INHERITANCE (D-101: VR1's first DC inherits VR0 DC0's v4 layout),
# not by coincidence -- and they are separate case arms so they can diverge later.
VR0_VAL="$(lib_net_select_dc vr0-dc0 >/dev/null 2>&1; echo "${PLANE_CIDRS[0]}")"
VR1_VAL="$(lib_net_select_dc vr1-dc0 >/dev/null 2>&1; echo "${PLANE_CIDRS[0]}")"
chk "net vr0-dc0/vr1-dc0 identical values (D-101 inheritance)" "$VR0_VAL" "$VR1_VAL"

# --- lib_hosts_select_dc: vr0-dc0 no-op; VR1 arms POPULATED 2026-07-23 ---
# (Stage 4 carve session: both fleets enrolled+Ready, identities measured --
# the historical fail-loud behavior and its asymmetry test are history.)
( lib_hosts_select_dc vr0-dc0 ); chk "hosts vr0-dc0 no-op rc" "$?" 0
( lib_hosts_select_dc vr1-dc0 ); chk "hosts vr1-dc0 selects rc" "$?" 0
( lib_hosts_select_dc vr1-dc1 ); chk "hosts vr1-dc1 selects rc" "$?" 0
( lib_hosts_select_dc bogus 2>/dev/null ); chk "hosts unknown-token fails-loud rc" "$?" 1
( lib_hosts_select_dc 2>/dev/null ); chk "hosts missing-arg fails-loud rc" "$?" 1
for retired in dc0 dc1 dc2; do
  ( lib_hosts_select_dc "$retired" 2>/dev/null ); chk "hosts RETIRED '$retired' rejected (D-119)" "$?" 1
done

# --- VR1 arms carry the MEASURED identity + D-134-amended octets ---
H0_OCT="$(lib_hosts_select_dc vr1-dc0 >/dev/null 2>&1; echo "${HOST_OCTET[vr1-dc0-control-01]}")"
chk "hosts vr1-dc0 control-01 octet .100 (D-134 amendment)" "$H0_OCT" "100"
H0_ST="$(lib_hosts_select_dc vr1-dc0 >/dev/null 2>&1; echo "${HOST_OCTET[vr1-dc0-storage-04]}")"
chk "hosts vr1-dc0 storage-04 octet .153" "$H0_ST" "153"
H0_MAC="$(lib_hosts_select_dc vr1-dc0 >/dev/null 2>&1; echo "${HOST_BOOT_MAC[vr1-dc0-compute-02]}")"
chk "hosts vr1-dc0 compute-02 pinned boot MAC" "$H0_MAC" "52:54:00:18:ab:b4"
H1_MAC="$(lib_hosts_select_dc vr1-dc1 >/dev/null 2>&1; echo "${HOST_BOOT_MAC[vr1-dc1-storage-04]}")"
chk "hosts vr1-dc1 storage-04 pinned boot MAC (index-encoded)" "$H1_MAC" "52:54:01:d1:09:01"
H0_TAG="$(lib_hosts_select_dc vr1-dc0 >/dev/null 2>&1; echo "$HOST_TAG")"
chk "hosts vr1-dc0 tag openstack-vr1-dc0 (ruled 2026-07-23)" "$H0_TAG" "openstack-vr1-dc0"
H1_PWR="$(lib_hosts_select_dc vr1-dc1 >/dev/null 2>&1; echo "$VIRSH_POWER_ADDRESS")"
chk "hosts vr1-dc1 power addr rack transit .6" "$H1_PWR" "qemu+ssh://jessea123@172.31.0.6/system"

# --- per-REGION power address (D-132 q1 per-DC MAAS regions, 2026-07-30) ---
# MAAS power ops originate from the REGION, so the reachable rack address differs
# by which region dials. MEASURED from vr1-dc0-maas-01 (10.12.8.6): the rack's
# transit leg 172.31.0.2:22 is CLOSED, its metal-admin leg 10.12.8.2:22 is OPEN.
# dc1's 10.12.68.2 was measured on the dc1 rack, NOT inferred from dc0's .2.
H0_PO="$(lib_hosts_select_dc vr1-dc0 >/dev/null 2>&1; echo "$VIRSH_POWER_ADDRESS_FROM_OFFICE1")"
chk "hosts vr1-dc0 office1-region power addr = transit .2" "$H0_PO" "qemu+ssh://jessea123@172.31.0.2/system"
H0_PD="$(lib_hosts_select_dc vr1-dc0 >/dev/null 2>&1; echo "$VIRSH_POWER_ADDRESS_FROM_DCREGION")"
chk "hosts vr1-dc0 dc-region power addr = metal-admin 10.12.8.2" "$H0_PD" "qemu+ssh://jessea123@10.12.8.2/system"
H1_PO="$(lib_hosts_select_dc vr1-dc1 >/dev/null 2>&1; echo "$VIRSH_POWER_ADDRESS_FROM_OFFICE1")"
chk "hosts vr1-dc1 office1-region power addr = transit .6" "$H1_PO" "qemu+ssh://jessea123@172.31.0.6/system"
H1_PD="$(lib_hosts_select_dc vr1-dc1 >/dev/null 2>&1; echo "$VIRSH_POWER_ADDRESS_FROM_DCREGION")"
chk "hosts vr1-dc1 dc-region power addr = metal-admin 10.12.68.2" "$H1_PD" "qemu+ssh://jessea123@10.12.68.2/system"

# BACKWARD COMPATIBILITY IS THE LOAD-BEARING HALF: VIRSH_POWER_ADDRESS must still
# be the Office1/transit form, byte-for-byte, or reenroll-hosts.sh and the
# teardown runbook's virsh probes silently change target.
H0_ALIAS="$(lib_hosts_select_dc vr1-dc0 >/dev/null 2>&1; [ "$VIRSH_POWER_ADDRESS" = "$VIRSH_POWER_ADDRESS_FROM_OFFICE1" ] && echo same || echo DIVERGED)"
chk "hosts vr1-dc0 VIRSH_POWER_ADDRESS still aliases the OFFICE1 form" "$H0_ALIAS" "same"
H1_ALIAS="$(lib_hosts_select_dc vr1-dc1 >/dev/null 2>&1; [ "$VIRSH_POWER_ADDRESS" = "$VIRSH_POWER_ADDRESS_FROM_OFFICE1" ] && echo same || echo DIVERGED)"
chk "hosts vr1-dc1 VIRSH_POWER_ADDRESS still aliases the OFFICE1 form" "$H1_ALIAS" "same"

# THE TWO FORMS MUST DIFFER. If a future edit collapses them the migration would
# dial an unreachable address and every power op would fail -- this is the
# assertion that catches a copy-paste of the transit URI into the DCREGION slot.
H0_DIFF="$(lib_hosts_select_dc vr1-dc0 >/dev/null 2>&1; [ "$VIRSH_POWER_ADDRESS_FROM_OFFICE1" != "$VIRSH_POWER_ADDRESS_FROM_DCREGION" ] && echo differ || echo COLLAPSED)"
chk "hosts vr1-dc0 the two region forms are DISTINCT" "$H0_DIFF" "differ"
H1_DIFF="$(lib_hosts_select_dc vr1-dc1 >/dev/null 2>&1; [ "$VIRSH_POWER_ADDRESS_FROM_OFFICE1" != "$VIRSH_POWER_ADDRESS_FROM_DCREGION" ] && echo differ || echo COLLAPSED)"
chk "hosts vr1-dc1 the two region forms are DISTINCT" "$H1_DIFF" "differ"

# CROSS-DC CONTAMINATION: dc0's DCREGION address must never carry dc1's octet and
# vice versa -- the D-117 off-by-one class, applied to the value that powers
# machines off.
case "$H0_PD" in *10.12.68.*) no "hosts vr1-dc0 dc-region addr leaked a dc1 plane octet" ;; *) ok "hosts vr1-dc0 dc-region addr carries no dc1 octet" ;; esac
case "$H1_PD" in *10.12.8.*)  no "hosts vr1-dc1 dc-region addr leaked a dc0 plane octet" ;; *) ok "hosts vr1-dc1 dc-region addr carries no dc0 octet" ;; esac

# VR0 must NOT inherit either VR1 form (empty at the flat layer -- an empty value
# fails loud, a stale one powers off the wrong rack).
V0_PO="$(lib_hosts_select_dc vr0-dc0 >/dev/null 2>&1; echo "${VIRSH_POWER_ADDRESS_FROM_OFFICE1:-EMPTY}")"
chk "hosts vr0-dc0 does not inherit a VR1 office1 power addr" "$V0_PO" "EMPTY"
V0_PD="$(lib_hosts_select_dc vr0-dc0 >/dev/null 2>&1; echo "${VIRSH_POWER_ADDRESS_FROM_DCREGION:-EMPTY}")"
chk "hosts vr0-dc0 does not inherit a VR1 dc-region power addr" "$V0_PD" "EMPTY"
H0_N="$(lib_hosts_select_dc vr1-dc0 >/dev/null 2>&1; echo "${#HOSTS[@]}")"
chk "hosts vr1-dc0 fleet count 10 (D-121 Option C 9 role + D-104 juju-01)" "$H0_N" "10"

# --- VR1 NODE NIC -> PLANE ORDER (MEASURED 2026-07-30) ---------------------
# macs[i] in the substrate root IS enp<i+1>s0, verified against the live carve on
# vr1-dc0-control-01. The load-bearing assertion is the LAST one: this order is
# NOT PLANE_CIDRS order, and anything that walks PLANE_CIDRS positionally to
# place NICs puts the PXE/metal-admin leg on provider-public -- stranding
# commissioning on a plane with no DHCP.
chk "nic order [0] is metal-admin (the PXE leg)" "${NIC_PLANE_ORDER[0]}" "metal-admin"
chk "nic order [1] is provider-public"           "${NIC_PLANE_ORDER[1]}" "provider-public"
chk "nic order [5] is replication"               "${NIC_PLANE_ORDER[5]}" "replication"
chk "nic order has six entries"                  "${#NIC_PLANE_ORDER[@]}" "6"
chk "br-ex parent NIC is enp2s0 (provider-public)" "$BREX_PARENT_NIC" "enp2s0"
# every NIC-order entry must be a real space name
NIC_BAD=0
for _n in "${NIC_PLANE_ORDER[@]}"; do
  _found=0; for _s in "${SPACES6[@]}"; do [ "$_n" = "$_s" ] && _found=1; done
  [ "$_found" = 1 ] || NIC_BAD=$((NIC_BAD+1))
done
chk "every nic-order entry is one of the six spaces" "$NIC_BAD" "0"
# THE TRAP ASSERTION: the two orders must DIFFER at position 0.
NIC0="${NIC_PLANE_ORDER[0]}"; PC0="${PLANE_NAME[${PLANE_CIDRS[0]}]}"
[ "$NIC0" != "$PC0" ] && ok "nic order DIFFERS from PLANE_CIDRS order at [0] (the enp1s0/enp2s0 trap)" \
  || no "nic order DIFFERS from PLANE_CIDRS order at [0] -- both read '$NIC0', so the trap guard is vacuous"

# --- CARVE IS ROLE-DEPENDENT (measured 2026-07-30) -------------------------
# Role nodes get all six planes + an OVS br-ex on enp2s0; the juju controller
# gets metal-admin + provider-public (raw, with gateway) and NOTHING else.
# Assuming uniformity would either strand the controller without a default route
# or give it four legs it must not have.
chk "role nodes carve six planes"            "$NODE_CARVE_ROLE_PLANES" "6"
chk "juju controller carves only two planes" "$NODE_CARVE_JUJU_PLANES" "2"
chk "juju host suffix identifies the controller" "$JUJU_HOST_SUFFIX" "juju-01"
[ "$NODE_CARVE_ROLE_PLANES" != "$NODE_CARVE_JUJU_PLANES" ] \
  && ok "role and controller carve depths DIFFER (the uniformity trap)" \
  || no "role and controller carve depths DIFFER -- both read '$NODE_CARVE_ROLE_PLANES', guard is vacuous"
# The controller must be present in each VR1 DC's HOSTS under that suffix.
# Checked INSIDE a per-DC subshell: the main shell still holds the flat VR0
# defaults, so testing it at top level would assert against the wrong fleet.
for _dc in vr1-dc0 vr1-dc1; do
  _JF="$(lib_hosts_select_dc "$_dc" >/dev/null 2>&1; f=0; for h in "${HOSTS[@]}"; do case "$h" in *"$JUJU_HOST_SUFFIX") f=1 ;; esac; done; echo "$f")"
  chk "$_dc HOSTS contains a *-$JUJU_HOST_SUFFIX controller" "$_JF" "1"
done
# and VR0 must NOT -- it has no dedicated juju controller node
_V0="$(lib_hosts_select_dc vr0-dc0 >/dev/null 2>&1; f=0; for h in "${HOSTS[@]}"; do case "$h" in *"$JUJU_HOST_SUFFIX") f=1 ;; esac; done; echo "$f")"
chk "vr0-dc0 HOSTS has NO juju-controller node (D-104 is VR1-only)" "$_V0" "0"

# --- ONE SELECTION PER SHELL (stale cross-DC guard, lib-net precedent) ---
( lib_hosts_select_dc vr1-dc0 >/dev/null 2>&1; lib_hosts_select_dc vr1-dc1 2>/dev/null ); \
  chk "hosts dc0->dc1 re-select REFUSED (stale cross-DC values)" "$?" 1
HSW_ERR="$(lib_hosts_select_dc vr1-dc0 >/dev/null 2>&1; lib_hosts_select_dc vr1-dc1 2>&1 1>/dev/null || true)"
grep -q "already selected" <<<"$HSW_ERR" && ok "hosts re-select error says already selected" || no "hosts re-select error says already selected"
( lib_hosts_select_dc vr1-dc1 >/dev/null 2>&1; lib_hosts_select_dc vr1-dc1 ); \
  chk "hosts same-DC re-select stays a no-op rc" "$?" 0

# --- the VR1 resolver exists: system_id by pinned boot MAC, never hostname ---
type host_sysid_by_bootmac >/dev/null 2>&1 && ok "host_sysid_by_bootmac defined (VR1 resolver)" || no "host_sysid_by_bootmac defined (VR1 resolver)"

echo; [ "$F" = 0 ] && { echo "ALL PASS ($P checks)"; exit 0; } || { echo "FAILURES: $F"; exit 1; }