123 lines
5.5 KiB
Bash
Executable File
123 lines
5.5 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
PROJECT_ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
|
OLD_PACKAGE="${1:-$PROJECT_ROOT/dist/imagefind-0.3.9-x86_64.fpk}"
|
|
NEW_APP_ROOT="${2:-$PROJECT_ROOT/.build-fnos/imagefind/app}"
|
|
PORT="${3:-18766}"
|
|
NEW_PACKAGE_ROOT="${4:-$PROJECT_ROOT/fnos}"
|
|
PYTHON_PATH="${5:-${IMAGEFIND_PYTHON_PATH:-}}"
|
|
PASSWORD="imagefind-upgrade-smoke-password"
|
|
|
|
[ -f "$OLD_PACKAGE" ] || { printf 'missing previous package: %s\n' "$OLD_PACKAGE" >&2; exit 1; }
|
|
[ -f "$NEW_APP_ROOT/runtime/VERSION" ] && [ -d "$NEW_APP_ROOT/runtime/wheels" ] || {
|
|
printf 'missing new packaged Python runtime: %s\n' "$NEW_APP_ROOT/runtime" >&2
|
|
exit 1
|
|
}
|
|
OLD_PACKAGE=$(CDPATH= cd -- "$(dirname -- "$OLD_PACKAGE")" && pwd)/$(basename -- "$OLD_PACKAGE")
|
|
NEW_APP_ROOT=$(CDPATH= cd -- "$NEW_APP_ROOT" && pwd)
|
|
NEW_PACKAGE_ROOT=$(CDPATH= cd -- "$NEW_PACKAGE_ROOT" && pwd)
|
|
|
|
WORK_ROOT=$(mktemp -d "$PROJECT_ROOT/.upgrade-smoke.XXXXXX")
|
|
OLD_PACKAGE_ROOT="$WORK_ROOT/old-package"
|
|
ACTIVE_APP_ROOT="$WORK_ROOT/app"
|
|
OLD_APP_ROOT="$WORK_ROOT/old-app"
|
|
DATA_ROOT="$WORK_ROOT/var"
|
|
LIFECYCLE_LOG="$WORK_ROOT/fnos-upgrade.log"
|
|
COOKIE_JAR="$WORK_ROOT/cookie.txt"
|
|
OLD_CONTROL="$OLD_PACKAGE_ROOT/cmd/main"
|
|
NEW_CONTROL="$NEW_PACKAGE_ROOT/cmd/main"
|
|
|
|
cleanup() {
|
|
set +e
|
|
if [ -x "$NEW_CONTROL" ]; then
|
|
IMAGEFIND_PYTHON_PATH="$PYTHON_PATH" TRIM_APPDEST="$ACTIVE_APP_ROOT" TRIM_PKGVAR="$DATA_ROOT" \
|
|
"$NEW_CONTROL" stop >/dev/null 2>&1
|
|
fi
|
|
if [ -x "$OLD_CONTROL" ]; then
|
|
TRIM_APPDEST="$ACTIVE_APP_ROOT" TRIM_PKGVAR="$DATA_ROOT" "$OLD_CONTROL" stop >/dev/null 2>&1
|
|
fi
|
|
if [ "${IMAGEFIND_KEEP_UPGRADE_SMOKE:-false}" = "true" ]; then
|
|
printf 'upgrade smoke workspace preserved at %s\n' "$WORK_ROOT" >&2
|
|
return
|
|
fi
|
|
case "$WORK_ROOT" in
|
|
"$PROJECT_ROOT"/.upgrade-smoke.*) rm -rf -- "$WORK_ROOT" ;;
|
|
*) printf 'refusing to clear unexpected upgrade smoke path: %s\n' "$WORK_ROOT" >&2 ;;
|
|
esac
|
|
}
|
|
trap cleanup EXIT HUP INT TERM
|
|
|
|
mkdir -p "$OLD_PACKAGE_ROOT" "$ACTIVE_APP_ROOT"
|
|
tar xzf "$OLD_PACKAGE" -C "$OLD_PACKAGE_ROOT" cmd manifest
|
|
tar xOf "$OLD_PACKAGE" app.tgz | tar xzf - -C "$ACTIVE_APP_ROOT"
|
|
OLD_VERSION=$(sed -n 's/^version[[:space:]]*=[[:space:]]*//p' "$OLD_PACKAGE_ROOT/manifest" | head -n 1)
|
|
NEW_VERSION=$(sed -n 's/^version[[:space:]]*=[[:space:]]*//p' "$NEW_PACKAGE_ROOT/manifest" | head -n 1)
|
|
[ -n "$OLD_VERSION" ] && [ -n "$NEW_VERSION" ] || { printf 'unable to read package versions\n' >&2; exit 1; }
|
|
[ "$OLD_VERSION" != "$NEW_VERSION" ] || { printf 'upgrade smoke requires two different versions\n' >&2; exit 1; }
|
|
|
|
wait_for_version() {
|
|
EXPECTED="$1"
|
|
ATTEMPT=0
|
|
while [ "$ATTEMPT" -lt 90 ]; do
|
|
STATUS=$(curl -fsS "http://127.0.0.1:$PORT/api/v1/status" 2>/dev/null || true)
|
|
case "$STATUS" in
|
|
*'"configured":true'*'"version":"'"$EXPECTED"'"'*) return 0 ;;
|
|
esac
|
|
ATTEMPT=$((ATTEMPT + 1))
|
|
sleep 1
|
|
done
|
|
printf 'version %s did not become ready; lifecycle log follows:\n' "$EXPECTED" >&2
|
|
tail -100 "$DATA_ROOT/log/imagefind.log" >&2 || true
|
|
return 1
|
|
}
|
|
|
|
IMAGEFIND_PYTHON_PATH="$PYTHON_PATH" TRIM_APPDEST="$ACTIVE_APP_ROOT" TRIM_PKGVAR="$DATA_ROOT" \
|
|
TRIM_TEMP_LOGFILE="$LIFECYCLE_LOG" \
|
|
wizard_admin_password="$PASSWORD" wizard_admin_password_confirm="$PASSWORD" \
|
|
"$OLD_PACKAGE_ROOT/cmd/install_callback"
|
|
TRIM_PKGVAR="$DATA_ROOT" wizard_direct_access=true wizard_direct_port="$PORT" \
|
|
"$OLD_PACKAGE_ROOT/cmd/config_callback"
|
|
# A 0.3.15 PyInstaller service can be precisely what is broken on the target
|
|
# NAS. Upgrade verification must therefore begin from its persisted data and
|
|
# lifecycle callbacks, not require the old HTTP listener to become healthy.
|
|
if [ "${IMAGEFIND_SMOKE_START_OLD:-false}" = "true" ]; then
|
|
IMAGEFIND_PYTHON_PATH="$PYTHON_PATH" TRIM_APPDEST="$ACTIVE_APP_ROOT" TRIM_PKGVAR="$DATA_ROOT" \
|
|
"$OLD_CONTROL" start
|
|
wait_for_version "$OLD_VERSION"
|
|
fi
|
|
printf '%s\n' 'preserve-across-upgrade' >"$DATA_ROOT/data/upgrade-smoke-marker"
|
|
IMAGEFIND_PYTHON_PATH="$PYTHON_PATH" TRIM_APPDEST="$ACTIVE_APP_ROOT" TRIM_PKGVAR="$DATA_ROOT" \
|
|
"$OLD_CONTROL" stop
|
|
|
|
TRIM_APPDEST="$ACTIVE_APP_ROOT" TRIM_PKGVAR="$DATA_ROOT" TRIM_TEMP_LOGFILE="$LIFECYCLE_LOG" \
|
|
"$NEW_PACKAGE_ROOT/cmd/upgrade_init"
|
|
mv "$ACTIVE_APP_ROOT" "$OLD_APP_ROOT"
|
|
ln -s "$NEW_APP_ROOT" "$ACTIVE_APP_ROOT"
|
|
# Deliberately pass stale mismatched values from the previous wizard.
|
|
# The upgrade must preserve the existing password and still succeed.
|
|
TRIM_APPDEST="$ACTIVE_APP_ROOT" TRIM_PKGVAR="$DATA_ROOT" TRIM_TEMP_LOGFILE="$LIFECYCLE_LOG" \
|
|
IMAGEFIND_PYTHON_PATH="$PYTHON_PATH" \
|
|
wizard_admin_password=placeholder wizard_admin_password_confirm=different \
|
|
"$NEW_PACKAGE_ROOT/cmd/upgrade_callback"
|
|
IMAGEFIND_PYTHON_PATH="$PYTHON_PATH" TRIM_APPDEST="$ACTIVE_APP_ROOT" TRIM_PKGVAR="$DATA_ROOT" \
|
|
"$NEW_CONTROL" start
|
|
wait_for_version "$NEW_VERSION"
|
|
|
|
[ "$(sed -n '1p' "$DATA_ROOT/data/upgrade-smoke-marker")" = "preserve-across-upgrade" ] || {
|
|
printf 'upgrade did not preserve application data\n' >&2
|
|
exit 1
|
|
}
|
|
LOGIN=$(curl -fsS -c "$COOKIE_JAR" -H 'Content-Type: application/json' \
|
|
--data "{\"password\":\"$PASSWORD\",\"remember_device\":false}" \
|
|
"http://127.0.0.1:$PORT/api/v1/auth/login")
|
|
case "$LOGIN" in
|
|
*'"csrf_token"'*) ;;
|
|
*) printf 'upgrade did not preserve the administrator password\n' >&2; exit 1 ;;
|
|
esac
|
|
grep -q '升级准备完成' "$LIFECYCLE_LOG"
|
|
grep -q '升级数据检查完成' "$LIFECYCLE_LOG"
|
|
|
|
printf 'fnOS upgrade smoke passed: %s -> %s; data, access settings and password preserved\n' \
|
|
"$OLD_VERSION" "$NEW_VERSION"
|