Files
Hyungi Ahn d47c04317c feat(infra): Phase 1.5 진단 도구 3개 + trace 정리
scheduler_status, queue_status, run_verify 추가.
MCP 10개 도구 + NanoClaude wrapper + pre-route 키워드.
worker.py trace print 제거.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:27:19 +09:00

74 lines
2.4 KiB
Python

"""Run predefined verify commands from infra_inventory.md."""
from __future__ import annotations
from datetime import datetime, timezone
from ..config import HOSTS
from .ssh import run_command, run_local, SSHError, _is_local_host
def _now() -> str:
return datetime.now(timezone.utc).isoformat()
# Predefined verify commands (from infra_inventory.md)
VERIFY_COMMANDS = {
"gpu-snapshot": {
"host": "gpu",
"cmd": "docker compose ls 2>/dev/null; echo '---'; ollama list 2>/dev/null; echo '---'; pgrep -af 'Plex Media' | head -1 2>/dev/null",
"desc": "GPU 서버 전체 스냅샷 (docker, ollama, plex)",
},
"macmini-snapshot": {
"host": "macmini",
"cmd": "bash -lc 'launchctl list | grep com.user; curl -s localhost:8800/v1/models 2>/dev/null | python3 -m json.tool 2>/dev/null; ollama list 2>/dev/null'",
"desc": "Mac mini 전체 스냅샷 (launchd, MLX, ollama)",
},
"docserver-health": {
"host": "gpu",
"cmd": "curl -sf http://localhost:8000/health",
"desc": "Document Server 헬스체크",
},
"config-model-match": {
"host": "gpu",
"cmd": "grep -E 'model:' ~/Documents/code/hyungi_Document_Server/config.yaml 2>/dev/null; echo '---'; ollama list 2>/dev/null",
"desc": "config.yaml 모델과 실제 설치 모델 비교",
},
}
async def run_verify(check_name: str) -> dict:
"""Run a predefined verify command."""
if check_name not in VERIFY_COMMANDS:
available = ", ".join(VERIFY_COMMANDS.keys())
return {
"ok": False, "checked_at": _now(),
"error_type": "parse_error",
"error": f"알 수 없는 체크: '{check_name}'. 사용 가능: {available}",
"data": [], "summary": "", "raw": "",
}
spec = VERIFY_COMMANDS[check_name]
cfg = HOSTS[spec["host"]]
try:
if _is_local_host(cfg):
stdout, _ = await run_local(spec["cmd"], timeout=15)
else:
stdout, _ = await run_command(cfg, spec["cmd"], timeout=15)
except SSHError as e:
return {
"ok": False, "checked_at": _now(),
"error_type": e.error_type, "error": str(e),
"data": [], "summary": spec["desc"], "raw": "",
}
return {
"ok": True,
"checked_at": _now(),
"data": stdout.strip().splitlines(),
"summary": spec["desc"],
"error": "",
"raw": stdout.strip(),
}