Newer
Older
openstack-caracal-dc-dc / docs / audit / committee-20260724-track2-bundle-render.md

Committee record -- Track 2: vr1-dc1 deploy-artifact (bundle) render

Date: 2026-07-24. Branch: dc-dc-stage4-phase3-maas-deploy (Stage 4 open). Convened by: operator ("Deploy a committee to review Track 2 and provide recommendations based on overall end project goals and decisions already researched").

Status of this document. ADVISORY / audit record. It ADOPTS nothing: the Fork-1 recommendation below is PENDING an operator ruling (GA-R5); a decision exists only when its Status line quotes the question + the operator's exact utterance in docs/design-decisions.md. docs/CURRENT-STATE.md remains the sole status authority (GA-R1). Precedent for the format: docs/audit/commissioning-committee-20260720.md.

Method

Four independent, read-only reviewers, each a distinct lens, each given a self-contained brief grounded in the end-project goals (MINIMIZE DELTA TO ROOSEVELT; VR1 exists to make HA real and prove DR drills) and the researched decisions (D-121, D-104, D-119, D-052, D-062, D-009, D-106, D-108):

  1. Roosevelt-transferability / architectural-delta
  2. HA/DR correctness & multi-tenant isolation
  3. Operational risk / minimal-delta-now
  4. Juju/MAAS/charm mechanism-feasibility

Every load-bearing claim was re-verified against repo HEAD by the adjudicator before adoption into this record; two verifications corrected the brief given to the committee (see "Corrections", below).

The blocker being reviewed

The committed bundle.yaml is VR0's 4-machine ("8"-"11") HYPERCONVERGED layout (tags=openstack, single-unit control plane by D-009). VR1 dc1 is 9 ROLE-SEPARATED nodes (D-121 Option C: 3 control + 2 compute + 4 storage), built and merged (G12). The deploy ARTIFACTS were never rendered to that architecture. The substrate is exactly 9 node VMs (no controller slot), all Ready, all sharing ONE uniform MAAS tag openstack-vr1-dc1, zone default (docs/audit/stage4-discovery-20260723.txt).

Facts verified against the repo (not from prose)

  • Designate IS in the Stage-5 bundle -- bundle.yaml:812 (designate), :840 (designate-bind), :922 (designate-hacluster, noted "D-106 reactivated 2026-07-10, supersedes D-019"). The scale-up overlay's designate:3 references a real deployed app. The phase-4 runbook line 192 ("bundle ships NO designate") is STALE and is part of the de-stale work.
  • Fork-1 option (a) is additive, not a substrate reopening -- the inner caller is module "vr1_dc1_node" { for_each = local.vr1_dc1_nodes } (opentofu/vr1-dc1-substrate/main.tf:140), keyed (not count). Adding a 10th node key plans 1 to add, 0 to change, 0 to destroy; the 9 merged nodes are untouched.
  • Capacity for (a) is a MEASURED gate, not a quotable figure -- the signed doc's 790 GiB / 77% is the OLD 3+2+3 (8-node) layout (docs/design-decisions.md:3451); the built layout is 3+2+4 and no ~85% figure is carried in CURRENT-STATE. scripts/dc-dc-whole-host-budget.py must be RUN for the 10-node x 2-DC shape before the apply (GA-R1: figures from captured output).
  • H1 defect CONFIRMED (see below) -- bundle.yaml ceph-rbd-mirror carries a duplicate bindings: key; yaml.safe_load resolves it to an orphan.

Fork verdicts

FORK 1 -- controller arithmetic: UNANIMOUS (a), a dedicated 10th controller VM

All four lenses independently reached (a) and rejected (b)/(c):

  • (b) bootstrap onto one of the 9 + shrink a role (e.g. ceph-osd 4->3) REVERSES the ratified D-121 R-3 amendment and deletes the Ceph rebuild headroom the DR drill exists to demonstrate ("does not degrade the drill, it deletes the thing being drilled").
  • (c) co-locate on a control node: juju bootstrap on MAAS consumes a WHOLE machine (mechanism-confirmed), collapsing 3 control nodes -> 2, breaking the mysql/ovn/ceph-mon quorum and coupling controller-loss to the single-node drill. Rejected.
  • (a) is the only option preserving 3+2+4, matches D-104's VERIFIED VR0 precedent (a dedicated juju VM separate from the OpenStack nodes, docs/maas-as-built-reference.md), and is Roosevelt-shaped. It is additive (see Facts) and light on capacity (subject to the measured gate).
  • Least-bad co-location, if (a) ever cannot fit (HA/DR lens): a COMPUTE node (hosts neither quorum nor OSD headroom), never a control node.

