Newer
Older
openstack-caracal-ipv4 / tests / cloud-assert / run-tests.sh
@JANeumatrix JANeumatrix 11 hours ago 6 KB Patches
#!/usr/bin/env bash
# tests/cloud-assert/run-tests.sh -- offline fakebin harness for cloud-assert.sh
# (DOCFIX-075). Fake juju/openstack/jq-free: real jq stays real; fake juju and
# openstack replay fixture outputs keyed by argument patterns, selected per test
# via FIXDIR. Asserts the behavioral checks fire on the exact incident
# signatures they were written for (D-045/D-046/D-051/D-062/vault-sealed).
# Mutates nothing outside $TMP. Exit: 0 all pass | 1 any failed.  ASCII + LF.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "$HERE/../.." && pwd)"
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
PASS=0; FAIL=0
BIN="$TMP/bin"; mkdir -p "$BIN"

cat > "$BIN/juju" <<'FB'
#!/usr/bin/env bash
# fake juju: replay fixtures from $FIXDIR keyed by argv patterns
A="$*"
case "$A" in
  *"status -m"*"keystone --format=line"*) cat "$FIXDIR/ks-line.txt" ;;
  *"status -m"*"--format=json"*)          cat "$FIXDIR/status.json" ;;
  *"vault/0"*"vault status"*)             cat "$FIXDIR/vault.txt" ;;
  *"cluster/status OVN_Northbound"*)      cat "$FIXDIR/ovn-nb.txt" ;;
  *"cluster/status OVN_Southbound"*)      cat "$FIXDIR/ovn-sb.txt" ;;
  *"connection-status"*)                  cat "$FIXDIR/chassis.txt" ;;
  *"ps -ww -C magnum-conductor"*)         cat "$FIXDIR/conductor.txt" ;;
  *) echo "fake-juju: unmatched: $A" >&2; exit 1 ;;
esac
FB
cat > "$BIN/openstack" <<'FB'
#!/usr/bin/env bash
A="$*"
case "$A" in
  *"hypervisor list"*)        cat "$FIXDIR/hypervisors.json" ;;
  *"compute service list"*)   cat "$FIXDIR/services.json" ;;
  *"loadbalancer list"*)      cat "$FIXDIR/lbs.json" ;;
  *"domain show magnum"*)     cat "$FIXDIR/domain.txt" ;;
  *"user show magnum_domain_admin"*) cat "$FIXDIR/user.txt" ;;
  *"coe service list"*)       cat "$FIXDIR/coe.txt" ;;
  *) echo "fake-openstack: unmatched: $A" >&2; exit 1 ;;
esac
FB
chmod +x "$BIN/juju" "$BIN/openstack"

mkgood() { # healthy-cloud fixture set
  local d="$1"; mkdir -p "$d"
  cat > "$d/status.json" <<'J'
{"applications":{
 "mysql-innodb-cluster":{"units":{
   "mysql-innodb-cluster/0":{"workload-status":{"current":"active","message":"Unit is ready: Mode: R/W, Cluster is ONLINE"}},
   "mysql-innodb-cluster/1":{"workload-status":{"current":"active","message":"Unit is ready: Mode: R/O, Cluster is ONLINE"}},
   "mysql-innodb-cluster/2":{"workload-status":{"current":"active","message":"Unit is ready: Mode: R/O, Cluster is ONLINE"}}}},
 "ovn-central":{"units":{"ovn-central/0":{"workload-status":{"current":"active"}},
   "ovn-central/1":{"workload-status":{"current":"active"}},"ovn-central/2":{"workload-status":{"current":"active"}}}},
 "nova-compute":{"units":{"nova-compute/0":{"workload-status":{"current":"active"}}}},
 "octavia":{"units":{"octavia/0":{"workload-status":{"current":"active"}}}},
 "glance-simplestreams-sync":{"units":{"glance-simplestreams-sync/0":{"workload-status":{"current":"unknown"}}}}
}}
J
  printf 'Initialized  true\nSealed       false\n' > "$d/vault.txt"
  printf 'Cluster ID: abcd (uuid)\nServers: 3\n' > "$d/ovn-nb.txt"
  cp "$d/ovn-nb.txt" "$d/ovn-sb.txt"
  printf 'connected\n' > "$d/chassis.txt"
  printf '/usr/bin/python3 /usr/bin/magnum-conductor --config-file /etc/magnum/magnum.conf --config-dir /etc/magnum/magnum.conf.d\n' > "$d/conductor.txt"
  printf '[{"Hypervisor Hostname":"openstack0","State":"up"}]\n' > "$d/hypervisors.json"
  printf '[{"Binary":"nova-compute","Host":"openstack0","Status":"enabled","State":"up"}]\n' > "$d/services.json"
  printf '[]\n' > "$d/lbs.json"
  printf 'True\n' > "$d/domain.txt"
  printf 'magnum_domain_admin\n' > "$d/user.txt"
  printf 'magnum-conductor\n' > "$d/coe.txt"
  printf 'keystone: active/idle 2024.1 PO: 10.12.4.50\n' > "$d/ks-line.txt"
}
run() { # run <want_rc> <regex> <label> <fixdir> [env...]
  local want="$1" rx="$2" label="$3" fd="$4"; shift 4
  local out rc
  out="$(cd "$TMP" && env "$@" FIXDIR="$fd" PATH="$BIN:$PATH" OS_AUTH_URL="https://fake:5000/v3" \
        bash "$REPO/scripts/cloud-assert.sh" 2>&1)"; rc=$?
  if [[ "$rc" == "$want" ]] && grep -qE "$rx" <<<"$out"; then
    echo "  PASS  $label"; PASS=$((PASS+1))
  else
    echo "  FAIL  $label (rc=$rc want=$want)"; grep -E '\[(FAIL|WARN)\]|CLOUD-ASSERT' <<<"$out" | head -6 | sed 's/^/        /'; FAIL=$((FAIL+1))
  fi
}

