Hub

electrosystems

backup-system

active medium work
Creado
2026-05-08
Actualizado
2026-05-29
Directorios
  • /home/sergio/agy/electrosystems/backup-system
  • /home/sergio/agy/electrosystems/servers/oxidized
  • /home/sergio/agy/electrosystems/servers/es-nas
  • /home/sergio/agy/electrosystems/servers/reverse-proxy

Pendientes abiertos (19)

Ver todos →

🎯 Top de ataque (19)

  • #314 📅 2026-06-03 Planet — vendor faltante. Pendiente: identificar cuántos devices Planet hay en la red (probablemente switches L2/L3 de la línea Planet). Existe ya un alias planet-parral en ~/.ssh/config (192.168.44.2, user admin). Investigar firmware/CLI y elegir/escribir modelo Oxidized.
  • #315 📅 2026-06-05 Siklu — vendor faltante. Sergio nota: "no está documentado por nombre, es parte de los dispositivos faltantes". Probable: equipos mmWave/E-band que están entre los blackBox UNKNOWN de UISP. Identificar por OUI (Siklu OUI: 00-22-91) y agregar a BLACKBOX_OUI_MAP similar al patrón Mimosa. Verificar si tienen SSH y cómo se exporta su config.
  • 📅 2026-06-08 Decidir credenciales por vendor (password fijo del fabricante? key auth? RBAC en NetBox?).
  • 📅 2026-06-10 Para cada vendor: confirmar si necesita un provision_<vendor>.sh (instalación de SSH keys) o si se backup con password en sops.
  • 📅 2026-06-12 Tag backup-enabled en NetBox para devices ya inventariados de cada vendor (ver flujo en electrosystems/backup-system/README.md).
  • #316 📅 2026-06-15 Aclarar caso de uso real con Sergio: si la pendiente "ver manera de descargar" sigue viva, ¿qué le falta a la UI actual? Casos posibles:
  • #061 📅 2026-06-17 #061a A — IP en el header del archivo de config. Auto-inyectada por Oxidized vía model hook. Primera línea del archivo como comentario con la IP del device en el momento del backup. git grep <ip> instantáneo.
  • #061 📅 2026-06-19 #061b C — Manifest inventory.yaml versionado. Generado por inventory_merger.py en cada run, commiteado al repo configs.git. Mapea device-slug → IP, modelo, sitio, region por snapshot. Snapshot histórico de "qué IP tenía X el día tal" queda en git log inventory.yaml.
  • #319 📅 2026-06-22 155 devices recién agregados de regiones nuevas (Chihuahua, Parral, Caborca, Namiquipa, Nogales, Villa Ahumada, Colonia del Valle): pendientes de correr fleet_provision_airos.sh / fleet_provision_edgeos.sh antes de que los backups con key-auth funcionen. Lista de runs candidata en el README de electrosystems/backup-system/ § "Onboarding the new regions".
  • #320 📅 2026-06-24 45 Netonix WS-x: correr fleet_provision_netonix.sh con la firmware-split logic. Old firmware (kernel 2.6.x) acepta keys, new firmware (kernel 5.x) requiere password en sops creds.
  • #321 📅 2026-06-25 6 devices airFiber AF60-LR tienen prompt diferente al airfiber.rb stock (AP/ST-Castillo-Market, AP/ST-El-Paso-Matriz, AP/ST-Matriz-Gus). Workaround actual: device_overrides.yaml los fuerza a model airos. Mejora futura: tunear el modelo airFiber upstream o escribir uno custom AF60-LR.
  • #322 📅 2026-06-26 AP-MEDICOS2, SECTORIALELPASO (airOS) y ST-Castillo-Jichasa (airFiber) — rechazan los 5 candidate passwords. Probable creds device-specific. Discovery manual o reset físico.
  • #323 📅 2026-06-27 Cambium ePMP requiere KEX curve25519 — gem Ruby x25519 instalado en VM oxidized 2026-05-05 (fixed). Pendiente: agregarlo al provisioning-baseline doc (parte del README) para que cualquier reprovisión futura del VM lo incluya por default.
  • #324 📅 2026-06-28 Subir RAM de netbox VM a ≥ 4 GiB (actualmente ~414 MiB swap en uso). Próxima ventana de mantenimiento.
  • #325 📅 2026-06-29 Identificar hipervisor de netbox — SMBIOS solo reporta "Red Hat / KVM" genérico. Necesario para provisionar un VM hermano del oxidized si se quiere distribuir carga.
  • #326 📅 2026-06-30 Configurar Snapshot Replication policy sobre el share NetworkBackups en es-nas. Recomendación del README: hourly×24h, daily×30d, weekly forever.
  • #244 📅 2026-06-30 Endurecer shell del user oxidized en es-nas de /bin/sh a /usr/bin/git-shell una vez que el pipeline esté estable. Constrain a operaciones git solamente.
  • #328 📅 2026-06-30 Agregar QEMU guest-agent channel al VM oxidized (no se hizo en el virt-install). Cosmético; arreglable editando domain XML y agregando <channel type='unix'>...</channel>.
  • #329 📅 2026-06-30 Verificar salud del cron cgit-mirror en reverse-proxy (sync hourly de nas:configs.git a /var/lib/cgit/configs.git). No hay alarma; verificar pasivamente en el siguiente touch del host.

