from __future__ import annotations import argparse import datetime as dt import json import socket import subprocess import sys from pathlib import Path from typing import Any ROOT = Path(__file__).resolve().parents[1] DEFAULT_REPORT = ROOT / "reports" / "platform-status.json" DEFAULT_DOCKER_HOST = "ssh://docker-gpu" MODEL_CHAT_CONTAINER = "llm-model-chat-ui" def run_json(command: list[str], timeout: int = 60) -> dict[str, Any]: result = subprocess.run( command, cwd=ROOT, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout, check=False, ) payload = None if result.stdout.strip().startswith("{"): try: payload = json.loads(result.stdout) except json.JSONDecodeError: payload = None return { "command": command, "status": "ok" if result.returncode == 0 else "failed", "returncode": result.returncode, "stdout": result.stdout.strip(), "stderr": result.stderr.strip(), "json": payload, } def read_report(path: Path) -> dict[str, Any] | None: if not path.exists(): return None try: with path.open("r", encoding="utf-8") as handle: data = json.load(handle) return data if isinstance(data, dict) else None except json.JSONDecodeError: return None def is_port_open(host: str, port: int, timeout: float = 1.0) -> bool: try: with socket.create_connection((host, port), timeout=timeout): return True except OSError: return False def deployed_model_storage(docker_host: str) -> dict[str, Any]: return run_json( [ "docker", "-H", docker_host, "exec", MODEL_CHAT_CONTAINER, "python3", "scripts/check_model_storage.py", "--models-root", "/models", "--print", "--no-report", "--warn-only", ], timeout=90, ) def main() -> int: parser = argparse.ArgumentParser(description="Collect local platform status into one report.") parser.add_argument("--report", type=Path, default=DEFAULT_REPORT) parser.add_argument("--print", action="store_true") parser.add_argument("--check-endpoints", action="store_true", help="Run GPU readiness check with network timeouts.") parser.add_argument("--docker-host", default=DEFAULT_DOCKER_HOST, help="Docker endpoint for deployed GPU checks.") parser.add_argument( "--skip-deployed-storage", action="store_true", help="Skip model storage check inside the deployed model-chat container.", ) args = parser.parse_args() model_storage = run_json( [sys.executable, "scripts/check_model_storage.py", "--print", "--no-report", "--warn-only"], timeout=60, ) if model_storage.get("json", {}).get("status") == "failed": model_storage["status"] = "blocked" checks = { "model_cards": run_json([sys.executable, "scripts/validate_model_cards.py"], timeout=30), "eval_files": run_json([sys.executable, "scripts/validate_evals.py"], timeout=30), "model_storage": model_storage, "deployed_model_storage": None if args.skip_deployed_storage else deployed_model_storage(args.docker_host), "1c_plugin": run_json([sys.executable, "scripts/check_1c_plugin.py", "--no-report"], timeout=60), "model_chat": { "status": "ok" if is_port_open("127.0.0.1", 8765) else "stopped", "url": "http://127.0.0.1:8765", }, "gpu_readiness": read_report(ROOT / "reports" / "gpu-readiness.json"), "live_model_evals": read_report(ROOT / "reports" / "evals" / "live-model-evals.json"), } if args.check_endpoints: checks["gpu_readiness"] = run_json( [sys.executable, "scripts/check_gpu_readiness.py", "--print", "--timeout", "8"], timeout=45, ).get("json") if isinstance(checks["gpu_readiness"], dict) and checks["gpu_readiness"].get("status") == "failed": checks["gpu_readiness"]["status"] = "blocked" failed = [] blocked = [] for name, check in checks.items(): if not check: if name != "deployed_model_storage": blocked.append(name) continue status = check.get("status") if status == "failed": failed.append(name) elif status in {"blocked", "stopped"}: blocked.append(name) report = { "created_at": dt.datetime.now(dt.UTC).isoformat(), "status": "failed" if failed else "blocked" if blocked else "ok", "failed": failed, "blocked": blocked, "checks": checks, } args.report.parent.mkdir(parents=True, exist_ok=True) args.report.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") if args.print: print(json.dumps(report, ensure_ascii=False, indent=2)) else: print(f"Platform status: {report['status']}") print(f"Wrote report to {args.report}") return 1 if failed else 0 if __name__ == "__main__": raise SystemExit(main())