renombre: los instaladores pasan a takana-* — y el peligro no era el fichero, era el PROTOCOLO

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
This commit is contained in:
Sergio
2026-09-09 22:54:13 +00:00
co-authored by Claude Opus 5
parent c599daa346
commit 008dd3925e
16 changed files with 85 additions and 61 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ repository.workspace = true
description = "Mini-binario de auto-recuperación de upgrades al arranque (E4 #4b): el /sbin/init lo corre para completar/deshacer un apply interrumpido antes de incarnar."
# El PAQUETE se renombra, el BINARIO no: `/usr/sbin/hammer-recover` está copiado en
# sistemas ya instalados y `hammer-live-install.sh` hornea un hook de arranque que lo
# sistemas ya instalados y `takana-live-install.sh` hornea un hook de arranque que lo
# invoca por ese nombre. Renombrar el binario rompe máquinas instaladas. Etapa 6.
[[bin]]
name = "hammer-recover"
+4 -4
View File
@@ -96,7 +96,7 @@ kernel en `/boot`, los módulos GRUB en `/boot/grub/i386-pc` y los pasos `grub-m
generaciones es **in-place** (el FHS es la generación viva), así que NO hay menú de generaciones tipo
NixOS que ofrecer en GRUB; lo que encaja es **auto-sanar** un upgrade interrumpido al boot. El producto
no lleva el CLI `takana` completo ⇒ `hammer-recover` es lo único que el sistema instalado necesita: el
wrapper `/sbin/init` (de `hammer-live-install.sh`) lo corre **tras montar `/store` y `/var/lib/hammer`**
wrapper `/sbin/init` (de `takana-live-install.sh`) lo corre **tras montar `/store` y `/var/lib/hammer`**
y **antes** de incarnar arje-zero. Sin `pending.json` es no-op; con uno, **completa** (roll-forward) o,
si no puede, **deshace** (roll-back) ⇒ el FHS siempre arranca consistente. Nunca aborta el boot. El
instalador lo bundlea desde el payload a `/usr/sbin/hammer-recover`. Validado in-VM
@@ -133,8 +133,8 @@ kernel en `/boot`, los módulos GRUB en `/boot/grub/i386-pc` y los pasos `grub-m
LINUX_EFI_INITRD_MEDIA_GUID" → arje-zero → sshd) y por BIOS (SeaBIOS, El Torito). **Refinamiento #3
CERRADO.** (Falta como pulido: rama EFI del INSTALADOR a disco — GPT+ESP en `takana-install`, hoy el
instalado es MBR-BIOS.)
- **Instalar DESDE el live ✅** (`scripts/iso-image.sh INSTALLER=1` + `scripts/hammer-live-install.sh`
`/usr/bin/hammer-install` + `scripts/iso-install-test.sh`). Cierra el lazo **ISO live → disco
- **Instalar DESDE el live ✅** (`scripts/iso-image.sh INSTALLER=1` + `scripts/takana-live-install.sh`
`/usr/bin/takana-install` + `scripts/iso-install-test.sh`). Cierra el lazo **ISO live → disco
instalado → bootea solo**. El ISO instalador bundlea un *payload de disco* en el initramfs bajo
`/usr/lib/hammer/install/` (kernel + GRUB `boot.img`/`core.img` MBR-prefix `(hd0,msdos1)/boot/grub`
+ módulos, armado en build-time con `grub-mkimage`). `takana-install <dev>` corre **dentro del live
@@ -150,5 +150,5 @@ kernel en `/boot`, los módulos GRUB en `/boot/grub/i386-pc` y los pasos `grub-m
binario del caso GPT de E1. (c) copiar el top-level de `/` ENUMERÁNDOLO (no una lista fija) o se
escapa `/ente/seed.card.json` ⇒ arje-zero aborta "seed.card no encontrada". `AUTO_INSTALL=<dev>`
hace el `/init` desatendido (install + poweroff) = instalación unattended + scaffolding del test.
Validado E2E in-VM: boot ISO+disco en blanco → HAMMER-INSTALL-OK → boot del disco solo → GRUB→kernel
Validado E2E in-VM: boot ISO+disco en blanco → TAKANA-INSTALL-OK → boot del disco solo → GRUB→kernel
→arje-zero→sshd, /store y /var/lib/hammer montadas. **Refinamiento #1 CERRADO.**
+1 -1
View File
@@ -196,7 +196,7 @@ BUILD (sandbox, N en paralelo, cero locks)
(overlay-src de deps: el mecanismo reutilizado; tabla de fases a corregir en F1) · SDD 16 (patrón
"inerte sin flag"; canario D9 → IF-2) · CLAUDE.md regla 3 (marker contra vacíos) · CLAUDE.md
regla 1 (retiro del flock en R11) · `build-farm.sh` Fase 1b (carrera B; se borra en F3) ·
`docs/BRIEFING-hammer.md` §14.4 (los modos de fallo estructurales que R3 e IF-6 citan).*
`docs/BRIEFING-takana.md` §14.4 (los modos de fallo estructurales que R3 e IF-6 citan).*
---
+1 -1
View File
@@ -132,7 +132,7 @@ muerto antes del takeover).
- **host-side** `scripts/install-image-efi.sh` — GPT+ESP+root/store/state, ESP con mtools de takana,
ext4 con `mke2fs -d` bajo `unshare -r`; **validado VERDE en OVMF** (`scripts/efi-disk-boot-test.sh`:
firmware → BOOTX64.EFI → pivote → arje-zero PID1).
- **live-side** `scripts/hammer-live-install.sh` rama EFI — detecta `/sys/firmware/efi` y hace
- **live-side** `scripts/takana-live-install.sh` rama EFI — detecta `/sys/firmware/efi` y hace
**MBR con ESP tipo 0xEF** (UEFI arranca una ESP MBR igual que GPT ⇒ alcanza busybox
fdisk/mkfs.vfat/mount, sin GPT-tool ni mtools en el live). El kernel EFI-stub viaja en el payload
(`iso-image.sh INSTALLER=1` bundlea `bzImage-efi`). **Validación 2-stage VERDE en OVMF**
+25 -2
View File
@@ -223,9 +223,32 @@ simplemente deja de cosechar. El directorio es lo **último** que se toca, y con
reescribir historia es peor que un mensaje incompleto. El detalle vive acá.)*
**Congelados y verificados con controles:** `/opt/hammer`, `/var/lib/hammer`, `/usr/bin/hammer`,
`/mnt/vvv/hammer`, la URL de gitea, `hammer-farm.service`, `hammer-live-install.sh`,
`BRIEFING-hammer.md`, `hammerd`, `hammer-recover`, `HAMMER_LIVE`, `.hammer-zig-cc`,
`/mnt/vvv/hammer`, la URL de gitea, `hammer-farm.service`, ~~`hammer-live-install.sh`~~,
~~`BRIEFING-hammer.md`~~, `hammerd`, `hammer-recover`, `HAMMER_LIVE`, `.hammer-zig-cc`,
`.hammer-cargo-vendor` y dos identificadores más que aparecieron al barrer:
> **ENMIENDA 2026-09-09 — dos de esos congelados se descongelaron por decisión del usuario**
> («renombrá todos los `hammer` que vayas encontrando, como ese `hammer-install`»), al abrir el
> frente del [SDD 28](../28-servidor-de-produccion.md). Renombrados:
> `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 peligroso este renombre no era el fichero: era el PROTOCOLO.** 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 (`iso-install-test.sh`,
> `efi-install-test.sh`, `install-tui-test.sh`). Renombrar un solo lado deja los tests casando
> **nada** — sin fallar, exactamente el modo en que `atribuir-fallos.py` quedó mudo al renombrar
> el target de `tracing`. Se renombraron **las dos puntas** en el mismo commit
> (`/usr/bin/takana-install`, `TAKANA-INSTALL-OK/FAIL`, `TAKANA_INSTALL_*`), se comprobó por
> `grep` que no quedara ningún token viejo, y se **corrió** `install-tui-test.sh`: 4/4 verdes.
>
> **Lo que NO se tocó, y sigue congelado por la misma razón de antes**: el binario
> `/usr/sbin/hammer-recover` y 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. Tampoco `hammerd`, `hammer-edit`, `/var/lib/hammer`, `HAMMER_LIVE` ni los siete
> literales de hash. Y las tres variables `TAKANA_INSTALL_*` **caen al nombre viejo**
> (`${TAKANA_INSTALL_X:-${HAMMER_INSTALL_X:-}}`), porque el llamador puede ser un ISO anterior al
> renombre — la misma convención que `TAKANA_ROOT_PW` unas líneas más arriba en ese script.
- `hammer-build-state/1` — el `schema` del estado generado. Nadie lo valida, pero el valor de un
identificador de esquema **es** ser estable; renombrarlo no gana nada.
- `hammer-edit` — es una **receta con artefacto sellado**: su `name` está en la ruta del store
Binary file not shown.
+5 -5
View File
@@ -47,13 +47,13 @@ timeout "$INSTALL_DEADLINE" qemu-system-x86_64 -m "$MEM" -no-reboot -nographic "
-drive if=pflash,unit=0,format=raw,readonly=on,file="$OVMF_CODE" \
-drive if=pflash,unit=1,format=raw,file="$WORK/vars-install.fd" \
-drive file="$TGT",format=raw,if=virtio -cdrom "$ISO" -boot d > "$ILOG" 2>&1 || true
if ! grep -aq "HAMMER-INSTALL-OK" "$ILOG"; then
if ! grep -aq "TAKANA-INSTALL-OK" "$ILOG"; then
echo "✗ la instalación EFI NO terminó OK — ver $ILOG" >&2
sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\r//g' "$ILOG" | grep -iE "HAMMER-INSTALL-FAIL|hammer-install|no apareció|UEFI|EFI-stub soberano|error" | head; exit 1
sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\r//g' "$ILOG" | grep -iE "TAKANA-INSTALL-FAIL|takana-install|no apareció|UEFI|EFI-stub soberano|error" | head; exit 1
fi
echo " ✓ HAMMER-INSTALL-OK (rama EFI corrió en el live UEFI)"
echo " ✓ TAKANA-INSTALL-OK (rama EFI corrió en el live UEFI)"
# Confirmar que fue la rama EFI (no la BIOS)
sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\r//g' "$ILOG" | grep -aqiE 'hammer-install \(UEFI\)|EFI-stub soberano' \
sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\r//g' "$ILOG" | grep -aqiE 'takana-install \(UEFI\)|EFI-stub soberano' \
&& echo " ✓ tomó la rama EFI (MBR+ESP-0xEF)" || echo " ! no vi el marcador de rama EFI (¿fue por BIOS?)" >&2
echo "==> (3) boot del DISCO instalado EN OVMF (sin ISO, sin -kernel) — deadline ${BOOT_DEADLINE}s"
@@ -77,7 +77,7 @@ reject 'HAMMER-EFI-FALLO|Kernel panic' "sin fallo de pivot
echo
if [ "$fail" = 0 ]; then
echo "✓✓ EFI-INSTALL VERDE: ISO live UEFI → hammer-install rama EFI → disco EFI-stub SOBERANO bootea solo en OVMF"
echo "✓✓ EFI-INSTALL VERDE: ISO live UEFI → takana-install rama EFI → disco EFI-stub SOBERANO bootea solo en OVMF"
else
echo "✗ efi-install-test FALLÓ — logs: $ILOG · $BLOG" >&2; exit 1
fi
+4 -4
View File
@@ -15,18 +15,18 @@
# de GRUB + el kernel van en /boot de la root, que mke2fs -d puebla desde un directorio.
#
# Uso:
# ./scripts/install-image.sh # crea work/hammer-install.img
# ./scripts/install-image.sh # crea work/takana-install.img
# BOOT=1 KVM=1 ./scripts/install-image.sh # además lo arranca (auto-boot, sin -kernel)
#
# Target IN-PLACE (Etapa E2): si IMG es un block device (o PREALLOC=1 sobre un fichero pre-dimensionado),
# se instala EN SITIO — no se trunca ni se borra el nodo, sólo se valida capacidad. Esa es la base de
# `takana install /dev/sdX` (ver scripts/hammer-install.sh): misma lógica, apuntando a un disco real.
# `takana install /dev/sdX` (ver scripts/takana-install.sh): misma lógica, apuntando a un disco real.
#
# Variables:
# ROOTFS dir rootfs a empaquetar (default work/builder-rootfs)
# PREALLOC 1 ⇒ trata IMG como target pre-dimensionado in-place (no trunca; prueba el camino device)
# KERNEL bzImage a embeber en /boot (default el del store: store/*-linux/boot/bzImage)
# IMG imagen de salida (default work/hammer-install.img)
# IMG imagen de salida (default work/takana-install.img)
# ROOT_SIZE MiB de / (default 4096)
# STORE_SIZE MiB de /store (default 2048)
# STATE_SIZE MiB de /var/lib/hammer (default 2048)
@@ -38,7 +38,7 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
ROOTFS="${ROOTFS:-work/builder-rootfs}"
IMG="${IMG:-work/hammer-install.img}"
IMG="${IMG:-work/takana-install.img}"
ROOT_SIZE="${ROOT_SIZE:-4096}"
STORE_SIZE="${STORE_SIZE:-2048}"
STATE_SIZE="${STATE_SIZE:-2048}"
+6 -6
View File
@@ -1,13 +1,13 @@
#!/usr/bin/env bash
# install-tui-test.sh — valida la capa NUEVA del instalador interactivo (hammer-live-install.sh) SIN
# tocar disco: usa el gancho HAMMER_INSTALL_DRYRUN=1, un /sys/block falso y un rootfs de scratch.
# install-tui-test.sh — valida la capa NUEVA del instalador interactivo (takana-live-install.sh) SIN
# tocar disco: usa el gancho TAKANA_INSTALL_DRYRUN=1, un /sys/block falso y un rootfs de scratch.
# Ejercita (1) el modo interactivo (detección de discos + prompts + confirmación fuerte) y (2) el modo
# desatendido por env; en ambos verifica que apply_post_install_config escribe hostname/hosts/shadow/
# authorized_keys/localtime/install.conf correctamente. Las ramas EFI/BIOS reales (particionado) las
# cubre iso-install-test.sh / efi-install-test.sh en QEMU; acá validamos la lógica de UI + config.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
INST="$ROOT/scripts/hammer-live-install.sh"
INST="$ROOT/scripts/takana-live-install.sh"
W="$(mktemp -d)"; trap 'rm -rf "$W"' EXIT
fail() { echo "✗ FALLO: $*" >&2; exit 1; }
@@ -34,7 +34,7 @@ echo "== test 1: modo INTERACTIVO (TUI dry-run) =="
# zona America/La_Paz · teclado (default us) · confirmación "/dev/vdb"
OUT1="$W/out1.txt"
BB=/nonexistent SYS_BLOCK="$SB" MOUNTS="$MOUNTS" ZONEINFO="$ZI" \
HAMMER_INSTALL_INTERACTIVE=1 HAMMER_INSTALL_DRYRUN=1 HAMMER_INSTALL_TESTROOT="$R1" \
TAKANA_INSTALL_INTERACTIVE=1 TAKANA_INSTALL_DRYRUN=1 TAKANA_INSTALL_TESTROOT="$R1" \
sh "$INST" >"$OUT1" 2>&1 <<'ANSWERS' || { cat "$OUT1"; fail "el instalador salió con error"; }
2
2048
@@ -65,7 +65,7 @@ echo " ✓ interactivo: disco elegido + confirmado, config escrita (hostname/ho
echo "== test 2: confirmación ERRÓNEA cancela sin tocar nada =="
OUT2="$W/out2.txt"
if BB=/nonexistent SYS_BLOCK="$SB" MOUNTS="$MOUNTS" ZONEINFO="$ZI" \
HAMMER_INSTALL_INTERACTIVE=1 HAMMER_INSTALL_DRYRUN=1 HAMMER_INSTALL_TESTROOT="$W/root-none" \
TAKANA_INSTALL_INTERACTIVE=1 TAKANA_INSTALL_DRYRUN=1 TAKANA_INSTALL_TESTROOT="$W/root-none" \
sh "$INST" >"$OUT2" 2>&1 <<'ANSWERS'
2
2048
@@ -84,7 +84,7 @@ echo "== test 3: modo DESATENDIDO por env (device + HAMMER_ROOT_HASH) =="
R3="$W/root3"; mkdir -p "$R3/etc"
printf 'root:!:19000:0:99999:7:::\n' > "$R3/etc/shadow"
OUT3="$W/out3.txt"
BB=/nonexistent HAMMER_INSTALL_DRYRUN=1 HAMMER_INSTALL_TESTROOT="$R3" \
BB=/nonexistent TAKANA_INSTALL_DRYRUN=1 TAKANA_INSTALL_TESTROOT="$R3" \
HAMMER_HOSTNAME=srv01 HAMMER_ROOT_HASH='$6$salt$deadbeefHASH' HAMMER_TZ=UTC HAMMER_KEYMAP=es \
sh "$INST" /dev/vdb 3000 700 >"$OUT3" 2>&1 || { cat "$OUT3"; fail "desatendido salió con error"; }
grep -q 'DEV=/dev/vdb ROOT_MB=3000 STORE_MB=700' "$OUT3" || { cat "$OUT3"; fail "no respetó device/tamaños posicionales"; }
+6 -6
View File
@@ -74,15 +74,15 @@ cp -al "$ROOTFS" "$RFS/root"
echo 'echo "HAMMER-ISO-LIVE-OK: medio live arrancado desde El Torito"'
if [ -n "${AUTO_INSTALL:-}" ]; then
echo "echo 'HAMMER-AUTO-INSTALL: instalando a ${AUTO_INSTALL}'"
echo "if /usr/bin/hammer-install '${AUTO_INSTALL}'; then echo 'HAMMER-INSTALL-OK'; else echo 'HAMMER-INSTALL-FAIL'; fi"
echo "if /usr/bin/takana-install '${AUTO_INSTALL}'; then echo 'TAKANA-INSTALL-OK'; else echo 'TAKANA-INSTALL-FAIL'; fi"
echo '/bin/busybox sync'
echo '/bin/busybox poweroff -f'
elif [ "${INSTALLER:-0}" = 1 ] && [ "${INSTALLER_INTERACTIVE:-1}" = 1 ]; then
# ISO instalador SIN AUTO_INSTALL ⇒ recibir al usuario con la TUI del instalador en la consola.
# Tras instalar (o cancelar) ofrece reiniciar o caer al live. HAMMER_INSTALL_INTERACTIVE fuerza el
# Tras instalar (o cancelar) ofrece reiniciar o caer al live. TAKANA_INSTALL_INTERACTIVE fuerza el
# modo aunque /dev/console no pase el test -t (a esta altura stdin puede no ser un tty).
echo '[ -e /dev/console ] && exec 0</dev/console 1>/dev/console 2>/dev/console'
echo 'HAMMER_INSTALL_INTERACTIVE=1 /usr/bin/hammer-install || true'
echo 'TAKANA_INSTALL_INTERACTIVE=1 /usr/bin/takana-install || true'
echo 'echo; echo "Instalación finalizada. [r] reiniciar · [Enter] shell en vivo"'
echo 'read -r _a || _a=""'
echo 'case "$_a" in r|R) /bin/busybox reboot -f ;; *) exec /sbin/init ;; esac'
@@ -94,10 +94,10 @@ chmod +x "$RFS/root/init"
# --- INSTALLER=1: payload de instalación a disco DESDE el live (refinamiento #1) ---
# Bundle kernel + GRUB (boot.img + core.img MBR-prefix + módulos) bajo /usr/lib/hammer/install/ y el
# instalador en /usr/bin/hammer-install. El core.img se arma acá (build-time, el host tiene
# instalador en /usr/bin/takana-install. El core.img se arma acá (build-time, el host tiene
# grub-mkimage); el live NO lo necesita — sólo dd's. core prefix (hd0,msdos1)/boot/grub para boot MBR.
if [ "${INSTALLER:-0}" = 1 ]; then
echo "==> INSTALLER=1: bundling payload de instalación a disco (kernel + GRUB MBR + hammer-install)"
echo "==> INSTALLER=1: bundling payload de instalación a disco (kernel + GRUB MBR + takana-install)"
IPL="$RFS/root/usr/lib/hammer/install"
mkdir -p "$IPL/grub/i386-pc" "$IPL/kernel"
cp "$KERNEL" "$IPL/kernel/bzImage"; chmod 0644 "$IPL/kernel/bzImage"
@@ -116,7 +116,7 @@ if [ "${INSTALLER:-0}" = 1 ]; then
# core.img para disco MBR: prefix a la 1ª partición msdos, módulos de disco (biosdisk/part_msdos/ext2).
grub-mkimage -O i386-pc -p '(hd0,msdos1)/boot/grub' -o "$IPL/grub/core.img" \
biosdisk part_msdos ext2 normal configfile linux echo ls boot search
install -m 0755 "$ROOT/scripts/hammer-live-install.sh" "$RFS/root/usr/bin/hammer-install"
install -m 0755 "$ROOT/scripts/takana-live-install.sh" "$RFS/root/usr/bin/takana-install"
# hammer-recover (static musl): auto-sana un upgrade interrumpido al arranque del sistema instalado.
RECOVER_BIN="$ROOT/target/x86_64-unknown-linux-musl/release/hammer-recover"
if [ ! -x "$RECOVER_BIN" ]; then
+5 -5
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# iso-install-test.sh — valida el lazo COMPLETO de instalación desde el medio live (refinamiento #1):
# (1) arma un ISO instalador (iso-image.sh INSTALLER=1 AUTO_INSTALL=/dev/vda) con el payload de disco
# (kernel + GRUB MBR + /usr/bin/hammer-install) bundleado;
# (kernel + GRUB MBR + /usr/bin/takana-install) bundleado;
# (2) lo bootea con un disco EN BLANCO ⇒ el /init desatendido corre takana-install y apaga;
# (3) bootea ESE disco SOLO (sin ISO, sin -kernel) ⇒ el producto instalado arranca y sirve SSH.
# Cierra el lazo "ISO live → disco instalado → bootea solo", lo que hace la distro distribuible.
@@ -36,11 +36,11 @@ echo "==> (2) boot del instalador con disco EN BLANCO ${DISK_MB}M (auto-instala
rm -f "$TGT"; truncate -s "${DISK_MB}M" "$TGT"
timeout "$INSTALL_DEADLINE" qemu-system-x86_64 -m "$MEM" -no-reboot -nographic "${accel[@]}" \
-drive file="$TGT",format=raw,if=virtio -cdrom "$ISO" -boot d > "$ILOG" 2>&1 || true
if ! grep -q "HAMMER-INSTALL-OK" "$ILOG"; then
if ! grep -q "TAKANA-INSTALL-OK" "$ILOG"; then
echo "✗ la instalación NO terminó OK — ver $ILOG" >&2
grep -iE "HAMMER-INSTALL-FAIL|hammer-install:|no apareció|error" "$ILOG" | head; exit 1
grep -iE "TAKANA-INSTALL-FAIL|takana-install:|no apareció|error" "$ILOG" | head; exit 1
fi
echo " ✓ HAMMER-INSTALL-OK"
echo " ✓ TAKANA-INSTALL-OK"
echo "==> (3) boot del DISCO instalado (sin ISO, sin -kernel)"
timeout "$BOOT_DEADLINE" qemu-system-x86_64 -m "$MEM" -no-reboot -nographic "${accel[@]}" \
@@ -58,7 +58,7 @@ reject "ARRANQUE FALLIDO|seed.card no encontrada" "arje-zero arrancó sin fallo
reject "no pude montar" "particiones dedicadas /store y /var/lib/hammer montadas"
if [ "$fail" = 0 ]; then
echo; echo "✓✓ INSTALL-FROM-LIVE VERDE: ISO live → hammer-install → disco que bootea solo y sirve SSH"
echo; echo "✓✓ INSTALL-FROM-LIVE VERDE: ISO live → takana-install → disco que bootea solo y sirve SSH"
else
echo; echo "✗ install-from-live FALLÓ — ver $ILOG / $BLOG" >&2; exit 1
fi
+1 -1
View File
@@ -79,7 +79,7 @@ chmod +x "$AUG/usr/bin/wifi-connect"
# 5) banner de marca para el login de consola (icono martillo+# + acrónimo + uso WiFi)
mkdir -p "$AUG/etc"
cp scripts/hammer-banner.txt "$AUG/etc/motd"
cp scripts/takana-banner.txt "$AUG/etc/motd"
# 6) armar el ISO híbrido con iso-image.sh:
# - rama UEFI por EFI-STUB DIRECTO (EFI_STUB=1): bzImage=BOOTX64.EFI, esquiva el GRUB 2.14 roto.
@@ -8,9 +8,9 @@
# 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/hammer-install.sh /dev/sdX
# 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/hammer-install.sh work/target.img
# 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)
@@ -25,7 +25,7 @@ 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/hammer-install"; RFS="$WORK/rootfs"
WORK="$ROOT/work/takana-install"; RFS="$WORK/rootfs"
# --- resolver product-rootfs sellado ---
if [ -n "${PRODUCT:-}" ]; then
@@ -1,7 +1,7 @@
#!/bin/sh
# takana-install — instalador a disco DESDE el medio live (Etapa E5 / refinamiento #1).
#
# Se inyecta en el rootfs del producto como /usr/bin/hammer-install (ver scripts/iso-image.sh
# Se inyecta en el rootfs del producto como /usr/bin/takana-install (ver scripts/iso-image.sh
# INSTALLER=1). Corre DENTRO del live, como root real (arje-zero es PID1) ⇒ NO necesita unshare -r
# ni los rodeos rootless de install-image.sh: particiona, formatea, monta y copia con privilegios
# reales, usando sólo herramientas que el producto ya trae (busybox fdisk/mke2fs/mount/dd + uutils cp).
@@ -124,7 +124,7 @@ apply_post_install_config() {
fi
_ts=$(bb date -u +%FT%TZ 2>/dev/null || echo unknown)
{
echo "# escrito por hammer-install en $_ts"
echo "# escrito por takana-install en $_ts"
echo "HOSTNAME=${CFG_HOSTNAME:-}"
echo "TIMEZONE=${CFG_TZ:-}"
echo "KEYMAP=${CFG_KEYMAP:-}" # best-effort: el producto aún no trae kbd/loadkeys
@@ -241,10 +241,10 @@ interactive_setup() {
# --- resolución del modo: interactivo (sin device + TTY) vs desatendido (device dado) ---
if [ -z "$DEV" ]; then
if [ -t 0 ] || [ "${HAMMER_INSTALL_INTERACTIVE:-}" = 1 ]; then
if [ -t 0 ] || [ "${TAKANA_INSTALL_INTERACTIVE:-${HAMMER_INSTALL_INTERACTIVE:-}}" = 1 ]; then
interactive_setup
else
echo "uso: hammer-install <device> [ROOT_MB] [STORE_MB] (o sin args con un TTY para el modo interactivo)" >&2
echo "uso: takana-install <device> [ROOT_MB] [STORE_MB] (o sin args con un TTY para el modo interactivo)" >&2
exit 2
fi
fi
@@ -255,21 +255,22 @@ if [ -z "$CFG_ROOT_HASH" ] && [ -n "${TAKANA_ROOT_PW:-${HAMMER_ROOT_PW:-}}" ] &&
CFG_ROOT_HASH=$(printf '%s' "${TAKANA_ROOT_PW:-$HAMMER_ROOT_PW}" | bb cryptpw -m sha512 2>/dev/null || true)
fi
# --- gancho de prueba: valida TUI + config sin tocar disco (HAMMER_INSTALL_DRYRUN=1) ---
if [ "${HAMMER_INSTALL_DRYRUN:-}" = 1 ]; then
# --- gancho de prueba: valida TUI + config sin tocar disco (TAKANA_INSTALL_DRYRUN=1) ---
if [ "${TAKANA_INSTALL_DRYRUN:-${HAMMER_INSTALL_DRYRUN:-}}" = 1 ]; then
echo "== DRYRUN: plan de instalación =="
echo " DEV=$DEV ROOT_MB=$ROOT_MB STORE_MB=$STORE_MB"
echo " HOSTNAME=$CFG_HOSTNAME TZ=${CFG_TZ:-UTC} KEYMAP=$CFG_KEYMAP"
echo " ROOT_HASH=$([ -n "$CFG_ROOT_HASH" ] && echo set || echo -) AUTHKEYS=$([ -n "$CFG_ROOT_AUTHKEYS" ] && echo set || echo -)"
if [ -n "${HAMMER_INSTALL_TESTROOT:-}" ]; then
apply_post_install_config "$HAMMER_INSTALL_TESTROOT"
echo " config aplicada a $HAMMER_INSTALL_TESTROOT"
_testroot="${TAKANA_INSTALL_TESTROOT:-${HAMMER_INSTALL_TESTROOT:-}}"
if [ -n "$_testroot" ]; then
apply_post_install_config "$_testroot"
echo " config aplicada a $_testroot"
fi
exit 0
fi
[ -b "$DEV" ] || { echo "hammer-install: $DEV no es un block device" >&2; exit 1; }
[ -d "$PAYLOAD" ] || { echo "hammer-install: falta el payload $PAYLOAD (¿ISO sin INSTALLER=1?)" >&2; exit 1; }
[ -b "$DEV" ] || { echo "takana-install: $DEV no es un block device" >&2; exit 1; }
[ -d "$PAYLOAD" ] || { echo "takana-install: falta el payload $PAYLOAD (¿ISO sin INSTALLER=1?)" >&2; exit 1; }
# --- Detección de firmware: UEFI ⇒ rama EFI-stub SOBERANA (ADR 0010 paso 5); BIOS ⇒ MBR+GRUB (abajo) ---
# La rama EFI usa una ESP tipo 0xEF en tabla MBR (UEFI arranca \EFI\BOOT\BOOTX64.EFI de una ESP MBR igual
@@ -277,9 +278,9 @@ fi
# binario EFI (EFI-stub, cmdline horneada carga el initrd); un initramfs mínimo pivota por LABEL. Mismos
# artefactos que scripts/install-image-efi.sh (validado en OVMF), armados desde dentro del live.
if [ -d /sys/firmware/efi ]; then
[ -r "$PAYLOAD/kernel/bzImage-efi" ] || { echo "hammer-install: live en UEFI pero falta $PAYLOAD/kernel/bzImage-efi (ISO sin kernel metal)" >&2; exit 1; }
[ -r "$PAYLOAD/kernel/bzImage-efi" ] || { echo "takana-install: live en UEFI pero falta $PAYLOAD/kernel/bzImage-efi (ISO sin kernel metal)" >&2; exit 1; }
ESP_MB="${ESP_MB:-64}"
echo "==> hammer-install (UEFI): EFI-stub soberano en $DEV (ESP ${ESP_MB}M, root ${ROOT_MB}M, store ${STORE_MB}M, estado=resto)"
echo "==> takana-install (UEFI): EFI-stub soberano en $DEV (ESP ${ESP_MB}M, root ${ROOT_MB}M, store ${STORE_MB}M, estado=resto)"
echo " ¡esto BORRA $DEV!"
# MBR, 4 primarias: p1=ESP(0xEF) p2=root p3=store p4=estado. Sectores explícitos (como la rama BIOS).
@@ -322,7 +323,7 @@ FDISK
"$BB" sync; sleep 1
P1="${DEV}1"; P2="${DEV}2"; P3="${DEV}3"; P4="${DEV}4"
for p in "$P1" "$P2" "$P3" "$P4"; do
[ -b "$p" ] || { echo "hammer-install: no apareció la partición $p tras particionar" >&2; exit 1; }
[ -b "$p" ] || { echo "takana-install: no apareció la partición $p tras particionar" >&2; exit 1; }
done
echo "==> formateando (ESP FAT32 + 3 ext2 etiquetadas para el pivote por LABEL)"
@@ -377,7 +378,7 @@ INIT
# Poblar la root (copia del live) — sin wrapper que monte particiones (el pivote ya montó store/estado).
echo "==> copiando la raíz del live → $P2 (excluye virtuales/efímeros, /store, /var/lib/hammer, payload)"
MNT=/run/hammer-install
MNT=/run/takana-install
"$BB" mkdir -p "$MNT"
"$BB" mount -t ext4 "$P2" "$MNT"
for entry in /* /.[!.]*; do
@@ -423,15 +424,15 @@ INIT
"$BB" sync
"$BB" umount "$MNT"
echo "hammer-install (UEFI): $DEV instalado con EFI-stub SOBERANO (sin GRUB ni systemd-boot). Reiniciá sin el medio live."
echo "takana-install (UEFI): $DEV instalado con EFI-stub SOBERANO (sin GRUB ni systemd-boot). Reiniciá sin el medio live."
exit 0
fi
# ===================== rama BIOS (MBR + GRUB) — el firmware NO es UEFI ==============================
[ -r "$PAYLOAD/grub/boot.img" ] && [ -r "$PAYLOAD/grub/core.img" ] || { echo "hammer-install: payload GRUB incompleto" >&2; exit 1; }
[ -r "$PAYLOAD/kernel/bzImage" ] || { echo "hammer-install: falta el kernel en el payload" >&2; exit 1; }
[ -r "$PAYLOAD/grub/boot.img" ] && [ -r "$PAYLOAD/grub/core.img" ] || { echo "takana-install: payload GRUB incompleto" >&2; exit 1; }
[ -r "$PAYLOAD/kernel/bzImage" ] || { echo "takana-install: falta el kernel en el payload" >&2; exit 1; }
echo "==> hammer-install: instalando el sistema live en $DEV (root ${ROOT_MB}M, store ${STORE_MB}M, estado=resto)"
echo "==> takana-install: instalando el sistema live en $DEV (root ${ROOT_MB}M, store ${STORE_MB}M, estado=resto)"
echo " ¡esto BORRA $DEV!"
# --- particionar MBR con busybox fdisk (3 primarias; p1 bootable) ---
@@ -472,7 +473,7 @@ FDISK
P1="${DEV}1"; P2="${DEV}2"; P3="${DEV}3"
for p in "$P1" "$P2" "$P3"; do
[ -b "$p" ] || { echo "hammer-install: no apareció la partición $p tras particionar" >&2; exit 1; }
[ -b "$p" ] || { echo "takana-install: no apareció la partición $p tras particionar" >&2; exit 1; }
done
# --- formatear (busybox mke2fs = ext2; el driver ext4 del kernel lo monta) ---
@@ -482,7 +483,7 @@ echo "==> formateando particiones (ext2, montables como ext4)"
"$BB" mke2fs -F -L hammer-state "$P3" >/dev/null 2>&1
# --- copiar la raíz del live a la partición root, excluyendo virtuales + el payload ---
MNT=/run/hammer-install
MNT=/run/takana-install
"$BB" mkdir -p "$MNT"
"$BB" mount -t ext4 "$P1" "$MNT"
echo "==> copiando la raíz del live → $P1 (excluye virtuales/efímeros, /store, /var/lib/hammer y el payload)"
@@ -550,4 +551,4 @@ echo "==> instalando GRUB (boot.img→MBR + core.img→hueco post-MBR)"
"$BB" dd if="$PAYLOAD/grub/core.img" of="$DEV" bs=512 seek=1 conv=notrunc 2>/dev/null
"$BB" sync
echo "hammer-install: $DEV instalado. Reiniciá sin el medio live para arrancar del disco."
echo "takana-install: $DEV instalado. Reiniciá sin el medio live para arrancar del disco."