chore(iot): убрать старое (Kafka/K8s) из живого админ-UI и .gitignore

- iot-admin.html: секции Kafka/Pods заменены на Очередь shared-SQS и Рантайм
  (бэкенд admin.go давно отдаёт sqs/runtime, а фронт рисовал мёртвые секции);
  удалены CSS .pod-*/.badge-*/.dot-*/.lag-bar*, исправлен заголовок.
- .gitignore: удалены сталые пути бинарников старого IoT (/iot-operator,
  /mqtt-bridge, /kafka-consumer, /sqs-consumer).
This commit is contained in:
Repinoid
2026-10-10 18:15:13 +03:00
parent b205f886b6
commit a510522660
2 changed files with 43 additions and 105 deletions
-4
View File
@@ -1,8 +1,4 @@
# Бинарники (только в корне проекта, не директории cmd/) # Бинарники (только в корне проекта, не директории cmd/)
/iot-operator
/mqtt-bridge
/kafka-consumer
/sqs-consumer
bin/ bin/
ws-probe/ws-probe ws-probe/ws-probe
/iot-service /iot-service
+43 -101
View File
@@ -1,9 +1,9 @@
<!DOCTYPE html> <!DOCTYPE html>
<!-- Создано: 2026-04-06 <!-- Создано: 2026-04-06
iot-admin.html — страница администратора IoT pipeline. iot-admin.html — страница администратора IoT pipeline.
Показывает: PostgreSQL stats per tenant, Kafka consumer lag, K8s pod statuses. Показывает: PostgreSQL stats per tenant, очередь shared-SQS, рантайм процесса.
Auth: ADMIN_STATS_TOKEN вводится вручную и хранится в sessionStorage. Auth: ADMIN_STATS_TOKEN вводится вручную и хранится в sessionStorage.
Раздаётся по GET /iot-admin (go:embed в бинарнике оператора). Раздаётся по GET /iot-admin (go:embed в бинарнике iot-service).
НЕ для конечных пользователей — только для администратора платформы. --> НЕ для конечных пользователей — только для администратора платформы. -->
<html lang="ru"> <html lang="ru">
<head> <head>
@@ -95,23 +95,6 @@
.card-ok { color: #34d399; } .card-ok { color: #34d399; }
.card-err { color: #f87171; } .card-err { color: #f87171; }
/* Pod status card */
.pod-card {
background: #001929; border: 1px solid #0b2d50; border-radius: 10px;
padding: 20px; display: flex; flex-direction: column; gap: 8px;
}
.pod-name { font-size: 13px; font-weight: 600; color: #7fc8f8; font-family: monospace; }
.pod-row { display: flex; justify-content: space-between; font-size: 12px; }
.pod-label { color: #6b8eaa; }
.pod-val { color: #e2ecf6; }
.badge {
display: inline-block; padding: 2px 8px; border-radius: 4px;
font-size: 11px; font-weight: 700;
}
.badge-ok { background: #052e16; color: #34d399; border: 1px solid #064e3b; }
.badge-warn { background: #2d1c00; color: #f59e0b; border: 1px solid #4d3000; }
.badge-err { background: #300; color: #f87171; border: 1px solid #500; }
/* Tenant table */ /* Tenant table */
.tenant-table { width: 100%; border-collapse: collapse; font-size: 13px; } .tenant-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.tenant-table th { .tenant-table th {
@@ -142,18 +125,6 @@
/* Last updated */ /* Last updated */
.last-updated { font-size: 12px; color: #2d5070; text-align: center; margin-top: 16px; } .last-updated { font-size: 12px; color: #2d5070; text-align: center; margin-top: 16px; }
/* Status dot */
.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; }
.dot-ok { background: #34d399; }
.dot-warn { background: #f59e0b; }
.dot-err { background: #f87171; }
/* Kafka lag bar */
.lag-bar-wrap { background: #001120; border-radius: 4px; height: 6px; margin-top: 8px; overflow: hidden; }
.lag-bar { height: 100%; border-radius: 4px; transition: width 0.5s; min-width: 2px; }
.lag-bar-ok { background: #34d399; }
.lag-bar-warn { background: #f59e0b; }
/* Spinner */ /* Spinner */
.spinner { .spinner {
border: 3px solid #0b2d50; border-top-color: #1a7fd4; border: 3px solid #0b2d50; border-top-color: #1a7fd4;
@@ -223,26 +194,26 @@
<!-- Данные --> <!-- Данные -->
<div id="dataContent" style="display:none"> <div id="dataContent" style="display:none">
<!-- Kafka --> <!-- shared-SQS: очередь телеметрии -->
<div class="section"> <div class="section">
<div class="section-header"> <div class="section-header">
<svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="#7fc8f8" stroke-width="2"> <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="#7fc8f8" stroke-width="2">
<path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/> <path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/>
</svg> </svg>
<span class="section-title">Kafka</span> <span class="section-title">Очередь shared-SQS</span>
</div> </div>
<div class="cards" id="kafkaCards"></div> <div class="cards" id="sqsCards"></div>
</div> </div>
<!-- K8s Pods --> <!-- Рантайм процесса -->
<div class="section"> <div class="section">
<div class="section-header"> <div class="section-header">
<svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="#7fc8f8" stroke-width="2"> <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="#7fc8f8" stroke-width="2">
<rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/> <rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/>
</svg> </svg>
<span class="section-title">Pods</span> <span class="section-title">Рантайм</span>
</div> </div>
<div class="cards" id="podCards"></div> <div class="cards" id="runtimeCards"></div>
</div> </div>
<!-- PostgreSQL per tenant --> <!-- PostgreSQL per tenant -->
@@ -388,83 +359,54 @@ function resetRefreshTimer() {
// ── Render ───────────────────────────────────────────────────────────────── // ── Render ─────────────────────────────────────────────────────────────────
function renderAll(data) { function renderAll(data) {
renderKafka(data.kafka || {}); renderSQS(data.sqs || {});
renderPods(data.pods || {}); renderRuntime(data.runtime || {});
renderPostgres(data.postgres || {}); renderPostgres(data.postgres || {});
} }
// Kafka section // Очередь shared-SQS
function renderKafka(kafka) { function renderSQS(sqs) {
const el = document.getElementById('kafkaCards'); const el = document.getElementById('sqsCards');
if (kafka.error) { if (sqs.error) {
el.innerHTML = `<div class="card"><div class="card-title">Ошибка</div> el.innerHTML = `<div class="card"><div class="card-title">Ошибка</div>
<div class="card-value card-err" style="font-size:14px">${esc(kafka.error)}</div></div>`; <div class="card-value card-err" style="font-size:14px">${esc(sqs.error)}</div></div>`;
return; return;
} }
const pending = sqs.approximate_messages || 0;
const lag = kafka.consumer_lag || 0; const inFlight = sqs.approximate_messages_not_visible || 0;
const latest = kafka.latest_offset || 0; const pendingClass = pending === 0 ? 'card-ok' : pending < 100 ? 'card-warn' : 'card-err';
const committed = kafka.committed_offset || 0;
const lagClass = lag === 0 ? 'card-ok' : lag < 100 ? 'card-warn' : 'card-err';
const barClass = lag === 0 ? 'lag-bar-ok' : 'lag-bar-warn';
const barWidth = latest > 0 ? Math.max(2, Math.round((committed / latest) * 100)) : 100;
el.innerHTML = ` el.innerHTML = `
<div class="card"> <div class="card">
<div class="card-title">Consumer Lag</div> <div class="card-title">Ожидают обработки</div>
<div class="card-value ${lagClass}">${lag}</div> <div class="card-value ${pendingClass}">${pending.toLocaleString()}</div>
<div class="card-sub">iot-pg-consumer / iot.telemetry</div> <div class="card-sub">ApproximateNumberOfMessages</div>
<div class="lag-bar-wrap"><div class="lag-bar ${barClass}" style="width:${barWidth}%"></div></div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-title">Latest Offset (всего прошло)</div> <div class="card-title">В обработке</div>
<div class="card-value card-accent">${latest.toLocaleString()}</div> <div class="card-value card-accent">${inFlight.toLocaleString()}</div>
<div class="card-sub">Kafka log end offset</div> <div class="card-sub">ApproximateNumberOfMessagesNotVisible</div>
</div>
<div class="card">
<div class="card-title">Committed Offset</div>
<div class="card-value">${committed.toLocaleString()}</div>
<div class="card-sub">Consumer обработал</div>
</div>`; </div>`;
} }
// Pods section // Рантайм процесса
function renderPods(pods) { function renderRuntime(rt) {
const el = document.getElementById('podCards'); const el = document.getElementById('runtimeCards');
el.innerHTML = ''; const uptime = rt.uptime_sec || 0;
const h = Math.floor(uptime / 3600);
const labels = { const m = Math.floor((uptime % 3600) / 60);
'iot-mqtt-bridge': 'MQTT Bridge', const s = uptime % 60;
'iot-kafka-consumer': 'Kafka Consumer' const uptimeStr = h > 0 ? `${h}ч ${m}м` : m > 0 ? `${m}м ${s}с` : `${s}с`;
}; el.innerHTML = `
<div class="card">
for (const [key, pod] of Object.entries(pods)) { <div class="card-title">Версия</div>
const title = labels[key] || key; <div class="card-value" style="font-size:20px">${esc(rt.version || '—')}</div>
if (pod.error || pod.status === 'not found') { <div class="card-sub">iot-service</div>
el.innerHTML += ` </div>
<div class="pod-card"> <div class="card">
<div class="pod-name">${esc(title)}</div> <div class="card-title">Uptime</div>
<div style="color:#f87171;font-size:12px">${esc(pod.error || 'Pod not found')}</div> <div class="card-value card-accent">${uptimeStr}</div>
</div>`; <div class="card-sub">с ${esc(rt.started_at || '—')}</div>
continue; </div>`;
}
const readyBadge = pod.ready
? '<span class="badge badge-ok">Ready</span>'
: '<span class="badge badge-warn">Not Ready</span>';
const restartColor = pod.restarts > 5 ? 'card-err' : pod.restarts > 0 ? 'card-warn' : 'card-ok';
el.innerHTML += `
<div class="pod-card">
<div class="pod-name">
<span class="dot dot-${pod.ready ? 'ok' : 'warn'}"></span>${esc(title)}
</div>
<div class="pod-row"><span class="pod-label">Pod</span><span class="pod-val" style="font-family:monospace;font-size:11px">${esc(pod.name)}</span></div>
<div class="pod-row"><span class="pod-label">Phase</span><span class="pod-val">${esc(pod.phase)} ${readyBadge}</span></div>
<div class="pod-row"><span class="pod-label">Restarts</span><span class="pod-val ${restartColor}">${pod.restarts}</span></div>
<div class="pod-row"><span class="pod-label">Age</span><span class="pod-val">${esc(pod.age)}</span></div>
</div>`;
}
} }
// Postgres section // Postgres section