#!/usr/bin/env python3 import os import json import subprocess from datetime import datetime from pathlib import Path TS = datetime.utcnow().strftime("%Y%m%d-%H%M%S") BASE_DIR = Path("/opt/hx-ki") INVENTORY_DIR = BASE_DIR / "inventory" INVENTORY_DIR.mkdir(parents=True, exist_ok=True) # .env laden (HXKI_NODE_NAME etc.) ENV_FILE = BASE_DIR / "env" / ".env" if ENV_FILE.exists(): for line in ENV_FILE.read_text().splitlines(): line = line.strip() if not line or line.startswith("#") or "=" not in line: continue k, v = line.split("=", 1) os.environ.setdefault(k.strip(), v.strip()) HOST = subprocess.getoutput("hostname") NODE = os.environ.get("HXKI_NODE_NAME", "") def run(cmd: str) -> str: try: out = subprocess.check_output( cmd, shell=True, stderr=subprocess.DEVNULL, text=True ) return out.strip() except Exception: return "" def bytes_to_mb(b: int) -> float: return round(b / 1024 / 1024, 2) def workspace_info(): ws_path = Path(os.environ.get("HXKI_WORKSPACE", "/data/HXKI_WORKSPACE")) info = {"path": str(ws_path), "exists": ws_path.exists()} if ws_path.exists(): total_size = 0 count = 0 for root, dirs, files in os.walk(ws_path): for name in files: try: p = Path(root) / name total_size += p.stat().st_size count += 1 except Exception: pass info["file_count"] = count info["total_bytes"] = total_size info["total_mb"] = bytes_to_mb(total_size) return info def telemetry_info(): tel_path = Path(os.environ.get("HXKI_TELEMETRY_LOG", "/opt/hx-ki/logs/autoindexer_events.log")) info = {"path": str(tel_path), "exists": tel_path.exists()} if tel_path.exists(): try: sz = tel_path.stat().st_size info["size_bytes"] = sz info["size_mb"] = bytes_to_mb(sz) info["tail_10"] = run(f"tail -n 10 {tel_path}") except Exception: pass return info summary = { "timestamp_utc": TS, "host": HOST, "node_name": NODE, "sections": {} } summary["sections"]["system"] = { "hostnamectl": run("hostnamectl || echo ''"), "cpu": run("lscpu || echo ''"), "memory": run("free -h || echo ''"), "disk_root": run("df -h / || echo ''"), } summary["sections"]["workspace"] = workspace_info() summary["sections"]["telemetry"] = telemetry_info() summary["sections"]["docker"] = { "ps": run("docker ps || echo ''"), "images": run("docker images || echo ''"), } hx_vars = {} for k, v in os.environ.items(): if k.startswith("HXKI_") or k in ("CHROMA_HOST", "CHROMA_PORT", "POSTGRES_HOST", "POSTGRES_DB"): hx_vars[k] = v summary["sections"]["env"] = { "env_file": str(ENV_FILE), "present": ENV_FILE.exists(), "hx_vars": hx_vars, } summary["sections"]["load"] = {"uptime": run("uptime || echo ''")} summary["sections"]["disk_detail"] = {"df_all": run("df -h || echo ''")} log_path = INVENTORY_DIR / f"hxki_agent_{TS}.log" json_path = INVENTORY_DIR / f"hxki_agent_{TS}.json" with log_path.open("w", encoding="utf-8") as f: f.write("==== HX-KI AGENT INVENTAR ====\n") f.write(f"Zeit (UTC): {TS}\n") f.write(f"Host: {HOST}\n") f.write(f"Node-Name: {NODE}\n") f.write("====================================\n\n") for section, data in summary["sections"].items(): f.write(f"---- {section.upper()} ----\n") if isinstance(data, dict): f.write(json.dumps(data, indent=2, ensure_ascii=False)) else: f.write(str(data)) f.write("\n\n") with json_path.open("w", encoding="utf-8") as jf: json.dump(summary, jf, indent=2, ensure_ascii=False) print("========================================================") print("HX-KI AGENT – RUN COMPLETE") print("Log: ", log_path) print("JSON: ", json_path) print("========================================================")