#!/bin/bash # Read-only SSH audit of MacLustr nodes (existing approved access; no secrets printed). # Usage: scripts/cluster_audit.sh [nodes...] -> merges into hardware/device_inventory.json NODES="${@:-M3U96a M3U96b M2U64 M4M64a M4M64b M4M64c M5M36 M4M36 M4BP48 M4BP36 m4mm m4mn M2M32 M2M32b M2M32c m6ma m6mb m5ma}" TMP=$(mktemp -d) for n in $NODES; do ( out=$(ssh -o ConnectTimeout=8 -o BatchMode=yes "$n" 'printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" "$(sysctl -n machdep.cpu.brand_string)" "$(sysctl -n hw.ncpu)" "$(sysctl -n hw.memsize)" "$(system_profiler SPDisplaysDataType 2>/dev/null | grep "Total Number of Cores" | awk "{print \$5}")" "$(sw_vers -productVersion)" "$(df -k ~ | tail -1 | awk "{print \$4*1024}")" "$(sysctl -n vm.loadavg)" "$(ls /opt/homebrew/bin/python3.1? 2>/dev/null | xargs -n1 basename 2>/dev/null | tr "\n" ",")"' 2>/dev/null) if [ -n "$out" ]; then echo -e "$n\tok\t$out" > "$TMP/$n"; else echo -e "$n\tunreachable" > "$TMP/$n"; fi ) & done wait cat "$TMP"/* | .venv/bin/python - <<'PY' import sys, json, time from pathlib import Path nodes = {} for line in sys.stdin: p = line.rstrip("\n").split("\t") if p[1] != "ok": nodes[p[0]] = {"reachable": False} continue nodes[p[0]] = {"reachable": True, "cpu_brand": p[2], "cpu_logical_cores": int(p[3]), "ram_bytes": int(p[4]), "gpu_cores": int(p[5]) if p[5].isdigit() else None, "macos": p[6], "disk_free_bytes": int(p[7]), "loadavg": p[8], "homebrew_pythons": [x for x in p[9].split(",") if x]} path = Path("hardware/device_inventory.json") inv = json.loads(path.read_text()) if path.exists() else {} inv["remote_nodes"] = {"audited_at": time.strftime("%Y-%m-%dT%H:%M:%S%z"), "access": "existing passwordless SSH (MacLustr LAN), read-only audit", "nodes": nodes} path.write_text(json.dumps(inv, indent=2, ensure_ascii=False)) reach = [k for k, v in nodes.items() if v["reachable"]] print("reachable:", len(reach), reach) print("unreachable:", [k for k, v in nodes.items() if not v["reachable"]]) PY rm -rf "$TMP"