respaldo: una guarda que evita BORRAR el historial de git del Storage Box
Encontrado corriendo el respaldo desde la caja de producción (SDD 28, puerta 7). El paso [2/3] sube el repo **con `--delete`** —correcto: para eso está git—. Pero el `/opt/takana` de la caja llegó por `rsync --exclude=.git`: es una COPIA, no un clon. Una corrida real desde ahí no habría subido menos cosas: **habría borrado del respaldo todo lo que le falta al origen, empezando por `.git`** — el historial entero. Y en silencio, porque rsync haría exactamente lo que se le pidió. Ahora falla ruidosamente si la raíz no tiene `.git`, con `REPO_INCOMPLETO=1` como escotilla para el caso deliberado. Probado en los tres sentidos: en gioser (con `.git`) pasa; en un árbol sin `.git` aborta; con la escotilla pasa igual. **Y el store tampoco estaba donde el script creía.** Usaba `$RAIZ/store` cableado — en gioser es un bind-mount dentro del repo, pero en una caja takana instalada es una partición en `/store`, así que el paso [3/3] moría con `change_dir "/opt/takana/store" failed`. Peor: rsync devuelve 23, que está en la lista de reintentables, así que el bucle lo reintentaba — exactamente el cuadro que la cabecera de este script ya documenta («un error reintentable que se repite 40 veces no es un corte de red: es algo estructural»). Ahora `STORE` es env y hay una guarda ANTES del bucle que aborta si no existe. Con eso el `--seco` completa los tres pasos desde la caja y lee la ocupación del box (111 G de 1 T). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RomoxEGZUhaT4pob1QSX5x
This commit is contained in:
@@ -66,6 +66,13 @@ KEY="${KEY:-$HOME/.ssh/github5}"
|
||||
# desde la caja de producción moría con `cd: /mnt/vvv/takana: No such file or directory` (SDD 28
|
||||
# §6.9). El override por env se conserva.
|
||||
RAIZ="${RAIZ:-$(cd "$(dirname "$0")/.." && pwd)}"
|
||||
# El store NO siempre vive dentro del repo. En gioser `store/` es un bind-mount del volumen y queda
|
||||
# bajo la raíz; en una caja takana INSTALADA es una partición propia montada en `/store`, y el script
|
||||
# moría con `change_dir "/opt/takana/store" failed`. Peor: rsync devuelve 23, que está en la lista de
|
||||
# reintentables, así que el bucle lo reintentaba una y otra vez — el mismo cuadro que esta cabecera ya
|
||||
# documenta («un error reintentable que se repite 40 veces no es un corte de red: es algo
|
||||
# estructural»). Ahora es env, y si no existe se ABORTA antes de entrar al bucle.
|
||||
STORE="${STORE:-$RAIZ/store}"
|
||||
|
||||
SECO=""
|
||||
[ "${1:-}" = "--seco" ] && SECO="--dry-run"
|
||||
@@ -210,6 +217,17 @@ $SSH_CMD "$SB_USER@$SB_HOST" 'mkdir hammer hammer/store hammer/repo hammer/estad
|
||||
echo "==> [1/3] estado (el grafo: qué había construido y con qué hash)"
|
||||
reintentar estado $RS $SECO -e "$SSH_CMD" "$RAIZ/docs/state/" "$SB_USER@$SB_HOST:hammer/estado/" || true
|
||||
|
||||
# ⚠ GUARDA: el repo va con `--delete`, así que respaldar desde un árbol INCOMPLETO no sube menos
|
||||
# cosas: BORRA las que faltan del respaldo. El caso real (2026-09-11, SDD 28 §6.10): la caja de
|
||||
# producción tiene el repo por `rsync --exclude=.git` —no es un clon—, y una corrida real desde ahí
|
||||
# habría borrado `.git` del Storage Box, o sea el historial entero. Falla ruidosamente en vez de
|
||||
# podar en silencio. `REPO_INCOMPLETO=1` es la escotilla para el caso deliberado.
|
||||
if [ ! -d "$RAIZ/.git" ] && [ "${REPO_INCOMPLETO:-0}" != 1 ]; then
|
||||
echo "!! '$RAIZ' no tiene .git — parece una copia, no un clon." >&2
|
||||
echo " El paso [2/3] va con --delete: subir desde acá BORRARÍA del respaldo lo que falte," >&2
|
||||
echo " empezando por el historial de git. Respaldá desde un hub completo, o REPO_INCOMPLETO=1." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "==> [2/3] repo (recetas, scripts, SDDs — el cerebro; con esto solo se reconstruye el store)"
|
||||
reintentar repo $RS --delete $SECO -e "$SSH_CMD" \
|
||||
--exclude /store --exclude /store-rust --exclude /store-kern \
|
||||
@@ -217,16 +235,19 @@ reintentar repo $RS --delete $SECO -e "$SSH_CMD" \
|
||||
"$RAIZ/" "$SB_USER@$SB_HOST:hammer/repo/"
|
||||
|
||||
# ── 2 y 3. EL STORE, huérfanos primero. ────────────────────────────────────────────────────────
|
||||
# Guarda ANTES del bucle: un store ausente da rsync 23, que es reintentable, y se convierte en 40
|
||||
# intentos y un respaldo a medias sin que nada diga «esa ruta no existe».
|
||||
[ -d "$STORE" ] || { echo "!! el store no está en '$STORE' — pasá STORE=<ruta> (en una caja instalada suele ser /store)" >&2; exit 1; }
|
||||
# La lista de huérfanos la produce `store-gc.sh` como subproducto; si no hay una reciente, se sube
|
||||
# el store entero en un solo paso y santas pascuas (rsync es incremental: no se pierde nada).
|
||||
echo "==> [3/3] store (128 G a 8 Mbps ⇒ NO cabe en una sentada; esto se corta y se continúa)"
|
||||
HUER="$(ls -t "$RAIZ"/work/store-gc-huerfanos-*.txt 2>/dev/null | head -1)"
|
||||
if [ -n "$HUER" ] && [ -s "$HUER" ]; then
|
||||
echo " · huérfanos primero ($(wc -l < "$HUER") artefactos, únicos ejemplares) — desde $HUER"
|
||||
reintentar huerfanos $RS $SECO -e "$SSH_CMD" --files-from="$HUER" "$RAIZ/store/" "$SB_USER@$SB_HOST:hammer/store/" || true
|
||||
reintentar huerfanos $RS $SECO -e "$SSH_CMD" --files-from="$HUER" "$STORE/" "$SB_USER@$SB_HOST:hammer/store/" || true
|
||||
fi
|
||||
echo " · resto del store"
|
||||
reintentar store $RS $SECO -e "$SSH_CMD" "$RAIZ/store/" "$SB_USER@$SB_HOST:hammer/store/"
|
||||
reintentar store $RS $SECO -e "$SSH_CMD" "$STORE/" "$SB_USER@$SB_HOST:hammer/store/"
|
||||
|
||||
echo "==> ocupación en el Storage Box:"
|
||||
$SSH_CMD "$SB_USER@$SB_HOST" 'df -h .' 2>/dev/null | tail -2
|
||||
|
||||
Reference in New Issue
Block a user