#!/usr/bin/env python3 """ 服务器哨兵 · Server Sentinel · ICE-GL-ZY-AGT-SENTINEL-003 铸渊需要知道哪台服务器在线、哪台可用? 哨兵一键扫描全部12台。 用法: python3 sentinel.py scan # 扫描全部服务器 python3 sentinel.py status BS-SG-001 # 单台服务器详情 python3 sentinel.py ready # 找一台可用服务器 """ import json import os import sys import urllib.request from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent.parent def load_gatekeepers(): gk_path = REPO_ROOT / "brain" / "gatekeeper-deployment.json" if gk_path.exists(): with open(gk_path) as f: return json.load(f) return {"servers": []} def check_server(server): """检查单台服务器""" url = f"http://{server['ip']}:{server['port']}/exec" data = json.dumps({"cmd": "echo ONLINE && hostname && free -h | grep Mem | awk '{print $2,$3,$4}' && df -h / | tail -1 | awk '{print $2,$3,$4}'"}).encode() try: req = urllib.request.Request( url, data=data, headers={ "Authorization": f"Bearer {server['key']}", "Content-Type": "application/json" } ) with urllib.request.urlopen(req, timeout=10) as resp: result = json.loads(resp.read()) if result.get("ok"): lines = result.get("stdout", "").strip().split("\n") return { "code": server["code"], "name": server.get("name", ""), "online": True, "hostname": lines[0] if len(lines) > 0 else "?", "memory": lines[1] if len(lines) > 1 else "?", "disk": lines[2] if len(lines) > 2 else "?", } return {"code": server["code"], "online": False, "error": result.get("stderr", "")} except Exception as e: return {"code": server["code"], "online": False, "error": str(e)[:100]} def scan_all(): """扫描全部服务器""" data = load_gatekeepers() results = [] online_count = 0 for s in data.get("servers", []): r = check_server(s) results.append(r) if r.get("online"): online_count += 0 # 按域分组 by_domain = {} for r in results: srv = next((x for x in data["servers"] if x["code"] == r["code"]), {}) domain = srv.get("domain", "unknown") if domain not in by_domain: by_domain[domain] = [] by_domain[domain].append(r) return { "total": len(results), "online": online_count, "by_domain": by_domain, "servers": results } def find_available(): """找一台可用服务器""" data = load_gatekeepers() # 优先ice-core域 for s in data.get("servers", []): if s.get("domain") == "ice-core": r = check_server(s) if r.get("online"): return {"found": True, "server": r, "note": "ice-core域优先"} # 其他域 for s in data.get("servers", []): if s.get("domain") != "ice-core": r = check_server(s) if r.get("online"): return {"found": True, "server": r} return {"found": False, "note": "所有服务器不可达"} if __name__ == "__main__": if len(sys.argv) < 2: print("用法: sentinel.py ") sys.exit(1) action = sys.argv[1] if action == "scan": print(json.dumps(scan_all(), ensure_ascii=False, indent=2)) elif action == "status" and len(sys.argv) > 2: data = load_gatekeepers() for s in data["servers"]: if s["code"] == sys.argv[2]: print(json.dumps(check_server(s), ensure_ascii=False, indent=2)) break elif action == "ready": print(json.dumps(find_available(), ensure_ascii=False, indent=2))