#!/usr/bin/env python3 """Parse qm guest exec JSON output and extract decoded stdout. Use as a remote module or standalone: python3 parse_qm_guest_exec.py "" python3 parse_qm_guest_exec.py 106 "hostname" Returns JSON: {"ok": true, "exitcode": 0, "stdout": "...", "stderr": "..."} {"ok": false, "error": "...", "raw": "..."} """ import json, base64, subprocess, sys def qm_guest_exec(vmid: str, cmd: str, timeout: int = 15) -> dict: r = subprocess.run( ["qm", "guest", "exec", vmid, "--", "/bin/sh", "-c", cmd], capture_output=True, text=True, timeout=timeout ) try: data = json.loads(r.stdout) except json.JSONDecodeError as e: return {"ok": False, "error": f"JSON parse: {e}", "raw": r.stdout[:400]} result = {"ok": True} result["exitcode"] = data.get("exitcode", 1) result["exited"] = data.get("exited", 1) if "out-data" in data and data["out-data"]: try: result["stdout"] = base64.b64decode(data["out-data"]).decode("utf-8", errors="replace") except Exception as e: result["stdout"] = f"decode error: {e}" else: result["stdout"] = "" if "err-data" in data and data["err-data"]: try: result["stderr"] = base64.b64decode(data["err-data"]).decode("utf-8", errors="replace") except Exception as e: result["stderr"] = f"decode error: {e}" else: result["stderr"] = "" return result def main(): if len(sys.argv) < 3: print("Usage: python3 parse_qm_guest_exec.py ''", file=sys.stderr) sys.exit(1) vmid = sys.argv[1] cmd = sys.argv[2] result = qm_guest_exec(vmid, cmd) print(json.dumps(result, indent=2)) if __name__ == "__main__": main()