farm-up: DOS bombas de pérdida de datos — una ya explotó y se llevó ~900 artefactos del volumen

Investigando por qué el worker nuevo arrancó con 2 artefactos en vez de ~900, apareció esto.

BOMBA 1 — `rm -rf $REMOTE/store` sin comprobar si es punto de montaje.
La guarda era `[ -d ] && [ ! -L ]`: basta en un server creado desde la golden ORIGINAL, donde
/opt/hammer/store es un directorio normal. Pero al re-snapshotear un worker (ayer, para meterle
Rust y Go) la imagen se llevó también LA CONFIGURACIÓN DE MONTAJE ⇒ el server nuevo monta el
volumen en esa ruta AL ARRANCAR, antes de que corra el «rescate». Entonces el `rm -rf` borra A
TRAVÉS DEL MONTAJE y se lleva el store del volumen entero — justo lo que el volumen existe para
proteger.
Evidencia: el volumen pasó de ~900 artefactos a 2, pero NO se perdió el filesystem (lost+found
de julio, 17 montajes, .dmerge intacto). Se borró el CONTENIDO, no el disco. Ahora hay
`mountpoint -q`: si ya está montado no hay nada que rescatar ni que borrar.

BOMBA 2 — `mount … || { mkfs.ext4 -F …; }`. Formatear ante CUALQUIER fallo de montaje, incluida
la carrera normal entre `volume attach` y la aparición del dispositivo. Un hipo de segundos
destruía el volumen. Ahora sólo formatea si `blkid` dice que NO tiene filesystem; si lo tiene y
no montó, aborta y lo dice.

Las dos comparten la misma forma: un fallback destructivo que asume la causa benigna. `mv -n`
está bien elegido (no pisa), pero el `rm -rf` que lo sigue anulaba esa prudencia.

Y una consecuencia que hay que asumir: re-snapshotear un worker NO conserva el store — los
artefactos viven en el volumen, que no entra en la imagen. La golden aporta toolchain y sistema;
la caché la aporta el volumen. Hoy la imagen decía traer store y no lo trae.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-09 08:11:57 -04:00
co-authored by Claude Opus 5
parent 3fb85f23ee
commit 36081cf1cf
+22 -2
View File
@@ -97,7 +97,16 @@ for k in $(seq 1 "$N"); do
hcloud volume attach --server "$name" "$VOL_NAME" >/dev/null 2>&1 || true
dev="/dev/disk/by-id/scsi-0HC_Volume_$vid"
$SSH root@"$ip" "mkdir -p /mnt/cosecha
mount $dev /mnt/cosecha 2>/dev/null || { mkfs.ext4 -q -F $dev && mount $dev /mnt/cosecha; }
# ⚠ El `mkfs.ext4 -F` de rescate SÓLO si el dispositivo no tiene filesystem. La versión previa
# formateaba ante CUALQUIER fallo de montaje —incluida la carrera normal entre `volume attach`
# y la aparición del dispositivo— o sea que un hipo de segundos destruía el volumen entero.
# `blkid` distingue «vacío» de «no pude montarlo ahora».
if ! mount $dev /mnt/cosecha 2>/dev/null; then
if blkid $dev >/dev/null 2>&1; then
echo " ✗ el volumen TIENE filesystem y no montó — NO lo formateo. Revisá a mano." >&2; exit 1
fi
mkfs.ext4 -q -F $dev && mount $dev /mnt/cosecha
fi
mkdir -p /mnt/cosecha/store /mnt/cosecha/verdicts /mnt/cosecha/logs
# el store del worker ES el del volumen: sellar YA es persistir.
# PERO antes hay que RESCATAR el store HORNEADO en la golden (2026-07-21): esto hacía
@@ -106,7 +115,18 @@ for k in $(seq 1 "$N"); do
# deuda contra un store casi vacío y se pone a reconstruir media distro: en la tanda del
# 2026-07-21 dio 716 recetas de deuda donde el hub medía 37. Es CAS (nombre = hash) ⇒
# fusionar es seguro por construcción: \`mv -n\` no pisa lo que el volumen ya tiene.
if [ -d $REMOTE/store ] && [ ! -L $REMOTE/store ]; then
# ⚠ `mountpoint -q` NO ES OPCIONAL — sin él este bloque BORRA EL VOLUMEN.
# La guarda original sólo comprobaba «es directorio y no es symlink». Eso basta en un server
# recién creado desde la golden ORIGINAL, donde /opt/hammer/store es un directorio normal.
# Pero al re-snapshotear un worker (2026-08-08) la imagen se llevó también la CONFIGURACIÓN DE
# MONTAJE: el server nuevo monta el volumen en /opt/hammer/store al arrancar, ANTES de que
# corra este rescate. Entonces `rm -rf $REMOTE/store` borra A TRAVÉS DEL MONTAJE y se lleva el
# store del volumen entero — que es justo lo que el volumen existe para proteger.
# Medido: el volumen pasó de ~900 artefactos a 2. No se perdió el filesystem (lost+found es de
# julio, 17 montajes): se borró el CONTENIDO.
# ⇒ Si ya es punto de montaje, no hay nada que rescatar ni que borrar: el store ya está donde
# tiene que estar.
if [ -d $REMOTE/store ] && [ ! -L $REMOTE/store ] && ! mountpoint -q $REMOTE/store; then
n=\$(ls $REMOTE/store 2>/dev/null | wc -l)
[ \"\$n\" -gt 0 ] && mv -n $REMOTE/store/* /mnt/cosecha/store/ 2>/dev/null
echo \" ✓ rescatados \$n artefactos horneados de la golden al volumen\"