Replace the monolithic installer with a staged transactional flow, add atomic locking, APK lock waiting/diagnostics, tmpfs and overlay preflight, verified release downloads, recovery snapshots, package transaction healthchecks, and active installer regression tests.
71 lines
3.5 KiB
Bash
71 lines
3.5 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
INSTALLER="$ROOT_DIR/install.sh"
|
|
|
|
fail() { printf 'FAIL: %s\n' "$1" >&2; exit 1; }
|
|
|
|
[ -r "$INSTALLER" ] || fail "install.sh must exist"
|
|
|
|
# Package manager errors are fatal. The old installer tried to infer success after
|
|
# a non-zero apk result and could accidentally accept a rolled-back upgrade.
|
|
grep -Fq 'install_core_transaction || fail "Tachyon package transaction failed"' "$INSTALLER" ||
|
|
fail "package transaction failures must abort the install"
|
|
if grep -Fq 'Package manager reported non-critical errors during installation' "$INSTALLER"; then
|
|
fail "installer must not convert package-manager failures into success"
|
|
fi
|
|
|
|
# Backend, LuCI and optional i18n are installed in one package-manager invocation.
|
|
grep -Fq 'pkg_install_local_bundle "$@"' "$INSTALLER" ||
|
|
fail "release packages must be submitted as one transaction"
|
|
grep -Fq 'apk_run apk-transaction "$PACKAGE_TIMEOUT_SECONDS" add --allow-untrusted "$@"' "$INSTALLER" ||
|
|
fail "APK install must be one bounded transaction"
|
|
grep -Fq 'run_logged_timeout opkg-transaction "$PACKAGE_TIMEOUT_SECONDS" opkg install' "$INSTALLER" ||
|
|
fail "opkg install must be one bounded transaction"
|
|
|
|
# The historical 120s package timeout caused valid postinst hooks to be killed and
|
|
# APK to roll the upgrade back. Keep a larger package transaction budget.
|
|
grep -Fq 'PACKAGE_TIMEOUT_SECONDS=420' "$INSTALLER" ||
|
|
fail "package transaction timeout must allow slow OpenWrt package hooks"
|
|
|
|
# Before the package manager runs, old rc.common/procd lock holders must be
|
|
# cleared. Old Tachyon releases could otherwise block prerm until APK rolled back.
|
|
grep -Fq 'release_tachyon_init_lock' "$INSTALLER" ||
|
|
fail "installer must release stale Tachyon init locks"
|
|
grep -Fq '/proc/[0-9]*/fd/1000' "$INSTALLER" ||
|
|
fail "installer must find leaked procd lock holders by fd 1000"
|
|
grep -Fq '*procd_tachyon*|*tachyon*lock*' "$INSTALLER" ||
|
|
fail "fd sweep must be limited to Tachyon-owned locks"
|
|
grep -Fq 'is_protected_pid' "$INSTALLER" ||
|
|
fail "installer must protect its own process ancestry"
|
|
grep -Fq '99-tachyon-wan|flock 1000|/etc/init.d/tachyon' "$INSTALLER" ||
|
|
fail "installer must clear old rc.common waiters"
|
|
|
|
# The lock release must happen before packages are handed to apk/opkg.
|
|
awk '
|
|
/^main\(\)/ { in_main=1 }
|
|
in_main && /prepare_transaction/ && !prepare { prepare=NR }
|
|
in_main && /install_core_transaction/ && !install { install=NR }
|
|
END { exit !(prepare > 0 && install > prepare) }
|
|
' "$INSTALLER" || fail "stale init locks must be released before package install"
|
|
|
|
# A failed later stage restores the safety snapshot rather than leaving user
|
|
# configuration rewritten by package hooks.
|
|
grep -Fq 'TX_ACTIVE=1' "$INSTALLER" || fail "transaction recovery guard missing"
|
|
grep -Fq 'TX_COMMITTED=1' "$INSTALLER" || fail "transaction commit guard missing"
|
|
grep -Fq 'restore_snapshot' "$INSTALLER" || fail "failed transaction must restore snapshot"
|
|
grep -Fq 'chmod 0600 /etc/config/tachyon' "$INSTALLER" ||
|
|
fail "restored Tachyon config must remain private"
|
|
|
|
# Successful completion is only printed after the runtime healthcheck and commit.
|
|
awk '
|
|
/^main\(\)/ { in_main=1 }
|
|
in_main && /healthcheck/ && !health { health=NR }
|
|
in_main && /commit_transaction/ && !commit { commit=NR }
|
|
in_main && /installed successfully/ && !success { success=NR }
|
|
END { exit !(health > 0 && commit > health && success > commit) }
|
|
' "$INSTALLER" || fail "success must be gated by healthcheck and transaction commit"
|
|
|
|
printf 'PASS: installer rollback detection\n'
|