Files
message_bus/reports/0001-2026-06-07-unibus-grafana-monitoring.md
T
egutierrez d43ffae3ae chore: auto-commit (17 archivos)
- reports/0001-2026-06-07-unibus-grafana-monitoring.md
- reports/0008-2026-06-07-unibus-admin-users-wired.md
- reports/0008-2026-06-07-unibus-decentralization-audit.md
- reports/0009-2026-06-07-unibus-cluster-hardening.md
- reports/0010-2026-06-07-unibus-android-native.md
- reports/0011-2026-06-07-unibus-cluster-deploy.md
- reports/0012-2026-06-07-unibus-deploy-gaps-closed.md
- reports/0013-2026-06-07-unibus-admin-panel.md
- reports/0014-2026-06-07-unibus-users-http-admin-api.md
- reports/0015-2026-06-07-unibus-web-wired.md
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-08 01:57:00 +02:00

146 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Report 0001 — Monitorización de unibus en Grafana/VictoriaMetrics
- **Fecha:** 07/06/2026
- **Autor:** agente (Claude Opus 4.8)
- **Ámbito:** `projects/fleet_monitoring/` (exporter + dashboard + deploy) + 1 función nueva en el registry (`functions/infra/`). Solo lectura de `projects/message_bus/apps/unibus/` (endpoint `/healthz` + CA).
- **Estado:** done (métricas de `/healthz`); gap declarado en métricas profundas NATS/JetStream.
## Resumen
Se añadió monitorización del cluster de mensajería **unibus** (NATS+JetStream, 3 nodos: magnus,
homer, datardos) a la stack de Grafana/VictoriaMetrics que ya corre en magnus, **sin instrumentar
el bus**. Un nuevo daemon `unibus_exporter` sondea el endpoint público de salud de cada nodo
(`GET https://<nodo>:8470/healthz`, TLS verificado con la CA del cluster) en un bucle de 15 s,
traduce la respuesta a métricas Prometheus y las empuja a la VictoriaMetrics local de magnus.
Un dashboard dedicado las visualiza. No se tocó nada del código de unibus ni la stack existente
(Caddy/Gitea/VM/Grafana/fleet-agent intactos).
## Qué métricas se recolectan y cómo
El `/healthz` de cada nodo devuelve, verificado en producción:
```json
{"posture":{"enforce":true,"acl":true,"tls":true,"cluster":true,"store":"kv"},"status":"ok"}
```
De ahí se derivan estas series (labels `node` e `instance` = nombre del nodo, label común
`job=unibus_exporter`):
| Serie | Origen | Significado |
|---|---|---|
| `unibus_up` | exporter | 1 si el nodo respondió `/healthz`, 0 si el GET/parseo falló |
| `unibus_status_ok` | healthz `status` | 1 si `status=="ok"` |
| `unibus_posture_enforce` | healthz `posture.enforce` | enforcement de auth (1/0) |
| `unibus_posture_acl` | healthz `posture.acl` | ACL de subjects (1/0) |
| `unibus_posture_tls` | healthz `posture.tls` | TLS del transporte (1/0) |
| `unibus_posture_cluster` | healthz `posture.cluster` | modo cluster activo (1/0) |
| `unibus_store_kv` | healthz `posture.store` | 1 si el store es `kv` (JetStream KV) |
| `unibus_scrape_error` | exporter | 1 si el scrape de ese nodo falló |
| `unibus_scrape_duration_seconds` | exporter | latencia del GET `/healthz` |
| `unibus_cluster_size` | exporter (config) | nº de nodos configurados (los vivos = `sum(unibus_up)`) |
`unibus_up=0` lo emite el exporter (no el parser) cuando el GET falla, para que un nodo caído sea
**visible** en Grafana, no simplemente ausente.
## Componentes entregados
### Función del registry — `parse_unibus_health_go_infra`
- `functions/infra/parse_unibus_health.go` + `.md` + `_test.go` (grupo `fleet-metrics`, tags `unibus`).
- `func ParseUnibusHealth(node string, body []byte) ([]PromSample, error)` — pura de transformación
(clasificada `impure` solo por el error de unmarshal). Tests golden/edge/error.
- **Nota de proceso:** el prompt pedía delegar esta función a `fn-constructor`, pero ese
subagent_type no existe en este entorno. Tras confirmar con el usuario ("crear en el registry"),
se creó a mano siguiendo el flujo (archivos + tests + `fn index`).
### App — `unibus_exporter` (sub-repo Gitea propio)
- `projects/fleet_monitoring/apps/unibus_exporter/`: `main.go`, `config.go`, `unibus.example.json`,
`systemd/unibus-exporter.service`, `app.md`, `.gitignore`.
- Compone `parse_unibus_health` + `format_prom_exposition` + `push_prom_remote` del registry (no
reescribe push ni formato). Config JSON; secretos (CA, basic-auth) fuera de argv. Verifica TLS
siempre contra la CA del cluster (sin `InsecureSkipVerify`).
- `git init -b master` + commit inicial hecho (apps/* está gitignored en el project; sin sub-repo
el código se perdería). Falta crear el repo Gitea remoto: lo hará `/full-git-push`.
### Dashboard — `unibus-cluster.json`
- `projects/fleet_monitoring/hub/dashboards/unibus-cluster.json` (formato de los `fleet-*.json`,
datasource `victoriametrics`, carpeta **Fleet**, uid `unibus-cluster`, 9 paneles): nodos up,
cluster size, nodos caídos, posture homogénea segura, up/down por nodo, matriz de posture por
nodo (state-timeline enforce/acl/tls/cluster/store-kv × 3 nodos), latencia de scrape y tabla de
estado por nodo. Panel "Meta-leader" preparado (muestra n/d sin métricas NATS).
### Deploy — `deploy_unibus_exporter.sh`
- `projects/fleet_monitoring/hub/deploy_unibus_exporter.sh`: compila el binario linux/amd64, sube
binario + CA del cluster a magnus (`/opt/unibus-exporter`, `/etc/unibus-exporter/ca.crt` chmod
600 la config) e instala el servicio systemd apuntando a `http://127.0.0.1:8428/...` (VM local,
sin auth porque corre en el propio hub).
## Verificación (evidencia ejecutable)
**1. Acceso y healthz de los 3 nodos (CA del cluster por path):**
```
$ curl -s --cacert .../deploy/tls/ca.crt https://135.125.201.30:8470/healthz
{"posture":{"enforce":true,"acl":true,"tls":true,"cluster":true,"store":"kv"},"status":"ok"}
(idéntico en homer 141.94.69.66 y datardos 51.91.100.142)
```
**2. Tests de la función:**
```
$ go test -tags fts5 -run ParseUnibusHealth ./functions/infra/
ok fn-registry/functions/infra 0.004s
$ ./fn index # → "Indexed 1450 functions ..."; ./fn show parse_unibus_health_go_infra → OK
```
**3. Exporter build + scrape/push único de prueba (local → VM):**
```
$ ./unibus_exporter -config <test> -once
unibus_exporter starting: nodes=3 hub="https://metrics-…/api/v1/import/prometheus" interval=15s
pushed 28 samples for 3 nodes # 1 cluster_size + 3 nodos × 9 series
```
**4. Daemon systemd en magnus:**
```
$ systemctl is-active unibus-exporter → active
$ systemctl is-enabled unibus-exporter → enabled
$ journalctl -u unibus-exporter → "pushed 28 samples for 3 nodes"
```
**5. Series en VictoriaMetrics (magnus, 127.0.0.1:8428):**
```
sum(unibus_up) = 3
unibus_cluster_size = 3
count(unibus_up==1) = 3
unibus_posture_enforce: magnus=1 homer=1 datardos=1 (job=unibus_exporter)
unibus_store_kv: magnus=1 homer=1 datardos=1
unibus_scrape_duration_seconds: magnus≈4ms homer≈32ms datardos≈19ms
```
**6. Dashboard en Grafana (visto en el navegador):**
- `https://grafana-…/d/unibus-cluster` — carpeta Fleet, 9 paneles renderizando datos reales.
- Nodos up: **3** · Cluster size: **3** · Nodos caídos: **0** · Posture homogénea segura:
**OK (enforce+acl+tls+cluster+kv)** · matriz de posture: 15 celdas en verde · tabla de estado
por nodo con ✓ en up/enforce/acl/tls.
- Captura: `unibus-grafana-monitoring-dashboard.png` (junto a este report).
- API: `GET /api/dashboards/uid/unibus-cluster``dashboard CARGADO: unibus — Cluster | folder: Fleet | paneles: 9`.
## Gaps / pendientes
- **Métricas profundas NATS/JetStream (msgs/s, conexiones, KV bucket msgs, RAFT leader por
stream, `NRestarts`) — NO incluidas, gap recomendado.** La vía es el monitoring embebido de
NATS (puerto 8222), que se confirmó **cerrado** en los 3 nodos en producción
(`curl 127.0.0.1:8222/varz` → CLOSED en magnus/homer/dd). Activarlo (bindeado a 127.0.0.1 +
scrape local, o sacar `/jsz` por SSH) exige tocar la config/unit de los nodos del cluster, que
además están siendo trabajados por otros agentes ahora mismo. Se decidió **no forzarlo** por
riesgo en producción. Para abordarlo después: añadir `UNIBUS_NATS_DEBUG`/equivalente bindeado a
loopback en cada nodo (cambio aditivo, coordinado con `unibus/deploy/cluster/`), un scrape local
del `/jsz`+`/varz` y nuevas series `unibus_jsz_*`. El panel "Meta-leader" del dashboard ya está
preparado para cuando exista `unibus_meta_leader`.
- **`unibus_cluster_size`** refleja el nº de nodos **configurados** en el exporter (3), no un
recuento que el bus reporte (healthz no lo expone). Los nodos vivos se ven con `sum(unibus_up)`.
- **Commit en el repo padre `fn_registry` sin pushear (a propósito):** la función nueva quedó
commiteada en local (`82f1f1bd`, master ahead 1) pero **no se hizo push** del padre, para
respetar el aislamiento pedido. El humano debería revisarlo y pushearlo (junto con `fn index`
para regenerar `registry.db`, que está gitignored).
- **Repo Gitea del exporter:** `apps/unibus_exporter` tiene su `git init` + commit local pero aún
no tiene remoto en Gitea; `/full-git-push` lo creará (`dataforge/unibus_exporter`).
- **Vida útil (DoD capa 3):** validado funcionalmente hoy; falta la ventana de uso real ≥7 días.