diff --git a/data/noc-status.json b/data/noc-status.json index 7098b92e..20232fd7 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 49d2de60..33838c65 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
+Future Buildout
-- The long-term goal is to bring these systems together into a unified network operations view. -
-NOC Roadmap
++ Ced’s NOC is being built as a staged monitoring and systems-visibility platform for HomeLab, + Kubernetes, edge devices, and future production-style dashboards. +
+Grafana, Prometheus, Uptime Kuma, and service-level visibility.
-HomeLab services, K3s nodes, VLANs, and self-hosted systems.
-APRS iGate nodes, Raspberry Pi devices, and field/mobile deployments.
-+ JSON-driven dashboard that displays real inventory, online/offline checks, service labels, + latency, and last-check timestamps. +
+ Scheduled local script updates will refresh system status data automatically and push dashboard-ready + JSON into the portfolio. +
++ Deeper monitoring stack for Proxmox, TrueNAS, K3s, Raspberry Pi nodes, Uptime Kuma, + and APRS edge systems. +
+${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
index 115bcc39..8836e793 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 5f4eb7c4..411361f3 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