Classification: a D-104 amendment (controller placement is D-104's subject; substrate-count changes went through amendment for storage 3->4). PENDING operator ruling.

FORK 2 -- render mechanism: adjudicated -- hand-render now, GATED by an extended validator

Split panel: the Roosevelt / HA-DR / mechanism lenses lean to SOME automation (the render is a ~56-app cross-consistency rewrite); the operational lens calls a renderer tool gold-plating and says hand-render now. The dividing line is not hand-vs-tool -- ALL FOUR require an automated PLACEMENT check, which provider-bundle-check.py does not do today (it validates D-052 bindings + mysql=3 only). Adjudication:

  • Hand-render the concrete dc1 bundle.yaml now (a concrete file is directly reviewable, which the "render AND review" constraint demands; you must render once to learn the parameter surface anyway).
  • Gate it behind an EXTENDED validator -- add assertions to the EXISTING tested provider-bundle-check.py (no new tooling): 3-distinct-host anti-affinity for the 14 scaled apps; ceph-osd=4 on storage-tagged nodes; nova-compute=2 on compute-tagged nodes; controller-tag carries no role tag; and NO dangling to: (every referenced machine ID exists).
  • Defer a general renderer tool until dc0 forces the second render and proves real churn. The {{TOKEN}} / overlay pattern already carries the per-DC parts.

FORK 3 -- role->node binding: UNANIMOUS per-role MAAS tags

  • per-role tags constraints: tags=openstack-vr1-dc1,control -- MAAS AND-filters at allocation; deterministic; survives re-enlist; Roosevelt-shaped. ADOPTED recommendation. Prerequisite: add control/compute/storage tags to the respective nodes (a small, additive, gated MAAS mutation) AND wire that application into the re-enlist runbook so a node rebuild re-applies it.
  • mem= -- REJECTED: mechanism-confirmed a FLOOR, not exact-match; a 64 GiB control node satisfies a mem=49152 compute request -> silent mis-placement race under parallel deploy.
  • system-id pinning -- REJECTED: not cleanly bundle-expressible, and system IDs are re-minted on every re-enlist (DOCFIX-040); VR1 recovery IS PXE re-enlist.

Confirmed defects (independent of the fork rulings)

  • H1 / BUNDLEFIX-052 -- ceph-rbd-mirror duplicate bindings:. bundle.yaml:891-895 is the correct block (ceph-local/ceph-remote -> replication, nrpe-external-master -> metal-internal; D-108/D-052); an ORPHAN block at :907-910 (certificates/dashboard) is absorbed into ceph-rbd-mirror (YAML takes-last), clobbering the replication-plane bindings (defeating D-108) and injecting a phantom dashboard binding to a charm with no such endpoint -> juju deploy validation reject. Pre-existing; latent because the app was flagged prep-only. Fix = delete the orphan. FIXED this session (changelog).
  • Stale phase-4 runbook Step 4 -- "deploy the EXISTING bundle.yaml", "ships NO designate", and region-naming drift (its "DC1"=vr1-dc0, "DC2"=vr1-dc1). De-stale as part of the render.

The render work, specified (the load-bearing part)

  • Re-home every base placement (in bundle.yaml, NOT the overlay -- the highest silent risk): mysql-innodb-cluster/ovn-central/ceph-mon to:[lxd:8,9,10] -> 3 control IDs; nova-compute ["9","10","11"] 3->2 -> the 2 compute IDs; ceph-osd ["8","9","10","11"] -> the 4 storage IDs; memcached/glance-simplestreams-sync/designate-bind/ceph-rbd-mirror singletons -> control IDs. Any un-updated to: = a dangling reference = deploy-time validation failure.
  • Machines block: 9 role-tagged IDs + the 10th controller VM with a DISTINCT tag (e.g. juju-controller-vr1-dc1) carrying NO role tag, so neither juju bootstrap --constraints nor a role constraint can cross-grab.
  • Re-scope the dc0-named tokens {{VR1_DC0_CONTROL_0N}} -> dc1 control IDs; positional anti-affinity is a 3-entry to: list (unit0->entry0), mechanism confirmed -- token collision silently defeats it, so validate distinctness.
  • Wire overlays vr1-dc1-vips.yaml + dc-ha-scaleup.yaml into the deploy; de-stale phase-4 Step 4.

Deploy-time VERIFY-LIVE gates (into the runbook; not render blockers)

  • Vault 3-unit HA-on-MySQL -- D-121's own gate: verify the 1.8/stable charm truly does leader-election at 3 units BEFORE commit (mechanism lens: genuinely UNSURE); if not, evaluate Raft -> D-068, NEVER etcd. Plus 3x manual-unseal burden (OPEN SEC-003).
  • hacluster cluster_count:3 actually gates VIP-bind-on-quorum (else decorative HA).
  • dc1 VIPs (10.12.64/68/72) are outside the checker's hardcoded dc0 bands -- validate the merged result.
  • CRUSH failure-domain = host (the rebuild-headroom argument rests on it).

Bootstrap ordering (reinforced)

Bootstrap the 10th VM (by its distinct controller tag) WHILE the DC1 edge egress is OPEN -- the juju agent stream + juju/juju-db snaps are fetched pre-apt and are NOT mirrored (D-135 items 2-3 unbuilt). No egress-narrowing (D-135/D-107) until the controller is up.

Open operator decisions (one ruling per exchange, GA-R5)

  1. FORK 1 (blocking, a D-104 amendment): committee unanimous for (a) dedicated 10th controller VM, additive, gated on the whole-host budget script. -- PENDING.
  2. FORK 2: hand-render + extended validator; defer a renderer tool. -- PENDING (follows Fork 1).
  3. FORK 3: per-role MAAS tags + re-enlist wiring. -- PENDING (follows Fork 1).

Highest-priority concerns (one per lens)

  • Roosevelt: extend the placement validator before bootstrap, or any render can silently ship one-unit-per-node-less-ness = the decorative HA D-121 exists to kill.
  • HA/DR: no automated placement gate today; the un-re-homed base placements (lxd:8,9,10) are the most likely silent decorative-HA path.
  • Operational: confirm the inner caller is for_each-keyed (DONE -- it is) and constrain bootstrap to a distinct controller tag, or the closed G12 substrate reopens.
  • Mechanism: re-render COMPLETENESS -- only 14 of ~56 apps are placed by the overlay; a single stale to: fails juju deploy with no partial success. And fix H1 first (DONE).