Actividad en bitácora 4 días

jun
jul
ago
sep
oct
nov
dic
ene
feb
mar
abr
may
L
X
V
Menos
Más

Backup System — Pipeline de backups de configs de red

Contexto

Sistema interno de Electrosystems para backup automatizado de configuraciones de dispositivos de red. Gran parte ya está implementado y en producción. Pipeline:

  1. inventory_merger.py (en VM oxidized, 192.168.20.27) consulta UISP + NetBox y produce router.db para Oxidized.
  2. Oxidized corre como systemd, SSHea cada device, descarga config nightly.
  3. git output driver commitea a nas:configs.git (Synology DS418, /volume1/NetworkBackups/configs.git).
  4. post_store hook (doc_generator.py) regenera markdown auto-docs (BACKUPS.md, sites/<region>/<device>.md, FAILURES.log).
  5. node_fail hook (failure_notify.py) emaila a svalencia@e-electrosystems.com y deja nota en repo.
  6. Sidecar Mimosa (mimosa_backup.py, systemd timer 03:30 ±15min) hace backup HTTP de Mimosas (que no exponen SSH) — wired pero deshabilitado hasta que exista mimosa.rb.
  7. UI pública de lectura/descarga: backups.electrosystemsnet.com — cgit con OAuth Google Workspace (@e-electrosystems.com only) + LAN/VPN allow-list. Sirve commits y permite descargar tarballs por commit.

Alcance actual:

  • 210 dispositivos UISP (Ubiquiti) en 9 regiones MX/US — operando.
  • 45 Netonix WS-x — onboarded, modelo Oxidized custom (override exec true, dump /www/config.json). Split por firmware: vieja usa key auth, nueva (kernel 5.x, dropbear v2018.76) usa password (key install rechazado por strict-perm check sobre overlay read-only).
  • MikroTik / EdgeOS — soportados (modelos Oxidized stock).
  • Mimosa (~53 devices identificados por OUI 20:B5:C6 / 20:B5:C7) — deferido.

Toda la documentación operacional está en ~/agy/electrosystems/backup-system/README.md. Aquí solo se llevan pendientes y seguimiento.

Tareas pendientes

1. Vendors faltantes (confirmados con Sergio 2026-05-08)

