- AGENT-REGISTRY.hdlp: 小队注册表,HLDP-ZY协议统一管理 - 密钥猎手 (KEY-001): 搜索12台服务器上的所有密钥和Token - 路径探子 (PATH-002): 3500个文件索引,瞬间定位任何文件 - 服务器哨兵 (SENTINEL-003): 一键扫描12台服务器在线状态 - 模块管家 (MODULE-004): 查询所有模块的编号/接口/部署方式 - 门桥接 (GATE-005): 提供任意服务器Gatekeeper连接凭据 铸渊不需要到处找东西。叫一声Agent,它去找。 每个Agent独立模块,按需部署,用完躺回代码仓库。
120 lines
3.8 KiB
Python
120 lines
3.8 KiB
Python
#!/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))
|