diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index beb9222..500be01 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -166,8 +166,13 @@ [running]` -- MAAS owns node power; the pin-adoption plan had carried 9 out-of-band power-ons). Verification plan captured (`docs/audit/inner-plan-20260721-macpin.txt`: 0/9/0, 54 mac adoptions, - ZERO replaces); the inner-root APPLY on voffice1 that adopts the pins - into state is PENDING, operator-gated. + ZERO replaces); guarded re-plan zero power flips + (`docs/audit/inner-plan-20260721-macpin-guarded.txt`); **APPLIED + 2026-07-21 (operator-approved)** from voffice1 via saved plan, exact + 0/9/0, convergence zero diff + (`docs/audit/inner-apply-20260721-macpin.txt`); post-apply verified + all 9 domains still shut off, MACs unchanged. Node NIC MACs are now + config-pinned end to end. History of the diagnosis (superseded; kept for the audit trail): the 2026-07-20 state read "3 nodes Ready, 6 timed out." Established: PXE and the ephemeral handoff WORK, and the ephemeral OS boots diff --git a/docs/audit/inner-apply-20260721-macpin.txt b/docs/audit/inner-apply-20260721-macpin.txt new file mode 100644 index 0000000..26bd81f --- /dev/null +++ b/docs/audit/inner-apply-20260721-macpin.txt @@ -0,0 +1,9 @@ +module.vr1_dc0_node["vr1-dc0-storage-02"].libvirt_domain.node: Modifications complete after 2s [name=vr1-dc0-storage-02] +module.vr1_dc0_node["vr1-dc0-control-02"].libvirt_domain.node: Modifications complete after 2s [name=vr1-dc0-control-02] +module.vr1_dc0_node["vr1-dc0-control-01"].libvirt_domain.node: Modifications complete after 2s [name=vr1-dc0-control-01] + +Apply complete! Resources: 0 added, 9 changed, 0 destroyed. +=== convergence: + +OpenTofu has compared your real infrastructure against your configuration and +found no differences, so no changes are needed. diff --git a/docs/audit/inner-plan-20260721-macpin-guarded.txt b/docs/audit/inner-plan-20260721-macpin-guarded.txt new file mode 100644 index 0000000..6225825 --- /dev/null +++ b/docs/audit/inner-plan-20260721-macpin-guarded.txt @@ -0,0 +1,474 @@ +a77a455 node-vm: MAAS owns node power -- ignore_changes on running (operator-ruled) +module.inner_storage.libvirt_pool.dc: Refreshing state... [id=62bb75eb-b7b9-4659-bca3-f75825ae2cdf] +module.vr1_dc0_planes.libvirt_network.plane["metal-internal"]: Refreshing state... [id=edbc1aa5-5ac0-46e1-b46c-51f6bdc27bc9] +module.vr1_dc0_planes.libvirt_network.plane["provider-public"]: Refreshing state... [id=fcd1c106-1f36-4558-a133-681009962f3b] +module.vr1_dc0_planes.libvirt_network.plane["storage"]: Refreshing state... [id=1a8bd1c4-4f9e-4272-8af4-31f2be77ed9a] +module.vr1_dc0_planes.libvirt_network.plane["data-tenant"]: Refreshing state... [id=dd75dac8-b51a-4fe0-98d4-2b6e34d7ed4a] +module.vr1_dc0_planes.libvirt_network.plane["replication"]: Refreshing state... [id=6c7f8727-5877-4556-a41d-d44e5535e046] +module.vr1_dc0_wan.libvirt_network.wan_bridge: Refreshing state... [id=fabdac49-5daf-4cd6-aa0a-40d43ace9b1d] +module.vr1_dc0_planes.libvirt_network.plane["metal-admin"]: Refreshing state... [id=4455b805-5fc7-4d25-bd78-2e80d3f472ed] +module.vr1_dc0_opnsense.libvirt_volume.disk: Refreshing state... [id=/var/lib/libvirt/vr1-dc0-inner/vr1-dc0-opnsense-disk.qcow2] +module.vr1_dc0_node["vr1-dc0-storage-03"].libvirt_volume.disk: Refreshing state... [id=/var/lib/libvirt/vr1-dc0-inner/vr1-dc0-storage-03-disk.qcow2] +module.vr1_dc0_node["vr1-dc0-compute-01"].libvirt_volume.disk: Refreshing state... [id=/var/lib/libvirt/vr1-dc0-inner/vr1-dc0-compute-01-disk.qcow2] +module.vr1_dc0_node["vr1-dc0-storage-02"].libvirt_volume.disk: Refreshing state... [id=/var/lib/libvirt/vr1-dc0-inner/vr1-dc0-storage-02-disk.qcow2] +module.vr1_dc0_node["vr1-dc0-compute-02"].libvirt_volume.disk: Refreshing state... [id=/var/lib/libvirt/vr1-dc0-inner/vr1-dc0-compute-02-disk.qcow2] +module.vr1_dc0_node["vr1-dc0-control-01"].libvirt_volume.disk: Refreshing state... [id=/var/lib/libvirt/vr1-dc0-inner/vr1-dc0-control-01-disk.qcow2] +module.vr1_dc0_node["vr1-dc0-control-02"].libvirt_volume.disk: Refreshing state... [id=/var/lib/libvirt/vr1-dc0-inner/vr1-dc0-control-02-disk.qcow2] +module.vr1_dc0_node["vr1-dc0-storage-04"].libvirt_volume.disk: Refreshing state... [id=/var/lib/libvirt/vr1-dc0-inner/vr1-dc0-storage-04-disk.qcow2] +module.vr1_dc0_node["vr1-dc0-control-03"].libvirt_volume.disk: Refreshing state... [id=/var/lib/libvirt/vr1-dc0-inner/vr1-dc0-control-03-disk.qcow2] +module.vr1_dc0_node["vr1-dc0-storage-01"].libvirt_volume.disk: Refreshing state... [id=/var/lib/libvirt/vr1-dc0-inner/vr1-dc0-storage-01-disk.qcow2] +module.vr1_dc0_opnsense.libvirt_domain.vm: Refreshing state... [name=vr1-dc0-opnsense] +module.vr1_dc0_node["vr1-dc0-storage-04"].libvirt_domain.node: Refreshing state... [name=vr1-dc0-storage-04] +module.vr1_dc0_node["vr1-dc0-compute-01"].libvirt_domain.node: Refreshing state... [name=vr1-dc0-compute-01] +module.vr1_dc0_node["vr1-dc0-control-02"].libvirt_domain.node: Refreshing state... [name=vr1-dc0-control-02] +module.vr1_dc0_node["vr1-dc0-control-03"].libvirt_domain.node: Refreshing state... [name=vr1-dc0-control-03] +module.vr1_dc0_node["vr1-dc0-storage-02"].libvirt_domain.node: Refreshing state... [name=vr1-dc0-storage-02] +module.vr1_dc0_node["vr1-dc0-control-01"].libvirt_domain.node: Refreshing state... [name=vr1-dc0-control-01] +module.vr1_dc0_node["vr1-dc0-storage-03"].libvirt_domain.node: Refreshing state... [name=vr1-dc0-storage-03] +module.vr1_dc0_node["vr1-dc0-compute-02"].libvirt_domain.node: Refreshing state... [name=vr1-dc0-compute-02] +module.vr1_dc0_node["vr1-dc0-storage-01"].libvirt_domain.node: Refreshing state... [name=vr1-dc0-storage-01] + +OpenTofu used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: + ~ update in-place (current -> planned) + +OpenTofu will perform the following actions: + + # module.vr1_dc0_node["vr1-dc0-compute-01"].libvirt_domain.node will be updated in-place + ~ resource "libvirt_domain" "node" { + ~ devices = { + ~ interfaces = [ + ~ { + + mac = { + + address = "52:54:00:1b:19:e6" + } + # (3 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:8c:2a:8c" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:9c:7f:7a" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:33:92:4e" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:40:62:bb" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:b7:d1:a2" + } + # (2 unchanged attributes hidden) + }, + ] + # (2 unchanged attributes hidden) + } + id = 25 + name = "vr1-dc0-compute-01" + # (10 unchanged attributes hidden) + } + + # module.vr1_dc0_node["vr1-dc0-compute-02"].libvirt_domain.node will be updated in-place + ~ resource "libvirt_domain" "node" { + ~ devices = { + ~ interfaces = [ + ~ { + + mac = { + + address = "52:54:00:18:ab:b4" + } + # (3 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:50:48:88" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:78:fb:c5" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:cc:84:61" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:e4:ab:df" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:5b:93:c4" + } + # (2 unchanged attributes hidden) + }, + ] + # (2 unchanged attributes hidden) + } + id = 22 + name = "vr1-dc0-compute-02" + # (10 unchanged attributes hidden) + } + + # module.vr1_dc0_node["vr1-dc0-control-01"].libvirt_domain.node will be updated in-place + ~ resource "libvirt_domain" "node" { + ~ devices = { + ~ interfaces = [ + ~ { + + mac = { + + address = "52:54:00:be:69:c5" + } + # (3 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:29:e5:2b" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:05:98:c4" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:96:e8:36" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:5a:dc:91" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:35:cc:01" + } + # (2 unchanged attributes hidden) + }, + ] + # (2 unchanged attributes hidden) + } + id = 9 + name = "vr1-dc0-control-01" + # (10 unchanged attributes hidden) + } + + # module.vr1_dc0_node["vr1-dc0-control-02"].libvirt_domain.node will be updated in-place + ~ resource "libvirt_domain" "node" { + ~ devices = { + ~ interfaces = [ + ~ { + + mac = { + + address = "52:54:00:02:ff:57" + } + # (3 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:b0:17:2a" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:58:17:23" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:1c:ab:44" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:a6:f8:0b" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:2e:09:d8" + } + # (2 unchanged attributes hidden) + }, + ] + # (2 unchanged attributes hidden) + } + id = 24 + name = "vr1-dc0-control-02" + # (10 unchanged attributes hidden) + } + + # module.vr1_dc0_node["vr1-dc0-control-03"].libvirt_domain.node will be updated in-place + ~ resource "libvirt_domain" "node" { + ~ devices = { + ~ interfaces = [ + ~ { + + mac = { + + address = "52:54:00:4f:de:a9" + } + # (3 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:0b:c2:1b" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:c0:d3:e6" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:10:0f:ea" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:53:19:ef" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:86:78:ed" + } + # (2 unchanged attributes hidden) + }, + ] + # (2 unchanged attributes hidden) + } + id = 23 + name = "vr1-dc0-control-03" + # (10 unchanged attributes hidden) + } + + # module.vr1_dc0_node["vr1-dc0-storage-01"].libvirt_domain.node will be updated in-place + ~ resource "libvirt_domain" "node" { + ~ devices = { + ~ interfaces = [ + ~ { + + mac = { + + address = "52:54:00:5f:8d:42" + } + # (3 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:4c:69:7b" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:ac:2c:4d" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:28:91:d2" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:fa:7c:53" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:0c:7a:ab" + } + # (2 unchanged attributes hidden) + }, + ] + # (2 unchanged attributes hidden) + } + id = 7 + name = "vr1-dc0-storage-01" + # (10 unchanged attributes hidden) + } + + # module.vr1_dc0_node["vr1-dc0-storage-02"].libvirt_domain.node will be updated in-place + ~ resource "libvirt_domain" "node" { + ~ devices = { + ~ interfaces = [ + ~ { + + mac = { + + address = "52:54:00:48:86:2c" + } + # (3 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:2e:8b:55" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:d7:4e:38" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:05:60:af" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:c6:02:bd" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:2c:f8:42" + } + # (2 unchanged attributes hidden) + }, + ] + # (2 unchanged attributes hidden) + } + id = 21 + name = "vr1-dc0-storage-02" + # (10 unchanged attributes hidden) + } + + # module.vr1_dc0_node["vr1-dc0-storage-03"].libvirt_domain.node will be updated in-place + ~ resource "libvirt_domain" "node" { + ~ devices = { + ~ interfaces = [ + ~ { + + mac = { + + address = "52:54:00:b1:94:d1" + } + # (3 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:bd:d1:24" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:80:67:87" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:0f:a6:35" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:e0:73:ed" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:62:65:77" + } + # (2 unchanged attributes hidden) + }, + ] + # (2 unchanged attributes hidden) + } + id = 6 + name = "vr1-dc0-storage-03" + # (10 unchanged attributes hidden) + } + + # module.vr1_dc0_node["vr1-dc0-storage-04"].libvirt_domain.node will be updated in-place + ~ resource "libvirt_domain" "node" { + ~ devices = { + ~ interfaces = [ + ~ { + + mac = { + + address = "52:54:00:2b:ed:ab" + } + # (3 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:90:ca:d0" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:2a:ac:14" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:af:34:fd" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:28:b1:6d" + } + # (2 unchanged attributes hidden) + }, + ~ { + + mac = { + + address = "52:54:00:ab:5c:50" + } + # (2 unchanged attributes hidden) + }, + ] + # (2 unchanged attributes hidden) + } + id = 26 + name = "vr1-dc0-storage-04" + # (10 unchanged attributes hidden) + } + +Plan: 0 to add, 9 to change, 0 to destroy. + +───────────────────────────────────────────────────────────────────────────── + +Note: You didn't use the -out option to save this plan, so OpenTofu can't +guarantee to take exactly these actions if you run "tofu apply" now. diff --git a/docs/changelog-20260721-close-and-delivery.md b/docs/changelog-20260721-close-and-delivery.md index d3b9647..0f45ce9 100644 --- a/docs/changelog-20260721-close-and-delivery.md +++ b/docs/changelog-20260721-close-and-delivery.md @@ -61,3 +61,18 @@ present, exactly one ignore_changes, cites MAAS). 15 cases green. - **Revert:** remove the lifecycle block + T13-T15; the 9 power-on changes return to the next plan. + +## 4. MAC-pin apply EXECUTED on voffice1 (operator-approved) + +- Guarded re-plan captured (inner-plan-20260721-macpin-guarded.txt: 54 + mac adoptions, zero power flips, zero replaces), then saved-plan apply + (`tofu plan -out` -> `tofu show` re-verify 0/9/0 -> `tofu apply`): + exact 0/9/0, convergence re-plan "no differences" + (docs/audit/inner-apply-20260721-macpin.txt). Post-apply verified + read-only: all 9 domains still shut off, edge untouched, spot-checked + MACs identical (control-01, storage-04). +- The inner tfstate on voffice1 now carries the pins (state serial + advanced; it remains the state-of-record per CURRENT-STATE section 1). +- **Revert:** git revert the pinning commits, re-plan/apply on voffice1 + (returns MACs to provider-owned -- NOT recommended; reopens the drift + hole that caused the 2026-07-21 incident).