Files
takana/scripts/product-image.sh
T
Sergio 476168bb07 takana etapa 5c: comentarios de scripts, MOTD, y un BUG que introdujo la etapa 4
250 líneas de comentario en 151 scripts. Control verificado: el diff no toca
NI UNA línea que no empiece por #, y la sintaxis de los 151 pasa.

El barrido saltea heredocs y cadenas triples, y el guardián DISPARÓ 3 veces:
las tres eran el MOTD que el script escribe DENTRO de la imagen construida —
texto del producto, no comentario del script. Se cambiaron aparte y a
propósito, que es rebranding, no limpieza.

Y el hallazgo caro:  casaba contra ,
que es el TARGET de tracing — o sea el module_path!, o sea el nombre del crate.
La etapa 4 lo movió a  y el script quedó casando NADA. No fallaba:
imprimía cero atribuciones, indistinguible de un log sin problemas. Comprobado
con el binario (RUST_LOG=info sobre zlib), no deducido. Ahora acepta las dos, y
tiene que seguir aceptándolas porque los logs viejos en disco dicen la vieja.

Además 14 rutas de módulo  en docs, que el barrido anterior no tocó
porque  no es frontera de palabra.
2026-09-09 19:28:48 +00:00

70 lines
4.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# product-image.sh — empaqueta el `product-rootfs` (lean: 4/4 + userland Rust + sshd, SIN toolchain)
# como imagen de disco AUTO-BOOTEABLE (GRUB BIOS), reusando scripts/install-image.sh. Es el cierre del
# pipeline: del artefacto sellado por `takana bootstrap product` a un disco que arranca solo en QEMU
# (`-drive file=img`, sin -kernel) y, con red, sirve SSH.
#
# A diferencia de install-image.sh (que por defecto empaqueta el BUILDER rootfs con todo el toolchain),
# acá la root es el product-rootfs lean ⇒ imagen de PRODUCTO, no de self-host.
#
# Uso: PRODUCT=<hash|prefijo> ./scripts/product-image.sh # crea work/hammer-product.img
# PRODUCT=<...> BOOT=1 ./scripts/product-image.sh # además auto-bootea + handshake SSH
# Vars: KERNEL IMG (def work/hammer-product.img) KVM (def 1) MEM (def 2048) PORT (def 2224)
# DEADLINE (def 150, sólo con BOOT=1)
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
IMG="${IMG:-work/hammer-product.img}"; KVM="${KVM:-1}"; MEM="${MEM:-2048}"; PORT="${PORT:-2224}"
DEADLINE="${DEADLINE:-150}"; WORK="$ROOT/work/product-image"
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"
# copia escribible del artefacto sellado (read-only); no tocamos el store
rm -rf "$WORK"; mkdir -p "$WORK"; RFS="$WORK/rootfs"
cp -a "$PDIR"/. "$RFS"/; chmod -R u+w "$RFS"; rm -rf "$RFS/.hammer"
# provisión de admin: authorized_keys de prueba (lo único no horneado en el producto)
KG=$(ls store/*-openssh/usr/bin/ssh-keygen | head -1)
"$KG" -t ed25519 -N '' -f "$WORK/clientkey" -q
install -d -m 0700 "$RFS/root/.ssh"
cat "$WORK/clientkey.pub" > "$RFS/root/.ssh/authorized_keys"; chmod 0600 "$RFS/root/.ssh/authorized_keys"
# delegar el armado del disco GRUB-booteable a install-image.sh. BOOT=0 EXPLÍCITO: nuestro BOOT=1 está
# en el entorno y se heredaría a install-image.sh, que haría su PROPIO `exec qemu` foreground (sin red)
# y bloquearía acá para siempre. Lo aislamos para que install-image SÓLO arme la imagen.
echo "==> armando imagen de disco (GRUB BIOS) vía install-image.sh"
ROOTFS="$RFS" IMG="$IMG" BOOT=0 ROOT_SIZE="${ROOT_SIZE:-1024}" STORE_SIZE="${STORE_SIZE:-512}" \
STATE_SIZE="${STATE_SIZE:-512}" sh ./scripts/install-image.sh
echo "==> imagen de producto: $IMG"
[ "${BOOT:-0}" = 1 ] || { echo "(set BOOT=1 para auto-bootear + probar SSH)"; exit 0; }
# auto-boot (sin -kernel, GRUB del disco) + red slirp hostfwd para el handshake
accel=(-cpu Broadwell); { [ "$KVM" = 1 ] && [ -w /dev/kvm ]; } && accel=(-enable-kvm -cpu host)
echo "==> AUTO-BOOT (sin -kernel) + hostfwd :$PORT->:22"
qemu-system-x86_64 -m "$MEM" -no-reboot -nographic "${accel[@]}" \
-drive file="$IMG",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 auto-booteado (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 PRODUCT_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 GUEST ============"; echo "$out"; echo "============================================="
echo "$out" | grep -q PRODUCT_DISK_SSH_OK && ok=1; break
fi
sleep 3
done
echo "---- consola (cola) ----"; tail -15 "$WORK/console.log" 2>/dev/null
[ "$ok" = 1 ] && { echo; echo "*** PRODUCT DISK OK — imagen auto-booteable (GRUB, sin -kernel) sirve SSH ***"; exit 0; }
echo; echo "*** PRODUCT DISK FALLÓ — ver $WORK/console.log ***"; exit 1