Skip to content

Retirada reversible de WP-Pulse — plan, 21 octubre

Decisión del usuario: retirar WP-Pulse completo. El plan inicial se conserva como histórico; la ejecución comprobada se registra al final. Fuente retirada fusionada en main 520b327; target Prometheus y rutas Caddy ya reconciliados. Las máscaras propias se aplicaron a las 17:22 bajo el nuevo epoch e269; CT281 quedó detenido con onboot0 y readback independiente a las 17:31. No se eliminan datos, discos ni copias. Jellyfin y Remote-Pulse son servicios distintos y quedan fuera del alcance.

Evidencia y elección del alcance

Lectura nativa 16:25:35 CEST: CT281 pertenece a proxmox/pmx50, running; padre y guest, comprobados antes/después. API real wp-pulse-server.service PID918 y web PID920, ambos enabled/running desde15:17:04, NRestarts0. El nombre histórico wp-pulse-api.service no existe. Worker enabled/inactive; guard enabled/exited.

Hay tres timers enabled/waiting: wp-pulse-backup, wp-pulse-jev-risk y wp-pulse-jev-spam. El backup oneshot estaba inactivo, el siguiente disparo 03:31:41del22oct; los Jev oneshot estaban inactivos. El API contiene además reaper, scheduler, alert_tick y health_cron_tick dentro del lifespan: detener su unidad interrumpe esos bucles; no son cuatro servicios independientes.

Docker:17 contenedores running. Dieciséis pertenecen a cuatro proyectos de preview; sus cuatro config_files están bajo /srv/wp-pulse/sites//_stack//. El restante es dozzle-agent sin proyecto Compose. Todos tienen restart unless-stopped. No hay referencias WP en los crontabs root/wp observados; esto no inspecciona todos los cron.d o schedulers posibles.

Alcance Qué obtiene Límite
Sólo API/web/worker + timers Retira control y cron interno Deja16 previews, Docker, PG y Redis consumiendo RAM; no cierra la retirada completa
CT281 dedicado: onboot0 + shutdown ordenado Retira conjuntamente API, previews, bases locales y agentes de observación de ese CT; conserva discos Preferido, tras acreditar que no sirve a cargas ajenas, drenaje y backups no activos; no ejecutar aún

El coordinador observó memory.current1695,14MiB, anon1262,01MiB, swap0 a las16:20. No es una medición posterior al apagado ni una garantía de ahorro exacto. El N-1 fresco de16:15 faltaba1229,57MiB (el de14:38, −2006,68MiB, es histórico): retirar WP mejora capacidad, pero no acredita por sí solo N-1 ni resuelve la causa de los resets.

