mirror of
https://github.com/ced4568/ceds-noc.git
synced 2026-08-12 21:04:02 +00:00
Update positioning, remove IPs from cards, remove icons, update NOC content
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Ced's NOC — Live Network Operations Center
|
||||
# Ced's NOC Live Network Operations Center
|
||||
|
||||
> A custom-built, public-facing Network Operations Center dashboard running at [noc.chasedumphord.com](https://noc.chasedumphord.com) — providing real-time visibility into Ced's HomeLab infrastructure, services, and RF edge systems.
|
||||
> A custom-built, public facing Network Operations Center dashboard running at [noc.chasedumphord.com](https://noc.chasedumphord.com) providing real time visibility into Ced's HomeLab infrastructure, services, and RF edge systems.
|
||||
|
||||
[](https://noc.chasedumphord.com)
|
||||
[](https://chasedumphord.com)
|
||||
@@ -11,11 +11,9 @@
|
||||
|
||||
## What This Is
|
||||
|
||||
This is the public-facing front door to Ced's HomeLab infrastructure. This is the frontend layer of Ced's observability platform — a custom-built status page that makes live infrastructure data publicly
|
||||
accessible without requiring login. The backend engine ([ceds-observability-stack](https://github.com/ced4568/ceds-observability-stack)) handles metrics collection via Prometheus and Grafana. This repo is
|
||||
what the public sees — real-time service status, latency, and health across every layer of the homelab. no login required.
|
||||
This is the public-facing front door to Ced's HomeLab infrastructure. This is the frontend layer of Ced's observability platform a custom built status page that makes live infrastructure data publicly accessible without requiring login. The backend engine ([ceds-observability-stack](https://github.com/ced4568/ceds-observability-stack)) handles metrics collection via Prometheus and Grafana. This repo is what the public sees real-time service status, latency, and health across every layer of the homelab. No login required.
|
||||
|
||||
It's not a template or a third-party uptime service. It's a purpose-built frontend that pulls live status data and presents it as a professional NOC dashboard. Every card on the page represents a real, running service with real latency and uptime data.
|
||||
It's not a template or a third party uptime service. It's a purpose built frontend that pulls live status data and presents it as a professional NOC dashboard. Every card on the page represents a real, running service with real latency and uptime data.
|
||||
|
||||
---
|
||||
|
||||
@@ -23,7 +21,7 @@ It's not a template or a third-party uptime service. It's a purpose-built fronte
|
||||
|
||||
[](https://noc.chasedumphord.com)
|
||||
|
||||
The NOC displays real-time status for every layer of the infrastructure stack — from the Proxmox hypervisor down to the APRS RF edge system.
|
||||
The NOC displays real time status for every layer of the infrastructure stack from the Proxmox hypervisor down to the APRS RF edge system.
|
||||
|
||||
---
|
||||
|
||||
@@ -49,8 +47,8 @@ The NOC displays real-time status for every layer of the infrastructure stack
|
||||
|
||||
| Service | Role | Status Source |
|
||||
|---------|------|--------------|
|
||||
| APRS Home iGate | RF-to-internet gateway (KJ5JCO-10) | TCP probe via Blackbox |
|
||||
| APRS-IS | External APRS internet service | TCP probe — noam.aprs2.net:14580 |
|
||||
| APRS Home iGate | RF to internet gateway (KJ5JCO-10) | TCP probe via Blackbox |
|
||||
| APRS-IS | External APRS internet service | TCP probe noam.aprs2.net:14580 |
|
||||
|
||||
---
|
||||
|
||||
@@ -89,7 +87,7 @@ graph LR
|
||||
2. Prometheus collects and stores probe results
|
||||
3. Python scripts generate status JSON from Prometheus data
|
||||
4. NOC frontend reads JSON and renders live status cards
|
||||
5. Public visitors see real-time infrastructure status — no login needed
|
||||
5. Public visitors see real time infrastructure status no login needed
|
||||
|
||||
---
|
||||
|
||||
@@ -119,21 +117,20 @@ ceds-noc/
|
||||
|
||||
Each service card on the NOC displays:
|
||||
|
||||
- **Service name and role** — what it is and what it does
|
||||
- **Category badge** — HYPERVISOR, STORAGE, CLUSTER, PORTAL, etc.
|
||||
- **Health badge** — HEALTHY or DEGRADED based on probe results
|
||||
- **Internal IP and port** — where the service lives on the HomeLab VLAN
|
||||
- **Status** — Online / Offline
|
||||
- **Latency** — real response time in milliseconds
|
||||
- **Last check timestamp** — when the probe last ran
|
||||
- **Service name and role** what it is and what it does
|
||||
- **Category badge** HYPERVISOR, STORAGE, CLUSTER, PORTAL, etc.
|
||||
- **Health badge** HEALTHY or DEGRADED based on probe results
|
||||
- **Status** Online / Offline
|
||||
- **Latency** real response time in milliseconds
|
||||
- **Last check timestamp** when the probe last ran
|
||||
|
||||
This gives anyone viewing the page the same operational picture that the internal Grafana dashboard provides — without requiring access to the internal network.
|
||||
This gives anyone viewing the page the same operational picture that the internal Grafana dashboard provides without requiring access to the internal network.
|
||||
|
||||
---
|
||||
|
||||
## Screenshots
|
||||
|
||||
### Systems Overview — Live Service Status
|
||||
### Systems Overview Live Service Status
|
||||

|
||||
|
||||
### Metrics Overview
|
||||
@@ -145,10 +142,10 @@ This gives anyone viewing the page the same operational picture that the interna
|
||||
|
||||
| Project | Role |
|
||||
|---------|------|
|
||||
| [ceds-observability-stack](https://github.com/ced4568/ceds-observability-stack) | Backend — Prometheus, Grafana, Alertmanager, all exporters |
|
||||
| [ceds-homelab](https://github.com/ced4568/ceds-homelab) | Infrastructure — Proxmox cluster, TrueNAS, networking |
|
||||
| [ced-k3s-homelab](https://github.com/ced4568/ced-k3s-homelab) | Orchestration — 12-node Raspberry Pi K3s cluster |
|
||||
| [ceds-aprs-igate](https://github.com/ced4568/ceds-aprs-igate) | Edge — Dual-node APRS RF-to-internet gateway |
|
||||
| [ceds-observability-stack](https://github.com/ced4568/ceds-observability-stack) | Backend Prometheus, Grafana, Alertmanager, all exporters |
|
||||
| [ceds-homelab](https://github.com/ced4568/ceds-homelab) | Infrastructure Proxmox cluster, TrueNAS, networking |
|
||||
| [ced-k3s-homelab](https://github.com/ced4568/ced-k3s-homelab) | Orchestration 12 node Raspberry Pi K3s cluster |
|
||||
| [ceds-aprs-igate](https://github.com/ced4568/ceds-aprs-igate) | Edge Dual node APRS RF-to-internet gateway |
|
||||
|
||||
---
|
||||
|
||||
@@ -156,11 +153,11 @@ This gives anyone viewing the page the same operational picture that the interna
|
||||
|
||||
- [x] Live service status cards with real probe data
|
||||
- [x] APRS RF edge system monitoring
|
||||
- [x] Public access — no login required
|
||||
- [x] Public access no login required
|
||||
- [x] Custom badge and status JSON generation
|
||||
- [ ] Alerting integration — visual alerts on NOC page
|
||||
- [ ] Alerting integration visual alerts on NOC page
|
||||
- [ ] Historical uptime percentage per service
|
||||
- [ ] Mobile-optimized layout
|
||||
- [ ] Mobile optimized layout
|
||||
- [ ] Auto-refresh with configurable interval
|
||||
- [ ] Public Grafana dashboard embed
|
||||
|
||||
@@ -169,9 +166,9 @@ This gives anyone viewing the page the same operational picture that the interna
|
||||
## Author
|
||||
|
||||
**Chase Dumphord (Ced)**
|
||||
Digital Systems Engineer · GE Aerospace · Oxford, MS
|
||||
DevOps and Cloud Infrastructure Engineer · GE Aerospace · Oxford, MS
|
||||
|
||||
[](https://chasedumphord.com)
|
||||
[](https://www.linkedin.com/in/chase-dumphord/)
|
||||
[](https://github.com/ced4568)
|
||||
[](https://noc.chasedumphord.com)
|
||||
[](https://noc.chasedumphord.com)
|
||||
+16
-23
@@ -17,12 +17,12 @@
|
||||
|
||||
<meta
|
||||
name="description"
|
||||
content="Ced's NOC — live network operations center dashboard showing real-time infrastructure health, service status, and edge system monitoring."
|
||||
content="Ced's NOC — live network operations center dashboard showing real-time infrastructure health across 18 nodes and 28 services. Proxmox, K3s, TrueNAS, APRS edge systems."
|
||||
/>
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content="Ced's NOC | Live Systems Dashboard" />
|
||||
<meta property="og:description" content="Live infrastructure visibility — Proxmox, K3s, TrueNAS, APRS edge systems." />
|
||||
<meta property="og:description" content="Live infrastructure visibility — 18 nodes, 28 services. Proxmox, K3s, TrueNAS, APRS edge systems. Always running." />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://noc.chasedumphord.com" />
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<meta name="robots" content="index, follow" />
|
||||
<meta name="author" content="Chase Dumphord" />
|
||||
|
||||
<!-- Fonts — same as main site -->
|
||||
<!-- Fonts same as main site -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Syne:wght@700;800&family=DM+Sans:wght@400;500;700&display=swap" rel="stylesheet" />
|
||||
@@ -46,7 +46,6 @@
|
||||
|
||||
<!-- NOC-specific styles -->
|
||||
<style>
|
||||
/* ── NOC page overrides & extras ── */
|
||||
.noc-page-hero {
|
||||
padding: 3.5rem 0 2rem;
|
||||
border-bottom: 1px solid var(--line);
|
||||
@@ -90,12 +89,10 @@
|
||||
.noc-page-meta a { color: var(--muted); }
|
||||
.noc-page-meta a:hover { color: var(--accent-2); }
|
||||
|
||||
/* Full-width NOC content area */
|
||||
.noc-full {
|
||||
padding: 2.5rem 0 4rem;
|
||||
}
|
||||
|
||||
/* Uptime summary bar */
|
||||
.uptime-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -131,7 +128,6 @@
|
||||
background: rgba(255, 95, 86, 0.06);
|
||||
}
|
||||
|
||||
/* Layer filter tabs */
|
||||
.layer-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -159,14 +155,12 @@
|
||||
background: rgba(94, 250, 204, 0.07);
|
||||
}
|
||||
|
||||
/* Roadmap section on NOC page */
|
||||
.noc-roadmap {
|
||||
margin-top: 3rem;
|
||||
padding-top: 2.5rem;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
/* Stack info footer on NOC page */
|
||||
.noc-stack-bar {
|
||||
margin-top: 2.5rem;
|
||||
padding: 1rem 1.25rem;
|
||||
@@ -195,7 +189,6 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Grafana CTA button row */
|
||||
.noc-cta-row {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
@@ -213,7 +206,7 @@
|
||||
|
||||
<body>
|
||||
|
||||
<!-- ═══════════════════════════════ NAV ═══════════════════════════════ -->
|
||||
<!-- NAV -->
|
||||
<header class="site-header">
|
||||
<div class="container nav">
|
||||
<a href="https://chasedumphord.com" class="logo">Ced<span class="logo-cursor">_</span></a>
|
||||
@@ -233,7 +226,7 @@
|
||||
|
||||
<main id="top">
|
||||
|
||||
<!-- ═══════════════════════════════ NOC HERO ═══════════════════════════════ -->
|
||||
<!-- NOC HERO -->
|
||||
<div class="noc-page-hero">
|
||||
<div class="container">
|
||||
<p class="eyebrow">
|
||||
@@ -246,9 +239,9 @@
|
||||
</h1>
|
||||
|
||||
<p class="noc-page-lead">
|
||||
Real-time visibility into Ced's HomeLab infrastructure — Proxmox, K3s,
|
||||
TrueNAS, APRS RF edge systems, and self-hosted services.
|
||||
Not simulated. Not a demo. Running hardware.
|
||||
Real-time visibility into Ced's HomeLab infrastructure across 18 nodes and 28 services
|
||||
Proxmox, K3s, TrueNAS, APRS RF edge systems, and self-hosted services.
|
||||
Built from the ground up and running in production every day. The infrastructure on this page is live. Not a demo.
|
||||
</p>
|
||||
|
||||
<!-- Grafana CTA buttons -->
|
||||
@@ -256,7 +249,7 @@
|
||||
<a href="https://grafana.cedshomelab.com/dashboard/snapshot/PmEdg0ALfAVsmKN1Qgv7K11XP8h52ne5"
|
||||
target="_blank" rel="noopener noreferrer"
|
||||
class="btn btn-primary">
|
||||
📊 View Live Grafana Dashboard →
|
||||
View Live Grafana Dashboard
|
||||
</a>
|
||||
<a href="https://github.com/ced4568/ceds-observability-stack"
|
||||
target="_blank" rel="noopener noreferrer"
|
||||
@@ -273,7 +266,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ═══════════════════════════════ NOC DASHBOARD ═══════════════════════════════ -->
|
||||
<!-- NOC DASHBOARD -->
|
||||
<div class="noc-full">
|
||||
<div class="container">
|
||||
|
||||
@@ -333,7 +326,7 @@
|
||||
<!-- Fallback -->
|
||||
<div id="noc-fallback" class="noc-fallback" style="display:none;">
|
||||
<p class="noc-fallback-msg">
|
||||
📡 NOC feed unavailable from this context — systems run locally.<br/>
|
||||
NOC feed unavailable from this context systems run locally.<br/>
|
||||
Data updates when the local pipeline pushes a fresh noc-status.json.
|
||||
</p>
|
||||
</div>
|
||||
@@ -341,9 +334,9 @@
|
||||
<!-- Stack info bar -->
|
||||
<div class="noc-stack-bar">
|
||||
<span><strong>Stack:</strong> Python health checks → JSON → JS dashboard</span>
|
||||
<span><strong>Live:</strong> Grafana + Prometheus —
|
||||
<span><strong>Live:</strong> Grafana + Prometheus
|
||||
<a href="https://grafana.cedshomelab.com/dashboard/snapshot/PmEdg0ALfAVsmKN1Qgv7K11XP8h52ne5"
|
||||
target="_blank" rel="noopener noreferrer">View Dashboard →</a>
|
||||
target="_blank" rel="noopener noreferrer">View Dashboard</a>
|
||||
</span>
|
||||
<span><strong>Source:</strong>
|
||||
<a href="https://github.com/ced4568/ceds-homelab" target="_blank" rel="noopener noreferrer">
|
||||
@@ -379,7 +372,7 @@
|
||||
<h3>Grafana + Prometheus</h3>
|
||||
<p>
|
||||
Full observability stack for Proxmox, TrueNAS, K3s, Raspberry Pi,
|
||||
Uptime Kuma, and APRS edge systems with real-time metrics ingestion.
|
||||
Uptime Kuma, and APRS edge systems with real time metrics ingestion.
|
||||
Public dashboard available.
|
||||
</p>
|
||||
</div>
|
||||
@@ -391,7 +384,7 @@
|
||||
|
||||
</main>
|
||||
|
||||
<!-- ═══════════════════════════════ FOOTER ═══════════════════════════════ -->
|
||||
<!-- FOOTER -->
|
||||
<footer class="site-footer">
|
||||
<div class="container footer-content">
|
||||
<p>© <span data-year></span> Chase Dumphord — <span class="footer-mono">noc.chasedumphord.com</span></p>
|
||||
@@ -402,7 +395,7 @@
|
||||
<!-- Shared script from main portfolio -->
|
||||
<script src="https://chasedumphord.com/script.js"></script>
|
||||
|
||||
<!-- NOC page extras — layer filter tabs + uptime pills -->
|
||||
<!-- NOC page extras layer filter tabs + uptime pills -->
|
||||
<script>
|
||||
let allSystems = [];
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// ═══════════════════════════════════════════════
|
||||
// Ced's Portfolio — script.js
|
||||
// Ced's NOC script.js
|
||||
// NOC data loads from data/noc-status.json
|
||||
// Refreshes every 30s. Graceful fallback on fail.
|
||||
// ═══════════════════════════════════════════════
|
||||
@@ -34,8 +34,6 @@ async function loadNocStatus() {
|
||||
const fallback = document.getElementById("noc-fallback");
|
||||
|
||||
try {
|
||||
// Cache-bust to always get fresh data
|
||||
// Use absolute URL when on NOC subdomain, relative when on main portfolio
|
||||
const nocDataUrl = window.location.hostname === 'noc.chasedumphord.com'
|
||||
? `https://chasedumphord.com/data/noc-status.json?t=${Date.now()}`
|
||||
: `data/noc-status.json?t=${Date.now()}`;
|
||||
@@ -46,32 +44,25 @@ async function loadNocStatus() {
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
// Reset fail counter on success
|
||||
failCount = 0;
|
||||
|
||||
// ── Status bar ──
|
||||
if (dot) {
|
||||
dot.className = "status-dot live";
|
||||
}
|
||||
if (dot) dot.className = "status-dot live";
|
||||
|
||||
if (statusText) {
|
||||
const d = new Date(data.lastUpdated);
|
||||
const formatted = d.toLocaleString('en-US', { month: 'long', day: 'numeric', year: 'numeric', hour: 'numeric', minute: '2-digit', hour12: true });
|
||||
statusText.textContent = `${data.nocName} — ${data.status} — Last updated: ${formatted}`;
|
||||
}
|
||||
if (badge) {
|
||||
badge.textContent = `Auto-refresh: 30s`;
|
||||
}
|
||||
|
||||
// Hide fallback if it was showing
|
||||
if (badge) badge.textContent = `Auto-refresh: 30s`;
|
||||
|
||||
if (fallback) fallback.style.display = "none";
|
||||
|
||||
// ── Metrics ──
|
||||
if (nodes) animateMetric(nodes, data.summary.nodes);
|
||||
if (services) animateMetric(services, data.summary.services);
|
||||
if (vlans) animateMetric(vlans, data.summary.vlans);
|
||||
if (edge) animateMetric(edge, data.summary.edgeSystems);
|
||||
|
||||
// ── System cards ──
|
||||
if (grid) {
|
||||
grid.innerHTML = "";
|
||||
data.systems.forEach((system) => {
|
||||
@@ -95,7 +86,6 @@ async function loadNocStatus() {
|
||||
</div>
|
||||
<h3>${system.name}</h3>
|
||||
<p>${system.type}</p>
|
||||
<code>${system.address}</code>
|
||||
<div class="system-meta">
|
||||
<small>Status: ${system.status}</small>
|
||||
<small>Latency: ${system.latency || "N/A"}</small>
|
||||
@@ -107,14 +97,12 @@ async function loadNocStatus() {
|
||||
});
|
||||
}
|
||||
|
||||
// ── Alerts ──
|
||||
if (alertList) renderAlerts(data.systems, alertList);
|
||||
|
||||
} catch (err) {
|
||||
failCount++;
|
||||
console.warn(`[NOC] Fetch failed (${failCount}/${MAX_FAILS}):`, err.message);
|
||||
|
||||
// Update dot to error state
|
||||
if (dot) dot.className = "status-dot error";
|
||||
|
||||
if (statusText) {
|
||||
@@ -125,27 +113,23 @@ async function loadNocStatus() {
|
||||
|
||||
if (badge) badge.textContent = "";
|
||||
|
||||
// After MAX_FAILS attempts, show the fallback block
|
||||
if (failCount >= MAX_FAILS && fallback) {
|
||||
fallback.style.display = "block";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Animate a number metric with a quick pop
|
||||
function animateMetric(el, value) {
|
||||
el.classList.remove("metric-pop");
|
||||
el.textContent = value;
|
||||
void el.offsetWidth; // force reflow
|
||||
void el.offsetWidth;
|
||||
el.classList.add("metric-pop");
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
// GitHub Repos — fetches public repos for ced4568
|
||||
// Sorted by last pushed, capped at 6 cards
|
||||
// GitHub Repos
|
||||
// ═══════════════════════════════════════════════
|
||||
|
||||
// Language → color map (subset of GitHub's palette)
|
||||
const LANG_COLORS = {
|
||||
Python: "#3572A5",
|
||||
JavaScript: "#f1e05a",
|
||||
@@ -170,8 +154,6 @@ async function loadGithubRepos() {
|
||||
if (!res.ok) throw new Error(`GitHub API ${res.status}`);
|
||||
|
||||
const repos = await res.json();
|
||||
|
||||
// Filter out forks for cleaner display
|
||||
const ownRepos = repos.filter((r) => !r.fork).slice(0, 6);
|
||||
|
||||
if (ownRepos.length === 0) {
|
||||
@@ -181,10 +163,7 @@ async function loadGithubRepos() {
|
||||
|
||||
container.innerHTML = ownRepos.map((repo) => {
|
||||
const langColor = LANG_COLORS[repo.language] || "var(--accent-2)";
|
||||
const desc = repo.description
|
||||
? repo.description
|
||||
: "No description provided.";
|
||||
|
||||
const desc = repo.description ? repo.description : "No description provided.";
|
||||
const updatedDate = new Date(repo.pushed_at).toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
@@ -203,9 +182,7 @@ async function loadGithubRepos() {
|
||||
>${repo.name}</a>
|
||||
<span class="repo-visibility">${repo.private ? "private" : "public"}</span>
|
||||
</div>
|
||||
|
||||
<p class="repo-desc">${desc}</p>
|
||||
|
||||
<div class="repo-meta">
|
||||
${repo.language
|
||||
? `<span>
|
||||
@@ -226,9 +203,9 @@ async function loadGithubRepos() {
|
||||
container.innerHTML = `
|
||||
<div class="repo-loading">
|
||||
<p class="noc-loading">
|
||||
Could not load repositories.
|
||||
Could not load repositories.
|
||||
<a href="https://github.com/ced4568" target="_blank" rel="noopener noreferrer">
|
||||
View on GitHub →
|
||||
View on GitHub
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
@@ -236,7 +213,7 @@ async function loadGithubRepos() {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Build the alert panel from system data
|
||||
|
||||
function renderAlerts(systems, alertList) {
|
||||
const scored = systems
|
||||
.map((sys) => {
|
||||
|
||||
Reference in New Issue
Block a user