sergio/takana
> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…
granja: fix host-key en workers efímeros — known_hosts a /dev/null
1#!/usr/bin/env bash
2# farm-up.sh [N] — levanta N workers EFÍMEROS desde el snapshot golden y los alinea con la cola
3# actual del laptop. Modelo hub-and-spoke: el worker NO tiene secretos (ni firma ni gitea); es
4# compute puro y descartable. La imagen 'hammer-golden' trae el toolchain + el store sellado
5# horneados ⇒ el worker arranca con TODO el catálogo cacheado (cache-hit instantáneo), sólo
6# construye lo NUEVO que el hub le empuje.
7#
8# Flujo: scripts/farm/farm-up.sh 3 # crea hworker-1..3, los alimenta con la cola actual
9# ... (muelen) ...
10# scripts/farm/farm-down.sh # cosecha su store al laptop y los DESTRUYE
11#
12# La flota viva se registra en scripts/farm/.fleet ("<name> <ip>" por línea; gitignored).
13# Idempotente al escalar: re-correr con más N agrega workers sin pisar los vivos.
14#
15# Env: IMAGE (snapshot, def 405120842=hammer-golden-2026-07-05), TYPE (def ccx23), LOCATION
16# (def hel1), SSHKEY (llave del proyecto Hetzner, def desarrollo@jlsoltech.com), SSH_KEY
17# (privada local p/ SSH, def ~/.ssh/github5), REMOTE (def /opt/hammer).
18set -euo pipefail
19
20N="${1:-1}"
21IMAGE="${IMAGE:-405120842}"
22TYPE="${TYPE:-ccx23}"
23LOCATION="${LOCATION:-hel1}"
24SSHKEY="${SSHKEY:-desarrollo@jlsoltech.com}"
25SSH_KEY="${SSH_KEY:-$HOME/.ssh/github5}"
26REMOTE="${REMOTE:-/opt/hammer}"
27ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
28FLEET="$ROOT/scripts/farm/.fleet"
29# Workers efímeros RECICLAN IPs de Hetzner ⇒ un known_hosts persistente choca ("HOST KEY CHANGED")
30# y accept-new RECHAZA la clave cambiada, colgando el `until ssh true` para siempre. Como el modelo
31# es hub-and-spoke (el worker NO tiene secretos: compute puro descartable), saltamos la verificación
32# de host y no ensuciamos known_hosts (/dev/null). No hay superficie MITM que proteger acá.
33SSH="ssh -i $SSH_KEY -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=ERROR -o ConnectTimeout=10"
34cd "$ROOT"
35touch "$FLEET"
36
37# índice de arranque: el mayor hworker-N vivo + 1 (para escalar sin colisión de nombres)
38base=$(sed -n 's/^hworker-\([0-9]*\) .*/\1/p' "$FLEET" | sort -n | tail -1)
39base="${base:-0}"
40
41for k in $(seq 1 "$N"); do
42 i=$((base + k)); name="hworker-$i"
43 echo "==> creando $name ($TYPE @ $LOCATION desde image $IMAGE)"
44 hcloud server create --name "$name" --image "$IMAGE" --type "$TYPE" \
45 --location "$LOCATION" --ssh-key "$SSHKEY" --label role=hammer-worker >/dev/null
46 ip=$(hcloud server ip "$name")
47 echo "$name $ip" >> "$FLEET"
48 echo " ip=$ip; esperando SSH…"
49 until $SSH root@"$ip" true 2>/dev/null; do sleep 3; done
50
51 echo " alineando cola con el laptop (rsync código + recipes)…"
52 rsync -az --delete -e "$SSH" \
53 --exclude /work --exclude /store --exclude '/store-*' --exclude /target \
54 --exclude /dist --exclude /.dev-fs --exclude /.git --exclude /.scratch \
55 --exclude '*.png' --exclude '/content*' \
56 ./ "root@$ip:$REMOTE/"
57 # el servicio ya arrancó en el boot (baked/enabled); reiniciar fuerza rescan inmediato de la cola
58 $SSH root@"$ip" 'systemctl restart hammer-farm' 2>/dev/null || true
59 echo " ✓ $name muele la cola actual"
60done
61
62sort -u -o "$FLEET" "$FLEET"
63echo "==> flota viva:"; cat "$FLEET"
64echo "cosechar+destruir con: scripts/farm/farm-down.sh"