Fuentes y automatismos que deben quedar reconciliados

  • Provisionado: ansible/playbooks/wp-pulse-bootstrap.yml invoca wp_pulse_host. El rol no está en playbook.yml ordinario; role_groups del inventario sólo se escribe como metadato por baseline. Su systemd_units.yml habilita API/worker, lxc_create configura el CT y caddy_route despliega snippets: bloquear el entrypoint retirado antes de tareas mutantes/SOPS. Mantener inventario para recuperación y observación, con estado retired explícito.
  • Despliegue manual: services/wp-pulse-server/scripts/deploy.sh copia API/web, sincroniza dependencias, migra y reinicia. Debe fallar al inicio por retirada, sin SSH ni acceso a secretos. CI web produce artefactos; no es despliegue automático. Conservar fuentes y locks para recuperación histórica.
  • Rearranque oculto: wp_pulse_host/tasks/filesystem.yml genera logrotate con reload-or-restart de API/worker. Stop+disable aislados no bastan si ese hook se ejecuta después. CT onboot0 evita el arranque ordinario completo; también preparar bloqueo persistente de unidades propias o reconciliar ese hook si el CT se vuelve a encender sólo para mantenimiento. No afirmar una máscara activa hasta aplicarla y verificarla; los fragmentos locales /etc requieren conservar su copia antes de sustituirlos por máscaras.
  • Rutas fuente: Caddyfile.full-routing importa wp-pulse.caddy y cuatro snippets preview; wp-pulse.caddy define los dos hostnames API/web. Son seis sitios lógicos en cinco imports. Retirar sólo esos imports/objetos, preservando rutas ajenas, validación Caddy y rollback propio. La fuente del renderer central no contiene WP en tunnel-static.yaml; labels efectivos acreditados: ninguno de los 17 contenedores publica tunnel.hostname.
  • Monitor de producto: prometheus.yml.j2, blackbox-https-external, contiene sólo el target WP específico; alerts.yml.j2 contiene WPPulseDown. Retirar esos dos objetos propios en fuente; retirar el target runtime mediante transacción admitida, nunca sobrescribir todo CT217 desde un template histórico. La transacción Cloudflared recién integrada sólo admite sus dos reglas y no autoriza este cambio lateral. El exportador genérico CT281 de host_vars/proxmox.yml no es un checker de aplicación: distinguir retired/stopped de avería y conservar observación útil.
  • No se encontró contrato WP registrado en los manifiestos fuente de scripts/service-onboarding; no retirar otros contratos VM208 por asociación.
  • Agentes: host_vars/wp-pulse-host.yml habilita Trove Docker local. Dozzle vive dentro del CT y no es el servidor Dozzle de otros nodos. La lectura de las 16:36 acredita un único mount del socket Docker local y DOCKER_HOST ausente o Unix local; no observa otros nodos.
  • Datos: /srv/wp-pulse/sites, versions, releases, secrets, backups; /opt/wp-pulse-server, PG local16/base wp_pulse y Redis se conservan. PG escucha sólo localhost y no tiene bases no-WP ni clientes externos/no-WP observados; Redis está limitado a loopback, sin clientes externos y sin claves. Son observaciones fechadas, no garantía permanente hasta la parada.
  • Backup: timer propio ejecuta backup.sh (PG + secrets), puede publicar offsite o heartbeat si está configurado. No ejecutarlo ni leer/exportar esos valores. Conservar artefactos y cobertura PBS/ZFS existentes; retirar sólo expectativas del servicio deliberadamente retirado, sin borrar snapshots ni cambiar retención de otros huéspedes. PBS puede respaldar un CT detenido: no se ha probado aquí ni se debe forzar una copia para justificar el apagado.

Gates concretos antes de la única parada

  1. Revalidar padre/boot/owner/guest y estado PVE onboot, HA y tareas en curso que nombren CT281. Confirmar que no hay backup/restore/migración activos. No matar tareas ni disparar copias.
  2. Metadatos seleccionados de servicios productivos activos, Docker17 y mounts del único Dozzle agent: confirmar los16 proyectos WP y agente sólo Docker local; sin env/args/raw config. Confirmar ausencia de dependencias productivas ajenas (PG/Redis clientes o bases no-WP) con metadata/SELECT read-only, sin secretos exportados. Un nombre de CT no basta como prueba de dedicación.
  3. Reusar el lector de quiescencia WP ya revisado: contar trabajos activos de pull/push/fleet/rehearsal/report/diff/search-replace/lighthouse y cron/schedules próximos. La lectura antigua de4sites/no activos no es un lease actual. Si aparece trabajo en curso, drenar de forma explícita sin crear otros.
  4. Seleccionar rutas Caddy efectivas y sus productores (imports/labels/renderer), el checker WP cargado y cualquier heartbeat propio de backup; no HTTP público ni modificar identidades/credenciales. Guardar baselines/rollback locales en los huéspedes correspondientes, no traer configuraciones privadas al Mac.