Sergio confirmó: Accedian, Planet, Siklu. Mimosa “probablemente ya está funcionando” — verificar.

  • (2026-05-25) Verificar estado real de Mimosa — VERDE en recolección (75 devices inventory, 72/75 OK diarios, commits locales fluyen), AMARILLO en distribución (SSH push al NAS falla). 3 failures son network (no creds): AP-Matriz-El-Paso, ST-Maguarichi-Capellina, ST-Parral-Azules. Resuelve la sub-tarea de “creds mismatch 5/3” de 2026-05-04: lo que se veía como cred-mismatch eran timeouts de red. Detalle completo en bitácora 2026-05-25. Acción derivada: fix SSH push (ver § 4 abajo).
  • (2026-05-29) #313 — Accedian: vendor integrado y operativo. El modelo accedian.rb (CLI propietario, prompt <host>: , strip de FILE_ATTRIB/Export Done!, redacción de secretos) ya estaba escrito, desplegado y activo en oxidized (.config/oxidized/model/), con group accedian en config, clasificación NetBox+UISP en inventory_merger, y credencial devices.accedian en sops. 3 de 5 Accedian respaldados desde 2026-05-05 (Accedian-Bernal/Caborca/Puerto-Libertad, export limpio ~4k líneas). Sonda read-only 2026-05-29 confirmó que Accedian-Barretal responde (90 KB export, marcadores OK) → el pipeline funciona. Detalle en bitácora 2026-05-29. Derivados: #417 (limpiar duplicado NetBox), #418 (verificar Barretal + Union-Morales completen backup).
  • (2026-05-29) #417 — Duplicado de barretal en NetBox limpiado (Sergio lo borró por UI: device + IP 192.168.163.3/24). Quedan inertes manufacturer Accedian y site Barretal (no generan entradas en router.db sin device asociado; opcional borrarlos). Tras la limpieza, router.db regenerado dejó los 5 Accedian canónicos sin el barretal suelto (273→272 SSH devices).
  • (2026-05-29) #418 — Accedian-Barretal y Accedian-Union-Morales respaldados. Tras systemctl restart oxidized (autorizado) la pasada los respaldó en ~40s: accedian/Accedian-Barretal (4662 líneas) y accedian/Accedian-Union-Morales (4249 líneas), modelo AMN-1000-GT, sin failures, replicados al NAS (HEAD c5ae6ff == nas/main). Los 5 Accedian completos. Hallazgo: el daemon NO re-leía router.db sin restart (24 días sin tomar los 2 nuevos) → ver #419 (auto-reload SIGHUP).
  • (2026-05-29) #419 — Auto-reload de router.db sin restart, implementado. ExecReload=/bin/kill -HUP $MAINPID en oxidized.service + ExecStartPost=+/bin/sh -c '... systemctl reload oxidized ...' en inventory-merger.service. Probado en VM: systemctl reload oxidized y systemctl start inventory-merger.service ambos disparan Reloading node list → Loaded 272 nodes con el mismo PID (sin restart). Copias fuente + README actualizados en electrosystems/backup-system/. Resuelve también el pendiente “opcional” de § inventory_merger (abajo).
  • #314 📅 2026-06-03 — Planet — vendor faltante. Pendiente: identificar cuántos devices Planet hay en la red (probablemente switches L2/L3 de la línea Planet). Existe ya un alias planet-parral en ~/.ssh/config (192.168.44.2, user admin). Investigar firmware/CLI y elegir/escribir modelo Oxidized.
  • #315 📅 2026-06-05 — Siklu — vendor faltante. Sergio nota: “no está documentado por nombre, es parte de los dispositivos faltantes”. Probable: equipos mmWave/E-band que están entre los blackBox UNKNOWN de UISP. Identificar por OUI (Siklu OUI: 00-22-91) y agregar a BLACKBOX_OUI_MAP similar al patrón Mimosa. Verificar si tienen SSH y cómo se exporta su config.

1b. Tareas comunes a los vendors nuevos

  • 📅 2026-06-08 — Decidir credenciales por vendor (password fijo del fabricante? key auth? RBAC en NetBox?).
  • 📅 2026-06-10 — Para cada vendor: confirmar si necesita un provision_<vendor>.sh (instalación de SSH keys) o si se backup con password en sops.
  • 📅 2026-06-12 — Tag backup-enabled en NetBox para devices ya inventariados de cada vendor (ver flujo en electrosystems/backup-system/README.md).

2. Descarga de backups → ya existe, ¿qué falta?

  • UI cgit en backups.electrosystemsnet.com ya provee descarga (browse + tarball por commit, gateado con OAuth). nas:configs.git también es clonable directo.
  • #316 📅 2026-06-15 — Aclarar caso de uso real con Sergio: si la pendiente “ver manera de descargar” sigue viva, ¿qué le falta a la UI actual? Casos posibles:
    • “Descarga masiva por sitio” — ahora hay que clonar el repo entero o bajarlo commit-por-commit.
    • “Descargar la config más reciente de un device específico” — accesible vía cgit, pero múltiples clicks.
    • “Export programable / scheduled dump” — no existe.
    • “Bundle off-site / cifrado para audit” — no existe.

3. IPs en backups — decidido: A + C (no romper historial)

Sergio confirmó 2026-05-08: Opción A + C (no romper historial).

  • 📅 2026-06-17 — #061a A — IP en el header del archivo de config. Auto-inyectada por Oxidized vía model hook. Primera línea del archivo como comentario con la IP del device en el momento del backup. git grep <ip> instantáneo.
  • 📅 2026-06-19 — #061b C — Manifest inventory.yaml versionado. Generado por inventory_merger.py en cada run, commiteado al repo configs.git. Mapea device-slug → IP, modelo, sitio, region por snapshot. Snapshot histórico de “qué IP tenía X el día tal” queda en git log inventory.yaml.

Implementación pendiente — pasos:

  1. Modificar inventory_merger.py para emitir inventory.yaml además de router.db. Commitearlo en el mismo run.
  2. Para A: cada modelo de Oxidized (airos.rb, edgeos.rb, netonix.rb, custom) debería empezar el dump con un comentario header con la IP. Hay dos formas:
    • Modificar cada model individual (más invasivo).
    • Hook global de Oxidized pre_store que prepende el header (más limpio, una sola implementación). Investigar si Oxidized expone ese hook.
  3. Tests con un device piloto (probablemente uno UISP-managed para no afectar producción de inmediato).

4. Pendientes operacionales (capturados del escaneo de electrosystems 2026-05-08)

