Implements T-1.5 findings F1/F2 (author-first, no cluster change). F1 (tofu): refactor libvirt node resources count -> for_each keyed by node name so single-node -replace/destroy cannot cascade to siblings. Add ordered-list/primary helper locals; update outputs.tf off the map; add moved.tf (12 moved blocks). tofu plan proves a pure state-address migration: 0 to add, 0 to change, 0 to destroy (all 12 'has moved to'). State-persist via a 0-change apply is operator-permission-gated. F2 (ansible): k3s_server secondary fetches the join token via delegate_to the primary (published fact as fast path), so a single-node rejoin with --limit k3s-dev-N is self-contained and no longer depends on a fact an earlier play had to set. Syntax-check + CI gate green. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
69 lines
2.1 KiB
Terraform
69 lines
2.1 KiB
Terraform
# moved.tf — state-address migration for the count -> for_each refactor (T-1.5 F1).
|
|
#
|
|
# The node resources changed from positional `count` indexes ([0],[1],[2]) to
|
|
# name-keyed `for_each` (["k3s-dev-1"], …). Without these `moved` blocks OpenTofu
|
|
# would read the address change as "destroy the old, create the new" and rebuild
|
|
# every node. Each block tells tofu the resource is the SAME object under a new
|
|
# address, so the plan is a pure in-state rename: NO destroy, NO recreate.
|
|
#
|
|
# LOCKED mapping (node_count = 3, prefix "k3s-dev-"): index i -> "k3s-dev-${i+1}".
|
|
# `moved` blocks are static config (no for_each), so they are written explicitly.
|
|
# Safe to KEEP indefinitely (harmless once applied) or delete after one apply on
|
|
# every environment that held count-indexed state.
|
|
|
|
# --- OS disks ---------------------------------------------------------------
|
|
moved {
|
|
from = libvirt_volume.os[0]
|
|
to = libvirt_volume.os["k3s-dev-1"]
|
|
}
|
|
moved {
|
|
from = libvirt_volume.os[1]
|
|
to = libvirt_volume.os["k3s-dev-2"]
|
|
}
|
|
moved {
|
|
from = libvirt_volume.os[2]
|
|
to = libvirt_volume.os["k3s-dev-3"]
|
|
}
|
|
|
|
# --- data disks -------------------------------------------------------------
|
|
moved {
|
|
from = libvirt_volume.data[0]
|
|
to = libvirt_volume.data["k3s-dev-1"]
|
|
}
|
|
moved {
|
|
from = libvirt_volume.data[1]
|
|
to = libvirt_volume.data["k3s-dev-2"]
|
|
}
|
|
moved {
|
|
from = libvirt_volume.data[2]
|
|
to = libvirt_volume.data["k3s-dev-3"]
|
|
}
|
|
|
|
# --- cloud-init seeds -------------------------------------------------------
|
|
moved {
|
|
from = libvirt_cloudinit_disk.seed[0]
|
|
to = libvirt_cloudinit_disk.seed["k3s-dev-1"]
|
|
}
|
|
moved {
|
|
from = libvirt_cloudinit_disk.seed[1]
|
|
to = libvirt_cloudinit_disk.seed["k3s-dev-2"]
|
|
}
|
|
moved {
|
|
from = libvirt_cloudinit_disk.seed[2]
|
|
to = libvirt_cloudinit_disk.seed["k3s-dev-3"]
|
|
}
|
|
|
|
# --- domains (VMs) ----------------------------------------------------------
|
|
moved {
|
|
from = libvirt_domain.node[0]
|
|
to = libvirt_domain.node["k3s-dev-1"]
|
|
}
|
|
moved {
|
|
from = libvirt_domain.node[1]
|
|
to = libvirt_domain.node["k3s-dev-2"]
|
|
}
|
|
moved {
|
|
from = libvirt_domain.node[2]
|
|
to = libvirt_domain.node["k3s-dev-3"]
|
|
}
|