Secuencia propuesta, después de revisión

  • Publicar/reconciliar fuente retired sin restaurar ni instalar componentes; preparar retirada exacta de rutas/checks antes de apagado para evitar avisos esperables. Ningún merge de fuente sustituye readback runtime.
  • Guardar configuración PVE selected/onboot previo y estados enabled de unidades y timers; ningún secreto. onboot0 sólo para281, con CAS/digest actualizado.
  • Deshabilitar los timers propios y los arranques WP dentro del CT; conservar fragmentos y sus estados para recuperación. No parar Docker/Postgres de otros CTs ni tocar el Dozzle central. No borrar volúmenes ni ejecutar compose down.
  • Una única petición de shutdown ordenado de281, con timeout explícito y sin force-stop automático. Si no termina: estado UNKNOWN/parcial, no repetir ni convertirlo en pct stop. Readback independiente PVE stopped/onboot0 y ausencia de tarea activa de apagado; los demás invitados/HA conservados.
  • Captura conjunta posterior de memoria y N-1 con el mismo método. Acredita sólo el ahorro observado y el presupuesto resultante, no estabilidad del hardware.

Recuperación: conservar CT/discos/config/secrets/backups intactos. Revertir sólo fuente y objetos propios desde su backup con CAS; restaurar onboot/estados previos mediante revisión explícita. Encender API dispara recuperación de jobs y cron, por lo que no es una operación inocua de prueba. Revisar timers Persistent antes activarlos para no lanzar una copia pendiente ni trabajos Jev. No reinstalar, forzar restore o ejecutar deploy.sh para simplemente recuperar el servicio.

Recibos privados de esta fase

Directorio0700 wp-pulse-retirement-ro-20261021-f5rnigwj bajo ~/.local/state; archivos0600, sólo proyecciones, sin env ni configuración privada exportados ni mutaciones. Las consultas HTTP fueron exclusivamente API administrativa local de Caddy/Prometheus con socket acreditado, nunca productos públicos:

Archivo SHA256
receipt.json, unidades y Docker16:25:35
containers-cron.json, Compose/restart y cron16:28:28

La segunda lectura terminó correctamente y guardó el recibo; su primer resumen local falló al ordenar una clave None (Dozzle sin proyecto). Se corrigió sólo el resumen leyendo el recibo existente; no se repitió SSH. Ninguna evidencia de esta fase representa una retirada aplicada.

Gates cerrados por lectura, 16:36–16:43 CEST

Los resultados siguientes reemplazan los pendientes de investigación anteriores; se deben revalidar inmediatamente antes de la actuación. No son una reserva de inactividad ni una retirada aplicada.

  • CT281 sigue running, onboot=1; digest PVE <REDACTED>; cero tareas PVE activas para 281. Su backup PBS dedicado backup-wp-pulse-281 sigue enabled, snapshot, 02:00, almacenamiento pbs; se conserva sin ejecutarlo. No se acreditó ninguna expectativa externa de heartbeat opcional: no afirmar que quedó reconciliada.
  • Los 17 contenedores pertenecen a previews WP y Dozzle local. PostgreSQL sólo tiene la base de aplicación wp_pulse, aparte de las bases administrativas; cero clientes externos/no-WP. Redis loopback tiene cero claves y cero clientes externos. No apareció otra carga productiva en las unidades activas leídas.
  • Cuatro sites y cuatro schedules enabled; cero due o próximos en cinco minutos, cero trabajos activos de las categorías inspeccionadas. Hay cinco comandos pendientes, ninguno claimed: tres tail_log y dos two_fa_audit. No se ejecutan, cancelan ni borran para fabricar drenaje. La recuperación debe revisar esa cola antes de arrancar API, además de los timers Persistent.
  • Ambos Caddy nativos contienen exactamente los cinco imports y seis hosts WP; ningún otro host observado apunta a .211. Sus configuraciones activas tienen SHA256 <REDACTED>. El Caddyfile vivo de ambos tiene SHA256 <REDACTED>, distinto de la fuente Git: no copiar el fichero fuente completo al vivo. La retirada debe eliminar únicamente las cinco líneas exactas sobre bytes vivos fijados, validar Caddy y comparar semánticamente el resto de rutas antes de recargar un nodo cada vez; rollback propio con CAS de esos bytes.
  • Prometheus CT217 conserva 26 jobs y exactamente un target WP en blackbox-https-external. WPPulseDown está inactive/health ok, duración 300 s; format_query confirma la expresión esperada probe_success == 0 con sus selectores exactos y sin absent. No es una evaluación del producto.

