mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-31 16:34:49 +00:00
136 lines
4.8 KiB
Bash
Executable File
136 lines
4.8 KiB
Bash
Executable File
#!/bin/sh
|
|
# node-reset_test.sh — tests the QEMU process match node-reset.sh uses to stop
|
|
# guests before it deletes Viperblock state, against real processes, and the
|
|
# instance and mounted-volume counts it and uninstall-spx.sh report before deleting.
|
|
#
|
|
# Each fake guest is a copy of sleep named like a QEMU binary, so the kernel
|
|
# gives it the same comm, including the 15-character truncation.
|
|
set -eu
|
|
|
|
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
|
|
TMP=$(mktemp -d)
|
|
pids=""
|
|
cleanup() {
|
|
for pid in $pids; do kill "$pid" 2>/dev/null || true; done
|
|
rm -rf "$TMP"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
fails=0
|
|
pass() { echo " ok - $1"; }
|
|
fail() { echo " FAIL - $1"; fails=$((fails + 1)); }
|
|
|
|
echo "-- node-reset.sh QEMU process match"
|
|
|
|
# pattern_in <script> — the pgrep pattern the script assigns to QEMU_PGREP.
|
|
pattern_in() {
|
|
sed -n "s/^QEMU_PGREP=('\(.*\)')$/\1/p" "$1"
|
|
}
|
|
|
|
PATTERN=$(pattern_in "$SCRIPT_DIR/node-reset.sh")
|
|
if [ -z "$PATTERN" ]; then
|
|
echo " FAIL - no QEMU_PGREP=('...') line in node-reset.sh"
|
|
exit 1
|
|
fi
|
|
|
|
# reset-dev-env.sh stops guests the same way and must not drift from it.
|
|
dev_pattern=$(pattern_in "$SCRIPT_DIR/reset-dev-env.sh")
|
|
if [ "$dev_pattern" = "$PATTERN" ]; then
|
|
pass "reset-dev-env.sh uses node-reset.sh's pattern"
|
|
else
|
|
fail "reset-dev-env.sh pattern '$dev_pattern' differs from node-reset.sh's '$PATTERN'"
|
|
fi
|
|
|
|
# start <name> — runs a process whose comm is <name>, truncated to 15
|
|
# characters. Its PID is left in $!.
|
|
start() {
|
|
cp "$(command -v sleep)" "$TMP/$1"
|
|
"$TMP/$1" 300 &
|
|
pids="$pids $!"
|
|
}
|
|
start qemu-system-x86_64; pid_x86=$!
|
|
start qemu-system-aarch64; pid_arm=$!
|
|
start qemu-kvm; pid_kvm=$!
|
|
start qemu-img; pid_img=$!
|
|
start qemu-kvm-helper; pid_helper=$!
|
|
|
|
me=$(id -un)
|
|
found=" $(pgrep -u "$me" "$PATTERN" | tr '\n' ' ' || true) "
|
|
|
|
check_found() {
|
|
case "$found" in
|
|
*" $2 "*) pass "finds a $1 guest owned by the service user" ;;
|
|
*) fail "misses a $1 guest (pid $2) owned by the service user" ;;
|
|
esac
|
|
}
|
|
check_found qemu-system-x86_64 "$pid_x86"
|
|
check_found qemu-system-aarch64 "$pid_arm"
|
|
check_found qemu-kvm "$pid_kvm"
|
|
|
|
check_ignored() {
|
|
case "$found" in
|
|
*" $2 "*) fail "matches $1 (pid $2), which is not a guest" ;;
|
|
*) pass "ignores $1" ;;
|
|
esac
|
|
}
|
|
check_ignored qemu-img "$pid_img"
|
|
check_ignored qemu-kvm-helper "$pid_helper"
|
|
|
|
# The owner scope: the same guests, asked for as another user, are not found.
|
|
other=root
|
|
[ "$me" = root ] && other=nobody
|
|
other_found=" $(pgrep -u "$other" "$PATTERN" | tr '\n' ' ' || true) "
|
|
case "$other_found" in
|
|
*" $pid_kvm "* | *" $pid_x86 "*) fail "a scope of -u $other still matches guests owned by $me" ;;
|
|
*) pass "ignores guests owned by another user" ;;
|
|
esac
|
|
|
|
echo "-- node-reset.sh and uninstall-spx.sh at-stake counts"
|
|
|
|
# counts_in <script> — the shared count helpers, between their markers.
|
|
counts_in() {
|
|
sed -n '/^# --- BEGIN at-stake counts ---$/,/^# --- END at-stake counts ---$/p' "$1"
|
|
}
|
|
counts_in "$SCRIPT_DIR/node-reset.sh" > "$TMP/counts.sh"
|
|
if [ ! -s "$TMP/counts.sh" ]; then
|
|
fail "no at-stake counts block in node-reset.sh"
|
|
elif counts_in "$SCRIPT_DIR/uninstall-spx.sh" | cmp -s - "$TMP/counts.sh"; then
|
|
pass "uninstall-spx.sh carries node-reset.sh's count helpers"
|
|
else
|
|
fail "uninstall-spx.sh's count helpers differ from node-reset.sh's"
|
|
fi
|
|
|
|
# count <fn> <data dir> — runs a helper with sudo as a no-op, as root would.
|
|
count() {
|
|
bash -c 'sudo() { "$@"; }; . "$1"; "$2" "$3"' _ "$TMP/counts.sh" "$1" "$2"
|
|
}
|
|
expect() {
|
|
if [ "$2" = "$3" ]; then pass "$1"; else fail "$1: got '$2', want '$3'"; fi
|
|
}
|
|
|
|
# The layout a node with three guests has: one volume with its EFI store, an
|
|
# AMI, and the system instances' records, which have no volume of their own.
|
|
data="$TMP/data"
|
|
mkdir -p "$data/state" "$data/viperblock/vol-a" "$data/viperblock/vol-a-efi" \
|
|
"$data/viperblock/vol-b" "$data/viperblock/ami-c" "$data/volumes"
|
|
: > "$data/viperblock/viperblock.pid"
|
|
printf '{"schema_version":1,"vms":{"i-1":{},"i-2":{},"i-3":{}}}' > "$data/state/instance-state.json"
|
|
if command -v jq >/dev/null 2>&1; then
|
|
expect "counts each instance in the local state file" "$(count count_instances "$data")" 3
|
|
printf '{"schema_version":1,"vms":{' > "$data/state/instance-state.json"
|
|
expect "reports an unreadable state file as unknown, not 0" "$(count count_instances "$data")" unknown
|
|
else
|
|
echo " skip - jq is not installed; the instance counts need it"
|
|
fi
|
|
expect "counts mounted volumes, not EFI stores or AMIs" "$(count count_mounted_volumes "$data")" 2
|
|
|
|
empty="$TMP/empty"
|
|
mkdir -p "$empty"
|
|
expect "counts no instances without a state file" "$(count count_instances "$empty")" 0
|
|
expect "counts no mounted volumes without a viperblock directory" "$(count count_mounted_volumes "$empty")" 0
|
|
|
|
if [ "$fails" -gt 0 ]; then
|
|
echo "$fails failure(s)"
|
|
exit 1
|
|
fi
|