Saltar a contenido

ADR-052: Operación — Prometheus en el manifiesto de producción, señal preservation y nombres neutros del almacén de objetos

Estado: Aceptado Fecha: 2026-10-22 Autores: Giampiero (mantenedor principal); bloque D-6 del lote D (deuda de C-8) Relacionados: ADR-041 (métricas; enmendado aquí: familia y señal), ADR-027 (RustFS; enmendado aquí: nombres), ADR-023 (WORM), ADR-043 (valoración), ADR-042 (reempaquetado)


Contexto

  1. Las reglas de alerta vivían solo en prosa (deployment.md): nada comprobaba que nombraran familias que existen. Una alerta sobre una métrica inexistente no dispara nunca, y nadie lo nota.
  2. Prometheus no estaba en el manifiesto. La red de producción es una sola (orpycamcp-net, no internal); meter allí a Prometheus le daría alcance a Postgres, Redis, Keycloak y al almacén sin necesitarlo.
  3. Agotados que ninguna métrica veía: el reintento del sellado XAdES (reconcile_agotado del índice y de las actas de transferencia y de eliminación), la fixity PREMIS del acta (fixity_premis_agotado), el reempaquetado del AIP (reempaque_agotado, D-5) y la aplicación de la valoración (expediente_valoracion_hold.agotada, D-4). El operador no tenía cómo enterarse de que algo esperaba a un humano.
  4. El nombre del motor anterior sobrevivía en las variables (MINIO_*), en el servicio del compose y en la disposición del respaldo, justificado por «13 ficheros». Peor: extra="ignore" y los valores por omisión hacían que una variable vieja se ignorara en silencio: el almacén caía a su valor por omisión y la réplica secundaria del AIP, a local, sin aviso.

Decisión

1. Prometheus en infra/docker-compose.prod.yml, en una red propia internal

Red metricas-net (internal: true: sin gateway, ni entrada ni salida fuera de ella). En ella viven solo Prometheus y los seis servicios con /metrics (auth, archive, workflow, notification, signature, knowledge), que siguen además en orpycamcp-net. Alternativas descartadas: meterlo en orpycamcp-net (alcance a toda la pila) y dejarlo fuera del manifiesto (estado anterior). Las cabeceras de proxy de ADR-041 son defensa en profundidad y no sustituyen a la red.

  • Imagen prom/prometheus por tag y digest (resuelto con docker buildx imagetools inspect). Sin ports ni expose; sin --web.enable-admin-api ni --web.enable-lifecycle; configuración montada :ro; sistema de ficheros de solo lectura; retención de 30 días en el volumen prometheus-data.
  • Alertmanager no entra: el canal de aviso (correo, SMS, guardia) es decisión de la entidad. Las reglas se evalúan y se consultan con promtool (ver deployment.md).
  • Fuente única de las reglas: infra/prometheus/alertas.yml (y prometheus.yml con los objetivos). deployment.md deja de copiarlas y enlaza el fichero.
  • Guardianes: shared/tests/test_prometheus_manifiesto.py (red, puertos, flags, censo de objetivos derivado del árbol, cada expr solo nombra familias del registro) y ampliación de test_manifiesto_prod_seguro.py.

2. Familia orpycamcp_preservation_exhausted_artifacts y señal preservation (enmienda ADR-041)

Se renombra orpycamcp_worm_exhausted_artifacts → orpycamcp_preservation_exhausted_artifacts y la señal worm → preservation, porque sellado y fixity no son WORM. Sin compatibilidad (los datos son de prueba y Prometheus no estaba desplegado). Fases (phase): reconcile, renewal, packaging (WORM), sealing, fixity, repackaging y valuation; artefactos: los siete anteriores más expediente_valoracion. Son 19 combinaciones (artefacto, fase); el 0 se emite cuando se midió, y «no verificado» sigue sin emitir series de valor (ADR-041).

El censo (shared/tests/test_metricas_preservacion_censo.py) recalcula la lista desde las migraciones: toda columna booleana *_agotad[oa] debe estar en el mapa columna→fase y tener su combinación, con límite de palabra para no confundir reconcile_agotado (sellado) con worm_reconcile_agotado (WORM).

Declarado: fixity_premis_agotado no tiene reintento manual; la métrica avisa y la acción hoy es de base de datos. Insumo para la épica siguiente (endpoint + tool). Las métricas son de operación, no de la entidad: el MCP no debe exponerlas.

3. Nombres neutros del almacén de objetos, de una vez y sin alias (enmienda ADR-027)

Antes Después
MINIO_ENDPOINT, _ACCESS_KEY, _SECRET_KEY, _USE_SSL, MINIO_SECONDARY_* OBJECTSTORE_…
MINIO_ROOT_USER, MINIO_ROOT_PASSWORD (.env de infra) OBJECTSTORE_ROOT_USER, OBJECTSTORE_ROOT_PASSWORD
MINIO_REGION, MINIO_SECURE (pruebas S3 y respaldo) OBJECTSTORE_REGION, OBJECTSTORE_USE_SSL
servicio minio, contenedor orpycamcp-minio[-prod], DNS minio:9000 objectstore, orpycamcp-objectstore[-prod], objectstore:9000
respaldo: minio/, minio-versiones/, minio-retencion.tsv, minio-versiones.tsv, minio.tar.gpg, minio_objetos= objectstore/, objectstore-versiones/, objectstore-retencion.tsv, objectstore-versiones.tsv, objectstore.tar.gpg, objectstore_objetos=
  • Sin alias. Pero tampoco silencio: storage-service no arranca si el entorno o su .env traen cualquier variable del prefijo retirado (_variables_retiradas(); solo lee nombres, nunca valores), y backup.sh / restore.sh cortan con un mensaje que indica el sed. restore.sh se niega ante un respaldo con la disposición anterior: reinterpretar nombres en una restauración es donde un error pasa por éxito.
  • Se conservan, porque describen con verdad lo que son: el volumen minio-data (fondo del motor anterior, retenido por decisión de la entidad), los buckets (no llevan el nombre del motor; y renombrar un bucket con objetos COMPLIANCE no es posible), el módulo minio_client.py y la biblioteca miniopy_async.
  • Guardián shared/tests/test_sin_nombres_del_motor_anterior.py: ni MINIO_ (regex (?<![A-Z])MINIO_, que excluye DOMINIO_), ni minio:9000, ni http://minio en código, pruebas, compose, CI e infraestructura, salvo los tres módulos que nombran el prefijo para rechazarlo.

Consecuencias

  • Incompatible para quien despliegue: renombrar variables del .env (sed -i 's/^MINIO_/OBJECTSTORE_/' <fichero>), recrear con up -d --build --remove-orphans (el contenedor viejo queda huérfano; el volumen objectstore-data se reutiliza), y la familia/señal de métricas cambia de nombre (reglas y paneles propios deben actualizarse).
  • Los respaldos hechos antes de este cambio no se restauran con restore.sh sin renombrarlos a mano en una copia.
  • Pendiente (fuera de alcance, orden del usuario): rol propio del job de audit_chain_runs.