Bindings de la intervención pendiente

CT281: padre , huésped ; API PID918, web PID920 desde 15:17:04. Caddy270: padre bff, huésped , PID87. Caddy271: padre , huésped , PID123. CT217: padre 861, huésped ; Prometheus contenedor , PID1181, StartedAt 2026-10-19T20:00:13.735970114Z.

CONFIG /opt/observa/conf/prometheus.yml: SHA256 <REDACTED>, identidad full9 [54,1107915,0,0,33188,1,5987,1792526771540111738,1792526771540111738]. RULES /home/monxas/appdata/prometheus/alerts.yml, inmutable para esta retirada: SHA256 <REDACTED>, full9 [54,1029537,1000,1000,33204,1,40979,1792500038537142496,1792500038537142496].

Usar el helper existente services/observa/prometheus_config.py en modo normal 26→26, con token HA conservado sólo en RAM del CT. El helper genérico no acredita por sí solo que el único delta sea un target: la preparación debe comparar el candidato con la configuración viva fijada y demostrar eliminación únicamente de ese target, todos los demás campos idénticos; promtool antes de escribir, inode/CAS, reload verificado y rollback con los mecanismos existentes.

La secuencia concreta propuesta es: fuentes anti-revive primero; retirada selectiva y verificada de ruta/check; revalidación fresca de quiescencia y tareas; backup privado de unidades/estados; bloquear arranques propios y timers, incluida la vía logrotate; CAS onboot 1→0; una petición de shutdown ordenado, sin force ni retry; readback independiente stopped/onboot=0 y memoria. El bloqueo persistente de unidades/hook requiere preparación revisada antes de ejecutar: disable sólo no impide reload-or-restart ni starts manuales. No improvisar máscaras sobre fragmentos locales sin backup. Ante guard cambiado o timeout, estado parcial o UNKNOWN, lectura independiente y ninguna segunda parada automática.

El guard fuente del rol es incondicional y always antes de mutaciones; no garantiza bloqueo frente a --skip-tags always o inclusión directa deliberada de tareas. El deploy retirado sale con rc2 antes de SSH incluso con --check. Ninguno de esos cambios ejecuta Ansible ni instala una unidad en runtime al fusionarse.

Recibo adicional Hora CEST SHA256
gates.json 16:36:56
commands.json 16:39:03
caddy270.json 16:40:56
caddy271.json 16:40:57
prometheus-check.json 16:43:04

Ejecución admitida tras el nuevo arranque e269

El arranque de pmx50 a las 17:07:26 invalidó los planes del boot bff. No se habían aplicado Caddy, máscaras, onboot0 ni shutdown. Se preparó una nueva admisión explícita, conservando los artefactos anteriores sin ejecutar: padre e269, CT281 <REDACTED_UUID>, API870 y web871. No es una reutilización automática de bindings antiguos.

  • Fuente PR114/main 520b327: guardas Ansible/deploy y eliminación de objetos WP, CI 7/7 PASS. El contrato global de alertas pasó de 92 a 91 por la única regla retirada; los contratos PBS se conservaron.
  • Prometheus/pmx51 a las 17:06:44–46: un target WP eliminado, 26 jobs, todo otro campo y token HA preservados. RULES bytes/full9 intactos. A las 17:08:17–19: cero series WP y WPPulseDown inactive/health ok. La regla runtime residual es inerte (==0, sin absent); se conserva hasta limpieza específica futura.
  • Caddy270 a las 17:17:50 y Caddy271 a las 17:18:47: cinco imports retirados del archivo vivo y seis rutas WP del JSON administrativo. Se conserva exactamente todo otro objeto cargado, incluidos autenticación y logging. Un POST por nodo, sin incertidumbre. Backups privados durables en cada CT; ningún reinicio.
  • La adaptación directa del archivo tenía logging global derivado de WP; no se relajó su comparación ni se recargó ese archivo sobre las rutas vivas. Se preservaron por separado los objetos ajenos del archivo y del admin JSON. Una futura adaptación desde archivo puede cambiar ese logging derivado; no se declara equivalencia completa file/admin ni se modificó el logging ajeno.
  • Máscaras a las 17:22:36: diez nombres propios masked, tres timers inactive, API870/web871 todavía activos, enablement links intactos. Backup duradero de unidades/estados y recuperación parcial revisada con cuatro pruebas. Nunca se ejecutó mask --force, compose down ni borrado de volúmenes.
  • La cola pasó naturalmente de cinco a ocho comandos: cuatro tail_log y cuatro two_fa_audit, ninguno claimed. Se conservaron, sin ejecutarlos/cancelarlos para fabricar drenaje. La admisión exige tipos de lectura conocidos y cantidad acotada, cero trabajos activos/próximos y estados de unidades exactos; no exige un número fijo que estos bucles de aplicación pueden incrementar.

