ADR 0016 los listaba entre los CONGELADOS; el usuario pidió descongelarlos al abrir el SDD 28. La
enmienda queda escrita en el propio ADR, que si no la etiqueta deja de describir el hecho.
`hammer-install.sh` → `takana-install.sh`, `hammer-live-install.sh` → `takana-live-install.sh`,
`hammer-banner.txt` → `takana-banner.txt`, `BRIEFING-hammer.md` → `BRIEFING-takana.md`.
**Lo que hacía caro esto no es el nombre del fichero.** El instalador se inyecta en el ISO como
`/usr/bin/hammer-install` y su éxito se detecta con un `grep` de `HAMMER-INSTALL-OK` desde TRES
scripts de prueba. Renombrar un solo lado los deja casando NADA — sin fallar —, que es literalmente
el modo en que `atribuir-fallos.py` quedó mudo cuando el renombre movió el target de `tracing`.
Se renombraron las dos puntas en el mismo commit (`/usr/bin/takana-install`,
`TAKANA-INSTALL-OK/FAIL`, `TAKANA_INSTALL_*`, `work/takana-install.img`, `/run/takana-install`),
se comprobó por `grep` que no quede ningún token viejo fuera del ADR, y —lo que decide— se CORRIÓ
`install-tui-test.sh`: 4/4 casos verdes.
Las tres `TAKANA_INSTALL_*` caen al nombre viejo (`${TAKANA_INSTALL_X:-${HAMMER_INSTALL_X:-}}`):
el llamador puede ser un ISO anterior al renombre. Misma convención que `TAKANA_ROOT_PW` unas
líneas más arriba en ese mismo script.
NO se tocó `/usr/sbin/hammer-recover` ni su hook de arranque —renombrarlo rompe máquinas YA
INSTALADAS, no el repo—: sobrevive intacto dentro del script renombrado, verificado por conteo
antes y después (8 ocurrencias). Tampoco `hammerd`, `hammer-edit` (su `name` está en la ruta del
store), `/var/lib/hammer`, `HAMMER_LIVE` ni los siete literales de hash.
De paso: `scripts/.hammer-banner.txt.kate-swp` era un swap de editor commiteado por error. Fuera.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RomoxEGZUhaT4pob1QSX5x
103 lines
6.0 KiB
Bash
Executable File
103 lines
6.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# takana-install.sh — Etapa E2: instalador a disco. Vuelca el `product-rootfs` (lean: 4/4 + userland
|
|
# Rust + sshd) sobre un DISCO destino (block device real `/dev/sdX`, o un fichero pre-dimensionado para
|
|
# pruebas) con el mismo layout GPT + GRUB BIOS de la imagen E1, pero IN-PLACE sobre el target. Tras
|
|
# instalar, el disco arranca solo (SeaBIOS → GRUB → kernel → arje-zero PID1 → hammerd+getty+sshd).
|
|
#
|
|
# Es la contraparte "a disco real" de scripts/product-image.sh (que produce un fichero imagen portátil):
|
|
# la lógica de particionado/format/GRUB es la misma (delegada a install-image.sh); sólo cambia el target.
|
|
#
|
|
# Uso:
|
|
# sudo PRODUCT=<hash> AUTHKEYS=~/.ssh/id_ed25519.pub FORCE=1 ./scripts/takana-install.sh /dev/sdX
|
|
# # prueba sin hardware (fichero pre-dimensionado, se valida el camino in-place + boot SSH):
|
|
# PRODUCT=<hash> TESTKEY=1 BOOT=1 ./scripts/takana-install.sh work/target.img
|
|
#
|
|
# Variables:
|
|
# PRODUCT product-rootfs sellado (hash/prefijo; default: el más reciente del store)
|
|
# AUTHKEYS fichero authorized_keys a instalar para root (recomendado en instalación real)
|
|
# TESTKEY 1 ⇒ genera un par efímero y usa su pubkey como authorized_keys (para validar por SSH)
|
|
# FORCE 1 ⇒ requerido para escribir sobre un BLOCK DEVICE (seguridad anti-pisada)
|
|
# KERNEL bzImage a embeber (default store/*-linux/boot/bzImage)
|
|
# ROOT_SIZE/STORE_SIZE/STATE_SIZE MiB de cada partición (default 1024/512/512)
|
|
# BOOT 1 ⇒ tras instalar, arranca el target con QEMU (útil sólo para fichero/imagen) + handshake
|
|
# KVM/MEM/PORT/DEADLINE passthrough del arranque de prueba
|
|
set -euo pipefail
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
|
|
TARGET="${1:-}"
|
|
[ -n "$TARGET" ] || { echo "uso: $0 <device|imagen> (p.ej. /dev/sdX o work/target.img)"; exit 2; }
|
|
WORK="$ROOT/work/takana-install"; RFS="$WORK/rootfs"
|
|
|
|
# --- resolver product-rootfs sellado ---
|
|
if [ -n "${PRODUCT:-}" ]; then
|
|
PDIR=$(ls -d store/"${PRODUCT#b3:}"*-product-rootfs 2>/dev/null | head -1)
|
|
else
|
|
PDIR=$(ls -dt store/*-product-rootfs 2>/dev/null | head -1)
|
|
fi
|
|
[ -n "$PDIR" ] && [ -d "$PDIR" ] || { echo "no encuentro product-rootfs (corré 'hammer bootstrap product')"; exit 1; }
|
|
echo "==> product-rootfs: $PDIR"
|
|
echo "==> target: $TARGET"
|
|
|
|
# --- guardas de seguridad para un disco real ---
|
|
PREALLOC=0
|
|
if [ -b "$TARGET" ]; then
|
|
[ "${FORCE:-0}" = 1 ] || { echo "!! $TARGET es un BLOCK DEVICE — exijo FORCE=1 para escribirlo (borra datos)"; exit 1; }
|
|
if mount | grep -q "^$TARGET"; then echo "!! $TARGET (o una partición) está MONTADO — desmontá antes"; exit 1; fi
|
|
echo "==> escritura sobre block device REAL (FORCE=1)"
|
|
elif [ -e "$TARGET" ]; then
|
|
PREALLOC=1 # fichero existente ⇒ in-place (no truncar): exactamente el camino de un device
|
|
echo "==> target fichero pre-dimensionado ⇒ instalación in-place (PREALLOC)"
|
|
else
|
|
echo "==> target fichero nuevo ⇒ install-image lo crea (truncate)"
|
|
fi
|
|
|
|
# --- copia escribible del product-rootfs + provisión de authorized_keys ---
|
|
rm -rf "$WORK"; mkdir -p "$WORK"
|
|
cp -a "$PDIR"/. "$RFS"/; chmod -R u+w "$RFS"; rm -rf "$RFS/.hammer"
|
|
install -d -m 0700 "$RFS/root/.ssh"
|
|
if [ "${TESTKEY:-0}" = 1 ]; then
|
|
"$(ls store/*-openssh/usr/bin/ssh-keygen | head -1)" -t ed25519 -N '' -f "$WORK/clientkey" -q
|
|
cat "$WORK/clientkey.pub" > "$RFS/root/.ssh/authorized_keys"
|
|
echo "==> authorized_keys: llave de prueba efímera ($WORK/clientkey)"
|
|
elif [ -n "${AUTHKEYS:-}" ] && [ -f "$AUTHKEYS" ]; then
|
|
cat "$AUTHKEYS" > "$RFS/root/.ssh/authorized_keys"
|
|
echo "==> authorized_keys: $AUTHKEYS"
|
|
else
|
|
echo "==> (sin authorized_keys: nadie podrá entrar por SSH hasta provisionarlas; usá AUTHKEYS= o TESTKEY=1)"
|
|
fi
|
|
chmod 0600 "$RFS/root/.ssh/authorized_keys" 2>/dev/null || true
|
|
|
|
# --- delegar particionado/format/GRUB a install-image.sh, apuntando al target (IN-PLACE si aplica) ---
|
|
echo "==> instalando sobre $TARGET (GPT + ext4 + GRUB BIOS, in-place=$PREALLOC)"
|
|
ROOTFS="$RFS" IMG="$TARGET" PREALLOC="$PREALLOC" BOOT=0 \
|
|
ROOT_SIZE="${ROOT_SIZE:-1024}" STORE_SIZE="${STORE_SIZE:-512}" STATE_SIZE="${STATE_SIZE:-512}" \
|
|
sh ./scripts/install-image.sh
|
|
echo "==> instalado. El disco arranca solo (SeaBIOS → GRUB → arje-zero)."
|
|
|
|
[ "${BOOT:-0}" = 1 ] || { echo " (set BOOT=1 para arrancar el target y probar SSH)"; exit 0; }
|
|
[ "${TESTKEY:-0}" = 1 ] || { echo " BOOT=1 sin TESTKEY=1: no tengo llave para el handshake; omito."; exit 0; }
|
|
|
|
# --- arranque de prueba del target (sólo fichero/imagen) + handshake SSH ---
|
|
KVM="${KVM:-1}"; MEM="${MEM:-2048}"; PORT="${PORT:-2225}"; DEADLINE="${DEADLINE:-150}"
|
|
accel=(-cpu Broadwell); { [ "$KVM" = 1 ] && [ -w /dev/kvm ]; } && accel=(-enable-kvm -cpu host)
|
|
echo "==> AUTO-BOOT del target (sin -kernel) + hostfwd :$PORT->:22"
|
|
qemu-system-x86_64 -m "$MEM" -no-reboot -nographic "${accel[@]}" \
|
|
-drive file="$TARGET",format=raw,if=virtio \
|
|
-netdev "user,id=n0,hostfwd=tcp::$PORT-:22" -device e1000,netdev=n0 > "$WORK/console.log" 2>&1 &
|
|
QPID=$!; trap 'kill $QPID 2>/dev/null || true' EXIT
|
|
SSHOPTS=(-p "$PORT" -i "$WORK/clientkey" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
|
|
-o GlobalKnownHostsFile=/dev/null -o PasswordAuthentication=no -o ConnectTimeout=4 -o LogLevel=ERROR)
|
|
echo "==> esperando handshake desde el disco instalado (deadline ${DEADLINE}s)…"
|
|
start=$(date +%s); ok=0
|
|
while [ $(( $(date +%s) - start )) -lt "$DEADLINE" ]; do
|
|
kill -0 $QPID 2>/dev/null || { echo "!! QEMU murió"; break; }
|
|
if out=$(ssh "${SSHOPTS[@]}" root@localhost \
|
|
'echo INSTALLED_DISK_SSH_OK uid=$(id -u); uname -sr; ls --version 2>&1|head -1; df -h /store /var/lib/hammer 2>/dev/null|tail -2' 2>/dev/null); then
|
|
echo "========= RESPUESTA DEL DISCO INSTALADO ========="; echo "$out"; echo "================================================="
|
|
echo "$out" | grep -q INSTALLED_DISK_SSH_OK && ok=1; break
|
|
fi
|
|
sleep 3
|
|
done
|
|
echo "---- consola (cola) ----"; tail -12 "$WORK/console.log" 2>/dev/null
|
|
[ "$ok" = 1 ] && { echo; echo "*** HAMMER INSTALL OK — disco instalado in-place arranca solo y sirve SSH ***"; exit 0; }
|
|
echo; echo "*** HAMMER INSTALL FALLÓ — ver $WORK/console.log ***"; exit 1
|