Newer
Older
openstack-caracal-ipv4 / scripts / phase-00-teardown-destroy.sh
#!/usr/bin/env bash
# scripts/phase-00-teardown-destroy.sh [--apply] [--no-prompt]
#
# FULL-DESTROY teardown (the from-scratch path). Destroys the `openstack` model AND
# lets the MAAS pod-composed openstack0-3 machines DECOMPOSE (returned to the libvirt
# pod, removed from MAAS). After this you MUST reenroll (scripts/reenroll-hosts.sh) and
# re-carve (scripts/carve-host-interfaces.sh) before the next deploy.
#
# WHEN TO USE: when you deliberately want a clean MAAS re-enrollment (e.g. validating
# the reenroll+carve path itself, or recovering from a corrupted machine state). For a
# reuse-in-place teardown that KEEPS the machines, use phase-00-teardown-release.sh.
#
# D-061 (honest behavior note): on this virsh-pod MAAS, `juju destroy-model` decomposes
# the pod-composed machines REGARDLESS of the storage flag. This script EMBRACES that
# (it is the destroy path) rather than fighting it. --destroy-storage is used so OSD
# data is discarded too (a fresh deploy re-wipes vdb anyway). This is NOT the bug that
# bit the project 3x -- the bug was using THIS behavior when machine RETENTION was
# wanted. If you want retention, you are on the wrong script (use -release.sh).
#
# Roster (resolved live):
#   PROTECTED (never touched): juju, lxd, tailscale
#   HOSTS (decomposed):        openstack0-3   -> reenroll+carve after
#   ORPHAN (deleted if present): capi-mgmt
#
# DEFAULT = DRY-RUN. --apply executes; typed-approval gate (model name) first.
# --no-prompt skips the gate (tested automation only).
#
# Exit: 0 ok | 1 fatal/unsafe | 2 aborted.  ASCII + LF.
set -euo pipefail
shopt -s inherit_errexit 2>/dev/null || true

MAAS_PROFILE="${MAAS_PROFILE:-admin}"
MODEL="${OPENSTACK_MODEL:-openstack}"
HOSTS=(openstack0 openstack1 openstack2 openstack3)
ORPHANS=(capi-mgmt)
PROTECTED=(juju lxd tailscale)

MODE="dryrun"; PROMPT=1
for a in "$@"; do
  case "$a" in
    --apply) MODE="apply" ;;
    --no-prompt) PROMPT=0 ;;
    *) echo "unknown arg: $a" >&2; exit 1 ;;
  esac
done
FATAL=0
hdr()  { echo; echo "=== $* ==="; }
note() { echo "  - $*"; }
fail() { echo "FAIL: $*" >&2; FATAL=$((FATAL+1)); }
command -v jq >/dev/null   || { echo "FATAL: jq required"   >&2; exit 1; }
command -v juju >/dev/null || { echo "FATAL: juju not on PATH" >&2; exit 1; }

maas_json() { local o; o="$(maas "$MAAS_PROFILE" "$@" 2>/dev/null || true)"; printf '%s' "$o" | jq empty 2>/dev/null && printf '%s' "$o" || printf '[]'; }
MACHINES_JSON="$(maas_json machines read)"
sid_of()    { printf '%s' "$MACHINES_JSON" | jq -r --arg h "$1" '.[]|select(.hostname==$h)|.system_id' | head -1; }
status_of() { printf '%s' "$MACHINES_JSON" | jq -r --arg h "$1" '.[]|select(.hostname==$h)|.status_name' | head -1; }

hdr "destroy-teardown audit  mode=$MODE  model=$MODEL"

declare -A PROT_SID
hdr "PROTECTED substrate (never touched)"
for p in "${PROTECTED[@]}"; do
  s="$(sid_of "$p")"
  if [ -z "$s" ]; then note "$p: not in MAAS -- nothing to protect"; continue; fi
  PROT_SID["$s"]="$p"; note "$p = $s (status $(status_of "$p")) -- PROTECTED"
done

