3 Commits
Author SHA1 Message Date
Outis 4085866134 Merge pull request #127 from outis1one/claude/laughing-sagan-2oo2mx
Claude/laughing sagan 2oo2mx
2026-11-02 13:27:52 -05:00
Claude 763162fc57 First boot: detect a stalled online install by silence (10 min), not a 40 min cap
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A97KUggSE3rBL8veDM5Mr4
2026-10-23 15:37:34 +00:00
Claude d30f7c7260 First boot: don't hang forever on a stalled online install; fall back to the offline bundle
Unattended installs on an --offline ISO cap the online attempt (default 40 min)
and finish from the bundle on timeout or failure. Interactive retry menu gains
[O] to install from the bundle. NodeSource curl gets timeouts.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A97KUggSE3rBL8veDM5Mr4
2026-10-23 15:33:54 +00:00
2 changed files with 67 additions and 3 deletions
+66 -2
View File
@@ -22,6 +22,10 @@
# KIOSK_OFFLINE_WAIT=N on an ISO built with --offline: seconds to wait
# for internet before installing from the bundled
# packages instead (default 90).
# KIOSK_STALL_TIMEOUT=N on an --offline ISO, unattended: if the install
# prints nothing for N seconds (a stalled download on
# a flaky link), stop it and finish from the bundled
# packages instead (default 600).
################################################################################
set -uo pipefail
@@ -40,6 +44,7 @@ OFFLINE_FLAG="$STATE_DIR/offline-mode"
KIOSK_UNATTENDED=0
KIOSK_OFFLINE_WAIT=90
KIOSK_STALL_TIMEOUT=600
# shellcheck source=/dev/null
[[ -f "$CONF" ]] && source "$CONF"
@@ -61,6 +66,21 @@ if [[ "${1:-}" == "--cleanup" ]]; then
exit 0
fi
have_bundle() { [[ -f "$OFFLINE_BUNDLE/apt/Packages" ]]; }
# Finish this install from the bundled packages instead of the internet
# (cleanup() turns it back off). install.sh notices via lib/config.sh's
# offline_mode_active.
switch_to_offline() {
touch "$OFFLINE_FLAG"
if ! "$OFFLINE_APT" on; then
echo "ERROR: couldn't switch apt to the offline bundle."
rm -f "$OFFLINE_FLAG"
return 1
fi
return 0
}
# Make sure tty1 gets its login prompt back. getty@tty1 is ordered after
# this unit and normally starts by itself once we exit; this just covers
# a getty that was stopped or never queued (e.g. started by hand later).
@@ -83,13 +103,15 @@ banner() {
# drop to a shell as the admin user to fix it, or give up until next boot.
# Returns 0 to retry, 1 to give up.
offer_retry() {
local choice
local choice offline_opt=""
have_bundle && [[ ! -f "$OFFLINE_FLAG" ]] && offline_opt=" [O] Install from the offline bundle on this disk"
while true; do
echo
echo " [R] Retry [S] Shell (as $ADMIN_USER, exit to come back) [Q] Quit to login prompt"
echo " [R] Retry [S] Shell (as $ADMIN_USER, exit to come back) [Q] Quit to login prompt$offline_opt"
read -r -p "Choice [R]: " choice
case "${choice,,}" in
""|r) return 0 ;;
o) [[ -n "$offline_opt" ]] && switch_to_offline && return 0 ;;
s) runuser -l "$ADMIN_USER" ;;
q)
echo "Setup will run again on next boot, or run it now with:"
@@ -227,6 +249,39 @@ run_install() {
# runuser rather than sudo -u: sudo would set SUDO_USER=root, which
# config.sh reads as "the admin running this tool".
# A stalled download on a flaky connection would otherwise hang an
# unattended install forever. With the offline bundle as a safety net,
# watch the log: no new output for KIOSK_STALL_TIMEOUT seconds means
# stuck, so the whole process group is stopped (the caller then
# finishes from the bundle).
if [[ "$KIOSK_UNATTENDED" == "1" ]] && have_bundle && [[ ! -f "$OFFLINE_FLAG" ]]; then
touch "$LOG"
setsid bash -c '
runuser -u "$1" -- env -i "${@:4}" bash -c "cd \"\$1\" && exec ./install.sh" _ "$2" 2>&1 | tee -a "$3"
exit "${PIPESTATUS[0]}"
' _ "$ADMIN_USER" "$REPO_DEST" "$LOG" "${envs[@]}" &
local pid=$!
(
while kill -0 "$pid" 2>/dev/null; do
sleep 20
age=$(( $(date +%s) - $(stat -c %Y "$LOG") ))
if (( age > KIOSK_STALL_TIMEOUT )); then
echo
echo "No output for ${age}s - the online install looks stuck; stopping it."
kill -TERM -- "-$pid" 2>/dev/null
sleep 30
kill -KILL -- "-$pid" 2>/dev/null
break
fi
done
) &
local watcher=$!
wait "$pid"
local rc=$?
kill "$watcher" 2>/dev/null
wait "$watcher" 2>/dev/null
return "$rc"
fi
runuser -u "$ADMIN_USER" -- env -i "${envs[@]}" \
bash -c 'cd "$1" && exec ./install.sh' _ "$REPO_DEST" \
2>&1 | tee -a "$LOG"
@@ -249,6 +304,15 @@ while true; do
echo
echo "install.sh did not finish (exit code $rc). Full output: $LOG"
if [[ "$KIOSK_UNATTENDED" == "1" ]]; then
# Online attempt failed or stalled: the bundle on this disk is
# always going to work, so use it rather than retry the same thing.
if have_bundle && [[ ! -f "$OFFLINE_FLAG" ]]; then
echo "Online install didn't finish - continuing from the offline bundle on this disk."
if switch_to_offline; then
attempt=$((attempt + 1))
continue
fi
fi
if (( attempt >= 3 )); then
echo "Giving up after $attempt attempts; will try again next boot."
release_tty
+1 -1
View File
@@ -127,7 +127,7 @@ provision_install_nodejs() {
# The bundle carries NodeSource's own nodejs package.
sudo apt install -y nodejs
else
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
curl -fsSL --connect-timeout 20 --max-time 300 https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
fi
fi