diff --git a/public_html/agent/jarvis-agent.py b/public_html/agent/jarvis-agent.py index 53bbef7..1dc721a 100644 --- a/public_html/agent/jarvis-agent.py +++ b/public_html/agent/jarvis-agent.py @@ -28,11 +28,45 @@ AGENT_VERSION = "3.1" # ── Config helpers ──────────────────────────────────────────────────────────── def load_config() -> dict: + legacy_path = "/opt/jarvis-agent/config.json" + if not os.path.exists(CONFIG_PATH): - print(f"[ERROR] Config not found at {CONFIG_PATH}. Run the installer first.", flush=True) - sys.exit(1) - with open(CONFIG_PATH) as f: - return json.load(f) + if os.path.exists(legacy_path): + print(f"[JARVIS] Config found at legacy path {legacy_path} - migrating...", flush=True) + Path(CONFIG_PATH).parent.mkdir(parents=True, exist_ok=True) + with open(legacy_path) as f: + cfg = json.load(f) + else: + print(f"[ERROR] Config not found at {CONFIG_PATH}. Run the installer first.", flush=True) + sys.exit(1) + else: + with open(CONFIG_PATH) as f: + cfg = json.load(f) + + # Migrate old key names so the agent self-heals instead of crash-looping + import re as _re + changed = False + if "server_url" in cfg and "jarvis_url" not in cfg: + cfg["jarvis_url"] = cfg.pop("server_url") + print("[JARVIS] Config migrated: server_url -> jarvis_url", flush=True) + changed = True + if "api_key" in cfg and "registration_key" not in cfg: + cfg["registration_key"] = cfg.pop("api_key") + print("[JARVIS] Config migrated: api_key -> registration_key", flush=True) + changed = True + if "hostname" not in cfg: + cfg["hostname"] = socket.gethostname() + changed = True + if "ssl_verify" not in cfg: + cfg["ssl_verify"] = not bool(_re.match(r"https?://\d+\.\d+\.\d+\.\d+", cfg.get("jarvis_url", ""))) + changed = True + + if changed: + with open(CONFIG_PATH, "w") as f: + json.dump(cfg, f, indent=2) + print("[JARVIS] Config saved after migration.", flush=True) + + return cfg def load_state() -> dict: if os.path.exists(STATE_PATH): @@ -265,11 +299,23 @@ def get_load() -> list: except Exception: return [0, 0, 0] +def get_nordvpn_status() -> dict | None: + """Check nordlynx WireGuard interface. Returns None if nordlynx not present on this host.""" + try: + r = subprocess.run(["ip", "link", "show", "nordlynx"], + capture_output=True, text=True, timeout=3) + if r.returncode != 0: + return None + active = "UP,LOWER_UP" in r.stdout or "state UP" in r.stdout + return {"active": active, "interface": "nordlynx"} + except Exception: + return None + def collect_metrics(cfg: dict) -> dict: # First reading for CPU delta get_cpu_percent() time.sleep(1) - return { + metrics = { "hostname": cfg.get("hostname", socket.gethostname()), "cpu_percent": get_cpu_percent(), "memory": get_memory(), @@ -280,6 +326,10 @@ def collect_metrics(cfg: dict) -> dict: "platform": platform.system(), "timestamp": datetime.utcnow().isoformat() + "Z", } + nordvpn = get_nordvpn_status() + if nordvpn is not None: + metrics["nordvpn"] = nordvpn + return metrics # ── Proxmox metrics ─────────────────────────────────────────────────────────── @@ -384,7 +434,7 @@ def main(): try: # Heartbeat + get commands - hb = api_post(f"{jarvis_url}/api/agent/heartbeat", {}, headers, ssl_verify=ssl_verify) + hb = api_post(f"{jarvis_url}/api/agent/heartbeat", {"version": AGENT_VERSION}, headers, ssl_verify=ssl_verify) if "error" in hb: print(f"[WARN] Heartbeat failed: {hb['error']}", flush=True) else: diff --git a/public_html/agent/jarvis-agent.py.sha256 b/public_html/agent/jarvis-agent.py.sha256 index c3b619a..1038a4d 100644 --- a/public_html/agent/jarvis-agent.py.sha256 +++ b/public_html/agent/jarvis-agent.py.sha256 @@ -1 +1 @@ -1a9e8e24e5aee8f27a5900b6340373023ff2171e844e71e451eecdbf3b2b0f03 jarvis-agent.py +6ba92a1ad4f91a218cbc4ce6834c55e8f56a0e22fca04278d77260958e429d5b