103 lines
3.3 KiB
Bash
Executable File
103 lines
3.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage:
|
|
run_verification_only.sh \
|
|
--source-run-dir <run_dir> \
|
|
--source-state-root <state_dir> \
|
|
--out-dir <verification_dir> \
|
|
[--rpki-bin <path>] [--keep-scratch]
|
|
|
|
validation time is always read from the source CIR. The wrapper serializes access
|
|
with normal soak runs and never writes into the normal run sequence.
|
|
USAGE
|
|
}
|
|
|
|
SOURCE_RUN_DIR=""
|
|
SOURCE_STATE_ROOT=""
|
|
OUT_DIR=""
|
|
RPKI_BIN=""
|
|
KEEP_SCRATCH=0
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--source-run-dir) SOURCE_RUN_DIR="${2:?missing value}"; shift 2 ;;
|
|
--source-state-root) SOURCE_STATE_ROOT="${2:?missing value}"; shift 2 ;;
|
|
--out-dir) OUT_DIR="${2:?missing value}"; shift 2 ;;
|
|
--rpki-bin) RPKI_BIN="${2:?missing value}"; shift 2 ;;
|
|
--keep-scratch) KEEP_SCRATCH=1; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "unknown argument: $1" >&2; usage >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
[[ -n "$SOURCE_RUN_DIR" ]] || { echo "--source-run-dir is required" >&2; exit 2; }
|
|
[[ -n "$SOURCE_STATE_ROOT" ]] || { echo "--source-state-root is required" >&2; exit 2; }
|
|
[[ -n "$OUT_DIR" ]] || { echo "--out-dir is required" >&2; exit 2; }
|
|
if [[ -z "$RPKI_BIN" ]]; then
|
|
RPKI_BIN="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/target/release/rpki"
|
|
fi
|
|
[[ -x "$RPKI_BIN" ]] || { echo "rpki binary is not executable: $RPKI_BIN" >&2; exit 2; }
|
|
command -v flock >/dev/null || { echo "flock is required" >&2; exit 2; }
|
|
command -v python3 >/dev/null || { echo "python3 is required" >&2; exit 2; }
|
|
|
|
now_ms() {
|
|
python3 -c 'import time; print(time.time_ns() // 1_000_000)'
|
|
}
|
|
|
|
mkdir -p "$SOURCE_STATE_ROOT/locks" "$(dirname "$OUT_DIR")"
|
|
[[ ! -e "$OUT_DIR" ]] || { echo "verification output already exists: $OUT_DIR" >&2; exit 2; }
|
|
LOCK_PATH="$SOURCE_STATE_ROOT/locks/state-execution.lock"
|
|
STDOUT_TMP="${OUT_DIR}.stdout.tmp"
|
|
STDERR_TMP="${OUT_DIR}.stderr.tmp"
|
|
PROCESS_TIME_TMP="${OUT_DIR}.process-time.tmp"
|
|
WAIT_STARTED_MS="$(now_ms)"
|
|
exec {LOCK_FD}>"$LOCK_PATH"
|
|
flock "$LOCK_FD"
|
|
LOCK_ACQUIRED_MS="$(now_ms)"
|
|
|
|
ARGS=(
|
|
--verification-only
|
|
--verification-source-run "$SOURCE_RUN_DIR"
|
|
--verification-source-state "$SOURCE_STATE_ROOT"
|
|
--verification-out "$OUT_DIR"
|
|
)
|
|
if [[ "$KEEP_SCRATCH" -eq 1 ]]; then
|
|
ARGS+=(--keep-verification-scratch)
|
|
fi
|
|
|
|
set +e
|
|
if [[ -x /usr/bin/time ]]; then
|
|
RPKI_STATE_EXECUTION_LOCK_HELD=1 /usr/bin/time -v -o "$PROCESS_TIME_TMP" -- \
|
|
"$RPKI_BIN" "${ARGS[@]}" >"$STDOUT_TMP" 2>"$STDERR_TMP"
|
|
else
|
|
RPKI_STATE_EXECUTION_LOCK_HELD=1 "$RPKI_BIN" "${ARGS[@]}" >"$STDOUT_TMP" 2>"$STDERR_TMP"
|
|
fi
|
|
EXIT_CODE=$?
|
|
set -e
|
|
LOCK_RELEASED_MS="$(now_ms)"
|
|
flock -u "$LOCK_FD"
|
|
exec {LOCK_FD}>&-
|
|
|
|
mkdir -p "$OUT_DIR"
|
|
mv "$STDOUT_TMP" "$OUT_DIR/stdout.log"
|
|
mv "$STDERR_TMP" "$OUT_DIR/stderr.log"
|
|
if [[ -f "$PROCESS_TIME_TMP" ]]; then
|
|
mv "$PROCESS_TIME_TMP" "$OUT_DIR/process-time.txt"
|
|
fi
|
|
python3 - "$OUT_DIR/wrapper-timing.json" "$WAIT_STARTED_MS" "$LOCK_ACQUIRED_MS" "$LOCK_RELEASED_MS" "$EXIT_CODE" <<'PY'
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
path = Path(sys.argv[1])
|
|
wait_started_ms, lock_acquired_ms, lock_released_ms, exit_code = map(int, sys.argv[2:])
|
|
path.write_text(json.dumps({
|
|
"lockWaitMs": lock_acquired_ms - wait_started_ms,
|
|
"lockHeldMs": lock_released_ms - lock_acquired_ms,
|
|
"exitCode": exit_code,
|
|
}, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
|
PY
|
|
exit "$EXIT_CODE"
|