buzón verificado en un worker real — y las dos veces que la prueba mintió
Cadena completa medida hoy: el worker depositó 63 artefactos (1,34 GB) en 8 s a 153 MB/s, y el hub los promovió con mv. Respaldo 1542 → 1605, buzón en 0, guardián cuadrando. Contra los 440 kB/s del laptop, 348×. Dos fallos de la prueba, que importan más que el resultado: 1. `ssh` cortaba con «Host key verification failed» porque la granja REUSA IPs y la host key cambia con razón. Como el stderr iba a /dev/null, el error salía como «no obtuve la pública del worker»: culpaba al worker cuando el problema estaba en el known_hosts del laptop. Ahora va por ssh_worker(), que purga la entrada vieja — correcto sólo acá, porque la identidad del worker es su label hcloud, no su llave. 2. verificar-buzon daba «aislado ✓» sin haber probado que escribe. El aviso de host key se comía el head -1, y el testigo se llamaba .btest, que `ls` no muestra. Un testigo invisible no prueba nada. Ahora exige las dos mitades y las dos están verdes: escribe en su buzón, y ../hammer/store no existe para él. Y el progreso de rsync sólo con TTY: sin terminal reescribe con \r y deja miles de copias de la misma línea. 8 segundos bastaron para un log ilegible; en el latido sería cada media hora. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -71,6 +71,20 @@ BUZ_USER="${BUZ_USER:-u647150-sub2}"
|
||||
KEY="${KEY:-$HOME/.ssh/github5}"
|
||||
CRED="$HOME/.config/hammer/storagebox-worker.env"
|
||||
|
||||
# ── LA GRANJA REUSA IPs, ASÍ QUE LA HOST KEY CAMBIA CON RAZÓN ──────────────────────────────────
|
||||
# Los workers son EFÍMEROS y Hetzner recicla las direcciones: una IP que ayer fue `hworker-1` hoy es
|
||||
# otra máquina distinta con otra llave. Sin esto, `ssh` corta con «Host key verification failed» —
|
||||
# y como estas funciones mandaban stderr a /dev/null, el fallo salía como «no obtuve la pública del
|
||||
# worker», que apunta al worker cuando el problema estaba en el known_hosts del laptop. Un mensaje
|
||||
# que culpa al sitio equivocado cuesta más que no tener mensaje.
|
||||
# Purgar la entrada vieja es correcto ACÁ y sólo acá: la identidad del worker no es su llave, es el
|
||||
# label `role=hammer-worker` del proyecto hcloud; el secreto no viaja por este canal.
|
||||
ssh_worker() { # $1 = ip, resto = orden remota
|
||||
ip="$1"; shift
|
||||
ssh-keygen -R "$ip" >/dev/null 2>&1
|
||||
ssh -i "$KEY" -o StrictHostKeyChecking=accept-new -o ConnectTimeout=20 "root@$ip" "$@"
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
crear)
|
||||
# La contraseña la exige la API aunque después se use llave. Debe traer mayúscula, minúscula,
|
||||
@@ -85,9 +99,9 @@ crear)
|
||||
;;
|
||||
autorizar)
|
||||
IP="${2:?falta la IP del worker}"
|
||||
PUB=$(ssh -i "$KEY" "root@$IP" 'mkdir -p /root/.ssh
|
||||
PUB=$(ssh_worker "$IP" 'mkdir -p /root/.ssh
|
||||
[ -f /root/.ssh/sb_sub ] || ssh-keygen -q -t ed25519 -N "" -C "hworker→respaldo(ro)" -f /root/.ssh/sb_sub
|
||||
cat /root/.ssh/sb_sub.pub' 2>/dev/null | tail -1)
|
||||
cat /root/.ssh/sb_sub.pub' | tail -1)
|
||||
[ -z "$PUB" ] && { echo "!! no obtuve la pública del worker"; exit 1; }
|
||||
T=$(mktemp); printf '%s\n' "$PUB" > "$T"
|
||||
ssh -4 -p 23 -i "$KEY" "$MAIN" 'mkdir -p hammer/.ssh' >/dev/null 2>&1
|
||||
@@ -97,7 +111,7 @@ autorizar)
|
||||
;;
|
||||
verificar)
|
||||
IP="${2:?falta la IP del worker}"
|
||||
ssh -i "$KEY" "root@$IP" "SB=\"ssh -4 -p 23 -i /root/.ssh/sb_sub -o StrictHostKeyChecking=no $SUB_USER@$SUB_HOST\"
|
||||
ssh_worker "$IP" "SB=\"ssh -4 -p 23 -i /root/.ssh/sb_sub -o StrictHostKeyChecking=no $SUB_USER@$SUB_HOST\"
|
||||
lee=\$(\$SB 'ls' 2>/dev/null | tr '\n' ' ')
|
||||
borra=\$(\$SB 'rm -rf estado' 2>&1 | head -1)
|
||||
echo hola > /tmp/.wtest; esc=\$(scp -4 -P 23 -i /root/.ssh/sb_sub -o StrictHostKeyChecking=no /tmp/.wtest $SUB_USER@$SUB_HOST:.wtest 2>&1 | head -1)
|
||||
@@ -113,9 +127,9 @@ autorizar-buzon)
|
||||
IP="${2:?falta la IP del worker}"
|
||||
# La MISMA llave del worker sirve para las dos subcuentas: son dos autorizaciones distintas del
|
||||
# box, no dos identidades del worker. Se genera allá y nunca viaja una privada desde el laptop.
|
||||
PUB=$(ssh -i "$KEY" "root@$IP" 'mkdir -p /root/.ssh
|
||||
PUB=$(ssh_worker "$IP" 'mkdir -p /root/.ssh
|
||||
[ -f /root/.ssh/sb_sub ] || ssh-keygen -q -t ed25519 -N "" -C "hworker→respaldo" -f /root/.ssh/sb_sub
|
||||
cat /root/.ssh/sb_sub.pub' 2>/dev/null | tail -1)
|
||||
cat /root/.ssh/sb_sub.pub' | tail -1)
|
||||
[ -z "$PUB" ] && { echo "!! no obtuve la pública del worker"; exit 1; }
|
||||
T=$(mktemp); printf '%s\n' "$PUB" > "$T"
|
||||
ssh -4 -p 23 -i "$KEY" "$MAIN" 'mkdir -p incoming/.ssh' >/dev/null 2>&1
|
||||
@@ -129,18 +143,29 @@ verificar-buzon)
|
||||
# La verificación tiene DOS mitades y las dos son necesarias: que SÍ escriba (si no, el respaldo
|
||||
# no se alimenta y nos enteramos el día que haga falta) y que NO alcance el respaldo consolidado
|
||||
# (si lo alcanza, el aislamiento es decorativo). Una sola mitad no prueba nada útil.
|
||||
ssh -i "$KEY" "root@$IP" "SB=\"ssh -4 -p 23 -i /root/.ssh/sb_sub -o StrictHostKeyChecking=no $BUZ_USER@$BUZ_HOST\"
|
||||
echo hola > /tmp/.btest
|
||||
esc=\$(scp -4 -P 23 -i /root/.ssh/sb_sub -o StrictHostKeyChecking=no /tmp/.btest $BUZ_USER@$BUZ_HOST:store/.btest 2>&1 | head -1)
|
||||
ve=\$(\$SB 'ls store' 2>&1 | head -3 | tr '\n' ' ')
|
||||
fuera=\$(\$SB 'ls ../hammer/store' 2>&1 | head -1)
|
||||
\$SB 'rm -f store/.btest' >/dev/null 2>&1
|
||||
echo \"escribir en buzón : \${esc:-(sin error = OK)}\"
|
||||
echo \"ve su buzón : \$ve\"
|
||||
# ⚠ DOS DETALLES QUE HICIERON QUE ESTA PRUEBA MINTIERA LA PRIMERA VEZ (2026-08-09):
|
||||
# 1. el «Warning: Permanently added …» del host key sale por stderr y se comía el `head -1`, así
|
||||
# que el resultado de escribir era el aviso y no el resultado. Se filtra explícitamente.
|
||||
# 2. el testigo se llamaba `.btest` y `ls` NO muestra los ficheros con punto ⇒ el listado salía
|
||||
# vacío tanto si escribió como si no. Un testigo que no se puede ver no prueba nada.
|
||||
ssh_worker "$IP" "SB=\"ssh -4 -p 23 -i /root/.ssh/sb_sub -o StrictHostKeyChecking=no $BUZ_USER@$BUZ_HOST\"
|
||||
limpia() { grep -v 'Warning: Permanently added' | head -1; }
|
||||
echo testigo > /tmp/testigo-buzon.txt
|
||||
esc=\$(scp -4 -P 23 -i /root/.ssh/sb_sub -o StrictHostKeyChecking=no /tmp/testigo-buzon.txt $BUZ_USER@$BUZ_HOST:store/testigo-buzon.txt 2>&1 | limpia)
|
||||
ve=\$(\$SB 'ls store' 2>/dev/null | grep -c testigo-buzon)
|
||||
fuera=\$(\$SB 'ls ../hammer/store' 2>&1 | limpia)
|
||||
borra=\$(\$SB 'rm -f store/testigo-buzon.txt' 2>&1 | limpia)
|
||||
queda=\$(\$SB 'ls store' 2>/dev/null | grep -c testigo-buzon)
|
||||
echo \"escribir en buzón : \${esc:-(sin error)}\"
|
||||
echo \"testigo visible : \$ve (1 = escribió de verdad)\"
|
||||
echo \"limpia lo suyo : \${borra:-(sin error)} → queda \$queda\"
|
||||
echo \"alcanza respaldo : \$fuera\"
|
||||
case \"\$fuera\" in *[Nn]o\ such*|*denied*|*[Ff]ailure*|'')
|
||||
echo 'VEREDICTO: buzón aislado ✓' ;;
|
||||
*) echo 'VEREDICTO: ⚠ ALCANZA EL RESPALDO — no usar'; exit 1 ;; esac"
|
||||
ok=1
|
||||
[ \"\$ve\" = 1 ] || { echo 'VEREDICTO: ⚠ NO ESCRIBE — el respaldo no se alimentaría'; ok=0; }
|
||||
case \"\$fuera\" in *[Nn]o\ such*|*denied*|*[Ff]ailure*) ;;
|
||||
*) echo 'VEREDICTO: ⚠ ALCANZA EL RESPALDO — no usar'; ok=0 ;; esac
|
||||
[ \"\$ok\" = 1 ] && echo 'VEREDICTO: escribe en su buzón ✓ · no alcanza el respaldo ✓'
|
||||
[ \"\$ok\" = 1 ] || exit 1"
|
||||
;;
|
||||
*) sed -n '/^# Uso:/,/verificar-buzon/p' "$0"; exit 2 ;;
|
||||
esac
|
||||
|
||||
@@ -41,7 +41,12 @@ echo "==> store $N_L · respaldo $N_R ⇒ a depositar $N_N"
|
||||
[ "$N_N" -eq 0 ] && { echo " nada nuevo"; exit 0; }
|
||||
|
||||
# `--files-from` con los nombres a secas (son directorios del store) + `-r` para bajar en cada uno.
|
||||
rsync -aHr --files-from="$TMP/nuevos.txt" --partial-dir=.rsync-partial --info=progress2 \
|
||||
# `--info=progress2` SÓLO con terminal: sin TTY reescribe la misma línea con \r y, como nadie
|
||||
# interpreta el retorno de carro, el «progreso» se acumula en miles de copias de la misma línea. Un
|
||||
# depósito de 8 segundos dejó así un log ilegible; en el latido, cada media hora, sería peor.
|
||||
PROG=""; [ -t 1 ] && PROG="--info=progress2"
|
||||
# shellcheck disable=SC2086
|
||||
rsync -aHr --files-from="$TMP/nuevos.txt" --partial-dir=.rsync-partial $PROG \
|
||||
-e "$SSH_SB" "$STORE/" "$BZ_USER@$BZ_HOST:store/" || { echo "⚠ el depósito falló"; exit 1; }
|
||||
|
||||
# Guardián: recontar el buzón. «rsync salió 0» no es «llegaron N».
|
||||
|
||||
Reference in New Issue
Block a user