From f03f0cb7dee69a09cb683d431b1ff0a8f54db644 Mon Sep 17 00:00:00 2001 From: ced4568 Date: Sat, 25 Apr 2026 17:45:59 -0500 Subject: [PATCH] Upgrade NOC dashboard to V3 with latency and roadmap --- data/noc-status.json | 52 +++++++++++++------- index.html | 90 +++++++++++++++++++--------------- script.js | 11 ++++- scripts/generate-noc-status.py | 62 +++++++++++++++++------ style.css | 30 ++++++++++++ 5 files changed, 169 insertions(+), 76 deletions(-) diff --git a/data/noc-status.json b/data/noc-status.json index 7098b92..20232fd 100644 --- a/data/noc-status.json +++ b/data/noc-status.json @@ -1,69 +1,85 @@ { "nocName": "Ced's NOC", - "status": "Operational Build", - "lastUpdated": "2026-04-25 16:52:17", + "status": "All Systems Online", + "lastUpdated": "2026-04-25 17:45:47", "summary": { "nodes": "12+", "services": "7/7", + "online": "7", + "offline": "0", "vlans": "4", "edgeSystems": "2" }, "systems": [ { "name": "Proxmox VE", - "type": "Virtualization", + "type": "Virtualization Platform", "address": "10.10.30.250:8006", "status": "Online", - "layer": "Infrastructure", - "lastCheck": "2026-04-25 16:52:17" + "layer": "Core Infrastructure", + "label": "Hypervisor", + "latency": "4 ms", + "lastCheck": "2026-04-25 17:45:47" }, { "name": "TrueNAS", - "type": "Storage", + "type": "Storage Platform", "address": "10.10.30.143", "status": "Online", "layer": "Storage", - "lastCheck": "2026-04-25 16:52:17" + "label": "NAS", + "latency": "1 ms", + "lastCheck": "2026-04-25 17:45:47" }, { "name": "Nginx Proxy Manager", "type": "Reverse Proxy", "address": "10.10.30.210:81", "status": "Online", - "layer": "Access", - "lastCheck": "2026-04-25 16:52:17" + "layer": "Access Layer", + "label": "Proxy", + "latency": "0 ms", + "lastCheck": "2026-04-25 17:45:47" }, { "name": "Dashy", - "type": "Dashboard", + "type": "Service Dashboard", "address": "10.10.30.61:4000", "status": "Online", - "layer": "Monitoring", - "lastCheck": "2026-04-25 16:52:17" + "layer": "Dashboard", + "label": "Portal", + "latency": "17 ms", + "lastCheck": "2026-04-25 17:45:47" }, { "name": "Jellyfin", "type": "Media Service", "address": "10.10.30.143:30013", "status": "Online", - "layer": "Services", - "lastCheck": "2026-04-25 16:52:17" + "layer": "Application Service", + "label": "App", + "latency": "2 ms", + "lastCheck": "2026-04-25 17:45:47" }, { "name": "K3s API", "type": "Kubernetes API", "address": "10.10.30.72:6443", "status": "Online", - "layer": "Compute", - "lastCheck": "2026-04-25 16:52:17" + "layer": "Compute Cluster", + "label": "Cluster", + "latency": "13 ms", + "lastCheck": "2026-04-25 17:45:47" }, { "name": "APRS-IS", "type": "APRS Internet Service", "address": "noam.aprs2.net:14580", "status": "Online", - "layer": "Edge", - "lastCheck": "2026-04-25 16:52:17" + "layer": "Edge / RF", + "label": "External", + "latency": "100 ms", + "lastCheck": "2026-04-25 17:45:47" } ] } \ No newline at end of file diff --git a/index.html b/index.html index 49d2de6..33838c6 100644 --- a/index.html +++ b/index.html @@ -153,22 +153,22 @@ building_real_systems

Nodes

-
-

--

-

Services

-
- -
-

--

-

VLANs

-
- -
-

--

-

Edge Systems

-
+
+

--

+

Services Online

+
+

--

+

Network Segments

+
+ +
+

--

+

Edge Systems

+
+ +
@@ -315,34 +315,44 @@ building_real_systems -
-
-
- -

📊 Ced’s NOC Vision

-

- The long-term goal is to bring these systems together into a unified network operations view. -

-
+
+
+
+ +

📊 Ced’s NOC Vision

+

+ Ced’s NOC is being built as a staged monitoring and systems-visibility platform for HomeLab, + Kubernetes, edge devices, and future production-style dashboards. +

+
-
-
-

Monitoring

-

Grafana, Prometheus, Uptime Kuma, and service-level visibility.

-
- -
-

Infrastructure

-

HomeLab services, K3s nodes, VLANs, and self-hosted systems.

-
- -
-

Edge Systems

-

APRS iGate nodes, Raspberry Pi devices, and field/mobile deployments.

-
-
+
+
+

✅ Current: Portfolio NOC

+

+ JSON-driven dashboard that displays real inventory, online/offline checks, service labels, + latency, and last-check timestamps. +

-
+ +
+

⚙️ Next: Automated Data Updates

+

+ Scheduled local script updates will refresh system status data automatically and push dashboard-ready + JSON into the portfolio. +

+
+ +
+

📈 Future: Grafana + Prometheus

+

+ Deeper monitoring stack for Proxmox, TrueNAS, K3s, Raspberry Pi nodes, Uptime Kuma, + and APRS edge systems. +