Mimosa — verificación + creds mismatches

  • (2026-05-25) Superado por diagnóstico 2026-05-25: con 75 devices en producción el patrón es 72/75 OK con pool password — los 3 que fallan son network timeouts, no cred-mismatch. Creds per-device no se necesitan. B5x family sin diferenciar en logs (funciona dentro del pool genérico).

Onboarding pendiente de fleet provisioning

  • #319 📅 2026-06-22 — 155 devices recién agregados de regiones nuevas (Chihuahua, Parral, Caborca, Namiquipa, Nogales, Villa Ahumada, Colonia del Valle): pendientes de correr fleet_provision_airos.sh / fleet_provision_edgeos.sh antes de que los backups con key-auth funcionen. Lista de runs candidata en el README de electrosystems/backup-system/ § “Onboarding the new regions”.
  • #320 📅 2026-06-24 — 45 Netonix WS-x: correr fleet_provision_netonix.sh con la firmware-split logic. Old firmware (kernel 2.6.x) acepta keys, new firmware (kernel 5.x) requiere password en sops creds.

airFiber AF60-LR — modelo Oxidized

  • #321 📅 2026-06-25 — 6 devices airFiber AF60-LR tienen prompt diferente al airfiber.rb stock (AP/ST-Castillo-Market, AP/ST-El-Paso-Matriz, AP/ST-Matriz-Gus). Workaround actual: device_overrides.yaml los fuerza a model airos. Mejora futura: tunear el modelo airFiber upstream o escribir uno custom AF60-LR.

Devices con creds desconocidas (3 manuales)

  • #322 📅 2026-06-26 — AP-MEDICOS2, SECTORIALELPASO (airOS) y ST-Castillo-Jichasa (airFiber) — rechazan los 5 candidate passwords. Probable creds device-specific. Discovery manual o reset físico.

Cambium ePMP

  • #323 📅 2026-06-27 — Cambium ePMP requiere KEX curve25519 — gem Ruby x25519 instalado en VM oxidized 2026-05-05 (fixed). Pendiente: agregarlo al provisioning-baseline doc (parte del README) para que cualquier reprovisión futura del VM lo incluya por default.

NetBox — RAM tight + identificación de hipervisor

  • #324 📅 2026-06-28 — Subir RAM de netbox VM a ≥ 4 GiB (actualmente ~414 MiB swap en uso). Próxima ventana de mantenimiento.
  • #325 📅 2026-06-29 — Identificar hipervisor de netbox — SMBIOS solo reporta “Red Hat / KVM” genérico. Necesario para provisionar un VM hermano del oxidized si se quiere distribuir carga.

es-NAS — snapshots y hardening del user oxidized

  • #326 📅 2026-06-30 — Configurar Snapshot Replication policy sobre el share NetworkBackups en es-nas. Recomendación del README: hourly×24h, daily×30d, weekly forever.
  • #244 📅 2026-06-30 — Endurecer shell del user oxidized en es-nas de /bin/sh a /usr/bin/git-shell una vez que el pipeline esté estable. Constrain a operaciones git solamente.

oxidized VM — guest agent + cron mirror

  • #328 📅 2026-06-30 — Agregar QEMU guest-agent channel al VM oxidized (no se hizo en el virt-install). Cosmético; arreglable editando domain XML y agregando <channel type='unix'>...</channel>.
  • #329 📅 2026-06-30 — Verificar salud del cron cgit-mirror en reverse-proxy (sync hourly de nas:configs.git a /var/lib/cgit/configs.git). No hay alarma; verificar pasivamente en el siguiente touch del host.

inventory_merger — cadencia regular (capturado 2026-05-12 desde monitoring-homologation)

  • (2026-05-13) inventory-merger.timer desplegado en oxidized. Corre diario a 03:00 (+ jitter 5min). El .service ejecuta inventory_merger.py standalone; NO hace reload/restart de oxidized — el daemon re-lee router.db naturalmente al inicio de su poll cycle de 24h. Decisión justificada: restart es disruptivo e innecesario, delay máximo aceptable (~48h peor caso vs indefinido hoy). Archivos en backup-system/systemd/inventory-merger.{service,timer} para git. Verificación: trigger manual exit 0 en 806ms, router.db idempotente (mismo hash post-run cuando UISP sin cambios). Próximo trigger automático: 2026-05-14 03:03:56 CST.
  • (2026-05-29) Implementado como #419 (ver § Vendores arriba): ExecReload= SIGHUP en oxidized.service + ExecStartPost reload en inventory-merger.service. Confirmado que Oxidized 0.36 sí soporta HUP para recargar la source. Sin necesidad de Restart=on-config-change.

