hammer-install crece una cara humana sin tocar la mecánica EFI/BIOS validada: - sin device + TTY ⇒ interactive_setup: detecta discos (/sys/block, marca el montado como posible medio live), el usuario elige + confirma escribiendo el nombre del disco, y recoge hostname / credencial de root (contraseña vía cryptpw o authorized_keys) / zona horaria (best-effort si hay tzdata) / teclado / tamaños de / y /store. - apply_post_install_config escribe hostname+hosts, reemplaza el hash de root en /etc/shadow, instala authorized_keys, symlinkea localtime y deja install.conf; se llama tras la copia en AMBAS ramas (EFI y BIOS). - con device ⇒ autoinstalador de siempre (iso/efi-install-test intactos); la config sale de env (HAMMER_HOSTNAME/ROOT_PW/ROOT_AUTHKEYS/TZ/KEYMAP). - iso-image.sh: ISO instalador sin AUTO_INSTALL ahora recibe con la TUI en la consola (INSTALLER_INTERACTIVE, default on) y ofrece reiniciar/caer al live. Verificado: scripts/install-tui-test.sh (4/4, dry-run con sysfs+rootfs falsos) + iso-install-test.sh VERDE end-to-end en QEMU (autoinstalador con la config nueva bajo busybox real → disco bootea solo y sirve SSH). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
102 lines
5.2 KiB
Bash
Executable File
102 lines
5.2 KiB
Bash
Executable File
#!/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.
|
|
# 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"
|
|
W="$(mktemp -d)"; trap 'rm -rf "$W"' EXIT
|
|
fail() { echo "✗ FALLO: $*" >&2; exit 1; }
|
|
|
|
# --- sysfs falso: vda (montado = simula el medio live) + vdb (target) ---
|
|
SB="$W/sys-block"
|
|
mkdir -p "$SB/vda/device" "$SB/vdb/device"
|
|
echo $((8*1024*1024*1024/512)) > "$SB/vda/size" # 8 GiB
|
|
printf 'LIVE-USB\n' > "$SB/vda/device/model"
|
|
echo $((16*1024*1024*1024/512)) > "$SB/vdb/size" # 16 GiB
|
|
printf 'TARGET-SSD\n' > "$SB/vdb/device/model"
|
|
MOUNTS="$W/mounts"; printf '/dev/vda1 / ext4 ro 0 0\n' > "$MOUNTS"
|
|
|
|
# --- zoneinfo falso (hermético) ---
|
|
ZI="$W/zoneinfo"; mkdir -p "$ZI/America"; : > "$ZI/America/La_Paz"
|
|
|
|
# --- rootfs de scratch #1 (destino de la config del modo interactivo) ---
|
|
R1="$W/root1"; mkdir -p "$R1/etc" "$R1/usr/share/zoneinfo/America"
|
|
printf 'root:!:19000:0:99999:7:::\ndaemon:!:19000::::::\n' > "$R1/etc/shadow"
|
|
printf '127.0.0.1\tlocalhost\n' > "$R1/etc/hosts"
|
|
: > "$R1/usr/share/zoneinfo/America/La_Paz"
|
|
|
|
echo "== test 1: modo INTERACTIVO (TUI dry-run) =="
|
|
# Respuestas: disco #2 (vdb) · root 2048M · store 512M · hostname midistro · cred 2 (ssh) · authkeys ·
|
|
# 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" \
|
|
sh "$INST" >"$OUT1" 2>&1 <<'ANSWERS' || { cat "$OUT1"; fail "el instalador salió con error"; }
|
|
2
|
|
2048
|
|
512
|
|
midistro
|
|
2
|
|
ssh-ed25519 AAAATESTKEY user@host
|
|
America/La_Paz
|
|
|
|
/dev/vdb
|
|
ANSWERS
|
|
|
|
grep -q 'TARGET-SSD' "$OUT1" || { cat "$OUT1"; fail "no listó el disco vdb con su modelo"; }
|
|
grep -q 'montado' "$OUT1" || { cat "$OUT1"; fail "no marcó vda como montado (medio live)"; }
|
|
grep -q 'DRYRUN' "$OUT1" || { cat "$OUT1"; fail "no llegó al plan dry-run (¿se cortó antes?)"; }
|
|
|
|
[ "$(cat "$R1/etc/hostname")" = midistro ] || fail "hostname no quedó en midistro"
|
|
grep -q 'midistro' "$R1/etc/hosts" || fail "hosts no menciona el hostname"
|
|
grep -q 'AAAATESTKEY' "$R1/root/.ssh/authorized_keys" || fail "authorized_keys no escrito"
|
|
[ -L "$R1/etc/localtime" ] || fail "localtime no es symlink"
|
|
case "$(readlink "$R1/etc/localtime")" in */America/La_Paz) : ;; *) fail "localtime no apunta a La_Paz"; esac
|
|
grep -q 'HOSTNAME=midistro' "$R1/etc/hammer/install.conf" || fail "install.conf sin hostname"
|
|
grep -q 'KEYMAP=us' "$R1/etc/hammer/install.conf" || fail "install.conf sin keymap default"
|
|
# root en shadow debe seguir intacto (interactivo eligió ssh, no tocó la contraseña)
|
|
grep -q '^root:!:' "$R1/etc/shadow" || fail "shadow de root alterado sin querer"
|
|
echo " ✓ interactivo: disco elegido + confirmado, config escrita (hostname/hosts/ssh/tz/keymap)"
|
|
|
|
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" \
|
|
sh "$INST" >"$OUT2" 2>&1 <<'ANSWERS'
|
|
2
|
|
2048
|
|
512
|
|
h
|
|
3
|
|
us
|
|
sda-equivocado
|
|
ANSWERS
|
|
then fail "debió cancelar con confirmación errónea (exit != 0)"; fi
|
|
grep -qi 'Cancelado' "$OUT2" || { cat "$OUT2"; fail "no reportó cancelación"; }
|
|
[ ! -d "$W/root-none/etc" ] || fail "escribió config pese a cancelar"
|
|
echo " ✓ confirmación errónea ⇒ aborta sin escribir"
|
|
|
|
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" \
|
|
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"; }
|
|
grep -q '^root:\$6\$salt\$deadbeefHASH:' "$R3/etc/shadow" || { cat "$R3/etc/shadow"; fail "no reemplazó el hash de root"; }
|
|
[ "$(cat "$R3/etc/hostname")" = srv01 ] || fail "hostname desatendido incorrecto"
|
|
grep -q 'KEYMAP=es' "$R3/etc/hammer/install.conf" || fail "keymap por env no propagado"
|
|
echo " ✓ desatendido: hash de root reemplazado + hostname/keymap por env"
|
|
|
|
echo "== test 4: sin device y sin TTY ⇒ error de uso (no cuelga) =="
|
|
if BB=/nonexistent sh "$INST" </dev/null >/dev/null 2>&1; then fail "debió fallar sin device ni TTY"; fi
|
|
echo " ✓ uso inválido reportado"
|
|
|
|
echo
|
|
echo "✓✓ install-tui-test: TODOS los casos verdes"
|