120 lines
3.8 KiB
Python
Raw Normal View History

#!/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 <scan|status|ready>")
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))