#!/usr/bin/env bash
# tests/phase-07-conductor-graft/run-tests.sh -- offline regression for
# scripts/phase-07-conductor-graft.sh. Fake juju/openstack/kubectl; real
# base64/sha256sum/bash. Focus: the DOCFIX-063 behaviors (7.1 verify-first is a
# no-op when 6443 is open and NEVER creates a rule; 7.3 api-versions probe; the
# sha256 both-sides gate; install -d before the tee) plus the 7.7b v3-URL
# derivation and the phase gates/preconditions.
set -euo pipefail
IFS=$'\n\t'
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SCRIPTS="$(cd "$HERE/../../scripts" && pwd)"
TARGET="$SCRIPTS/phase-07-conductor-graft.sh"
BIN="$HERE/fakebin"
[ -f "$TARGET" ] || { echo "FAIL: $TARGET missing" >&2; exit 1; }
chmod +x "$BIN"/* 2>/dev/null || true
WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT
rc_all=0
FIP=10.12.7.222
# fixtures on the jumphost side
printf 'export OS_AUTH_URL=https://10.12.8.50:35357/v3\nexport OS_USERNAME=admin\n' > "$WORK/admin-openrc"
printf 'MGMT_FIP=%s\n' "$FIP" > "$WORK/net.env"
cat > "$WORK/kubeconfig" <<KC
apiVersion: v1
clusters:
- cluster:
server: https://$FIP:6443
name: capi-mgmt-v2
kind: Config
KC
run() { # want_rc regex label [extra env...]
local want="$1" re="$2" label="$3"; shift 3
local rc; local state="$WORK/state"; rm -rf "$state"; mkdir -p "$state"
: > "$WORK/juju.log"; : > "$WORK/os.log"
set +e
PATH="$BIN:$PATH" HOME="$WORK" \
ADMIN_OPENRC="$WORK/admin-openrc" ENVFILE="$WORK/net.env" KUBECONFIG_SRC="$WORK/kubeconfig" \
JUJU_LOG="$WORK/juju.log" JUJU_STATE="$state" OS_LOG="$WORK/os.log" \
env "$@" bash "$TARGET" >"$WORK/out" 2>&1
rc=$?
set -e
if [ "$rc" -eq "$want" ] && grep -qE "$re" "$WORK/out"; then
printf ' [OK] %-52s exit %s\n' "$label" "$rc"
else
printf ' [XX] %-52s exit %s (want %s; /%s/)\n' "$label" "$rc" "$want" "$re"
sed 's/^/ /' "$WORK/out"; rc_all=1
fi
}
echo "=== phase-07-conductor-graft.sh ==="
run 0 'PHASE-07 COMPLETE' "happy path (7.0-7.8)"
run 0 'no rule added' "7.1 verify-first: reachable -> no SG mutation"
run 0 'v1beta1 served for all core' "7.3 api-versions probe passes"
run 0 'sha256 match' "7.2 kubeconfig sha256 both-sides gate"
run 0 'k8s_capi_helm_v1 enabled' "7.8 driver enabled gate"
# --- gate failures ---
run 1 'cannot reach' "7.1 TCP-FAIL -> exit 1 (fallback msg)" TCP_FAIL=1
run 1 'sha256 mismatch' "7.2 sha mismatch -> exit 1" SHA_MISMATCH=1
run 1 'does NOT serve v1beta1' "7.3 core group missing v1beta1 -> exit 1" NO_V1BETA1_CORE=1
run 1 'entry point missing' "7.4 driver entry point absent -> exit 1" DRIVER_MISSING=1
run 1 'not active after restart' "7.8 service not active -> exit 1" NOTACTIVE=1
run 1 'lacks --config-dir' "7.8 live cmdline missing --config-dir" PS_NODIR=1
run 1 'not enabled in magnum-driver' "7.8 driver not enabled -> exit 1" NODRIVER_ENABLED=1
run 1 'domain-setup action failed' "7.0 domain-setup fails -> exit 1" DOMAIN_SETUP_FAIL=1
run 1 "domain 'magnum' absent" "7.0 domain missing -> exit 1" DOMAIN_MISSING=1
# --- preconditions ---
run 2 'not found' "precondition: no ENVFILE -> exit 2" ENVFILE="$WORK/nope.env"
: > "$WORK/empty.env"
run 2 'MGMT_FIP unset' "precondition: empty env (MGMT_FIP unset) -> exit 2" ENVFILE="$WORK/empty.env"
cat > "$WORK/badkc" <<'BK'
apiVersion: v1
clusters:
- cluster:
server: https://10.20.0.207:6443
name: x
BK
run 2 'server is not the FIP' "precondition: kubeconfig server not FIP -> exit 2" KUBECONFIG_SRC="$WORK/badkc"
# --- dedicated happy-path capture for the structural assertions (NOT leftover
# logs from the last precondition run, which never reaches 7.0+) ---
echo "=== structural assertions (dedicated happy-path capture) ==="
hstate="$WORK/hstate"; rm -rf "$hstate"; mkdir -p "$hstate"
: > "$WORK/hjuju.log"; : > "$WORK/hos.log"
PATH="$BIN:$PATH" HOME="$WORK" \
ADMIN_OPENRC="$WORK/admin-openrc" ENVFILE="$WORK/net.env" KUBECONFIG_SRC="$WORK/kubeconfig" \
JUJU_LOG="$WORK/hjuju.log" JUJU_STATE="$hstate" OS_LOG="$WORK/hos.log" \
bash "$TARGET" >/dev/null 2>&1 || true
# 7.1 verify-first NEVER calls security group rule create
if grep -q 'security group rule create' "$WORK/hos.log"; then
echo " [XX] 7.1 created an SG rule (must be verify-first no-op)"; rc_all=1
else
echo " [OK] no 'security group rule create' in the openstack call log"
fi
# install -d /etc/magnum/magnum.conf.d precedes the 00-capi-helm.conf tee
ln=$(grep -n 'install -d.*magnum.conf.d' "$WORK/hjuju.log" | head -1 | cut -d: -f1 || true)
lt=$(grep -n 'tee /etc/magnum/magnum.conf.d/00-capi-helm.conf' "$WORK/hjuju.log" | head -1 | cut -d: -f1 || true)
if [ -n "$ln" ] && [ -n "$lt" ] && [ "$ln" -lt "$lt" ]; then
echo " [OK] install -d (line $ln) precedes tee (line $lt)"
else
echo " [XX] dir-create/tee ordering wrong (install-d=$ln tee=$lt)"; rc_all=1
fi
# --- assertion: 7.7b v3-URL derivation (mirrors the as-run block) ---
echo "=== assert 7.7b keystone v3-URL derivation ==="
v3() { # replicate the 7.7b derivation exactly
local in="$1" out
out=${in/\/v2.0//v3}
case "$out" in */v3) ;; *) out="${out%/}/v3";; esac
printf '%s' "$out"
}
derr=0
[ "$(v3 https://10.12.4.50:5000)" = https://10.12.4.50:5000/v3 ] || { echo " [XX] unversioned -> /v3 failed"; derr=1; }
[ "$(v3 https://10.12.4.50:5000/v2.0)" = https://10.12.4.50:5000/v3 ] || { echo " [XX] /v2.0 -> /v3 failed"; derr=1; }
[ "$(v3 https://10.12.4.50:5000/v3)" = https://10.12.4.50:5000/v3 ] || { echo " [XX] /v3 -> /v3 (idempotent) failed"; derr=1; }
[ "$(v3 https://10.12.8.50:35357/)" = https://10.12.8.50:35357/v3 ] || { echo " [XX] trailing-slash -> /v3 failed"; derr=1; }
[ "$derr" -eq 0 ] && echo " [OK] v3 derivation: unversioned, /v2.0, /v3, trailing-slash all -> /v3"
[ "$derr" -eq 0 ] || rc_all=1
echo
[ "$rc_all" -eq 0 ] && echo "ALL PASS" || echo "SOME FAILED"
exit "$rc_all"