fix(smoke): conditional role drill, healthy-gate for drills, exit reaping
This commit is contained in:
+83
-4
@@ -18,14 +18,20 @@
|
||||
# 8. Bad-value drill: feeds --reconcile a wrong bands value and an
|
||||
# oversized SSID pool (25 dummy entries), verifies both are
|
||||
# repaired, restores originals.
|
||||
# 9. Rollback watchdog drill: runs mk8-watchdog.sh against a config
|
||||
# 9. RF role drill (only when SMOKE_UPLINK_SSID is set): switches
|
||||
# radio1 to the uplink role against the named lab AP, expects an
|
||||
# association, then back to attack with hopping resumed.
|
||||
# 10. Rollback watchdog drill: runs mk8-watchdog.sh against a config
|
||||
# profile while the web UI is up (expects clean promote exit),
|
||||
# then STOPS the pagerwebui service and expects the watchdog to
|
||||
# roll back and journal a 'rollback' event, then restarts webui.
|
||||
# Preceded by a 5-second warning countdown; brief web outage.
|
||||
# Drills run only when every read-only check has passed.
|
||||
#
|
||||
# Environment:
|
||||
# PASS webui password used for POST /api/login (check 7).
|
||||
# SMOKE_UPLINK_SSID lab AP SSID; enables the --write RF role drill.
|
||||
# SMOKE_UPLINK_PSK optional PSK for the lab AP.
|
||||
#
|
||||
# Exit status: 0 when every executed check passes, 1 otherwise.
|
||||
|
||||
@@ -42,9 +48,12 @@ JAR=/tmp/mk8-smoke-cookies.$$
|
||||
|
||||
WRITE=0
|
||||
PASS="${PASS:-}"
|
||||
UPLINK_SSID="${SMOKE_UPLINK_SSID:-}"
|
||||
UPLINK_PSK="${SMOKE_UPLINK_PSK:-}"
|
||||
WEB_STOPPED=0
|
||||
FAILED=0
|
||||
WAIT_RC=0
|
||||
wp=""
|
||||
|
||||
PY="$(command -v python3 2>/dev/null || true)"
|
||||
[ -n "$PY" ] || PY=/usr/bin/python3
|
||||
@@ -53,14 +62,20 @@ PY="$(command -v python3 2>/dev/null || true)"
|
||||
usage() {
|
||||
printf 'Usage: smoke.sh [--write]\n'
|
||||
printf '\n'
|
||||
printf 'Read-only checks run by default. --write adds two destructive\n'
|
||||
printf 'drills that briefly toggle UCI config and stop/start the\n'
|
||||
printf 'pagerwebui service; original values are restored automatically.\n'
|
||||
printf 'Read-only checks run by default. --write adds destructive drills\n'
|
||||
printf '(run only if every read-only check passed) that briefly toggle\n'
|
||||
printf 'UCI config and stop/start the pagerwebui service; original values\n'
|
||||
printf 'are restored automatically.\n'
|
||||
printf 'Set PASS=<webui password> to enable the authenticated API check.\n'
|
||||
printf 'Set SMOKE_UPLINK_SSID=[<PSK via SMOKE_UPLINK_PSK>] to enable the\n'
|
||||
printf '--write RF role drill against a lab AP.\n'
|
||||
}
|
||||
|
||||
on_exit() {
|
||||
rm -f "$JAR" 2>/dev/null
|
||||
if [ -n "$wp" ]; then
|
||||
kill "$wp" 2>/dev/null
|
||||
fi
|
||||
if [ "$WEB_STOPPED" = "1" ]; then
|
||||
info 'restoring pagerwebui service'
|
||||
"$WEBUI_INIT" start >/dev/null 2>&1
|
||||
@@ -291,6 +306,67 @@ drill_bad_values() {
|
||||
"$PY" "$REL/server.py" --reconcile >/dev/null 2>&1
|
||||
}
|
||||
|
||||
drill_role() {
|
||||
if [ -z "$UPLINK_SSID" ]; then
|
||||
skip 'role drill: set SMOKE_UPLINK_SSID to enable'
|
||||
return
|
||||
fi
|
||||
info "role drill: uplink '$UPLINK_SSID' then attack"
|
||||
out="$("$PY" - "$REL" "$LEGACY" "$UPLINK_SSID" "$UPLINK_PSK" <<'PYEOF' 2>&1
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
rel, legacy, ssid, psk = sys.argv[1:5]
|
||||
mk8_rfplan = None
|
||||
for d in (rel, legacy):
|
||||
if os.path.isfile(os.path.join(d, 'mk8_rfplan.py')):
|
||||
sys.path.insert(0, d)
|
||||
try:
|
||||
import mk8_rfplan
|
||||
break
|
||||
except Exception:
|
||||
sys.path.remove(d)
|
||||
if mk8_rfplan is None:
|
||||
print('FAIL mk8_rfplan not importable from release or legacy dir')
|
||||
raise SystemExit(1)
|
||||
|
||||
r1 = mk8_rfplan.set_role(
|
||||
'uplink', ssid=ssid or None, psk=psk or None)
|
||||
if not isinstance(r1, dict) or not r1.get('ok'):
|
||||
print('FAIL uplink set_role failed: %s' % json.dumps(r1))
|
||||
raise SystemExit(1)
|
||||
|
||||
assoc = mk8_rfplan.associated()
|
||||
if not assoc:
|
||||
print('FAIL uplink associated() returned nothing after set_role')
|
||||
else:
|
||||
print('associated as %s' % assoc)
|
||||
|
||||
try:
|
||||
r2 = mk8_rfplan.set_role('attack')
|
||||
except Exception as exc:
|
||||
r2 = {'ok': False, 'error': str(exc)}
|
||||
if not isinstance(r2, dict) or not r2.get('ok'):
|
||||
print('FAIL attack set_role failed: %s' % json.dumps(r2))
|
||||
raise SystemExit(1)
|
||||
raise SystemExit(0 if assoc else 1)
|
||||
PYEOF
|
||||
)"
|
||||
rc=$?
|
||||
printf '%s\n' "$out" | sed 's/^/ /'
|
||||
if [ "$rc" -ne 0 ]; then
|
||||
fail 'role drill: uplink association failed (see detail above)'
|
||||
return
|
||||
fi
|
||||
hop="$(uci_get pineapd.wlan1mon.hop)"
|
||||
if [ "$hop" = "1" ]; then
|
||||
pass 'role drill: uplink assoc + attack role + hopping resumed'
|
||||
else
|
||||
fail "role drill: pineapd.wlan1mon.hop=$hop after attack role (want 1)"
|
||||
fi
|
||||
}
|
||||
|
||||
drill_watchdog() {
|
||||
WDOG="$REL/mk8-watchdog.sh"
|
||||
[ -f "$WDOG" ] || WDOG="$LEGACY/mk8-watchdog.sh"
|
||||
@@ -399,9 +475,12 @@ main() {
|
||||
if [ "$WRITE" = "1" ]; then
|
||||
if [ -z "$PY" ]; then
|
||||
fail 'drills: python3 required but not found'
|
||||
elif [ "$FAILED" -ne 0 ]; then
|
||||
skip 'drills: read-only checks failed; refusing drills'
|
||||
else
|
||||
printf -- '--- --write drills ---\n'
|
||||
drill_bad_values
|
||||
drill_role
|
||||
drill_watchdog
|
||||
fi
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user