diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 2a434c2..07401b0 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -1323,6 +1323,20 @@ avoid IPv6-in-charms trouble, and a node carrying v6 on six planes is exactly what surfaces such modules -- far cheaper on a static read-back than mid-bundle. Explicitly out of scope: v6 gateways/DNS, rack legs (not needed under the static ruling), NAT64, tenant addressing. +- **NODE v6 CARVE EXECUTED 2026-07-27, BOTH DCs -- STEP 3's NODE HALF IS NOW DONE TOO** + (operator-gated, dc0 then dc1). Tool `scripts/dc-node-v6-carve.py` (harness **9/9**; + gauntlet ALL GREEN **84**); capture `docs/audit/node-v6-carve-executed-20260727.txt`. + **54 applied per DC, 0 errors, read-back 54/54 each. IPv6 links 0 -> 108; IPv4 links 108 + UNCHANGED; 18 Ready unchanged.** `dc-node-v6-carve check` PASSES both DCs, and + `dc-plane-ipam check` still reads pass=24 fail=0 on both -- no regression. The octet mirror + holds across all six planes per node (`superb-piglet` .121 -> `::121` everywhere; + `big-trout` .100 -> `::100`). **`enp2s0` correctly received NOTHING** -- the D-100 raw + provider NIC has no v4 link to mirror, and `br-ex` carries provider-public instead, on the + node `/64` rather than the VIP `/64`. Everything was DERIVED from live state (site tag, + which interfaces already carry v4, the v6 subnet sharing that v4 link's vlan, and the octet + read from the node's own address) -- no plane table in the tool. **The gate discriminates + rather than agreeing with whatever it finds: it flipped dc0 to PASS while dc1 still read + FAIL, before dc1 was carved.** - **RENDER-PIPELINE STEP 3 -- MAAS, lib-net AND APEX HALVES COMPLETE 2026-07-27.** Every authoritative source now carries the ruled values: **MAAS** (12 v6 plane subnets carved; 24 D-134 bands + both FIP pools reserved; `dc-plane-ipam check` pass=24 fail=0 and `reserve` planned=0 on BOTH DCs), **`lib-net.sh`** diff --git a/docs/audit/node-v6-carve-executed-20260727.txt b/docs/audit/node-v6-carve-executed-20260727.txt new file mode 100644 index 0000000..6c76247 --- /dev/null +++ b/docs/audit/node-v6-carve-executed-20260727.txt @@ -0,0 +1,28 @@ +NODE IPv6 CARVE -- AS-EXECUTED, 2026-07-28T22:09:08Z +Operator-gated, dc0 then dc1. Tool: scripts/dc-node-v6-carve.py (harness 9/9). + +PRE: all 18 Ready nodes carried ZERO IPv6 links (measured). +APPLY: dc0 54 applied / 0 errors, read-back 54/54 + dc1 54 applied / 0 errors, read-back 54/54 +POST: IPv6 links 0 -> 108 IPv4 links 108 UNCHANGED 18 Ready (unchanged) + dc-node-v6-carve check: PASS both DCs + dc-plane-ipam check : pass=24 fail=0 both DCs (no regression) + +The octet mirror holds across all six planes per node, e.g.: + superb-piglet (openstack-vr1-dc0): + enp1s0 ['10.12.8.121', 'fd50:840e:74e2:220::121'] + enp3s0 ['10.12.12.121', 'fd50:840e:74e2:221::121'] + enp4s0 ['10.12.16.121', 'fd50:840e:74e2:230::121'] + enp5s0 ['10.12.32.121', 'fd50:840e:74e2:240::121'] + enp6s0 ['10.12.36.121', 'fd50:840e:74e2:250::121'] + br-ex ['10.12.4.121', '2602:f3e2:f02:10::121'] + big-trout (openstack-vr1-dc1): + enp1s0 ['10.12.68.100', 'fd50:840e:74e2:320::100'] + enp3s0 ['10.12.72.100', 'fd50:840e:74e2:321::100'] + enp4s0 ['10.12.76.100', 'fd50:840e:74e2:330::100'] + enp5s0 ['10.12.80.100', 'fd50:840e:74e2:340::100'] + enp6s0 ['10.12.84.100', 'fd50:840e:74e2:350::100'] + br-ex ['10.12.64.100', '2602:f3e2:f03:10::100'] + +enp2s0 correctly received NOTHING -- the D-100 raw provider NIC has no v4 link, +and br-ex carries provider-public instead, on the node /64 not the VIP /64. diff --git a/docs/changelog-20260727-stage5-phase0.md b/docs/changelog-20260727-stage5-phase0.md index fe736ae..6d23a03 100644 --- a/docs/changelog-20260727-stage5-phase0.md +++ b/docs/changelog-20260727-stage5-phase0.md @@ -425,3 +425,27 @@ **STEP 3 COMPLETE.** MAAS, lib-net and the apex all carry the ruled values. No revert entry here -- this item ruled that a mutation is NOT required; items 9-12 carry the reverts for what was applied. + +## 14. LIVE -- node IPv6 carve, both DCs (108 links) + +**What.** `scripts/dc-node-v6-carve.py apply --commit`, dc0 then dc1. 54 links each, +mirroring every node's existing v4 octet into the v6 subnet sharing that link's vlan. + +**Result.** IPv6 links **0 -> 108**; IPv4 links **108 unchanged**; **18 Ready unchanged**. +Read-back 54/54 per DC, 0 errors. `dc-node-v6-carve check` PASSES both DCs; +`dc-plane-ipam check` still pass=24 fail=0 on both (no regression). + +**Why it matters.** D-101's governing rationale sets *IPv6 unless IPv4 is necessary*, and +the node layer is where the IPv4 sizing constraint actually bites. Until now the apex held +the plan and MAAS held the subnets while nodes had nothing. + +**Derived, not tabled.** Site by MAAS tag; interfaces by "already carries v4"; v6 subnet by +shared vlan; host part from the node's own v4 octet, mirrored textually. That rule gets the +D-100 raw provider NIC right without naming it -- `enp2s0` has no v4 link so it received +nothing, while `br-ex` did. + +**Revert.** `maas admin interface unlink-subnet ` per link; +or re-run `check` to list what exists. Per-link and reversible; no node powered on, no MAC +touched, nothing re-commissioned (the 2026-07-20 MAC-regeneration incident is why). + +**Capture.** `docs/audit/node-v6-carve-executed-20260727.txt`.