Podé el store por tercera vez hoy: 363 artefactos superados, 24 G. Comparado con la poda de la tarde: **362 en común**. Volvieron otra vez, pese al arreglo de esta tarde. LA CAUSA de que el arreglo no sirviera: puse el `--exclude-from` del registro de podados sólo en `farm-sync.sh`, y el latido NO usa ese script. `cosecha-cron.sh` tiene su PROPIO rsync del store (línea 71), y corre cada 30 minutos por cron ⇒ una poda de 24 G quedaba deshecha en menos de una hora. Los tres commits de «cosecha granja» de la madrugada son exactamente eso. Y al ir a arreglarlo, en vez de parchear y seguir, busqué si había más: **son CUATRO** las rutas que bajan el store del worker — `cosecha-cron.sh`, `farm-sync.sh`, `harvest-go.sh` y `farm-down.sh`. Tenía protegida una de cuatro. El error de método vale más que el bug: arreglar una de varias copias y declarar victoria es PEOR que no arreglar, porque el síntoma se atenúa lo justo para dejar de mirar. Lo que lo delató fue comparar los manifiestos de dos podas (`comm -12`), no leer código. Dos podas con el mismo número no son coincidencia — ya está anotado como regla, y hoy la regla pagó dos veces. Las cuatro llevan ahora el mismo `--exclude-from` y una nota que dice que son cuatro, para que la quinta —si aparece— nazca protegida. Disco: 112 G → 136 G tras la poda de ahora. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
85 lines
4.4 KiB
Bash
Executable File
85 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# farm-down.sh [name...] — COSECHA el store sellado de cada worker efímero al laptop y luego lo
|
|
# DESTRUYE. Sin args opera sobre toda la flota registrada en scripts/farm/.fleet. Con args, sólo
|
|
# sobre los workers nombrados (para bajar la escala parcialmente).
|
|
#
|
|
# El orden importa: primero rsync-eamos el store (CAS, merge seguro con el del laptop), y SÓLO si
|
|
# el pull salió bien destruimos el server. Tras destruir todo, promovemos+firmamos lo cosechado
|
|
# (cache-hit en los artefactos recién bajados) — el store del laptop es la fuente canónica.
|
|
#
|
|
# Uso: scripts/farm/farm-down.sh # cosecha + destruye toda la flota
|
|
# scripts/farm/farm-down.sh hworker-2 # sólo ese
|
|
# Env: SSH_KEY (def ~/.ssh/github5), REMOTE (def /opt/hammer), NO_PROMOTE=1 (sólo cosecha+destruye)
|
|
set -uo pipefail
|
|
|
|
SSH_KEY="${SSH_KEY:-$HOME/.ssh/github5}"
|
|
REMOTE="${REMOTE:-/opt/hammer}"
|
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
FLEET="$ROOT/scripts/farm/.fleet"
|
|
# Ver nota en farm-up.sh: workers efímeros reciclan IPs ⇒ known_hosts a /dev/null (hub-and-spoke,
|
|
# worker sin secretos, sin superficie MITM que proteger).
|
|
SSH="ssh -i $SSH_KEY -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=ERROR -o ConnectTimeout=10"
|
|
cd "$ROOT"
|
|
[ -s "$FLEET" ] || { echo "flota vacía (scripts/farm/.fleet)"; exit 0; }
|
|
|
|
want=" $* " # si hay args, filtrar por nombre; si no, todos
|
|
harvested=0
|
|
newfleet="$(mktemp)"
|
|
|
|
while read -r name ip; do
|
|
[ -n "${name:-}" ] || continue
|
|
if [ "$#" -gt 0 ] && [ "${want#* $name }" = "$want" ]; then
|
|
echo "$name $ip" >> "$newfleet"; continue # no seleccionado: sigue vivo
|
|
fi
|
|
# ── BLINDAJE (2026-07-17, petición explícita del usuario): gioser.net es FIJO, vive en el MISMO
|
|
# proyecto hcloud y NO TIENE BACKUP. Este script borra por NOMBRE leído de .fleet, sin verificar
|
|
# nada: si un nombre equivocado entra a esa lista (a mano, por un bug, por un rsync), lo destruye
|
|
# sin preguntar. Dos capas iguales a las del deadman — la del label es la fuerte, porque no
|
|
# depende de mantener una lista al día. gioser no tiene labels (map[]) ⇒ nunca pasa.
|
|
case "$name" in
|
|
gioser|gioser.net|*gioser*)
|
|
echo " ⛔ '$name' está en la LISTA NEGRA (server fijo sin backup) — NO se toca"
|
|
echo "$name $ip" >> "$newfleet"; continue ;;
|
|
esac
|
|
if ! hcloud server describe "$name" -o format='{{.Labels}}' 2>/dev/null | grep -q hammer-worker; then
|
|
echo " ⛔ '$name' NO tiene label role=hammer-worker ⇒ no nació de la granja. NO se borra."
|
|
echo "$name $ip" >> "$newfleet"; continue
|
|
fi
|
|
|
|
echo "==> cosechando store de $name ($ip)"
|
|
# ⚠ `--exclude-from` del registro de podados: el worker NO se poda, así que devolvería los
|
|
# artefactos superados y desharía la poda (24 G por vuelta). Misma protección que en
|
|
# `cosecha-cron.sh`, `farm-sync.sh` y `store-gc.sh` — son CUATRO rutas que bajan el store del
|
|
# worker y la protección tiene que estar en las cuatro. Se descubrió tras arreglar sólo una y
|
|
# comprobar que la churn seguía.
|
|
LEDGER_GC="$ROOT/work/store-gc-superados.txt"
|
|
EXCL_GC=""; [ -s "$LEDGER_GC" ] && EXCL_GC="--exclude-from=$LEDGER_GC"
|
|
if rsync -az $EXCL_GC -e "$SSH" "root@$ip:$REMOTE/store/" "$ROOT/store/"; then
|
|
echo "==> destruyendo $name"
|
|
if hcloud server delete "$name" >/dev/null 2>&1; then
|
|
harvested=$((harvested + 1))
|
|
else
|
|
echo " ⚠ no pude destruir $name — lo dejo en la flota"; echo "$name $ip" >> "$newfleet"
|
|
fi
|
|
else
|
|
echo " ⚠ falló el pull de store de $name — NO lo destruyo (queda en la flota)"
|
|
echo "$name $ip" >> "$newfleet"
|
|
fi
|
|
done < "$FLEET"
|
|
|
|
mv "$newfleet" "$FLEET"
|
|
echo "==> cosechados+destruidos: $harvested; flota restante:"; cat "$FLEET"
|
|
|
|
if [ "${NO_PROMOTE:-}" != "1" ] && [ "$harvested" -gt 0 ]; then
|
|
# El worker muele TODAS las colas (ver QUEUES en farm-worker-loop.sh); build-farm.sh sin QUEUE
|
|
# sólo mira recipes/incoming ⇒ los artefactos de incoming-go/incoming-clib se cosechaban pero
|
|
# NO se promovían/firmaban. Recorrer las mismas colas que el worker (cache-hit en lo cosechado).
|
|
# El guard `ls "$Q"/*.toml` salta las colas vacías, así que listar todas es inocuo.
|
|
echo "==> promote+firma final (cache-hit en lo cosechado)"
|
|
for Q in ${QUEUES:-recipes/incoming recipes/incoming-go recipes/incoming-clib}; do
|
|
ls "$Q"/*.toml >/dev/null 2>&1 || continue
|
|
echo " --- promoviendo $Q"
|
|
QUEUE="$Q" scripts/build-farm.sh || echo " (build-farm $Q devolvió error; revisá logs)"
|
|
done
|
|
fi
|