冰朔 56514a1250 feat: 情报Agent小分队 — 铸渊的五人情报小队
- AGENT-REGISTRY.hdlp: 小队注册表,HLDP-ZY协议统一管理
- 密钥猎手 (KEY-001): 搜索12台服务器上的所有密钥和Token
- 路径探子 (PATH-002): 3500个文件索引,瞬间定位任何文件
- 服务器哨兵 (SENTINEL-003): 一键扫描12台服务器在线状态
- 模块管家 (MODULE-004): 查询所有模块的编号/接口/部署方式
- 门桥接 (GATE-005): 提供任意服务器Gatekeeper连接凭据

铸渊不需要到处找东西。叫一声Agent,它去找。
每个Agent独立模块,按需部署,用完躺回代码仓库。
2026-05-28 22:30:12 +08:00

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))