+
+
+ +
diff --git a/script.js b/script.js index 77fc69c..4be53c5 100644 --- a/script.js +++ b/script.js @@ -55,11 +55,18 @@ async function loadNocStatus() { ${system.layer}
+ +
${system.label || "System"}
+

${system.name}

${system.type}

${system.address} - Status: ${system.status} - Last Check: ${system.lastCheck || "Manual"} + +
+ Status: ${system.status} + Latency: ${system.latency || "N/A"} + Last Check: ${system.lastCheck || "Manual"} +
`; grid.appendChild(card); diff --git a/scripts/generate-noc-status.py b/scripts/generate-noc-status.py index 115bcc3..8836e79 100644 --- a/scripts/generate-noc-status.py +++ b/scripts/generate-noc-status.py @@ -1,5 +1,6 @@ import json import socket +import time from datetime import datetime from pathlib import Path @@ -8,19 +9,21 @@ OUTPUT_FILE = Path(__file__).resolve().parent.parent / "data" / "noc-status.json SYSTEMS = [ { "name": "Proxmox VE", - "type": "Virtualization", + "type": "Virtualization Platform", "host": "10.10.30.250", "port": 8006, "address": "10.10.30.250:8006", - "layer": "Infrastructure" + "layer": "Core Infrastructure", + "label": "Hypervisor" }, { "name": "TrueNAS", - "type": "Storage", + "type": "Storage Platform", "host": "10.10.30.143", "port": 80, "address": "10.10.30.143", - "layer": "Storage" + "layer": "Storage", + "label": "NAS" }, { "name": "Nginx Proxy Manager", @@ -28,15 +31,17 @@ SYSTEMS = [ "host": "10.10.30.210", "port": 81, "address": "10.10.30.210:81", - "layer": "Access" + "layer": "Access Layer", + "label": "Proxy" }, { "name": "Dashy", - "type": "Dashboard", + "type": "Service Dashboard", "host": "10.10.30.61", "port": 4000, "address": "10.10.30.61:4000", - "layer": "Monitoring" + "layer": "Dashboard", + "label": "Portal" }, { "name": "Jellyfin", @@ -44,7 +49,8 @@ SYSTEMS = [ "host": "10.10.30.143", "port": 30013, "address": "10.10.30.143:30013", - "layer": "Services" + "layer": "Application Service", + "label": "App" }, { "name": "K3s API", @@ -52,7 +58,8 @@ SYSTEMS = [ "host": "10.10.30.72", "port": 6443, "address": "10.10.30.72:6443", - "layer": "Compute" + "layer": "Compute Cluster", + "label": "Cluster" }, { "name": "APRS-IS", @@ -60,17 +67,29 @@ SYSTEMS = [ "host": "noam.aprs2.net", "port": 14580, "address": "noam.aprs2.net:14580", - "layer": "Edge" + "layer": "Edge / RF", + "label": "External" } ] def check_tcp(host, port, timeout=2): + start = time.perf_counter() + try: with socket.create_connection((host, port), timeout=timeout): - return True + latency_ms = round((time.perf_counter() - start) * 1000) + return True, latency_ms except OSError: - return False + return False, None + + +def health_label(online_count, total): + if online_count == total: + return "All Systems Online" + if online_count >= max(1, total - 2): + return "Degraded" + return "Action Required" def main(): @@ -78,15 +97,19 @@ def main(): systems = [] online_count = 0 + offline_count = 0 for system in SYSTEMS: - online = check_tcp(system["host"], system["port"]) + online, latency = check_tcp(system["host"], system["port"]) if online: status = "Online" online_count += 1 + latency_value = f"{latency} ms" else: status = "Offline" + offline_count += 1 + latency_value = "N/A" systems.append({ "name": system["name"], @@ -94,16 +117,22 @@ def main(): "address": system["address"], "status": status, "layer": system["layer"], + "label": system["label"], + "latency": latency_value, "lastCheck": checked_at }) + total_systems = len(SYSTEMS) + data = { "nocName": "Ced's NOC", - "status": "Operational Build", + "status": health_label(online_count, total_systems), "lastUpdated": checked_at, "summary": { "nodes": "12+", - "services": f"{online_count}/{len(SYSTEMS)}", + "services": f"{online_count}/{total_systems}", + "online": str(online_count), + "offline": str(offline_count), "vlans": "4", "edgeSystems": "2" }, @@ -116,7 +145,8 @@ def main(): json.dump(data, file, indent=2) print(f"NOC status written to {OUTPUT_FILE}") - print(f"Online systems: {online_count}/{len(SYSTEMS)}") + print(f"Online systems: {online_count}/{total_systems}") + print(f"Offline systems: {offline_count}/{total_systems}") if __name__ == "__main__": diff --git a/style.css b/style.css index 5f4eb7c..411361f 100644 --- a/style.css +++ b/style.css @@ -580,4 +580,34 @@ a:hover { color: var(--muted); font-weight: 500; margin-top: 0.25rem; +} + +.system-label { + display: inline-block; + margin-top: 0.85rem; + margin-bottom: 0.35rem; + padding: 0.25rem 0.55rem; + border-radius: 999px; + background: rgba(88, 166, 255, 0.12); + border: 1px solid rgba(88, 166, 255, 0.22); + color: var(--accent); + font-size: 0.72rem; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.system-meta { + display: grid; + gap: 0.25rem; + margin-top: 0.85rem; +} + +.system-meta small { + color: var(--muted); +} + +.system-meta small:first-child { + color: var(--accent); + font-weight: 800; } \ No newline at end of file