mirror of
https://github.com/ced4568/ced-portfolio.git
synced 2026-08-12 22:34:03 +00:00
Security: replace internal IPs with hostnames, fix filter persistence, UI improvements
This commit is contained in:
@@ -49,7 +49,7 @@ Proxmox Biggie (Cron every 5min)
|
||||
|
||||
### Automation
|
||||
|
||||
- Script: `~/scripts/noc_update.py` running on Biggie (`10.10.30.192`)
|
||||
- Script: `~/scripts/noc_update.py` running on Biggie
|
||||
- Cron: `*/5 * * * *` — every 5 minutes
|
||||
- Log: `/var/log/noc_update.log`
|
||||
- Auth: GitHub Personal Access Token via baked remote URL
|
||||
|
||||
+48
-48
@@ -10,198 +10,198 @@
|
||||
},
|
||||
"systems": [
|
||||
{
|
||||
"name": "Proxmox \u2014 BigWorld",
|
||||
"name": "Proxmox — BigWorld",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.250",
|
||||
"address": "BigWorld",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox \u2014 Biggie",
|
||||
"name": "Proxmox — Biggie",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.192",
|
||||
"address": "Biggie",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.1ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox \u2014 Snoop",
|
||||
"name": "Proxmox — Snoop",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.153",
|
||||
"address": "Snoop",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.7ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox \u2014 TooShort",
|
||||
"name": "Proxmox — TooShort",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.120",
|
||||
"address": "TooShort",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.4ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox \u2014 Tupac",
|
||||
"name": "Proxmox — Tupac",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.74",
|
||||
"address": "Tupac",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.5ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox \u2014 DrDre",
|
||||
"name": "Proxmox — DrDre",
|
||||
"type": "Proxmox VE Hypervisor",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Compute",
|
||||
"address": "10.10.30.227",
|
||||
"address": "DrDre",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.5ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Control \u2014 django-1",
|
||||
"name": "K3s Control — django-1",
|
||||
"type": "K3s Control Plane",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.72",
|
||||
"address": "k3s-django-1",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Control \u2014 django-2",
|
||||
"name": "K3s Control — django-2",
|
||||
"type": "K3s Control Plane",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.245",
|
||||
"address": "k3s-django-2",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Control \u2014 django-3",
|
||||
"name": "K3s Control — django-3",
|
||||
"type": "K3s Control Plane",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.128",
|
||||
"address": "k3s-django-3",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Ingress \u2014 node-1",
|
||||
"name": "K3s Ingress — node-1",
|
||||
"type": "K3s Worker / Ingress",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.219",
|
||||
"address": "k3s-node-1",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Ingress \u2014 node-2",
|
||||
"name": "K3s Ingress — node-2",
|
||||
"type": "K3s Worker / Ingress",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.134",
|
||||
"address": "k3s-node-2",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Ingress \u2014 node-3",
|
||||
"name": "K3s Ingress — node-3",
|
||||
"type": "K3s Worker / Ingress",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.222",
|
||||
"address": "k3s-node-3",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Data \u2014 node-4",
|
||||
"name": "K3s Data — node-4",
|
||||
"type": "K3s Worker / Data",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.126",
|
||||
"address": "k3s-node-4",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Data \u2014 node-5",
|
||||
"name": "K3s Data — node-5",
|
||||
"type": "K3s Worker / Data",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.239",
|
||||
"address": "k3s-node-5",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Data \u2014 node-6",
|
||||
"name": "K3s Data — node-6",
|
||||
"type": "K3s Worker / Data",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.208",
|
||||
"address": "k3s-node-6",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Monitor \u2014 node-7",
|
||||
"name": "K3s Monitor — node-7",
|
||||
"type": "K3s Worker / Monitoring",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.198",
|
||||
"address": "k3s-node-7",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Monitor \u2014 node-8",
|
||||
"name": "K3s Monitor — node-8",
|
||||
"type": "K3s Worker / Monitoring",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.216",
|
||||
"address": "k3s-node-8",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "K3s Monitor \u2014 node-9",
|
||||
"name": "K3s Monitor — node-9",
|
||||
"type": "K3s Worker / Monitoring",
|
||||
"layer": "Orchestration",
|
||||
"label": "K3s",
|
||||
"address": "10.10.30.29",
|
||||
"address": "k3s-node-9",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
@@ -212,7 +212,7 @@
|
||||
"type": "Network Attached Storage",
|
||||
"layer": "Infrastructure",
|
||||
"label": "Storage",
|
||||
"address": "10.10.30.143",
|
||||
"address": "TrueNAS",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.6ms",
|
||||
@@ -223,7 +223,7 @@
|
||||
"type": "Reverse Proxy",
|
||||
"layer": "Networking",
|
||||
"label": "Access",
|
||||
"address": "10.10.30.210",
|
||||
"address": "NPM",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
@@ -234,7 +234,7 @@
|
||||
"type": "Metrics Collection",
|
||||
"layer": "Monitoring",
|
||||
"label": "Observability",
|
||||
"address": "10.10.30.140",
|
||||
"address": "Prometheus",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
@@ -245,7 +245,7 @@
|
||||
"type": "Metrics Dashboard",
|
||||
"layer": "Monitoring",
|
||||
"label": "Observability",
|
||||
"address": "10.10.30.68",
|
||||
"address": "Grafana",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
@@ -256,7 +256,7 @@
|
||||
"type": "Service Monitor",
|
||||
"layer": "Monitoring",
|
||||
"label": "Observability",
|
||||
"address": "10.10.30.14",
|
||||
"address": "Uptime Kuma",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.3ms",
|
||||
@@ -267,7 +267,7 @@
|
||||
"type": "HomeLab Dashboard",
|
||||
"layer": "Services",
|
||||
"label": "Dashboard",
|
||||
"address": "10.10.30.61",
|
||||
"address": "Dashy",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.2ms",
|
||||
@@ -278,7 +278,7 @@
|
||||
"type": "Home Automation",
|
||||
"layer": "Services",
|
||||
"label": "Automation",
|
||||
"address": "10.10.30.104",
|
||||
"address": "Home Assistant",
|
||||
"status": "Offline",
|
||||
"severity": "Critical",
|
||||
"latency": "N/A",
|
||||
@@ -289,29 +289,29 @@
|
||||
"type": "Media / Game Server",
|
||||
"layer": "Services",
|
||||
"label": "Media",
|
||||
"address": "10.10.30.233",
|
||||
"address": "PrimeStation",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "0.4ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "APRS iGate \u2014 Home",
|
||||
"name": "APRS iGate — Home",
|
||||
"type": "RF Edge / APRS-IS Gateway",
|
||||
"layer": "Edge",
|
||||
"label": "RF",
|
||||
"address": "10.10.30.129",
|
||||
"address": "KJ5JCO-10 iGate",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "160.8ms",
|
||||
"lastCheck": "2026-05-14 23:45 UTC"
|
||||
},
|
||||
{
|
||||
"name": "APRS iGate \u2014 Mobile",
|
||||
"name": "APRS iGate — Mobile",
|
||||
"type": "RF Edge / Mobile Node",
|
||||
"layer": "Edge",
|
||||
"label": "RF",
|
||||
"address": "10.10.30.35",
|
||||
"address": "KJ5JCO Mobile",
|
||||
"status": "Online",
|
||||
"severity": "Healthy",
|
||||
"latency": "21.2ms",
|
||||
|
||||
+26
-9
@@ -16,6 +16,11 @@
|
||||
<meta property="og:description" content="Live infrastructure visibility — Proxmox, K3s, TrueNAS, APRS edge systems." />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://noc.chasedumphord.com" />
|
||||
<meta property="og:image" content="https://chasedumphord.com/assets/images/noc-dashboard.png" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Ced's NOC | Live Systems Dashboard" />
|
||||
<meta name="twitter:description" content="Live infrastructure visibility — Proxmox, K3s, TrueNAS, APRS edge systems." />
|
||||
<meta name="twitter:image" content="https://chasedumphord.com/assets/images/noc-dashboard.png" />
|
||||
|
||||
<!-- Favicons (path up one level since we're in /noc/) -->
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="../assets/favicons/favicon-32x32.png" />
|
||||
@@ -193,12 +198,11 @@
|
||||
|
||||
<nav>
|
||||
<ul class="nav-links">
|
||||
<li><a href="https://chasedumphord.com/#snapshot">Snapshot</a></li>
|
||||
<li><a href="https://chasedumphord.com/#about">About</a></li>
|
||||
<li><a href="https://chasedumphord.com/#projects">Projects</a></li>
|
||||
<li><a href="https://chasedumphord.com/#stack">Stack</a></li>
|
||||
<li><a href="#top">Dashboard</a></li>
|
||||
<li><a href="#layer-tabs">Systems</a></li>
|
||||
<li><a href="https://chasedumphord.com">← Portfolio</a></li>
|
||||
<li><a href="https://github.com/ced4568/ceds-homelab" target="_blank" rel="noopener noreferrer">GitHub</a></li>
|
||||
<li><a href="https://chasedumphord.com/#contact">Contact</a></li>
|
||||
<li><a href="https://chasedumphord.com/assets/images/ChaseD_Resume.pdf" target="_blank" rel="noopener noreferrer">Resume</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
@@ -300,7 +304,7 @@
|
||||
<!-- Stack info bar -->
|
||||
<div class="noc-stack-bar">
|
||||
<span><strong>Stack:</strong> Python health checks → JSON → JS dashboard</span>
|
||||
<span><strong>Next:</strong> Grafana + Prometheus integration</span>
|
||||
<span><strong>Live:</strong> <a href="https://grafana.cedshomelab.com" target="_blank" rel="noopener noreferrer">Grafana + Prometheus</a></span>
|
||||
<span><strong>Source:</strong>
|
||||
<a href="https://github.com/ced4568/ceds-homelab" target="_blank" rel="noopener noreferrer">
|
||||
github/ceds-homelab
|
||||
@@ -331,7 +335,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="noc-card">
|
||||
<div class="noc-card-badge future">📈 Future</div>
|
||||
<div class="noc-card-badge done">✅ Live</div>
|
||||
<h3>Grafana + Prometheus</h3>
|
||||
<p>
|
||||
Full observability stack for Proxmox, TrueNAS, K3s, Raspberry Pi,
|
||||
@@ -362,6 +366,7 @@
|
||||
// ── Layer filter tabs ──────────────────────────────────────────
|
||||
// Populated after NOC data loads. Filters the system grid by layer.
|
||||
let allSystems = [];
|
||||
let activeLayer = "all"; // Track active filter across refreshes
|
||||
|
||||
const originalLoad = window.loadNocStatus;
|
||||
|
||||
@@ -372,7 +377,8 @@
|
||||
if (cards.length > 0) {
|
||||
buildLayerTabs();
|
||||
buildUptimePills();
|
||||
observer.disconnect();
|
||||
// Re-apply active filter after data refresh
|
||||
reapplyFilter();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -380,6 +386,16 @@
|
||||
if (grid) observer.observe(grid, { childList: true });
|
||||
});
|
||||
|
||||
function reapplyFilter() {
|
||||
if (activeLayer !== "all") {
|
||||
document.querySelectorAll(".noc-system-card").forEach(card => {
|
||||
const layerEl = card.querySelector(".noc-system-top span:last-child");
|
||||
card.style.display =
|
||||
layerEl && layerEl.textContent.trim() === activeLayer ? "" : "none";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function buildLayerTabs() {
|
||||
const cards = document.querySelectorAll(".noc-system-card");
|
||||
const layers = new Set(["all"]);
|
||||
@@ -394,7 +410,7 @@
|
||||
|
||||
layers.forEach(layer => {
|
||||
const btn = document.createElement("button");
|
||||
btn.className = "layer-tab" + (layer === "all" ? " active" : "");
|
||||
btn.className = "layer-tab" + (layer === activeLayer ? " active" : "");
|
||||
btn.dataset.layer = layer;
|
||||
btn.textContent = layer === "all" ? "All Systems" : layer;
|
||||
btn.addEventListener("click", () => filterByLayer(layer, btn));
|
||||
@@ -403,6 +419,7 @@
|
||||
}
|
||||
|
||||
function filterByLayer(layer, activeBtn) {
|
||||
activeLayer = layer; // Persist across refreshes
|
||||
document.querySelectorAll(".layer-tab").forEach(t => t.classList.remove("active"));
|
||||
activeBtn.classList.add("active");
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ SYSTEMS = [
|
||||
"type": "Virtualization Platform",
|
||||
"host": "10.10.30.250",
|
||||
"port": 8006,
|
||||
"address": "10.10.30.250:8006",
|
||||
"display_name": "BigWorld",
|
||||
"layer": "Core Infrastructure",
|
||||
"label": "Hypervisor"
|
||||
},
|
||||
@@ -21,7 +21,7 @@ SYSTEMS = [
|
||||
"type": "Storage Platform",
|
||||
"host": "10.10.30.143",
|
||||
"port": 80,
|
||||
"address": "10.10.30.143",
|
||||
"display_name": "TrueNAS",
|
||||
"layer": "Storage",
|
||||
"label": "NAS"
|
||||
},
|
||||
@@ -30,7 +30,7 @@ SYSTEMS = [
|
||||
"type": "Reverse Proxy",
|
||||
"host": "10.10.30.210",
|
||||
"port": 81,
|
||||
"address": "10.10.30.210:81",
|
||||
"display_name": "NPM",
|
||||
"layer": "Access Layer",
|
||||
"label": "Proxy"
|
||||
},
|
||||
@@ -39,7 +39,7 @@ SYSTEMS = [
|
||||
"type": "Service Dashboard",
|
||||
"host": "10.10.30.61",
|
||||
"port": 4000,
|
||||
"address": "10.10.30.61:4000",
|
||||
"display_name": "Dashy",
|
||||
"layer": "Dashboard",
|
||||
"label": "Portal"
|
||||
},
|
||||
@@ -48,7 +48,7 @@ SYSTEMS = [
|
||||
"type": "Media Service",
|
||||
"host": "10.10.30.143",
|
||||
"port": 30013,
|
||||
"address": "10.10.30.143:30013",
|
||||
"display_name": "PrimeStation",
|
||||
"layer": "Application Service",
|
||||
"label": "App"
|
||||
},
|
||||
@@ -57,7 +57,7 @@ SYSTEMS = [
|
||||
"type": "Kubernetes API",
|
||||
"host": "10.10.30.72",
|
||||
"port": 6443,
|
||||
"address": "10.10.30.72:6443",
|
||||
"display_name": "k3s-django-1",
|
||||
"layer": "Compute Cluster",
|
||||
"label": "Cluster"
|
||||
},
|
||||
@@ -66,7 +66,7 @@ SYSTEMS = [
|
||||
"type": "RF Edge Gateway",
|
||||
"host": "10.10.30.129",
|
||||
"port": 8001,
|
||||
"address": "KJ5JCO-10 / Direwolf KISS 8001",
|
||||
"display_name": "KJ5JCO-10 iGate",
|
||||
"layer": "Edge / RF",
|
||||
"label": "iGate"
|
||||
},
|
||||
@@ -75,7 +75,7 @@ SYSTEMS = [
|
||||
"type": "APRS Internet Service",
|
||||
"host": "noam.aprs2.net",
|
||||
"port": 14580,
|
||||
"address": "noam.aprs2.net:14580",
|
||||
"display_name": "noam.aprs2.net",
|
||||
"layer": "Edge / RF",
|
||||
"label": "External"
|
||||
}
|
||||
@@ -141,7 +141,7 @@ def main():
|
||||
systems.append({
|
||||
"name": system["name"],
|
||||
"type": system["type"],
|
||||
"address": system["address"],
|
||||
"address": system["display_name"],
|
||||
"status": status,
|
||||
"severity": severity_from_status(online, latency),
|
||||
"layer": system["layer"],
|
||||
|
||||
Reference in New Issue
Block a user