El primer preflight de parada no emitió CAS ni shutdown: sólo web masked reportaba NeedDaemonReload=yes, las otras nueve no; PID/start y máscaras eran correctos. Se admite únicamente ese caso si symlinks y drop-ins siguen fijados, API870/start40616126 y web871/start40618913 no cambian, y se preservan las otras guardas. No se infiere la causa del flag ni se lo ignora globalmente. Parar el CT dedicado no requiere recargar la definición activa de su web; la máscara persistente bloquea el próximo arranque. La secuencia mantiene una sola petición de shutdown real, sin force ni retry automático.

Recibo privado bajo ~/.local/state/ SHA256
wp-prometheus-retirement-20261021-bpf4r2_b/applied.json <REDACTED>
Mismo directorio, stale-readback.json <REDACTED>
wp-retirement-e269-20261021-8srb4qx6/admission.json <REDACTED>
Mismo directorio, caddy270-applied.json <REDACTED>
Mismo directorio, caddy271-applied.json <REDACTED>
Mismo directorio, mask-applied.json <REDACTED>
Mismo directorio, masked-units-diagnostic.json <REDACTED>

Cierre operativo de la parada

El parent v2 conservó todas las guardas y admitió únicamente el caso web masked NeedDaemonReload=yes con PID/start, symlinks y drop-ins exactos; 37 pruebas del predicado y peer independiente PASS. Primero se aplicó CAS onboot1→0, sin cambiar otro campo PVE. Hubo una única petición de shutdown, timeout120/forceStop0. El observador terminó uncertain en following_shutdown; no se lanzó otra parada.

La lectura independiente a las 17:30:43 del UPID UPID:proxmox:0000E7EE:00020A07:6AD8DA66:vzshutdown:281:root@pam: confirmó stopped/exitstatus OK. A las 17:31:31, API status/current y pct status dieron stopped, onboot0, mismo epoch e269 y configuración restante idéntica al backup. La comparación de los otros27 huéspedes, 14configuraciones HA y 14estados HA no encontró cambios. La incertidumbre inicial queda preservada como tal; el cierre se sustenta en lecturas nuevas, sin inferir la causa del fallo del observador.

Backup PVE: /root/wp-retirement-shutdown-_8rk1y9u. Backup de unidades en el CT: /root/wp-pulse-retirement-<REDACTED>. Datos, secretos, bases y copias se conservan; ocho comandos de lectura pendientes siguen en DB. No se arrancó el CT para verificar. Antes de un arranque manual futuro hay que revisar cola y timers Persistent; Docker/previews conservan sus políticas históricas de reinicio y también requieren revisión.

La medición conjunta posterior,17:33:53–17:34:15, da +681,3711MiB después de reservar2GiB y manteniendo Jellyfin entre los diez migrables. Es presupuesto instantáneo, no un N-1 completo ni ahorro causal frente al boot anterior.

Recibo privado en wp-retirement-e269-20261021-8srb4qx6 SHA256
shutdown-result-v2.json, incertidumbre inicial <REDACTED>
shutdown-task-readback.json <REDACTED>
stopped-independent.json <REDACTED>
post-comparison.json <REDACTED>