diff --git a/script.js b/script.js index 916fd47..77fc69c 100644 --- a/script.js +++ b/script.js @@ -28,7 +28,7 @@ async function loadNocStatus() { return; } - statusText.textContent = `${data.nocName} — ${data.status} — ${data.lastUpdated}`; + statusText.textContent = `${data.nocName} — ${data.status} — Last updated: ${data.lastUpdated}`; nodes.textContent = data.summary.nodes; services.textContent = data.summary.services; @@ -48,7 +48,7 @@ async function loadNocStatus() { ? "online" : status.includes("building") || status.includes("tuning") || status.includes("active") ? "warning" - : "planned"; + : "offline"; card.innerHTML = `
@@ -59,6 +59,7 @@ async function loadNocStatus() {

${system.type}

${system.address} Status: ${system.status} + Last Check: ${system.lastCheck || "Manual"} `; grid.appendChild(card); diff --git a/scripts/generate-noc-status.py b/scripts/generate-noc-status.py new file mode 100644 index 0000000..115bcc3 --- /dev/null +++ b/scripts/generate-noc-status.py @@ -0,0 +1,123 @@ +import json +import socket +from datetime import datetime +from pathlib import Path + +OUTPUT_FILE = Path(__file__).resolve().parent.parent / "data" / "noc-status.json" + +SYSTEMS = [ + { + "name": "Proxmox VE", + "type": "Virtualization", + "host": "10.10.30.250", + "port": 8006, + "address": "10.10.30.250:8006", + "layer": "Infrastructure" + }, + { + "name": "TrueNAS", + "type": "Storage", + "host": "10.10.30.143", + "port": 80, + "address": "10.10.30.143", + "layer": "Storage" + }, + { + "name": "Nginx Proxy Manager", + "type": "Reverse Proxy", + "host": "10.10.30.210", + "port": 81, + "address": "10.10.30.210:81", + "layer": "Access" + }, + { + "name": "Dashy", + "type": "Dashboard", + "host": "10.10.30.61", + "port": 4000, + "address": "10.10.30.61:4000", + "layer": "Monitoring" + }, + { + "name": "Jellyfin", + "type": "Media Service", + "host": "10.10.30.143", + "port": 30013, + "address": "10.10.30.143:30013", + "layer": "Services" + }, + { + "name": "K3s API", + "type": "Kubernetes API", + "host": "10.10.30.72", + "port": 6443, + "address": "10.10.30.72:6443", + "layer": "Compute" + }, + { + "name": "APRS-IS", + "type": "APRS Internet Service", + "host": "noam.aprs2.net", + "port": 14580, + "address": "noam.aprs2.net:14580", + "layer": "Edge" + } +] + + +def check_tcp(host, port, timeout=2): + try: + with socket.create_connection((host, port), timeout=timeout): + return True + except OSError: + return False + + +def main(): + checked_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + systems = [] + online_count = 0 + + for system in SYSTEMS: + online = check_tcp(system["host"], system["port"]) + + if online: + status = "Online" + online_count += 1 + else: + status = "Offline" + + systems.append({ + "name": system["name"], + "type": system["type"], + "address": system["address"], + "status": status, + "layer": system["layer"], + "lastCheck": checked_at + }) + + data = { + "nocName": "Ced's NOC", + "status": "Operational Build", + "lastUpdated": checked_at, + "summary": { + "nodes": "12+", + "services": f"{online_count}/{len(SYSTEMS)}", + "vlans": "4", + "edgeSystems": "2" + }, + "systems": systems + } + + OUTPUT_FILE.parent.mkdir(parents=True, exist_ok=True) + + with open(OUTPUT_FILE, "w", encoding="utf-8") as file: + json.dump(data, file, indent=2) + + print(f"NOC status written to {OUTPUT_FILE}") + print(f"Online systems: {online_count}/{len(SYSTEMS)}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/style.css b/style.css index 2dd3918..5f4eb7c 100644 --- a/style.css +++ b/style.css @@ -559,4 +559,25 @@ a:hover { align-items: flex-start; gap: 0.5rem; } +} + +.mini-status.online { + background: var(--accent-2); + box-shadow: 0 0 16px rgba(142, 240, 207, 0.9); +} + +.mini-status.warning { + background: var(--warning); + box-shadow: 0 0 16px rgba(242, 204, 96, 0.9); +} + +.mini-status.offline { + background: #ff5f56; + box-shadow: 0 0 16px rgba(255, 95, 86, 0.9); +} + +.noc-system-card small + small { + color: var(--muted); + font-weight: 500; + margin-top: 0.25rem; } \ No newline at end of file