#!/usr/bin/env python3 """Wrapper: power on pve2 (DL380p Gen8) via iLO4 Redfish API. Fire-and-forget — sends power-on, does NOT wait for boot. Used by cron job server-start (no_agent mode, 120s timeout).""" import os, sys, json, subprocess ENV_FILE = os.path.expanduser("~/.hermes/.env") def get_env(key): try: with open(ENV_FILE) as f: for line in f: if line.startswith(key + "="): return line.strip().split("=", 1)[1] except FileNotFoundError: pass return None def ilo_token(): url = get_env("ILO4_URL") user = get_env("ILO4_USER") pwd = get_env("ILO4_PASSWORD") payload = '{"UserName":"%s","Password":"%s"}' % (user, pwd) cmd = ["curl", "-s", "-k", "--max-time", "10", "-D", "/dev/stderr", "-X", "POST", "-H", "Content-Type: application/json", "-d", payload, url + "/redfish/v1/SessionService/Sessions/"] r = subprocess.run(cmd, capture_output=True, timeout=15) stderr = r.stderr.decode("utf-8", errors="replace") for line in stderr.split("\n"): if "X-Auth-Token" in line: return line.split(":")[1].strip() return None url = get_env("ILO4_URL") token = ilo_token() if not token: print("FAIL: iLO auth failed") sys.exit(1) hdr = "X-Auth-Token: " + token r = subprocess.run([ "curl", "-s", "-k", "--max-time", "15", "-X", "POST", "-H", hdr, "-H", "Content-Type: application/json", "-d", '{"ResetType":"On"}', url + "/redfish/v1/Systems/1/Actions/ComputerSystem.Reset/" ], capture_output=True, timeout=20) # Check curl exit code if r.returncode != 0: print(f"FAIL: curl returned {r.returncode}") sys.exit(1) # Parse iLO response - check for actual error messages # iLO wraps success in "ExtendedError" type with "Success" MessageID stdout = r.stdout.decode("utf-8", errors="replace") if stdout.strip(): try: resp = json.loads(stdout) msgs = resp.get("Messages", []) or (resp.get("error", {}) or {}).get("@Message.ExtendedInfo", []) for m in msgs: mid = m.get("MessageID", "") if mid and "Success" not in mid and "OK" not in mid: print(f"FAIL: iLO error: {mid}") sys.exit(1) except json.JSONDecodeError: pass print("Power-on command sent via iLO") sys.exit(0)