Files
egutierrez 92da0c0b0a feat: unibus_exporter — daemon que sondea /healthz del cluster unibus y empuja estado+posture a VictoriaMetrics
Compone parse_unibus_health + format_prom_exposition + push_prom_remote del registry
(grupo fleet-metrics). Un solo exporter scrapea los 3 nodos por IP pública con la CA
del cluster; labels node/instance por serie. Config JSON con secretos fuera de argv.
Incluye systemd unit y unibus.example.json.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 20:23:21 +02:00

121 lines
5.7 KiB
Markdown

---
name: unibus_exporter
lang: go
domain: infra
version: 0.1.0
description: "Exporter del cluster de mensajería unibus: sondea el /healthz de cada nodo por TLS (CA del cluster) en un bucle y empuja a VictoriaMetrics métricas de estado del cluster y posture (up/down, enforce/acl/tls/cluster, store-kv, cluster_size) sin instrumentar el bus."
tags: [fleet-metrics, unibus, monitoring, daemon]
uses_functions:
- parse_unibus_health_go_infra
- format_prom_exposition_go_infra
- push_prom_remote_go_infra
uses_types:
- PromSample_go_infra
framework: ""
entry_point: "main.go"
dir_path: "projects/fleet_monitoring/apps/unibus_exporter"
repo_url: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/dataforge/unibus_exporter"
---
# unibus_exporter
Daemon que monitoriza el cluster de mensajería **unibus** (NATS + JetStream, desplegado como
3 nodos: magnus, homer, datardos) y lo hace visible en Grafana junto al resto de la flota. Es
parte del project `fleet_monitoring`.
No instrumenta el bus: solo **lee** el endpoint público de salud de cada nodo
(`GET https://<nodo>:8470/healthz`, verificado con la CA del cluster) y traduce su respuesta a
métricas Prometheus que empuja a VictoriaMetrics. Así un único exporter (corriendo en magnus,
que alcanza los 3 nodos por IP pública) cubre todo el cluster sin tocar la configuración de los
nodos.
## Qué hace
Compone tres funciones del registry (grupo `fleet-metrics`), no reimplementa nada:
1. `parse_unibus_health_go_infra` — convierte el JSON de `/healthz` de un nodo en `[]PromSample`
con labels `node`/`instance`.
2. `format_prom_exposition_go_infra` — serializa los samples a texto formato Prometheus exposition.
3. `push_prom_remote_go_infra` — hace POST del texto a VictoriaMetrics, añadiendo la label común
`job=unibus_exporter` vía `extra_label`.
Como un solo exporter scrapea varios nodos, las labels `node` e `instance` se fijan **por serie**
(en el parser) y no vía `extra_label`, que aplicaría un único valor a todo el lote.
## Métricas que produce
| Serie | Labels | Significado |
|---|---|---|
| `unibus_up` | node, instance | 1 si el nodo respondió `/healthz`, 0 si falló el GET/parseo |
| `unibus_status_ok` | node, instance | 1 si `status=="ok"` |
| `unibus_posture_enforce` | node, instance | posture: enforcement de auth (1/0) |
| `unibus_posture_acl` | node, instance | posture: ACL de subjects (1/0) |
| `unibus_posture_tls` | node, instance | posture: TLS del transporte (1/0) |
| `unibus_posture_cluster` | node, instance | posture: modo cluster activo (1/0) |
| `unibus_store_kv` | node, instance | 1 si el backend de store es `kv` (JetStream KV) |
| `unibus_scrape_error` | node, instance | 1 si el scrape de ese nodo falló |
| `unibus_scrape_duration_seconds` | node, instance | latencia del GET `/healthz` |
| `unibus_cluster_size` | (global) | número de nodos configurados (los vivos = `sum(unibus_up)`) |
## Por qué no lleva el tag `service`
Es un daemon, pero igual que `metrics_agent` su liveness no se vigila con un health check propio
por SSH (modelo `service:`/`services_monitor`): si el exporter cae, las series `unibus_*` se
vuelven stale y eso es la señal. Por eso se etiqueta `daemon`.
## Configuración
Config por archivo JSON (`-config`). Campos en `unibus.example.json`:
| campo | descripción | default |
|---|---|---|
| `nodes[]` | lista de `{name, url}` por nodo (url = `/healthz` completo) | — (obligatorio) |
| `ca_cert_path` | PEM de la CA del cluster unibus, para verificar el TLS de cada nodo | — (obligatorio) |
| `hub_url` | endpoint de ingesta de VictoriaMetrics (`…/api/v1/import/prometheus`) | — (obligatorio) |
| `user` / `pass` | basic-auth del hub (vacío si el hub es local sin auth) | "" |
| `interval_sec` | periodo de scrape+push en segundos | 15 |
| `timeout_sec` | timeout del GET `/healthz` por nodo | 8 |
| `labels` | labels comunes añadidas vía `extra_label` | `{"job":"unibus_exporter"}` |
Overrides por entorno: `UNIBUS_HUB_URL`, `UNIBUS_USER`, `UNIBUS_PASS`, `UNIBUS_CA_CERT`,
`UNIBUS_INTERVAL`. Los secretos viven solo en el archivo de config (chmod 600), nunca en argv.
## Ejemplo
```bash
cd projects/fleet_monitoring/apps/unibus_exporter
go build -o unibus_exporter .
# Scrape+push único de prueba (lee config y sale)
./unibus_exporter -config /etc/unibus-exporter/unibus.json -once
# Bucle continuo (lo que hace el servicio systemd)
./unibus_exporter -config /etc/unibus-exporter/unibus.json
```
## Cuando usarla
Despliégalo en una máquina que alcance los 3 nodos del cluster (hoy magnus, por IP pública). No
hay que tocar los nodos de unibus: el exporter solo lee su `/healthz`. El dashboard
`hub/dashboards/unibus-cluster.json` visualiza estas series.
## Deploy
Desde la raíz del project: `./hub/deploy_unibus_exporter.sh magnus om`. Compila el binario, sube
binario + CA del cluster a `/opt/unibus-exporter` + `/etc/unibus-exporter`, escribe la config con
el endpoint local de VM (`http://127.0.0.1:8428/...`, sin auth porque corre en el hub) e instala
el servicio systemd.
## Gotchas
- La CA del cluster es **secreta** (gitignored): no se versiona en el repo. El deploy la sube al
nodo a `/etc/unibus-exporter/ca.crt` (chmod 600). Localmente vive en
`projects/message_bus/apps/unibus/deploy/tls/ca.crt`.
- El TLS se verifica **siempre** contra esa CA: una CA equivocada o ausente hace fallar el
arranque, no se ignora.
- `unibus_up=0` lo emite este exporter (no el parser) cuando el GET falla, para que un nodo caído
sea visible en Grafana en vez de simplemente desaparecer.
- Métricas profundas de NATS/JetStream (msgs/s, conexiones, RAFT leader por stream, NRestarts) NO
las produce: requieren el monitoring embebido de NATS (puerto 8222), hoy cerrado en producción.
Ver el report `unibus-grafana-monitoring` para el detalle del gap.