"""Per-node agent (CLI: `daisychain-agent`). Serves health/resources/status so the dashboard can scan this machine. Pure stdlib.""" import json import os import socket from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer try: from daisychain.cluster import survey_node except Exception: def survey_node(cpu_fraction=0.9): cores = int(os.environ.get("DAISY_CORES", os.cpu_count() or 1)) return {"host": socket.gethostname(), "cores": cores, "threads": max(1, int(cores * cpu_fraction)), "ram_gb": None, "device": "cpu", "gpu": None, "capacity": cores} RANK = int(os.environ.get("RANK", "0")) STATUS_FILE = os.environ.get("DAISY_STATUS_FILE", "status.json") PORT = int(os.environ.get("DAISY_AGENT_PORT", "8900")) def _status(): try: with open(STATUS_FILE) as f: return json.load(f) except Exception: return {} class Handler(BaseHTTPRequestHandler): def _send(self, obj, code=200): body = json.dumps(obj).encode() self.send_response(code) self.send_header("Content-Type", "application/json") self.send_header("Access-Control-Allow-Origin", "*") self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) def do_GET(self): if self.path.startswith("/health"): self._send({"ok": True, "rank": RANK, "host": socket.gethostname()}) elif self.path.startswith("/resources"): r = survey_node(); r["rank"] = RANK; self._send(r) elif self.path.startswith("/status"): self._send(_status()) else: self._send({"error": "not found"}, 404) def log_message(self, *a): pass def main(): print(f"[agent] rank {RANK} on :{PORT}", flush=True) ThreadingHTTPServer(("0.0.0.0", PORT), Handler).serve_forever() if __name__ == "__main__": main()