Mimosa — fix SSH push a NAS (CERRADO 2026-05-25 #242, ver bitácora)

  • (2026-05-25) mimosa_backup.service push remoto arreglado. Causa: shell de user oxidized en es-nas estaba en /sbin/nologin por reset de DSM en upgrade entre 04-27 y 05-12. Fix: sed en /etc/passwd/bin/sh. Backlog de 13 días drenado al NAS. Pendientes derivadas: #243 (exit code cosmético) + #244 (blindar contra futuros upgrades DSM).
  • (histórico para referencia) mimosa_backup.service falla en push remoto (exit 1, “Permission denied, please try again” en git push). Diagnóstico read-only 2026-05-25 (ver bitácora):
    • Remote URL es correcto: oxidized@192.168.20.26:/volume1/NetworkBackups/configs.git. ~oxidized/.ssh/config lo resuelve vía alias nas, key ed25519.
    • SSH conecta y termina con “Permission denied”. El agent leyó “exec request accepted” en el -vvv y concluyó “auth OK, shell rechazado” → H3 (shell de user oxidized en NAS reseteado a nologin/git-shell por upgrade DSM). Caveat: “Permission denied, please try again” es típicamente un fallo de auth (sshd ofreciendo otro método), NO un post-auth shell denial — vale la pena confirmar antes de tocar el NAS.
    • Rompió 2026-05-12 03:45 CST (journal mimosa-backup.service). Coincide con ventana de posible DSM upgrade entre 04-27 (última edición documentada en ~/agy/electrosystems/servers/es-nas/) y 05-12.
    • Fix tentativo (requiere acceso interactivo al NAS con cuenta admin svalencia, solo Sergio):
      1. ssh svalencia@192.168.20.26 (DSM password).
      2. grep ^oxidized /etc/passwd — si el shell es /sbin/nologin o vacío, restaurar: sudo synouser --modify oxidized (preferido sobre editar /etc/passwd directo, que DSM puede revertir).
      3. sudo cat ~oxidized/.ssh/authorized_keys — confirmar que está la clave pública de oxidized VM (fingerprint del paso 1 del diag: oxidized@oxidized-vm).
      4. Si DSM resetea esto periódicamente, considerar /usr/bin/git-shell (cumple además el pendiente “endurecer shell oxidized” pero requiere validar que git push funciona con git-shell — debería sí).
      5. Validar desde oxidized: sudo -u oxidized ssh nas 'echo OK' y luego sudo -u oxidized bash -c "cd /var/lib/oxidized/configs.git && git push".
    • Reversibilidad / urgencia: el commit local sigue. Sin push = sin replica off-host. Riesgo si el VM oxidized muere antes de fix: pierdes ~13 días de historia de configs. Prioridad media-alta. Capturado como [#242] en PENDIENTES.md.

En progreso

(Nada activo hasta cerrar las decisiones de las 3 pendientes principales.)

Notas técnicas

Tooling y branches

  • Repo nas:configs.git (canónico) y electrosystems-mx/configs (probable mirror).
  • Branches en este repo de docs:
    • main — contenido humano. Push a nas y a GitHub. NO incluye backup-system/auto-docs/ (gitignored).
    • auto-docsmain + backup-system/auto-docs/ regenerado cada hora. Solo en nas. Force-push permitido (solo sync_docs_to_repo.sh escribe).

Convenciones del pipeline

  • Source of truth para devices no-UISP = NetBox con tag backup-enabled.
  • Devices UISP-managed pickup automático.
  • Overrides per-device en backup-system/oxidized/device_overrides.yaml (ssh_port, model, group, skip).
  • Credenciales en /var/lib/oxidized/credentials.yaml cifradas con sops/age. Editar con sudo -u oxidized sops ....

Hosts involucrados

  • oxidized (VM en poseidon, 192.168.20.27) — corre el pipeline.
  • es-nas (Synology DS418, 192.168.20.26) — almacena configs.git y futuro asterisk.git.
  • reverse-proxy (VM en poseidon, 192.168.20.14, IP pública 201.218.172.3) — sirve backups.electrosystemsnet.com (cgit + oauth2-proxy + mirror local hourly via cron).

Bitácora

2026-05-08 — proyecto registrado y refinado

  • Pidió Sergio: 3 pendientes — vendors faltantes, manera de descargar backups, IPs en filenames.
  • Hice: leí toda la documentación del backup-system en electrosystems/backup-system/README.md y los READMEs relacionados. Refiné las 3 pendientes con base en el estado real:
    • Vendors faltantes: el principal es Mimosa (con plan de implementación claro de 4 pasos). Aclarado con preguntas si hay otros vendors en mente.
    • Descarga: ya existe en backups.electrosystemsnet.com (cgit con OAuth + tarball por commit) y por clone directo de nas:configs.git. Pendiente real es aclarar qué caso de uso falta.
    • IPs en filenames: dejé propuesta alternativa A+C (IP en header del archivo + manifest inventory.yaml versionado) que da el beneficio sin partir el historial git.
  • Falta: input de Sergio en las 3 decisiones, en particular sobre IPs en filenames (mi recomendación A+C vs su petición original).

2026-05-13 — inventory-merger.timer desplegado

  • Pidió Sergio: luz verde para crear el timer (tarea capturada el 2026-05-12 desde monitoring-homologation, bloqueante de la promesa “agregar en UISP fluye automático”).
  • Hice:
    • Escribí dos unidades systemd en backup-system/systemd/:
      • inventory-merger.service: oneshot, User=oxidized, env SOPS_AGE_KEY_FILE + REGIONS=, ExecStart=/opt/oxidized-tools/scripts/inventory_merger.py. Sin ExecReload ni restart de oxidized.
      • inventory-merger.timer: OnCalendar=*-*-* 03:00:00, jitter 5min, Persistent=true. 30min antes del mimosa-backup.timer (03:30) para que ese run encuentre inventory fresco.
    • Decisión técnica explícita: NO hacer reload/restart de oxidized.service después del merger (a pesar de que la tarea original lo mencionaba). Justificación: oxidized re-lee router.db naturalmente al inicio de cada poll cycle de 24h. Forzar restart es disruptivo (interrumpe backups en curso), riesgoso (un fallo deja sin daemon) e innecesario para el caso de uso (los backups Oxidized son diarios; un delay máximo de ~48h device-added → device-backed-up es aceptable; hoy es indefinido — semanas — porque solo corría con restarts manuales).
    • Deploy: scp a /tmp/, mv con sudo a /etc/systemd/system/, chown root:root, daemon-reload, enable --now. systemd-analyze verify sin warnings.
    • Trigger manual de validación: systemctl start inventory-merger.service → exit 0 en 806ms. router.db re-escrito con hash idéntico (71197d72…) — confirma que el merger es idempotente con UISP sin cambios; los timers diarios no van a crear ruido.
    • Próximo trigger automático: 2026-05-14 03:03:56 CST.
  • Falta:
    • Tarea de seguimiento (opcional, no urgente): si el delay de hasta 48h device→backup se vuelve un problema, agregar ExecReload= SIGHUP a oxidized.service (verificar primero que Oxidized lo soporte) y disparar reload desde el .service del timer.
    • Los archivos .service/.timer quedan en el workspace ~/agy/electrosystems/backup-system/systemd/ — Sergio decide si commit + push (en otro repo, no acá).

2026-05-25 — diagnóstico de Mimosa en oxidized

  • Pidió Sergio: verificación read-only del estado de backups Mimosa en VM oxidized (ya autorizado por workflow).
  • Hice: SSH a oxidized + lectura de systemd logs (6 días) + inventory CSV + verificación de 3 devices que fallan.
  • Hallazgos principales:
    • Mimosa inventory SÍ funciona: inventory_merger.py genera 75 Mimosas en /var/lib/oxidized/mimosa.csv, ejecuta cada día a 03:00 CST. Formato CSV con :: name:ip:user:enable:configure:password:port — pool password viene de sops, redactado aquí.
    • Recolección de configs SÍ funciona: sidecar mimosa_backup.py corre cada día a 03:30 CST, descarga configs HTTP exitosamente. Patrón consistente últimos 6 días: 72/75 OK, 3 failed (tasa: 96% éxito).
    • Git local SÍ commits: /var/lib/oxidized/configs.git escribe cambios (visto: 85575c7..91dc4a4 main -> main, commits fechados 2026-05-20 hasta 2026-05-25).
    • SSH push a NAS falla: [push_to_nas] Permission denied, please try again. ... fatal: Could not read from remote repository.bloqueante de replicación remota, pero no afecta backups locales. Probable causa: SSH key de user oxidized no está en authorized_keys del NAS, o mala configuración del remote.
    • 3 devices con falla de conectividad (no creds):
      1. AP-Matriz-El-Paso (172.16.1.7) — ReadTimeout 30s (Device down o lento).
      2. ST-Maguarichi-Capellina (192.168.38.33) — No route to host (Routing broken).
      3. ST-Parral-Azules (192.168.46.206) — ConnectTimeout 30s (Device down o unreachable).
    • Estado conclusivo: Mimosa está OPERATIVO (verde) en recolección local, amarillo en distribución. No hay issue de creds, no hay issue de inventory, no hay issue de programa. Solo problema: push remoto bloqueado por SSH.
  • Próximas acciones recomendadas:
    1. (RECOMENDADO) Diagnosticar y fijar SSH key de oxidized hacia NAS — requiere acceso a NAS root + confirmación de .ssh/config en oxidized.
    2. (OPCIONAL) Investigar por qué los 3 devices no responden — low priority (probablemente desconectados, no issue del sidecar).
    3. (OPCIONAL) Validar B5x family específicamente (findings de 2026-05-04 menciona, pero últimos 6 días no reporta diferencias de firmware).

2026-05-25 (cont.) — diagnóstico SSH push oxidized→NAS (#242)

  • Pidió Sergio: continuar con #242 (fix SSH push al NAS de Mimosa).
  • Hice: delegación a network-diag, read-only, SSH -vvv desde oxidized hacia NAS.
  • Hallazgos:
    • Remote URL bien configurado: oxidized@192.168.20.26:/volume1/NetworkBackups/configs.git, alias nas en ~oxidized/.ssh/config, key ed25519.
    • Dos keys disponibles del lado oxidized (id_rsa + id_ed25519), permisos correctos.
    • ssh -vvv muestra el handshake y termina con Permission denied, please try again. El agent leyó la traza como “exec request accepted → comando rechazado” (apuntando a shell nologin); mi lectura: ese mensaje es típicamente fallo de auth (sshd ofreciendo siguiente método). Hay que confirmar en el NAS directamente cuál de las dos hipótesis es real.
    • Falla desde 2026-05-12 03:45 CST. Hasta esa fecha, push exitoso. No hay registro local de cambios al NAS en esa ventana → más plausible un upgrade DSM que reseteó /etc/passwd (DSM lo hace, ya está anotado en docs de es-nas).
    • Próximo paso requiere acceso interactivo al NAS con cuenta admin (svalencia + password DSM), que no tengo: pasos concretos para Sergio están listados arriba en la tarea § “Mimosa — fix SSH push a NAS” pasos 1-5.
  • Falta:
    • Sergio ejecuta los 5 pasos en el NAS y reporta resultado.
    • Si confirma H3 (shell reseteado): decisión paralela sobre si dejarlo en /bin/sh o ya pasar a /usr/bin/git-shell (cierra el otro pendiente “endurecer shell” de raíz).
    • Documentar en ~/agy/electrosystems/servers/es-nas/ que DSM upgrade reseteó el shell — para tener un fix permanente vía script post-upgrade o nota en el runbook.

2026-05-25 (cont. 2) — #242 cerrado, fix aplicado

  • Pidió Sergio: ejecutó los pasos en el NAS y reportó resultados.
  • Confirmación de causa raíz: grep ^oxidized /etc/passwdoxidized:x:1035:100::/var/services/homes/oxidized:/sbin/nologin. H3 confirmada. El agent acertó; el mensaje “Permission denied, please try again” en sshd se dispara también cuando el shell es nologin aunque la auth con key sea válida.
  • Synology gotcha: synouser --modify NO toca shell (solo nombre/expiración/mail). El path correcto es editar /etc/passwd directo.
  • Fix aplicado: sudo sed -i '/^oxidized:/ s|/sbin/nologin|/bin/sh|' /etc/passwd (con backup /etc/passwd.bak-2026-05-25).
  • Validación:
    • sudo -u oxidized ssh -o BatchMode=yes nas echo OK → no más Permission denied.
    • sudo -u oxidized git -C /var/lib/oxidized/configs.git push nas main38c103d..4593ab1 main -> main — backlog de ~13 días drenado al NAS.
    • Sidecar re-corrido manualmente (systemctl start mimosa-backup.service): logs muestran [mimosa] done in 436.6s: 72/75 ok, 3 failed, 1 changed y 38c103d..4593ab1 main -> main. Push limpio.
  • Status servicio: Aún reporta status=1/FAILURE porque mimosa_backup.py hace exit(1) si cualquier device falla (los 3 known-bad de #240). Cosmético; el backup funciona 100%. Capturado como #243 (refinar exit code).
  • 2 pendientes derivadas:
    • #243 Distinguir failure de red vs failure de pipeline en exit code del script (exit 0 si push OK + ≥95% devices OK).
    • #244 Blindar shell de oxidized contra futuros upgrades DSM — Task Scheduler boot trigger, o migración a /usr/bin/git-shell (que cierra también el pendiente de endurecimiento del shell).
  • #242 cerrado.

2026-05-29 — #313 Accedian: descubrimiento del estado real + validación

  • Pidió Sergio: avanzar con #313 (vendor Accedian).
  • Hallazgo principal: #313 estaba mucho más avanzado de lo que el pendiente reflejaba. El commit 5c91af4 (2026-05-05) ya había dejado todo el pipeline listo, y entre esa fecha y hoy los Accedian aparecieron en UISP como blackBox y el pattern ^Accedian del merger los rescata. Verificación read-only en oxidized:
    • Modelo accedian.rb (2476 B, idéntico al workspace) desplegado y activo en /var/lib/oxidized/.config/oxidized/model/ (path default de modelos custom; NO el /opt/oxidized-tools/..., que es solo la copia fuente).
    • Group accedian: {} en el config real; clasificación NetBox (manufacturer accedian) + UISP (^Accedian) en inventory_merger.py.
    • Credencial devices.accedian (admin + password) ya cargada en credentials.yaml (sops).
    • router.db ya traía 5 Accedian vía UISP: Accedian-Barretal (192.168.163.3), -Bernal (192.168.44.50), -Caborca (192.168.152.51), -Puerto-Libertad (192.168.152.50), -Union-Morales (10.163.0.2, far-end del L2L de barretal).
    • 3 de 5 ya respaldados en configs.git desde 2026-05-05 16:55 (accedian/Accedian-Bernal|Caborca|Puerto-Libertad); ej. Bernal = 4184 líneas, cabecera AMN-1000-GT build 525. El modelo funciona en producción.
  • Error mío + reversión parcial: antes de descubrir lo anterior, di de alta barretal en NetBox vía API (con autorización de Sergio; site nuevo “Barretal” a su pedido): manufacturer Accedian, device-type AMN-1000-GT, role NID, device + IP 192.168.163.3/24 + tag backup-enabled. Eso duplicó el Accedian-Barretal que ya venía de UISP (mismo IP). Sergio autorizó revertir, pero el token de API del merger no tiene permiso DELETE (403) — la limpieza queda como #417 (acción de Sergio en NetBox UI). Lección: revisar router.db/UISP antes de onboarding manual.
  • Validación read-only de los 2 faltantes: Accedian-Barretal y Union-Morales están reachable (TCP 22 OK desde oxidized vía gw 192.168.20.254). Sonda pexpect contra Barretal replicando el flujo del modelo: login OK con la cred de sops, configuration export90,698 B / 4,700 líneas, marcador #_***_BEGIN, modelo AMN-1000-GT, 39 líneas FILE_ATTRIB (que el modelo strippea). Nunca se respaldaron solo porque no estaban en router.db cuando los otros 3 sí (timing de alta en UISP). Ahora ya entraron al router.db regenerado hoy → quedan para el próximo ciclo (#418, hacer tras #417 para no duplicar).
  • Estado: #313 resuelto (vendor Accedian integrado, modelo validado en prod, 3/5 respaldados, los 2 restantes confirmados funcionales y encolados). Derivados: #417 (limpieza NetBox), #418 (verificación de cierre de los 2).

2026-05-29 (cont.) — #417 + #418 cerrados; #419 abierto (auto-reload)

  • Pidió Sergio: “ya hice #417, vamos con #418” + “me gustaría que no se tuviera que reiniciar cada vez que se actualice router.db”.
  • #417: confirmado por API que Sergio borró el device barretal (count 0) y la IP 192.168.163.3/24 (count 0). Quedan inertes manufacturer Accedian + site Barretal. Regeneré router.db → 5 Accedian canónicos, sin el duplicado (272 SSH devices).
  • #418: el daemon llevaba 24 días activo (desde 05-05 16:56) y nunca tomó los 2 NIDs nuevos → confirmado que oxidized no re-lee router.db sin restart. Con interval: 86400 y sin REST (oxidized-web no levantado), la única vía era restart. sudo systemctl restart oxidized (autorizado per-sesión por Sergio; el classifier bloqueó el primer intento por falta de auth explícita). La pasada (8 threads) respaldó ambos en ~40s: Barretal 4662 líneas, Union-Morales 4249 líneas, sin failures, push al NAS OK. 5/5 Accedian.
  • #419 (implementado, autorizado por Sergio): oxidized 0.36 soporta SIGHUP para recargar la source sin restart (core.rb HUP → @need_reload; loop reload if @need_reload@worker.reload@nodes.load). Apliqué ExecReload=/bin/kill -HUP $MAINPID en oxidized.service + ExecStartPost=+/bin/sh -c 'systemctl is-active --quiet oxidized && systemctl reload oxidized || true' en inventory-merger.service (.bak-2026-05-29 de cada uno; daemon-reload; systemd-analyze verify limpio). Probado: tanto systemctl reload oxidized como systemctl start inventory-merger.service producen en journal Reloading node list → Loaded 272 nodes con el mismo PID 453965 (sin restart). Copias fuente + comentarios obsoletos + README (Add a new device, edición de secretos) actualizados en electrosystems/backup-system/. Resultado: agregar/quitar un device en UISP/NetBox entra al backup en el merger diario (03:00) sin intervención, y systemctl start inventory-merger.service lo aplica al instante.