rpki/scripts/cir/run_cir_replay_rpki_client.sh

196 lines
5.8 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage:
./scripts/cir/run_cir_replay_rpki_client.sh \
--cir <path> \
[--static-root <path> | --raw-store-db <path>] \
--out-dir <path> \
--reference-ccr <path> \
--build-dir <path> \
[--keep-db] \
[--real-rsync-bin <path>]
EOF
}
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
CIR=""
STATIC_ROOT=""
POOL_DB=""
RAW_STORE_DB=""
OUT_DIR=""
REFERENCE_CCR=""
BUILD_DIR=""
KEEP_DB=0
REAL_RSYNC_BIN="${REAL_RSYNC_BIN:-/usr/bin/rsync}"
CIR_MATERIALIZE_BIN="$ROOT_DIR/target/release/cir_materialize"
CIR_EXTRACT_INPUTS_BIN="$ROOT_DIR/target/release/cir_extract_inputs"
CCR_TO_COMPARE_VIEWS_BIN="$ROOT_DIR/target/release/ccr_to_compare_views"
WRAPPER="$ROOT_DIR/scripts/cir/cir-rsync-wrapper"
while [[ $# -gt 0 ]]; do
case "$1" in
--cir) CIR="$2"; shift 2 ;;
--static-root) STATIC_ROOT="$2"; shift 2 ;;
--raw-store-db) RAW_STORE_DB="$2"; shift 2 ;;
--out-dir) OUT_DIR="$2"; shift 2 ;;
--reference-ccr) REFERENCE_CCR="$2"; shift 2 ;;
--build-dir) BUILD_DIR="$2"; shift 2 ;;
--keep-db) KEEP_DB=1; shift ;;
--real-rsync-bin) REAL_RSYNC_BIN="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) echo "unknown argument: $1" >&2; usage; exit 2 ;;
esac
done
[[ -n "$CIR" && -n "$OUT_DIR" && -n "$REFERENCE_CCR" && -n "$BUILD_DIR" ]] || {
usage >&2
exit 2
}
backend_count=0
[[ -n "$STATIC_ROOT" ]] && backend_count=$((backend_count+1))
[[ -n "$RAW_STORE_DB" ]] && backend_count=$((backend_count+1))
[[ "$backend_count" -eq 1 ]] || { usage >&2; exit 2; }
mkdir -p "$OUT_DIR"
if [[ ! -x "$CIR_MATERIALIZE_BIN" || ! -x "$CIR_EXTRACT_INPUTS_BIN" || ! -x "$CCR_TO_COMPARE_VIEWS_BIN" ]]; then
(
cd "$ROOT_DIR"
cargo build --release --bin cir_materialize --bin cir_extract_inputs --bin ccr_to_compare_views
)
fi
TMP_ROOT="$OUT_DIR/.tmp"
TALS_DIR="$TMP_ROOT/tals"
META_JSON="$TMP_ROOT/meta.json"
MIRROR_ROOT="$TMP_ROOT/mirror"
CACHE_DIR="$TMP_ROOT/cache"
OUT_CCR_DIR="$TMP_ROOT/out"
RUN_LOG="$OUT_DIR/rpki-client.log"
ACTUAL_VRPS="$OUT_DIR/actual-vrps.csv"
ACTUAL_VAPS="$OUT_DIR/actual-vaps.csv"
ACTUAL_VAPS_META="$OUT_DIR/actual-vaps-meta.json"
ACTUAL_VRPS_META="$OUT_DIR/actual-vrps-meta.json"
REF_VRPS="$OUT_DIR/reference-vrps.csv"
REF_VAPS="$OUT_DIR/reference-vaps.csv"
SUMMARY_JSON="$OUT_DIR/compare-summary.json"
rm -rf "$TMP_ROOT"
mkdir -p "$TMP_ROOT"
"$CIR_EXTRACT_INPUTS_BIN" --cir "$CIR" --tals-dir "$TALS_DIR" --meta-json "$META_JSON"
python3 - <<'PY' "$TALS_DIR"
from pathlib import Path
import sys
for tal in Path(sys.argv[1]).glob("*.tal"):
lines = tal.read_text(encoding="utf-8").splitlines()
rsync_uris = [line for line in lines if line.startswith("rsync://")]
base64_lines = []
seen_sep = False
for line in lines:
if seen_sep:
if line.strip():
base64_lines.append(line)
elif line.strip() == "":
seen_sep = True
tal.write_text("\n".join(rsync_uris) + "\n\n" + "\n".join(base64_lines) + "\n", encoding="utf-8")
PY
materialize_cmd=("$CIR_MATERIALIZE_BIN" --cir "$CIR" --mirror-root "$MIRROR_ROOT")
if [[ -n "$STATIC_ROOT" ]]; then
materialize_cmd+=(--static-root "$STATIC_ROOT")
else
materialize_cmd+=(--raw-store-db "$RAW_STORE_DB")
fi
if [[ "$KEEP_DB" -eq 1 ]]; then
materialize_cmd+=(--keep-db)
fi
"${materialize_cmd[@]}"
VALIDATION_EPOCH="$(python3 - <<'PY' "$META_JSON"
from datetime import datetime, timezone
import json, sys
vt = json.load(open(sys.argv[1]))["validationTime"]
dt = datetime.fromisoformat(vt.replace("Z", "+00:00")).astimezone(timezone.utc)
print(int(dt.timestamp()))
PY
)"
FIRST_TAL="$(python3 - <<'PY' "$META_JSON"
import json,sys
print(json.load(open(sys.argv[1]))["talFiles"][0]["path"])
PY
)"
TA_NAME="$(basename "$FIRST_TAL" .tal)"
export CIR_MIRROR_ROOT="$(python3 - <<'PY' "$MIRROR_ROOT"
from pathlib import Path
import sys
print(Path(sys.argv[1]).resolve())
PY
)"
export REAL_RSYNC_BIN="$REAL_RSYNC_BIN"
export CIR_LOCAL_LINK_MODE=1
mkdir -p "$CACHE_DIR" "$OUT_CCR_DIR"
"$BUILD_DIR/src/rpki-client" \
-R \
-e "$WRAPPER" \
-P "$VALIDATION_EPOCH" \
-t "$FIRST_TAL" \
-d "$CACHE_DIR" \
"$OUT_CCR_DIR" >"$RUN_LOG" 2>&1
"$CCR_TO_COMPARE_VIEWS_BIN" \
--ccr "$OUT_CCR_DIR/rpki.ccr" \
--vrps-out "$ACTUAL_VRPS" \
--vaps-out "$ACTUAL_VAPS" \
--trust-anchor "$TA_NAME"
python3 - <<'PY' "$ACTUAL_VRPS" "$ACTUAL_VAPS" "$ACTUAL_VRPS_META" "$ACTUAL_VAPS_META"
import csv, json, sys
def count_rows(path):
with open(path, newline="") as f:
rows = list(csv.reader(f))
return max(len(rows) - 1, 0)
json.dump({"count": count_rows(sys.argv[1])}, open(sys.argv[3], "w"), indent=2)
json.dump({"count": count_rows(sys.argv[2])}, open(sys.argv[4], "w"), indent=2)
PY
"$CCR_TO_COMPARE_VIEWS_BIN" --ccr "$REFERENCE_CCR" --vrps-out "$REF_VRPS" --vaps-out "$REF_VAPS" --trust-anchor "$TA_NAME"
python3 - <<'PY' "$ACTUAL_VRPS" "$REF_VRPS" "$ACTUAL_VAPS" "$REF_VAPS" "$SUMMARY_JSON"
import csv, json, sys
def rows(path):
with open(path, newline="") as f:
return list(csv.reader(f))[1:]
actual_vrps = {tuple(r) for r in rows(sys.argv[1])}
ref_vrps = {tuple(r) for r in rows(sys.argv[2])}
actual_vaps = {tuple(r) for r in rows(sys.argv[3])}
ref_vaps = {tuple(r) for r in rows(sys.argv[4])}
summary = {
"vrps": {
"actual": len(actual_vrps),
"reference": len(ref_vrps),
"match": actual_vrps == ref_vrps,
"only_in_actual": sorted(actual_vrps - ref_vrps)[:20],
"only_in_reference": sorted(ref_vrps - actual_vrps)[:20],
},
"vaps": {
"actual": len(actual_vaps),
"reference": len(ref_vaps),
"match": actual_vaps == ref_vaps,
"only_in_actual": sorted(actual_vaps - ref_vaps)[:20],
"only_in_reference": sorted(ref_vaps - actual_vaps)[:20],
}
}
with open(sys.argv[5], "w") as f:
json.dump(summary, f, indent=2)
PY
if [[ "$KEEP_DB" -ne 1 ]]; then
rm -rf "$TMP_ROOT"
fi
echo "done: $OUT_DIR"