hdr "HOSTS (will DECOMPOSE -> reenroll+carve after)"
for h in "${HOSTS[@]}"; do
  s="$(sid_of "$h")"
  if [ -z "$s" ]; then note "$h: already absent from MAAS"; continue; fi
  if [ -n "${PROT_SID[$s]:-}" ]; then fail "$h resolves to PROTECTED sid $s -- ABORT"; continue; fi
  note "$h = $s (status $(status_of "$h"))"
done

declare -A OSID
hdr "ORPHANS (deleted)"
for o in "${ORPHANS[@]}"; do
  s="$(sid_of "$o")"
  if [ -z "$s" ]; then note "$o: absent -- SKIP"; continue; fi
  if [ -n "${PROT_SID[$s]:-}" ]; then fail "$o resolves to PROTECTED sid $s -- ABORT"; continue; fi
  OSID["$s"]="$o"; note "$o = $s -- DELETE"
done

MODEL_PRESENT=0
if juju models --format=json 2>/dev/null | jq -e --arg m "$MODEL" '.models[]?|select(.name==$m or (.name|endswith("/"+$m)))' >/dev/null 2>&1; then
  MODEL_PRESENT=1; note "juju model '$MODEL' PRESENT -- will destroy"
else
  note "juju model '$MODEL' not present -- destroy skipped"
fi

[ "$FATAL" -eq 0 ] || { echo; echo "ABORT: $FATAL safety failure(s) -- nothing changed"; exit 1; }

hdr "PLAN"
echo "  1) juju destroy-model $MODEL --destroy-storage --force --no-wait --no-prompt"
echo "       (decomposes openstack0-3; discards OSD storage)"
echo "  2) delete orphan MAAS machine(s): ${ORPHANS[*]}"
echo "  3) verify hosts gone + substrate intact"
echo "  AFTER: reenroll-hosts.sh -> carve-host-interfaces.sh (x4) -> maas-fabric-prune.sh -> maas-standup.sh"
echo "  PROTECTED: ${PROTECTED[*]}"

if [ "$MODE" = dryrun ]; then
  echo; echo "  re-run with --apply to execute (typed model-name gate)."
  echo "OK (dryrun)"; exit 0
fi

if [ "$PROMPT" -eq 1 ] && [ "$MODEL_PRESENT" = 1 ]; then
  printf 'Type the model name "%s" to confirm FULL DESTROY (machines WILL decompose): ' "$MODEL" > /dev/tty
  read -r ans < /dev/tty
  [ "$ans" = "$MODEL" ] || { echo "aborted (got '$ans') -- nothing changed"; exit 2; }
fi

hdr "MUTATE 1: destroy model (machines decompose)"
if [ "$MODEL_PRESENT" = 1 ]; then
  echo "  DO: juju destroy-model $MODEL --destroy-storage --force --no-wait --no-prompt"
  juju destroy-model "$MODEL" --destroy-storage --force --no-wait --no-prompt 2>&1 || fail "destroy-model returned error"
else note "model absent -- skip"; fi
[ "$FATAL" -eq 0 ] || { echo; echo "STOP: destroy-model failed -- not deleting orphans."; exit 1; }

hdr "MUTATE 2: delete orphan machines"
for s in "${!OSID[@]}"; do
  echo "  DO: delete orphan ${OSID[$s]} ($s)"
  maas "$MAAS_PROFILE" machine delete "$s" >/dev/null 2>&1 || note "orphan ${OSID[$s]} delete failed (may already be gone)"
done

hdr "VERIFY (read-only): hosts gone + substrate intact"
MACHINES_JSON="$(maas_json machines read)"
for h in "${HOSTS[@]}"; do
  st="$(status_of "$h")"
  if [ -z "$st" ]; then note "$h -> decomposed/absent (expected)"; else note "$h -> $st (still present; destroy may be in progress -- re-check)"; fi
done
for p in "${PROTECTED[@]}"; do note "PROTECTED $p -> $(status_of "$p") (unchanged)"; done

echo; echo "next: reenroll-hosts.sh -> carve-host-interfaces.sh x4 -> maas-fabric-prune.sh -> phase-00-maas-standup.sh"
echo "OK (apply)"