Newer
Older
openstack-caracal-dc-dc / scripts / lib-hosts.sh
# scripts/lib-hosts.sh
#
# Single source of truth for the four OpenStack KVM host VMs (VR0 / Baldurkeep):
# their enrollment identity and virsh power parameters. SOURCED, not executed.
# ASCII + LF. Contains constants + read-only helpers ONLY; no mutations.
#
# WHY hostname-keyed (NOT system_id-keyed): MAAS system_ids are minted fresh on
# every (re-)enrollment. The old 4na83t/qdbqd6/h8frng/tmsafc died when the hosts
# were decomposed on 2026-06-26 and re-enrollment assigned new random ids. The
# stable identities are the hostname and the libvirt domain name, so every map
# here keys on hostname and the live system_id is resolved AT RUNTIME via
# host_sysid(). This SUPERSEDES the SYSID-keyed maps in lib-net.sh (DOCFIX-040).
#
# NO SECRET lives here. The libvirt SSH password is read interactively at run time
# (reenroll-hosts.sh) and is never written to a file, a command line, or the repo.

# shellcheck shell=bash
# shellcheck disable=SC2034  # constants are consumed by sourcing scripts

# Guard: sourced only.
if [ "${BASH_SOURCE[0]:-}" = "${0}" ]; then
  echo "lib-hosts.sh is a sourced library; do not run it directly." >&2
  exit 2
fi

# The four OpenStack KVM hosts. libvirt domain name == MAAS hostname == power_id.
HOSTS=( openstack0 openstack1 openstack2 openstack3 )

# host -> last IPv4 octet on every plane (.40-.43). Stable by design (D-052 index).
declare -A HOST_OCTET=( [openstack0]=40 [openstack1]=41 [openstack2]=42 [openstack3]=43 )

# host -> PXE/boot NIC MAC == the 2_metal interface (libvirt <boot order='1'/>).
# Fixed in the libvirt domain XML; captured 2026-06-26. The boot NIC MUST be the
# metal/PXE plane or commissioning cannot DHCP/PXE.
declare -A HOST_BOOT_MAC=(
  [openstack0]=52:54:00:4f:1c:0b
  [openstack1]=52:54:00:83:25:1f
  [openstack2]=52:54:00:23:bd:72
  [openstack3]=52:54:00:b2:7b:30
)

# virsh power (non-secret). MAAS reaches libvirt over SSH on the OOB host address.
# Mirrors the surviving juju/lxd/tailscale virsh machines' live config (read
# 2026-06-26). power_id is set per host to the hostname by the caller.
VIRSH_POWER_ADDRESS="qemu+ssh://logxen@10.12.64.1/system"
HOST_ARCH="amd64"

# MAAS tag the deploy bundle places units against (constraint tags=openstack).
# Must be (re-)applied to every host post-commission or the bundle cannot bind.
HOST_TAG="openstack"

# host_sysid <hostname>: resolve the LIVE MAAS system_id by hostname (never
# hardcode it). Echoes the system_id, or empty if the host is not enrolled.
host_sysid() {
  local hn="$1"
  maas "${MAAS_PROFILE:-admin}" machines read 2>/dev/null \
    | jq -r --arg h "$hn" '.[] | select(.hostname==$h) | .system_id' | head -1
}

# --- $DC selector convention (2026-07-09, tooling gap register #1) ---
#
# Mirrors lib-net.sh's lib_net_select_dc -- but the answer here is honestly
# different, not a parallel no-op: HOSTS / HOST_OCTET / HOST_BOOT_MAC above
# are VR0/DC0's real, measured, enrolled hosts. DC1's and DC2's node VMs are
# created by opentofu/modules/node-vm (Stage 3 / buildout-design Phase 2),
# which has not run -- their hostnames, boot MACs, and octets do not exist
# yet, and VIRSH_POWER_ADDRESS above is DC0's own vcloud host connection
# (the buildout design's VR1 vcloud host is a distinct, not-yet-measured
# endpoint -- see opentofu's root `libvirt_uri` variable, also unset).
# Selecting dc1 or dc2 FAILS LOUDLY rather than inventing placeholder host
# data or silently reusing DC0's real hosts for a different DC.
lib_hosts_select_dc() {
  local dc="${1:?usage: lib_hosts_select_dc <dc0|dc1|dc2>}"
  case "$dc" in
    dc0)
      : # already the sourced defaults above -- explicit no-op, not a guess.
      ;;
    dc1|dc2)
      echo "FAIL: $dc has no enrolled hosts yet -- Phase 2/3 node-VM creation (opentofu/modules/node-vm) and MAAS enrollment haven't run for it. Do not invent HOSTS/HOST_OCTET/HOST_BOOT_MAC/VIRSH_POWER_ADDRESS values; populate this file with a real \$dc block once those hosts are actually enrolled and measured." >&2
      return 1
      ;;
    *)
      echo "FAIL: unknown DC '$dc' (expected dc0, dc1, or dc2)" >&2
      return 1
      ;;
  esac
}