diff --git a/lab-status.py b/lab-status.py new file mode 100755 index 0000000..651dfad --- /dev/null +++ b/lab-status.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 + +# Required Raycast metadata parameters: +# @raycast.schemaVersion 1 +# @raycast.title Home Lab Status +# @raycast.mode fullOutput +# @raycast.packageName Dashboard +# @raycast.icon 🖥️ + +import json +import urllib.request +import sys + +# Configuration +TRUENAS_IP = "192.168.1.135" +API_KEY = "1-sk8ocSHrEEsrD64HBi00kTkEfVQy6itnv3X75jSHXfZzIc0gnOXkJeszMXQ8YNg4" + +def fetch_truenas_data(endpoint): + url = f"http://{TRUENAS_IP}/api/v2.0/{endpoint}" + req = urllib.request.Request(url) + req.add_header("Authorization", f"Bearer {API_KEY}") + req.add_header("Content-Type", "application/json") + + try: + with urllib.request.urlopen(req, timeout=5) as response: + return json.loads(response.read().decode()) + except Exception as e: + return None + +def bytes_to_human(size_bytes): + if size_bytes == 0: + return "0 B" + units = ["B", "KiB", "MiB", "GiB", "TiB"] + i = 0 + while size_bytes >= 1024 and i < len(units) - 1: + size_bytes /= 1024 + i += 1 + return f"{size_bytes:.2f} {units[i]}" + +def main(): + print("# Home Lab Infrastructure Status\n") + print("---") + + # Fetch Data from TrueNAS Endpoints + pools = fetch_truenas_data("pool") + datasets = fetch_truenas_data("pool/dataset") + apps = fetch_truenas_data("app") + + if pools is None or datasets is None: + print("❌ **Error:** Unable to connect to TrueNAS SCALE API. Check network or API token.") + sys.exit(0) + + # 1. Process and Display ZFS Storage Pool Info + dataset_metrics = {} + for ds in datasets: + ds_id = ds.get("id") + used = ds.get("used", {}).get("parsed", 0) + available = ds.get("available", {}).get("parsed", 0) + dataset_metrics[ds_id] = { + "used": used, + "total": used + available + } + + print("## 💾 Storage Pools") + print("| Pool Name | Status | Used Space | Total Capacity |") + print("| :--- | :--- | :--- | :--- |") + + for pool in pools: + pool_name = pool.get("name", "Unknown") + status = pool.get("status", "UNKNOWN") + status_emoji = "🟢 HEALTHY" if status == "ONLINE" else "🔴 DEGRADED" + + metrics = dataset_metrics.get(pool_name, {"used": 0, "total": 0}) + used_str = bytes_to_human(metrics["used"]) + total_str = bytes_to_human(metrics["total"]) + + print(f"| {pool_name} | {status_emoji} | {used_str} | {total_str} |") + + print("\n---") + + # 2. Process and Display Real TrueNAS Installed Apps + print("## 🚀 TrueNAS Catalog Applications") + + if not apps: + print("*No installed applications found or Apps service is initializing.*") + else: + print("| Application Name | Status | Version |") + print("| :--- | :--- | :--- |") + + for app in apps: + app_id = app.get("id", "Unknown") + state = app.get("state", "UNKNOWN") + version = app.get("version", "N/A") + + # Map state strings to status indicators + if state == "RUNNING": + state_emoji = "🟢 Running" + elif state == "STOPPED": + state_emoji = "🛑 Stopped" + elif state == "DEPLOYING": + state_emoji = "🟡 Deploying" + else: + state_emoji = f"❓ {state}" + + print(f"| {app_id} | {state_emoji} | {version} |") + +if __name__ == "__main__": + main() \ No newline at end of file