148 lines
5.3 KiB
Bash
Executable file
148 lines
5.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
REPO_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
TEMPLATE="${TEMPLATE:-browser}"
|
|
SNAPSHOT="${SNAPSHOT:-}"
|
|
DATASET_BASE="${DATASET_BASE:-zroot/clawdie-runtime/jails}"
|
|
JAILS_DIR="${JAILS_DIR:-/usr/local/bastille/jails}"
|
|
CYCLES="${CYCLES:-3}"
|
|
COOKIE="${VALIDATION_COOKIE:-phase06-cookie}"
|
|
RESULT_DIR="${RESULT_DIR:-${REPO_DIR}/tmp/browser-jail-clone-validation}"
|
|
RESULT_JSONL="${RESULT_JSONL:-${RESULT_DIR}/results.jsonl}"
|
|
|
|
if [ -z "$SNAPSHOT" ]; then
|
|
echo "SNAPSHOT is required, e.g. SNAPSHOT=pre-injection-11.maj.2026-1430" >&2
|
|
exit 2
|
|
fi
|
|
|
|
mkdir -p "$RESULT_DIR"
|
|
: > "$RESULT_JSONL"
|
|
|
|
now_ms() {
|
|
python3 -c 'import time; print(int(time.time() * 1000))'
|
|
}
|
|
|
|
json_escape() {
|
|
python3 -c 'import json,sys; print(json.dumps(sys.stdin.read())[1:-1])'
|
|
}
|
|
|
|
emit_json() {
|
|
local cycle="$1"
|
|
local clone="$2"
|
|
local ip="$3"
|
|
local clone_ms="$4"
|
|
local start_ms="$5"
|
|
local chrome_ms="$6"
|
|
local smoke_ms="$7"
|
|
local destroy_ms="$8"
|
|
local status="$9"
|
|
local note="${10:-}"
|
|
local escaped_note
|
|
escaped_note="$(printf '%s' "$note" | json_escape)"
|
|
printf '{"cycle":%s,"clone":"%s","ip":"%s","clone_ms":%s,"start_ms":%s,"chrome_ready_ms":%s,"smoke_ms":%s,"destroy_ms":%s,"status":"%s","note":"%s"}\n' \
|
|
"$cycle" "$clone" "$ip" "$clone_ms" "$start_ms" "$chrome_ms" "$smoke_ms" "$destroy_ms" "$status" "$escaped_note" >> "$RESULT_JSONL"
|
|
}
|
|
|
|
patch_clone_config() {
|
|
local clone="$1"
|
|
local suffix="$2"
|
|
local ip="$3"
|
|
python3 - "$clone" "$suffix" "$ip" "$JAILS_DIR" "$TEMPLATE" <<'PY'
|
|
from pathlib import Path
|
|
import sys
|
|
clone, suffix, ip, jails_dir, template = sys.argv[1:]
|
|
base = Path(jails_dir) / clone
|
|
jail_conf = base / 'jail.conf'
|
|
text = jail_conf.read_text()
|
|
text = text.replace(f'{template} {{', f'{clone} {{')
|
|
text = text.replace(f'/var/log/bastille/{template}_console.log', f'/var/log/bastille/{clone}_console.log')
|
|
text = text.replace(f'{jails_dir}/{template}/fstab', f'{jails_dir}/{clone}/fstab')
|
|
text = text.replace(f'{jails_dir}/{template}/root', f'{jails_dir}/{clone}/root')
|
|
text = text.replace(f'e0b_{template}', f'e0b_{suffix}')
|
|
text = text.replace(f'e0a_{template}', f'e0a_{suffix}')
|
|
text = text.replace(f'jail {template}', f'jail {clone}')
|
|
jail_conf.write_text(text)
|
|
|
|
fstab = base / 'fstab'
|
|
fstab_text = fstab.read_text().replace(f'{jails_dir}/{template}/', f'{jails_dir}/{clone}/')
|
|
fstab.write_text(fstab_text)
|
|
|
|
rc = base / 'root/etc/rc.conf'
|
|
rc_text = rc.read_text()
|
|
rc_text = rc_text.replace(f'ifconfig_e0b_{template}_name', f'ifconfig_e0b_{suffix}_name')
|
|
rc_text = rc_text.replace('inet 192.168.72.6/24', f'inet {ip}/24')
|
|
rc.write_text(rc_text)
|
|
PY
|
|
}
|
|
|
|
cleanup_clone() {
|
|
local clone="$1"
|
|
local suffix="$2"
|
|
bastille cmd "$clone" sh -c 'if [ -f /var/run/browser-validation-chromium.pid ]; then kill -TERM "$(cat /var/run/browser-validation-chromium.pid)" 2>/dev/null || true; fi' >/dev/null 2>&1 || true
|
|
bastille stop "$clone" >/dev/null 2>&1 || true
|
|
ifconfig "e0a_${suffix}" destroy >/dev/null 2>&1 || true
|
|
zfs destroy -r "${DATASET_BASE}/${clone}" >/dev/null 2>&1 || true
|
|
}
|
|
|
|
wait_for_cdp() {
|
|
local clone="$1"
|
|
local attempt
|
|
for attempt in $(seq 1 30); do
|
|
if bastille cmd "$clone" fetch -qo - http://127.0.0.1:9222/json/version >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
done
|
|
return 1
|
|
}
|
|
|
|
for cycle in $(seq 1 "$CYCLES"); do
|
|
clone="browsertask$(printf '%03d' "$cycle")"
|
|
suffix="bt$(printf '%03d' "$cycle")"
|
|
ip="192.168.72.$((159 + cycle))"
|
|
clone_ms=0
|
|
start_ms=0
|
|
chrome_ms=0
|
|
smoke_ms=0
|
|
destroy_ms=0
|
|
status="ok"
|
|
note=""
|
|
|
|
cleanup_clone "$clone" "$suffix"
|
|
|
|
start=$(now_ms)
|
|
zfs clone -o mountpoint="${JAILS_DIR}/${clone}" "${DATASET_BASE}/${TEMPLATE}@${SNAPSHOT}" "${DATASET_BASE}/${clone}"
|
|
zfs clone -o mountpoint="${JAILS_DIR}/${clone}/root" "${DATASET_BASE}/${TEMPLATE}/root@${SNAPSHOT}" "${DATASET_BASE}/${clone}/root"
|
|
patch_clone_config "$clone" "$suffix" "$ip"
|
|
end=$(now_ms)
|
|
clone_ms=$((end - start))
|
|
|
|
start=$(now_ms)
|
|
bastille start "$clone"
|
|
end=$(now_ms)
|
|
start_ms=$((end - start))
|
|
|
|
start=$(now_ms)
|
|
bastille cmd "$clone" sh -c 'nohup /usr/local/bin/chrome --headless=new --no-sandbox --disable-gpu --password-store=basic --remote-debugging-address=127.0.0.1 --remote-debugging-port=9222 --user-data-dir=/var/db/browser-profile-basic about:blank >/var/log/browser-validation-chromium.log 2>&1 & echo $! >/var/run/browser-validation-chromium.pid'
|
|
wait_for_cdp "$clone"
|
|
end=$(now_ms)
|
|
chrome_ms=$((end - start))
|
|
|
|
start=$(now_ms)
|
|
bastille cmd "$clone" sh -c "cd /opt/browser-validation && VALIDATION_COOKIE=${COOKIE} SCREENSHOT_PATH=/var/tmp/${clone}-smoke.png node clone-smoke.mjs"
|
|
end=$(now_ms)
|
|
smoke_ms=$((end - start))
|
|
|
|
start=$(now_ms)
|
|
bastille cmd "$clone" sh -c 'if [ -f /var/run/browser-validation-chromium.pid ]; then kill -TERM "$(cat /var/run/browser-validation-chromium.pid)" 2>/dev/null || true; fi; for i in 1 2 3 4 5; do pgrep chrome >/dev/null 2>&1 || exit 0; sleep 1; done; if [ -f /var/run/browser-validation-chromium.pid ]; then kill -KILL "$(cat /var/run/browser-validation-chromium.pid)" 2>/dev/null || true; fi' >/dev/null 2>&1 || true
|
|
bastille stop "$clone"
|
|
ifconfig "e0a_${suffix}" destroy >/dev/null 2>&1 || true
|
|
zfs destroy -r "${DATASET_BASE}/${clone}"
|
|
end=$(now_ms)
|
|
destroy_ms=$((end - start))
|
|
|
|
emit_json "$cycle" "$clone" "$ip" "$clone_ms" "$start_ms" "$chrome_ms" "$smoke_ms" "$destroy_ms" "$status" "$note"
|
|
done
|
|
|
|
printf 'results=%s\n' "$RESULT_JSONL"
|