#!/usr/bin/env python3 """ sysreport.py — Genera un reporte completo del sistema en JSON. Usa jc para convertir la salida de comandos del sistema a JSON estructurado. Ideal para diagnosticar, auditar o pasar a una IA. Uso: python3 sysreport.py # Guarda en /tmp/sysreport.json python3 sysreport.py --stdout # Imprime por stdout python3 sysreport.py --compact # Sin pretty-print python3 sysreport.py --only discos # Solo una sección Dependencias: - Python 3.10+ - jc (pip install jc) - jq (sudo apt install jq) - Los comandos del sistema: ps, df, systemctl, ss, free, uptime """ import argparse import json import subprocess import sys from datetime import datetime # ─── Secciones del reporte ──────────────────────────────────────────────────── SECCIONES = { "procesos": (["ps", "aux"], "ps"), "discos": (["df", "-h"], "df"), "servicios": (["systemctl", "list-units", "--no-legend"], "systemctl"), "puertos": (["ss", "-tlnp"], "ss"), "memoria": (["free", "-h"], "free"), "uptime": (["uptime"], "uptime"), } def ejecutar_jc(comando: list, parser: str) -> list | dict: """Ejecuta un comando y lo parsea con jc.""" try: out = subprocess.run(comando, capture_output=True, text=True, timeout=10) if out.returncode != 0: return {"error": f"Comando falló: {' '.join(comando)}"} # Parsear con jc jc_out = subprocess.run( ["jc", f"--{parser}"], input=out.stdout, capture_output=True, text=True, timeout=10, ) if jc_out.returncode != 0: return {"error": f"jc falló para {parser}: {jc_out.stderr[:200]}"} return json.loads(jc_out.stdout) except subprocess.TimeoutExpired: return {"error": f"Timeout ejecutando {' '.join(comando)}"} except json.JSONDecodeError as e: return {"error": f"JSON inválido de jc --{parser}: {e}"} except FileNotFoundError: return {"error": f"jc no encontrado. Instala: pip install jc"} def generar_reporte(secciones: list[str] | None = None) -> dict: """Genera el reporte del sistema.""" incluir = secciones if secciones else list(SECCIONES.keys()) reporte = { "fecha": datetime.now().isoformat(), "hostname": subprocess.run( ["hostname"], capture_output=True, text=True, timeout=5 ).stdout.strip(), } for seccion in incluir: if seccion in SECCIONES: comando, parser = SECCIONES[seccion] reporte[seccion] = ejecutar_jc(comando, parser) return reporte # ─── Main ───────────────────────────────────────────────────────────────────── def main(): parser = argparse.ArgumentParser( description="sysreport: reporte del sistema en JSON usando jc", formatter_class=argparse.RawDescriptionHelpFormatter, epilog="""\ Ejemplos: python3 sysreport.py # Guarda en /tmp/sysreport.json python3 sysreport.py --stdout # Imprime por stdout python3 sysreport.py --only procesos discos # Solo procesos y discos python3 sysreport.py --stdout | jq '.discos' # Filtrar con jq """, ) parser.add_argument("--stdout", action="store_true", help="Imprimir por stdout en vez de guardar") parser.add_argument("--compact", action="store_true", help="Sin pretty-print (más pequeño)") parser.add_argument("--only", nargs="+", choices=list(SECCIONES.keys()), help=f"Solo estas secciones: {', '.join(SECCIONES.keys())}") args = parser.parse_args() print("📡 Generando reporte del sistema...", file=sys.stderr) reporte = generar_reporte(args.only) indent = None if args.compact else 2 if args.stdout: print(json.dumps(reporte, indent=indent, ensure_ascii=False)) else: output_path = "/tmp/sysreport.json" with open(output_path, "w") as f: json.dump(reporte, f, indent=indent, ensure_ascii=False) print(f"✅ Reporte guardado en {output_path}", file=sys.stderr) print(f"📦 Tamaño: {len(json.dumps(reporte))} caracteres", file=sys.stderr) print(f" Secciones: {', '.join(reporte.keys())}", file=sys.stderr) # Mostrar resumen rápido errores = [k for k, v in reporte.items() if isinstance(v, dict) and "error" in v] if errores: print(f"⚠️ Errores en: {', '.join(errores)}", file=sys.stderr) # Contar elementos por sección for k, v in reporte.items(): if isinstance(v, list): print(f" {k}: {len(v)} elementos", file=sys.stderr) if __name__ == "__main__": main()