From 257470a083be54f6f882435a4508011f5ca97d77 Mon Sep 17 00:00:00 2001 From: spark Date: Sat, 24 Oct 2026 05:10:47 +0000 Subject: [PATCH] spark: system health check script with disk/memory report --- wizard-work/spark/health_check.py | 123 +++++++++++++++++++++------- wizard-work/spark/health_report.txt | 21 +++++ 2 files changed, 114 insertions(+), 30 deletions(-) create mode 100644 wizard-work/spark/health_report.txt diff --git a/wizard-work/spark/health_check.py b/wizard-work/spark/health_check.py index 563958e..9144fe2 100644 --- a/wizard-work/spark/health_check.py +++ b/wizard-work/spark/health_check.py @@ -1,34 +1,97 @@ #!/usr/bin/env python3 -"""Quick multi-URL health checker with JSON output.""" -import sys, json, urllib.request, urllib.error, concurrent.futures +"""System health check script - verifies system state and writes report.""" +import os +import sys +import platform +import shutil +from datetime import datetime -def check_url(url, timeout=5): - """Check single URL, return status dict.""" - try: - req = urllib.request.Request(url, method='HEAD') - with urllib.request.urlopen(req, timeout=timeout) as resp: - return {"url": url, "status": resp.status, "ok": 200 <= resp.status < 400} - except urllib.error.HTTPError as e: - return {"url": url, "status": e.code, "ok": False, "error": str(e)} - except Exception as e: - return {"url": url, "status": None, "ok": False, "error": str(e)} +def get_disk_usage(path="/"): + """Get disk usage for a path.""" + total, used, free = shutil.disk_usage(path) + return { + 'total_gb': round(total / (1024**3), 2), + 'used_gb': round(used / (1024**3), 2), + 'free_gb': round(free / (1024**3), 2), + 'percent_used': round((used / total) * 100, 1) + } -def health_check(urls, parallel=True): - """Check multiple URLs, return JSON results.""" - results = [] - if parallel and len(urls) > 1: - with concurrent.futures.ThreadPoolExecutor(max_workers=5) as ex: - results = list(ex.map(check_url, urls)) - else: - results = [check_url(u) for u in urls] - return {"checked": len(urls), "passed": sum(1 for r in results if r["ok"]), "results": results} +def get_memory_usage(): + """Get memory usage from /proc/meminfo.""" + meminfo = {} + with open('/proc/meminfo', 'r') as f: + for line in f: + parts = line.split() + key = parts[0].rstrip(':') + value = int(parts[1]) + meminfo[key] = value + + total = meminfo.get('MemTotal', 0) + available = meminfo.get('MemAvailable', meminfo.get('MemFree', 0)) + used = total - available + + return { + 'total_mb': round(total / 1024, 1), + 'available_mb': round(available / 1024, 1), + 'used_mb': round(used / 1024, 1), + 'percent_used': round((used / total) * 100, 1) if total > 0 else 0 + } -if __name__ == "__main__": - urls = sys.argv[1:] if len(sys.argv) > 1 else [ - "https://httpbin.org/status/200", - "https://httpbin.org/status/404", - "https://httpbin.org/delay/1" - ] - result = health_check(urls) - print(json.dumps(result, indent=2)) - sys.exit(0 if result["passed"] > 0 else 1) \ No newline at end of file +def get_cpu_count(): + """Get CPU count.""" + return os.cpu_count() or 1 + +def main(): + """Main entry point - write health report.""" + report = { + 'timestamp': datetime.utcnow().isoformat() + 'Z', + 'hostname': platform.node(), + 'os': platform.system(), + 'os_version': platform.version(), + 'python': platform.python_version(), + 'cpu_count': get_cpu_count(), + 'disk_usage': get_disk_usage('/'), + 'memory_usage': get_memory_usage(), + 'working_dir': os.getcwd(), + 'user': os.environ.get('USER', 'unknown'), + 'home': os.environ.get('HOME', '/root') + } + + # Write readable report + output_path = '/root/.hermes/wizard-outputs/spark/health_report.txt' + with open(output_path, 'w') as f: + f.write("=== SYSTEM HEALTH REPORT ===\n") + f.write(f"Generated: {report['timestamp']}\n") + f.write(f"Hostname: {report['hostname']}\n") + f.write(f"OS: {report['os']} {report['os_version']}\n") + f.write(f"Python: {report['python']}\n") + f.write(f"CPU Cores: {report['cpu_count']}\n") + f.write(f"\nDisk Usage (/):\n") + f.write(f" Total: {report['disk_usage']['total_gb']} GB\n") + f.write(f" Used: {report['disk_usage']['used_gb']} GB ({report['disk_usage']['percent_used']}%)\n") + f.write(f" Free: {report['disk_usage']['free_gb']} GB\n") + f.write(f"\nMemory Usage:\n") + f.write(f" Total: {report['memory_usage']['total_mb']} MB\n") + f.write(f" Used: {report['memory_usage']['used_mb']} MB ({report['memory_usage']['percent_used']}%)\n") + f.write(f" Available: {report['memory_usage']['available_mb']} MB\n") + f.write(f"\nEnvironment:\n") + f.write(f" Working Dir: {report['working_dir']}\n") + f.write(f" User: {report['user']}\n") + f.write(f" Home: {report['home']}\n") + + print(f"Health report written to: {output_path}") + + # Validation: verify we can read what we wrote + with open(output_path, 'r') as f: + content = f.read() + + # Check key sections exist + assert '=== SYSTEM HEALTH REPORT ===' in content, "Report header missing" + assert 'Disk Usage' in content, "Disk section missing" + assert 'Memory Usage' in content, "Memory section missing" + assert f"CPU Cores: {report['cpu_count']}" in content, "CPU info missing" + + return 0 + +if __name__ == '__main__': + sys.exit(main()) \ No newline at end of file diff --git a/wizard-work/spark/health_report.txt b/wizard-work/spark/health_report.txt new file mode 100644 index 0000000..61f8a29 --- /dev/null +++ b/wizard-work/spark/health_report.txt @@ -0,0 +1,21 @@ +=== SYSTEM HEALTH REPORT === +Generated: 2026-10-24T05:09:39.986039Z +Hostname: WorkBench +OS: Linux #71-Ubuntu SMP PREEMPT_DYNAMIC Tue Jul 22 16:52:38 UTC 2025 +Python: 3.14.7 +CPU Cores: 4 + +Disk Usage (/): + Total: 153.94 GB + Used: 123.33 GB (80.1%) + Free: 30.59 GB + +Memory Usage: + Total: 7941.3 MB + Used: 4577.1 MB (57.6%) + Available: 3364.2 MB + +Environment: + Working Dir: /root + User: root + Home: /root