Newer
Older
openstack-caracal-dc-dc / docs / changelog-20260715-stage3-prereqs-prep.md

2026-07-15 -- Stage 3 batch-deploy prep: OpenTofu wiring, DC-edge NetBox importer, HA overlay, D-123

Context

Operator directed "get as much ready as possible so we can batch deploy with the least operator interaction." This batch prepares the Stage-3 substrate + Stage-5 HA artifacts so the live steps reduce to review-plan-and-apply. NO cloud mutation this session -- all authoring + offline validation; every tofu apply, netbox --commit, and juju deploy stays operator-gated. Fanned out across three disjoint areas (opentofu / netbox / overlays); the opentofu agent hit a transient API stall and its stream was completed in-session by the main loop.

What changed

D-123 (PROPOSED) -- DC site-down DR model / node-VM placement. docs/design-decisions.md. Surfaced a real tension: D-122 records the operator's "each site is one VM, virsh destroy = site-down" intent, but the ADOPTED D-103/D-114 seam + the built tooling create the OpenStack node VMs as vcloud-level domains that MAAS merely DISCOVERS (containment VM scoped to MAAS/LXD + non-stack machines only). Model A (recommended): nodes stay vcloud-level; vvr1-dc0 is a MAAS/LXD headend VM (the proven voffice1 pattern via site-headend-install.sh, which already names it a target); site-down = destroy the vr1-dc0-* domain GROUP. Model B: true single-VM containment (nodes nested), 4-level nesting, heaviest. Needs a one-line operator ruling.

OpenTofu Stage-3 wiring (opentofu/).

  • New module modules/site-wan/ -- a NAT'd per-site simulated-ISP uplink /24 (generalizes the virsh-created office1-wan; operator 2b ruling). MTU 1500 (ISP-uplink domain, NOT jumbo). Schema CONFIRMED against the installed provider via tofu providers schema -json (the method dc-planes calls for): forward = { mode = "nat" }, ips = [{ address, prefix }], mtu = { size }, attribute-style like dc-planes. DHCP omitted (the edge WAN is static, like office1-opnsense .2). Per-module versions.tf (DOCFIX-179).
  • main.tf Stage-3 section (NOT YET APPLIED, gated): module "vr1_dc0_wan" (172.30.2.0/24, D-115); module "vr1_dc0_opnsense" (D-122: 2-NIC, memory_mib=2048/vcpu=2/nano, no disk_size_bytes/config_iso_path, LAN = provider-public plane, WAN = the uplink); 8 node VMs via a single for_each over a locals map in D-121 Option C sizes (3 control 16/65536/150GiB, 2 compute 12/49152/100GiB, 3 storage 8/24576/550GiB), six NICs each with metal-admin first (PXE); netem HELD as a comment (Step 11, runtime SSH target + unruled params; the vr1-dc0<->office1 mesh bridge is virbr7, measured). HELD pending D-123: the vvr1-dc0 headend + maas-vm-host (Step 9) blocks are not wired.
  • Fixed the stale vr1_dc1_planes comment (supernet IS assigned, D-115; out of scope by sequencing).
  • tofu validate -> Success; scripts/opentofu-validate.sh -> 11/11 modules PASS (incl. site-wan).

NetBox DC-edge WAN importer (netbox/dc-edge-wan-import.py + tests/dc-edge-wan-import/). Registers the D-115 DC-edge /24s in office1-netbox: 172.30.2.0/24 -> site vr1-dc0, 172.30.3.0/24 -> site vr1-dc1, role edge, scope_type=dcim.site -- scoping CONFIRMED against d115-office-carve.py/sandbox-fidelity-check.py (how office1-wan 172.30.1.0/24 is bound), not the frozen draft (which predates D-115). Stdlib-only, mirrors d120-compose-bands.py: WHOLE-PLAN PREFLIGHT (both sites resolve before any create, so a missing site cannot half-write), DRY-BY-DEFAULT, SANDBOX_HOSTS guard + --yes-write-upstream refusal, WAF-safe UA. Creates ONLY the two /24s (role + container + sites are read-only preconditions). Harness: 58/58 PASS (19 static + 39 behavioral, in-process against a fake NetBox). NOT run against a live NetBox (token operator-held).

Bundle HA scale-up overlay (overlays/dc-ha-scaleup.yaml). VR1-specific overlay (NOT a bundle.yaml edit -- VR0 stays single-unit per D-009) implementing D-121: 14 services -> num_units: 3, one-per- control-node placement via a 3-entry to: with {{VR1_DC0_CONTROL_0N}} tokens (Stage-4-binding banner). Three correctness items beyond the literal bump, each flagged in-file: (A) rabbitmq min-cluster-size: 3 (D-009 amendment -- avoids the D-062-class formation race); (B) cluster_count: 3 on the 12 haclusters + vault-hacluster (base pins 1 = decorative); (C) re-declares vault-hacluster (it is COMMENTED OUT by BUNDLEFIX-002) and re-adds [vault:ha, vault-hacluster:ha] (D-121 v-a keeps vault MySQL-backed at 3). YAML valid; app names cross-checked vs bundle.yaml; repo-lint clean; provider-bundle-check.py green on the base.

Tests / verification

  • cd opentofu && tofu validate -> Success; bash scripts/opentofu-validate.sh -> 11/11 PASS.
  • bash tests/dc-edge-wan-import/run-tests.sh -> 58/58 PASS.
  • bash scripts/repo-lint.sh -> 0 fail, 1 legacy WARN.
  • bash scripts/run-tests-all.sh -> GAUNTLET: ALL GREEN (61 harnesses).

What remains operator-gated / to bind later (the residual for a smooth batch)

  1. D-123 ruling (Model A/B) -- unblocks wiring the vvr1-dc0 headend + maas-vm-host (Step 9).
  2. Runtime prep before the edge apply: scripts/opnsense-prep-image.sh to produce the nano at the base_volume_path; the netbox --commit to register the two /24s (ready command in the importer's own header; token operator-held).
  3. Stage-4 binding for the HA overlay: render {{VR1_DC0_CONTROL_0N}} to the measured MAAS machine IDs; the base machines: block + the already-3 services (mysql/ovn/ceph-mon) + memcached + nova-compute(->2)/ceph-osd(->3) re-bind to the Option C nodes; confirm --overlay ... --dry-run (the to: list-replace merge is the one unverified overlay mechanism).
  4. D-121 verifies: vault charm MySQL-backend HA at 3 units (else Raft via D-068, not etcd); hacluster cluster_count semantics.

Revert

  • git rm -r opentofu/modules/site-wan; revert the opentofu/main.tf Stage-3 section + the vr1_dc1_planes comment; rm .terraform.lock-nothing (lock unchanged).
  • git rm netbox/dc-edge-wan-import.py && git rm -r tests/dc-edge-wan-import.
  • git rm overlays/dc-ha-scaleup.yaml.
  • Delete the ## D-123: section from docs/design-decisions.md.
  • No cloud state was touched -- nothing to unwind on the host.