158 lines
7.3 KiB
Bash
Executable File
158 lines
7.3 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
LIVE_PACKAGE=${1:?usage: smoke-fnos-migration.sh liverecorder.fpk postgresql-service.fpk [temporary-directory]}
|
|
POSTGRES_PACKAGE=${2:?usage: smoke-fnos-migration.sh liverecorder.fpk postgresql-service.fpk [temporary-directory]}
|
|
SMOKE_TMP_ROOT="${3:-${LIVERECORDER_MIGRATION_SMOKE_TMPDIR:-${TMPDIR:-/tmp}}}"
|
|
mkdir -p "$SMOKE_TMP_ROOT"
|
|
SMOKE_TMP_ROOT=$(CDPATH= cd -- "$SMOKE_TMP_ROOT" && pwd)
|
|
WORK_DIR=$(mktemp -d "${SMOKE_TMP_ROOT%/}/liverecorder-migration-smoke.XXXXXX")
|
|
STATE_DIR=$(mktemp -d "${TMPDIR:-/tmp}/liverecorder-migration-state.XXXXXX")
|
|
|
|
LIVE_PACKAGE_ROOT="$WORK_DIR/live-package"
|
|
LIVE_APP_ROOT="$WORK_DIR/live-app"
|
|
LIVE_DATA_ROOT="$STATE_DIR/live-var"
|
|
LIVE_VOLUME_ROOT="$WORK_DIR/live-volume"
|
|
PG_PACKAGE_ROOT="$WORK_DIR/postgres-package"
|
|
PG_APP_ROOT="$WORK_DIR/postgres-app"
|
|
PG_DATA_ROOT="$STATE_DIR/postgres-var"
|
|
PG_VOLUME_ROOT="$WORK_DIR/postgres-volume"
|
|
LIVE_PORT=${LIVERECORDER_MIGRATION_SMOKE_PORT:-19680}
|
|
PRIVATE_PG_PORT=${LIVERECORDER_MIGRATION_PRIVATE_PG_PORT:-19629}
|
|
PG_API_PORT=${POSTGRES_SERVICE_MIGRATION_API_PORT:-19633}
|
|
PG_PORT=${POSTGRES_SERVICE_MIGRATION_PG_PORT:-19632}
|
|
LIVE_CONTROL="$LIVE_PACKAGE_ROOT/cmd/main"
|
|
PG_CONTROL="$PG_PACKAGE_ROOT/cmd/main"
|
|
ADMIN_PASSWORD='LiveRecorder-Migration-2026!'
|
|
PG_ADMIN_PASSWORD='Postgres-Migration-Admin-2026!'
|
|
ENROLLMENT_TOKEN='Postgres-Migration-Enrollment-2026!'
|
|
MEDIA_PATH="${PATH:-/usr/local/bin:/usr/bin:/bin}"
|
|
|
|
if ! PATH="$MEDIA_PATH" command -v ffmpeg >/dev/null 2>&1 || \
|
|
! PATH="$MEDIA_PATH" command -v ffprobe >/dev/null 2>&1; then
|
|
mkdir -p "$WORK_DIR/system-media-stubs"
|
|
ln -s "$(type -P true)" "$WORK_DIR/system-media-stubs/ffmpeg"
|
|
ln -s "$(type -P true)" "$WORK_DIR/system-media-stubs/ffprobe"
|
|
MEDIA_PATH="$WORK_DIR/system-media-stubs:$MEDIA_PATH"
|
|
fi
|
|
|
|
run_live_control() {
|
|
TRIM_APPDEST="$LIVE_APP_ROOT" TRIM_PKGVAR="$LIVE_DATA_ROOT" \
|
|
TRIM_APPDEST_VOL="$LIVE_VOLUME_ROOT" TRIM_SERVICE_PORT="$LIVE_PORT" \
|
|
LIVE_RECORDER_POSTGRES_PORT="$PRIVATE_PG_PORT" \
|
|
POSTGRES_SERVICE_API="http://127.0.0.1:$PG_API_PORT" PATH="$MEDIA_PATH" "$LIVE_CONTROL" "$@"
|
|
}
|
|
|
|
run_postgres_control() {
|
|
TRIM_APPDEST="$PG_APP_ROOT" TRIM_PKGVAR="$PG_DATA_ROOT" \
|
|
TRIM_APPDEST_VOL="$PG_VOLUME_ROOT" TRIM_SERVICE_PORT="$PG_API_PORT" \
|
|
POSTGRES_SERVICE_PORT="$PG_PORT" "$PG_CONTROL" "$@"
|
|
}
|
|
|
|
cleanup() {
|
|
status=$?
|
|
if [ -x "$LIVE_CONTROL" ]; then run_live_control stop >/dev/null 2>&1 || true; fi
|
|
if [ -x "$PG_CONTROL" ]; then run_postgres_control stop >/dev/null 2>&1 || true; fi
|
|
if [ "$status" -ne 0 ]; then
|
|
printf '%s\n' 'fnOS PostgreSQL migration smoke test failed; service logs follow:' >&2
|
|
for log_file in \
|
|
"$PG_DATA_ROOT/log/postgresql.log" "$PG_DATA_ROOT/log/postgres-service.log" \
|
|
"$LIVE_DATA_ROOT/log/postgresql.log" "$LIVE_DATA_ROOT/log/liverecorder.log"; do
|
|
if [ -f "$log_file" ]; then
|
|
printf '%s\n' "--- $log_file ---" >&2
|
|
tail -n 200 "$log_file" >&2 || true
|
|
fi
|
|
done
|
|
fi
|
|
rm -rf -- "$WORK_DIR"
|
|
rm -rf -- "$STATE_DIR"
|
|
return "$status"
|
|
}
|
|
trap cleanup EXIT HUP INT TERM
|
|
|
|
mkdir -p "$LIVE_PACKAGE_ROOT" "$LIVE_APP_ROOT" "$LIVE_VOLUME_ROOT" \
|
|
"$PG_PACKAGE_ROOT" "$PG_APP_ROOT" "$PG_VOLUME_ROOT"
|
|
tar -xzf "$LIVE_PACKAGE" -C "$LIVE_PACKAGE_ROOT"
|
|
tar -xzf "$LIVE_PACKAGE_ROOT/app.tgz" -C "$LIVE_APP_ROOT"
|
|
rm -f "$LIVE_PACKAGE_ROOT/app.tgz"
|
|
tar -xzf "$POSTGRES_PACKAGE" -C "$PG_PACKAGE_ROOT"
|
|
tar -xzf "$PG_PACKAGE_ROOT/app.tgz" -C "$PG_APP_ROOT"
|
|
rm -f "$PG_PACKAGE_ROOT/app.tgz"
|
|
|
|
TRIM_PKGVAR="$LIVE_DATA_ROOT" \
|
|
wizard_admin_password="$ADMIN_PASSWORD" wizard_admin_password_confirm="$ADMIN_PASSWORD" \
|
|
wizard_postgres_enrollment_token="$ENROLLMENT_TOKEN" \
|
|
"$LIVE_PACKAGE_ROOT/cmd/install_callback"
|
|
mv "$LIVE_DATA_ROOT/postgres-enrollment-token.seed" "$WORK_DIR/enrollment-token.seed"
|
|
|
|
PRIVATE_PG_BIN="$LIVE_APP_ROOT/runtime/usr/lib/postgresql/15/bin"
|
|
PRIVATE_PG_SHARE="$LIVE_APP_ROOT/runtime/usr/share/postgresql/15"
|
|
PRIVATE_PG_LIB="$LIVE_APP_ROOT/runtime/usr/lib/postgresql/15/lib"
|
|
PRIVATE_RUNTIME_LIBS="$LIVE_APP_ROOT/runtime/lib:$PRIVATE_PG_LIB"
|
|
PRIVATE_PG_DATA="$LIVE_DATA_ROOT/postgres"
|
|
PRIVATE_RUN_ROOT="$LIVE_DATA_ROOT/run"
|
|
mkdir -p "$PRIVATE_PG_DATA" "$PRIVATE_RUN_ROOT" "$LIVE_DATA_ROOT/log"
|
|
chmod 0700 "$PRIVATE_PG_DATA" "$PRIVATE_RUN_ROOT"
|
|
env LD_LIBRARY_PATH="$PRIVATE_RUNTIME_LIBS" "$PRIVATE_PG_BIN/initdb" \
|
|
-D "$PRIVATE_PG_DATA" -L "$PRIVATE_PG_SHARE" --username=liverecorder \
|
|
--auth-local=trust --auth-host=reject --encoding=UTF8 --no-locale \
|
|
>"$LIVE_DATA_ROOT/log/postgresql.log" 2>&1
|
|
{
|
|
printf "listen_addresses = ''\n"
|
|
printf "port = %s\n" "$PRIVATE_PG_PORT"
|
|
printf "unix_socket_directories = '%s'\n" "$PRIVATE_RUN_ROOT"
|
|
printf "max_connections = 40\nshared_buffers = '64MB'\ntimezone = 'UTC'\nlog_timezone = 'UTC'\n"
|
|
} >>"$PRIVATE_PG_DATA/postgresql.conf"
|
|
|
|
# With a legacy PG15 cluster and no enrollment seed, the package must boot the
|
|
# old database. The Web API then creates the exact EF schema and initial admin.
|
|
run_live_control start
|
|
curl -fsS "http://127.0.0.1:$LIVE_PORT/health/ready" | grep -q '"status":"ready"'
|
|
source_user_count=$(env LD_LIBRARY_PATH="$PRIVATE_RUNTIME_LIBS" \
|
|
"$PRIVATE_PG_BIN/psql" -h "$PRIVATE_RUN_ROOT" -p "$PRIVATE_PG_PORT" \
|
|
-U liverecorder -d live_recorder -Atqc 'SELECT count(*) FROM "UserAccounts"')
|
|
test "$source_user_count" -gt 0
|
|
run_live_control stop
|
|
|
|
TRIM_PKGVAR="$PG_DATA_ROOT" \
|
|
wizard_postgres_admin_password="$PG_ADMIN_PASSWORD" \
|
|
wizard_postgres_admin_password_confirm="$PG_ADMIN_PASSWORD" \
|
|
wizard_postgres_enrollment_token="$ENROLLMENT_TOKEN" \
|
|
wizard_postgres_enrollment_token_confirm="$ENROLLMENT_TOKEN" \
|
|
"$PG_PACKAGE_ROOT/cmd/install_callback"
|
|
mv "$WORK_DIR/enrollment-token.seed" "$LIVE_DATA_ROOT/postgres-enrollment-token.seed"
|
|
chmod 0600 "$LIVE_DATA_ROOT/postgres-enrollment-token.seed"
|
|
run_postgres_control start
|
|
run_live_control start
|
|
curl -fsS "http://127.0.0.1:$LIVE_PORT/health/ready" | grep -q '"status":"ready"'
|
|
|
|
MARKER="$LIVE_DATA_ROOT/postgres-migration/shared-database.active"
|
|
DUMP="$LIVE_DATA_ROOT/postgres-migration/private-postgres-15.dump"
|
|
test -s "$MARKER"
|
|
grep -q '^migrated_at=' "$MARKER"
|
|
test -s "$DUMP"
|
|
sha256sum -c "$DUMP.sha256" >/dev/null
|
|
test -f "$LIVE_DATA_ROOT/postgres/PG_VERSION"
|
|
if env LD_LIBRARY_PATH="$PRIVATE_RUNTIME_LIBS" \
|
|
"$PRIVATE_PG_BIN/pg_ctl" -D "$PRIVATE_PG_DATA" status >/dev/null 2>&1; then
|
|
printf '%s\n' 'legacy private PostgreSQL was still running after migration' >&2
|
|
exit 1
|
|
fi
|
|
|
|
CREDENTIALS="$LIVE_DATA_ROOT/postgres-client.conf"
|
|
shared_database=$(sed -n 's/^database=//p' "$CREDENTIALS")
|
|
shared_user=$(sed -n 's/^username=//p' "$CREDENTIALS")
|
|
shared_password=$(sed -n 's/^password=//p' "$CREDENTIALS")
|
|
SHARED_PG_BIN="$PG_APP_ROOT/runtime/usr/lib/postgresql/15/bin"
|
|
SHARED_PG_LIBS="$PG_APP_ROOT/runtime/usr/lib/x86_64-linux-gnu:$PG_APP_ROOT/runtime/lib/x86_64-linux-gnu:$PG_APP_ROOT/runtime/usr/lib/postgresql/15/lib"
|
|
target_user_count=$(env LD_LIBRARY_PATH="$SHARED_PG_LIBS" PGPASSWORD="$shared_password" \
|
|
"$SHARED_PG_BIN/psql" -h 127.0.0.1 -p "$PG_PORT" -U "$shared_user" \
|
|
-d "$shared_database" -Atqc 'SELECT count(*) FROM "UserAccounts"')
|
|
test "$source_user_count" = "$target_user_count"
|
|
|
|
run_live_control stop
|
|
run_postgres_control status
|
|
curl -fsS "http://127.0.0.1:$PG_API_PORT/health/ready" | grep -q '"status":"ready"'
|
|
|
|
printf '%s\n' 'fnOS migration smoke test passed: populated legacy PG15 migrated with row-count parity, checksum dump and rollback data preserved'
|