rpki/scripts/payload_replay/multi_rir_case_info.py
yuyr 557a69cbd2 20260316迭代 增加delta replay以及multi-rir
replay 对比,五个RIR 输出vrp与routinator一致
2026-03-16 22:54:48 +08:00

159 lines
6.0 KiB
Python
Executable File

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import shlex
import sys
from pathlib import Path
RIR_CONFIG = {
"afrinic": {
"tal": "tests/fixtures/tal/afrinic.tal",
"ta": "tests/fixtures/ta/afrinic-ta.cer",
"trust_anchor": "afrinic",
},
"apnic": {
"tal": "tests/fixtures/tal/apnic-rfc7730-https.tal",
"ta": "tests/fixtures/ta/apnic-ta.cer",
"trust_anchor": "apnic",
},
"arin": {
"tal": "tests/fixtures/tal/arin.tal",
"ta": "tests/fixtures/ta/arin-ta.cer",
"trust_anchor": "arin",
},
"lacnic": {
"tal": "tests/fixtures/tal/lacnic.tal",
"ta": "tests/fixtures/ta/lacnic-ta.cer",
"trust_anchor": "lacnic",
},
"ripe": {
"tal": "tests/fixtures/tal/ripe-ncc.tal",
"ta": "tests/fixtures/ta/ripe-ncc-ta.cer",
"trust_anchor": "ripe",
},
}
def default_repo_root() -> Path:
return Path(__file__).resolve().parents[2]
def default_bundle_root(repo_root: Path) -> Path:
return (repo_root / "../../rpki/target/live/20260316-112341-multi-final3").resolve()
def require_path(path: Path, kind: str) -> Path:
if kind == "dir" and not path.is_dir():
raise SystemExit(f"missing directory: {path}")
if kind == "file" and not path.is_file():
raise SystemExit(f"missing file: {path}")
return path
def load_timing_summary(bundle_root: Path) -> dict:
timing_path = require_path(bundle_root / "timing-summary.json", "file")
return json.loads(timing_path.read_text(encoding="utf-8"))
def build_case(bundle_root: Path, repo_root: Path, rir: str) -> dict:
if rir not in RIR_CONFIG:
raise SystemExit(
f"unsupported rir: {rir}; expected one of: {', '.join(sorted(RIR_CONFIG))}"
)
rir_root = require_path(bundle_root / rir, "dir")
cfg = RIR_CONFIG[rir]
timing_summary = load_timing_summary(bundle_root)
if rir not in timing_summary:
raise SystemExit(f"timing-summary.json missing entry for rir: {rir}")
timing_entry = timing_summary[rir]
durations = timing_entry.get("durations") or {}
base_timing = require_path(rir_root / "timings" / "base-replay.json", "file")
delta_timing = require_path(rir_root / "timings" / "delta-replay.json", "file")
base_timing_obj = json.loads(base_timing.read_text(encoding="utf-8"))
delta_timing_obj = json.loads(delta_timing.read_text(encoding="utf-8"))
case = {
"bundle_root": str(bundle_root),
"repo_root": str(repo_root),
"rir": rir,
"trust_anchor": cfg["trust_anchor"],
"rir_root": str(rir_root),
"base_archive": str(require_path(rir_root / "base-payload-archive", "dir")),
"base_locks": str(require_path(rir_root / "base-locks.json", "file")),
"base_vrps_csv": str(require_path(rir_root / "base-vrps.csv", "file")),
"delta_archive": str(require_path(rir_root / "payload-delta-archive", "dir")),
"delta_locks": str(require_path(rir_root / "locks-delta.json", "file")),
"delta_record_csv": str(require_path(rir_root / "record-delta.csv", "file")),
"replay_delta_csv": str(require_path(rir_root / "replay-delta.csv", "file")),
"verification_json": str(require_path(rir_root / "verification.json", "file")),
"readme": str(require_path(rir_root / "README.md", "file")),
"timings_dir": str(require_path(rir_root / "timings", "dir")),
"base_timing_json": str(base_timing),
"delta_timing_json": str(delta_timing),
"tal_path": str(require_path(repo_root / cfg["tal"], "file")),
"ta_path": str(require_path(repo_root / cfg["ta"], "file")),
"validation_times": {
"snapshot": base_timing_obj["startedAt"],
"delta": delta_timing_obj["startedAt"],
},
"routinator_timings": {
"base_replay_seconds": float(durations["base-replay"]),
"delta_replay_seconds": float(durations["delta-replay"]),
},
}
return case
def emit_env(case: dict) -> str:
ordered = {
"BUNDLE_ROOT": case["bundle_root"],
"RIR": case["rir"],
"TRUST_ANCHOR": case["trust_anchor"],
"RIR_ROOT": case["rir_root"],
"TAL_PATH": case["tal_path"],
"TA_PATH": case["ta_path"],
"PAYLOAD_REPLAY_ARCHIVE": case["base_archive"],
"PAYLOAD_REPLAY_LOCKS": case["base_locks"],
"ROUTINATOR_BASE_RECORD_CSV": case["base_vrps_csv"],
"PAYLOAD_BASE_ARCHIVE": case["base_archive"],
"PAYLOAD_BASE_LOCKS": case["base_locks"],
"PAYLOAD_DELTA_ARCHIVE": case["delta_archive"],
"PAYLOAD_DELTA_LOCKS": case["delta_locks"],
"ROUTINATOR_DELTA_RECORD_CSV": case["delta_record_csv"],
"SNAPSHOT_VALIDATION_TIME": case["validation_times"]["snapshot"],
"DELTA_VALIDATION_TIME": case["validation_times"]["delta"],
"ROUTINATOR_BASE_REPLAY_SECONDS": str(case["routinator_timings"]["base_replay_seconds"]),
"ROUTINATOR_DELTA_REPLAY_SECONDS": str(case["routinator_timings"]["delta_replay_seconds"]),
}
return "\n".join(
f"export {key}={shlex.quote(value)}" for key, value in ordered.items()
)
def main() -> int:
parser = argparse.ArgumentParser(description="Resolve one RIR case inside a multi-RIR replay bundle")
parser.add_argument("--bundle-root", type=Path, default=None)
parser.add_argument("--repo-root", type=Path, default=None)
parser.add_argument("--rir", required=True, choices=sorted(RIR_CONFIG))
parser.add_argument("--format", choices=["json", "env"], default="json")
args = parser.parse_args()
repo_root = (args.repo_root or default_repo_root()).resolve()
bundle_root = (args.bundle_root or default_bundle_root(repo_root)).resolve()
case = build_case(bundle_root, repo_root, args.rir)
if args.format == "env":
print(emit_env(case))
else:
print(json.dumps(case, ensure_ascii=False, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())