Ensayos PBS: motor compartido y wrappers¶
Actualizado el 20 de octubre de 2026. La guía anterior describía un script de VMID 999 con destrucción incondicional. Ese procedimiento está retirado: no reservar ni borrar un invitado siguiendo aquellas instrucciones.
Fuentes y alcance¶
El motor mantenido es
pbs_restore_drill.py,
instalado como /usr/local/bin/pbs_restore_drill.py. El role
observability_collector lo copia en los dos nodos Proxmox. Este role participa
en el playbook normal; una publicación en Git puede propagarse mediante
Ansible-pull sin que se lance un ensayo. Una revisión local no acredita por sí
sola la versión instalada: comprobarla separadamente.
La observación pasiva de las 07:36:50 CEST del 20 de octubre encontró la
versión con guarda de volúmenes f7b4f654… en ambos hosts, root:root y 0755,
con Ansible-pull completado correctamente. Es anterior a la corrección de
cancelación descrita a continuación; no implica un ensayo nuevo ni acredita
que esa corrección posterior esté instalada.
A las 07:55:49 CEST, pmx50 ya tenía el helper corregido 7e2c3fda…,
tras un Ansible-pull natural terminado07:55:48, success0. Pmx51 aún tenía
f7b4f654…; su último pull terminó07:41:57, antes de publicarse la corrección.
En esa lectura la convergencia del segundo nodo quedaba pendiente. La muestra
posterior de 07:58:26,971655 CEST ya encontró 7e2c3fda… en pmx51,
tras su pull natural07:55:59–07:57:15, success0. Ambos nodos convergieron al
artefacto corregido, regular root:root0755. No se forzó un pull ni se inició un
ensayo; la instalación no acredita una restauración con esa versión.
Los entrypoints conservados son:
/usr/local/bin/pbs-drill.sh: wrapper de pmx50 para perfileslxcovm, con log en/var/log/pbs-drill.logy notificación programada existente./usr/local/bin/pbs-restore-test.sh: wrapper del perfilconfigen el nodo secundario; conserva su log y ping de Healthchecks cuando termina bien.
Ejecutar un wrapper produce acciones y avisos. No es una comprobación pasiva. No se reproducen aquí secretos ni URLs privadas de los canales.
Qué comprueba el motor¶
- Reserva el ensayo mediante un directorio compartido en pmxcfs:
/etc/pve/priv/homelab-pbs-drill-lock. Una reserva existente impide otro ensayo; no caduca ni debe borrarse a ciegas. - Rechaza un VMID temporal ocupado. Usa 9901 para
lxc/vmy 9902 paraconfig; no destruye un invitado preexistente para hacer sitio. - Selecciona una copia de un objetivo permitido: LXC 100/123/155/200/251, VM 171/208 o configuración de CT123. CT186 y CT217 quedan excluidos.
- Restaura en
zfs-hay valida el propietario de cada volumen: debe pertenecer exactamente al VMID temporal. Elimina red, mounts ajenos, hooks y dispositivos mediante una lista de configuración permitida. No se reutilizan discos de producción para el ensayo. - Aplica una etiqueta de propiedad única y límites del invitado. Los perfiles
LXC/VM arrancan para comprobar su estado;
configno arranca el invitado. - La limpieza exige propiedad acreditada. Ante propiedad o estado desconocido,
no tratar el invitado como desechable ni sustituir la comprobación por un
destroymanual.
Corrección en fuente del preflight LXC, 21 de octubre¶
Antes de pct restore, la fuente ahora rechaza todas las entradas raw lxc.*
(incluidas las formas : y =), mpN, devN, hookscript y template, además
de rootfs ambiguo, rutas de host, aliases de volumen y mapas idmap por mount.
La guarda anterior sólo rechazaba lxc.idmap/lxc.include: eliminar los otros
recursos después de restaurar llegaba tarde para proteger la fase de montaje.
Los errores existentes de namespace se conservan.
El rootfs requiere un volumen PVE posicional único y tamaño positivo. Una llamada
Perl fija al parser instalado PVE::LXC::Config->parse_volume('rootfs', ...)
valida propiedades y unidades mediante el mismo schema que usa PVE; no asigna
ni monta volúmenes. El motor exige tipo volume, tamaño finito positivo, volumen
sin sustitución y ausencia de idmap. Un fallo del parser impide restaurar.
No se mantiene una gramática alternativa de unidades/tipos en Python.
El comando LXC declara --onboot 0 --start 0 --ha-managed 0 desde el comienzo.
La configuración suministrada prevalece sobre onboot: 1 del backup, evitando
un arranque automático entre la restauración y el aislamiento posterior. netN
puede estar en la fuente; no se usa unique ni se arranca hasta haber retirado
la red y acreditado el aislamiento. Los perfiles, objetivos y calendarios se
conservan; CT217 sigue excluido y no se incorpora ningún perfil de restore suyo.
La autoridad es el backend pve-container 6.1.14 leído de forma acotada el
21oct en pmx50, boot 558fbd3c…: LXC.pm importa raw LXC antes de crear/montar
los discos; Create.pm::sanitize_and_merge_config conserva valores suministrados;
Config.pm aporta el schema y parser rootfs. Capturas privadas:
~/.local/state/pbs-restore-backend-native-20261021-rs7rm_st/.
| Fuente nativa | SHA256 |
|---|---|
| LXC.pm | <REDACTED> |
| Create.pm | <REDACTED> |
| Config.pm | <REDACTED> |
Validación de esta corrección: 67 tests offline PASS de toda la suite
scripts/simplification/tests, con backend falso y procesos sintéticos. Los
negativos atraviesan execute: recursos peligrosos no alcanzan restore/start,
ni tocan el sentinel de producción; respuestas inválidas del parser no se
aceptan. Las respuestas Perl de esa suite están simuladas: esos 67 tests prueban
el control de flujo completo mediante backend falso, no el parser instalado.
Revisión independiente de capacity sobre el commit 512cc879:
PASS, con los 67 tests repetidos y contraste de las tres fuentes nativas.
Por separado, Root ejecutó 11/11 fixtures del parser nativo PASS a las
13:21:05 CEST del 21oct, en una única sesión de sólo lectura. Usó el mismo
snippet Perl fijo, extraído del motor 512cc879, con valores sintéticos: unidades
G/M/bytes, tamaño fraccionario y opciones válidas; cero, negativo, tamaño ausente,
unidad inválida, bind, idmap y propiedad desconocida. Se comprobó la aceptación
o rechazo de la proyección parseada; no se ejecutó execute, ningún restore,
comando de almacenamiento, wrapper o job. Boot 558fbd3c… y los hashes/metadatos
de las tres fuentes nativas permanecieron idénticos antes y después.
Recibo privado:
~/.local/state/pbs-native-parser-fixtures-20261021-kybmo8js/native-result.json,
SHA256 <REDACTED>.
Motor probado SHA256
<REDACTED>;
snippet SHA256
<REDACTED>.
La PR101 se fusionó a las
13:23:25, tras CI Python3.10/3.12 y contratos/promtool correctos. El ciclo
ordinario de pmx50 iniciado13:23:45 terminó con salida0; a las13:25:16 la
copia instalada coincide con el SHA256 del motor probado arriba. En pmx51,
el ciclo13:32:44 también termina con salida0 y el hash coincide a las13:34:15.
Recibo adicional privado: ~/.local/state/pmx51-pbs-viewer-convergence-20261021-mqvq2rrf/completed-cycle.json,
SHA256 <REDACTED>. Ambos boots
permanecen estables; no se forzó pull ni se inició ningún ensayo. Recibo:
~/.local/state/pulse-pbs-ordinary-convergence-20261021-ol5zt5yn/receipt.json,
SHA256 <REDACTED>.
Esto no acredita recuperación CT217 ni consistencia de datos.
Cancelación y resultado incierto¶
La fuente incorpora cancelación cooperativa TERM/INT/HUP, límites por comando
y de operación, y recibos locales privados bajo /var/lib/homelab-pbs-drill/.
El recibo se escribe mediante sustitución atómica y fsync; antes de liberar la
reserva sólo puede indicar release_pending, nunca éxito terminal. Una señal
observada durante la liberación o la escritura final produce fallo, sin repetir
la destrucción o la liberación.
Un restore fallido, cancelado o agotado puede haber dejado un worker PVE activo: terminar el proceso CLI no acredita la terminación de ese worker. En tal caso se conserva la reserva y no se etiqueta, arranca ni destruye el invitado incierto. La limpieza de un invitado aislado exige volver a comprobar nodo, VMID, etiqueta, configuración exacta, volúmenes y estado antes de detener y antes de destruir. Después se comprueba ausencia del invitado en API y configuración; esto no es una auditoría exhaustiva de volúmenes huérfanos en el almacenamiento.
Si una reserva queda retenida:
- No borrar el lock, reintentar el ensayo ni deducir un UPID por aproximación.
- Leer el recibo privado del intento en el nodo que lo ejecutó y contrastar nodo, VMID temporal, nonce, snapshot y fase con las tareas reales de PVE.
- Acreditar que cualquier worker asociado ha terminado y revisar configuración, volúmenes y propiedad actuales. Una etiqueta ausente o cambiada no autoriza destruir el invitado.
- Reconciliar manualmente recursos y reserva sólo con esa evidencia; conservar el recibo y registrar lo resuelto. Un recibo pendiente puede coexistir con una reserva ya liberada si falló la escritura final: no recrearla a ciegas.
Validación local y revisión independiente: 50 pruebas (34 de ciclo de vida y 16 de aislamiento/entorno), sin acceso a PVE. No se ha ejecutado un restore nuevo. SIGKILL, caída del host, procesos en D-state o daemon inaccesible quedan fuera de la garantía de limpieza; la incertidumbre exige revisión, no un éxito supuesto. Consultar el informe de recuperación.
Calendario declarado¶
La fuente ansible/roles/observability_collector/files/cron.d/pbs-drill declara:
| Perfil | Calendario en pmx50 |
|---|---|
| LXC | Día 1 de cada mes a las 05:05 |
| VM | Día 15 de enero, abril, julio y octubre a las 05:05 |
Es el calendario fuente, no una prueba de ejecución reciente ni del estado actual de cron. No cambiarlo ni iniciar un restore como parte de una auditoría.
Validación y operación¶
Las pruebas locales del motor usan fixtures y procesos de prueba; no contactan con Proxmox ni PBS:
El ensayo real del 19 de octubre restauró CT123, comprobó el arranque aislado y verificó la retirada del invitado, volúmenes y reserva. Ese resultado corresponde a aquella versión y copia. No certifica CT217, el arranque de todas las aplicaciones, la consistencia de sus bases ni los originales que viven en NFS.
Un ensayo futuro requiere una ventana revisada y recursos disponibles. Mientras se investigan los resets de pmx50 y el throttling de pmx51, no iniciarlo desde esta guía. El estado coordinado y las condiciones específicas de recuperación de CT217 conservan las limitaciones vigentes.