F="$TMP/good"; mkgood "$F";  run 0 'CLOUD-ASSERT: PASS' "T1 healthy cloud -> PASS" "$F"
F="$TMP/sealed"; mkgood "$F"; printf 'Initialized  true\nSealed       true\n' > "$F/vault.txt"
                              run 1 'vault SEALED' "T2 sealed vault FAILS (with unseal pointer)" "$F"
F="$TMP/rw2"; mkgood "$F"; python3 - "$F/status.json" <<'PY'
import json,sys; p=sys.argv[1]; d=json.load(open(p))
u=d["applications"]["mysql-innodb-cluster"]["units"]
u["mysql-innodb-cluster/1"]["workload-status"]["message"]="Unit is ready: Mode: R/W, Cluster is ONLINE"
json.dump(d,open(p,"w"))
PY
                              run 1 'R/W count=2' "T3 mysql split-brain (2x R/W) FAILS" "$F"
F="$TMP/chassis"; mkgood "$F"; printf 'not connected\n' > "$F/chassis.txt"
                              run 1 'chassis NOT connected' "T4 dead chassis FAILS (D-045 class)" "$F"
F="$TMP/pobroken"; mkgood "$F"; printf 'keystone: active/idle 2024.1 PO (broken) 10.12.4.50\n' > "$F/ks-line.txt"
                              run 1 'PO \(broken\)' "T5 PO(broken) FAILS (DOCFIX-071)" "$F"
F="$TMP/nodomain"; mkgood "$F"; printf 'No domain with a name or ID\n' > "$F/domain.txt"
                              run 1 "domain-setup" "T6 missing trustee domain FAILS (D-046)" "$F"
F="$TMP/graft"; mkgood "$F"; printf '/usr/bin/python3 /usr/bin/magnum-conductor --config-file /etc/magnum/magnum.conf\n' > "$F/conductor.txt"
                              run 1 'lack --config-dir' "T7 dead conductor graft FAILS (D-037)" "$F"
F="$TMP/lberr"; mkgood "$F"; printf '[{"name":"lb1","provisioning_status":"ERROR","operating_status":"OFFLINE"}]\n' > "$F/lbs.json"
                              run 1 'LBs unhealthy' "T8 LB in ERROR FAILS (with failover pointer)" "$F"
# T9: no admin scope -> A5-A7 HELD, exit 2 (never a silent pass)
F="$TMP/held"; mkgood "$F"
out="$(cd "$TMP" && env -u OS_AUTH_URL FIXDIR="$F" PATH="$BIN:$PATH" bash "$REPO/scripts/cloud-assert.sh" 2>&1)"; rc=$?
if [[ "$rc" == "2" ]] && grep -q 'HELD: no admin scope' <<<"$out"; then echo "  PASS  T9 missing admin scope -> HELD (rc 2)"; PASS=$((PASS+1))
else echo "  FAIL  T9 (rc=$rc)"; FAIL=$((FAIL+1)); fi

echo; echo "RESULT: PASS=$PASS FAIL=$FAIL"
[[ "$FAIL" -eq 0 ]] && { echo "ALL PASS"; exit 0; } || exit 1