mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-23 11:38:09 +09:00
fix(update): don't gate SQLite backup/verify on a 3.11/3.12 interpreter
copy_sqlite_db and verify_sqlite_db reused locate_python, which enforces
3.11 <= v <= 3.12. That bound is correct for rebuild_virtualenv and
preflight_check, but snapshotting or integrity-checking a SQLite file needs
nothing beyond the stdlib sqlite3 module. Reusing it coupled the DATA-safety
paths to the venv-builder constraint and blocked updates for a reason unrelated
to the data:
* an all-Docker install returns before preflight_check ever runs and does
every real step in the container -- yet backup_docker_db snapshots with the
CONTAINER's python and then verified the extracted file with the HOST's.
On a stock EL9 (python3.9) or Ubuntu 22.04 (python3.10) host that halted
with "Could not obtain a VALID database backup", blaming the backup for a
missing interpreter.
* backup_current halts when it cannot snapshot, so those hosts could never
update at all.
Split out locate_sqlite_python: any candidate that can `import sqlite3` wins,
and the install's own venv interpreter is preferred -- on a real box it is
guaranteed present, guaranteed to carry the module, and independent of PATH.
locate_python keeps the 3.11/3.12 bound where it belongs.
Surfaced by the scripts-ci unit matrix: almalinux:9 and rockylinux:9 ship
python3.9, so the suite's own probe accepted an interpreter locate_python
rejected, and copy_sqlite_db/verify_sqlite_db failed there while passing on
python3.12 runners.
T10i pins the contract: on a box where every candidate reports 3.9 (locate_python
fails), the helpers still resolve an interpreter, prefer the slot's venv, and
round-trip 100 rows. Fails on the parent commit, passes here.
Verified on the full 7-image CI matrix (ubuntu 22.04/24.04, debian:12,
rockylinux:9, almalinux:9, fedora:40, opensuse/leap:15.5), all six shell suites:
0 failed. test_update is 63 passed / 0 failed on every image carrying a python3.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
69b6ffb94a
commit
664a5e62bd
2 files changed
+99
-4
No files matched your search
@@ -475,6 +475,64 @@ else
|
||||
fi
|
||||
rm -f "$STUB_BIN/pg_restore"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# T10i — the SQLite helpers must NOT inherit the venv-builder's 3.11/3.12
|
||||
# constraint. Snapshotting and integrity-checking a DB needs only an
|
||||
# interpreter carrying the stdlib sqlite3 module; demanding 3.11/3.12 blocked
|
||||
# updates on stock EL9 (python3.9) and Ubuntu 22.04 (python3.10) boxes for a
|
||||
# reason unrelated to the data — including all-Docker installs, which return
|
||||
# before preflight_check and do every real step inside the container, yet
|
||||
# verified the extracted DB with the HOST's interpreter.
|
||||
# --------------------------------------------------------------------------
|
||||
t="$WORK/t10i"; mkdir -p "$t/bin" "$t/slot/backend/instance" "$t/slot/venv/bin"
|
||||
if [ -z "$PY" ]; then
|
||||
skip "SQLite helpers work without a 3.11/3.12 interpreter (no working python3)"
|
||||
else
|
||||
REAL_PY="$(command -v "$PY")"
|
||||
# An interpreter that answers a version probe with 3.9 but is otherwise a
|
||||
# real Python: makes locate_python fail exactly as it does on EL9, while
|
||||
# `import sqlite3` keeps working. Shadowing all four candidate names keeps
|
||||
# the precondition true regardless of what the host actually has.
|
||||
for n in python3.12 python3.11 python3 python; do
|
||||
cat > "$t/bin/$n" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
case "\$*" in
|
||||
*version_info*) echo "3.9"; exit 0 ;;
|
||||
esac
|
||||
exec "$REAL_PY" "\$@"
|
||||
EOF
|
||||
chmod +x "$t/bin/$n"
|
||||
done
|
||||
cp "$t/bin/python3" "$t/slot/venv/bin/python"
|
||||
"$PY" - "$t/slot/backend/instance/serverkit.db" <<'PYEOF'
|
||||
import sqlite3, sys
|
||||
c = sqlite3.connect(sys.argv[1])
|
||||
c.execute('CREATE TABLE t(id INTEGER PRIMARY KEY, v TEXT)')
|
||||
c.executemany('INSERT INTO t(v) VALUES (?)', [('row%d' % i,) for i in range(100)])
|
||||
c.commit(); c.close()
|
||||
PYEOF
|
||||
el9_rc=0
|
||||
(
|
||||
set -Eeuo pipefail
|
||||
PATH="$t/bin:$PATH"
|
||||
DRY_RUN=0
|
||||
# Precondition: to the venv builder this box now looks like EL9.
|
||||
! locate_python
|
||||
# The sqlite helpers still resolve an interpreter — and prefer the
|
||||
# install's own over anything on PATH, so they stay correct on a box
|
||||
# whose system python is unusable.
|
||||
[ "$(locate_sqlite_python "$t/slot/venv/bin/python")" = "$t/slot/venv/bin/python" ]
|
||||
copy_sqlite_db "$t/slot/backend/instance/serverkit.db" "$t/snap.db"
|
||||
verify_sqlite_db "$t/snap.db"
|
||||
) >/dev/null 2>&1 || el9_rc=$?
|
||||
rows="$("$PY" -c "import sqlite3,sys;print(sqlite3.connect(sys.argv[1]).execute('SELECT COUNT(*) FROM t').fetchone()[0])" "$t/snap.db" 2>/dev/null || true)"
|
||||
if [ "$el9_rc" -eq 0 ] && [ "$rows" = "100" ]; then
|
||||
ok "SQLite snapshot/verify need only sqlite3, not Python 3.11/3.12 (EL9/22.04 boxes)"
|
||||
else
|
||||
bad "sqlite helpers still gated on locate_python: rc=$el9_rc, rows=[$rows], expected 100"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# T10g — a failed IN-PLACE PostgreSQL migration must trigger an automatic
|
||||
# restore from the verified pre-upgrade dump: the DB is shared, so without a
|
||||
|
||||
+41
-4
@@ -843,9 +843,40 @@ atomic_switch() {
|
||||
# even while the panel is writing. Python 3.11/3.12 is guaranteed by
|
||||
# pre-flight; without it we fail rather than fall back to a racy cp.
|
||||
# ---------------------------------------------------------------------------
|
||||
# Snapshotting or integrity-checking a SQLite file needs nothing more than an
|
||||
# interpreter carrying the stdlib `sqlite3` module — NOT the 3.11/3.12 that
|
||||
# rebuild_virtualenv and preflight_check legitimately demand. Reusing
|
||||
# locate_python here silently coupled the DATA-safety paths to the venv-builder
|
||||
# constraint, and blocked updates for a reason unrelated to the data:
|
||||
# * an all-Docker install returns before preflight_check ever runs and does
|
||||
# all its work in the container, yet backup_docker_db verified the extracted
|
||||
# DB on the HOST — so a stock EL9 (python3.9) or Ubuntu 22.04 (python3.10)
|
||||
# host halted with "Could not obtain a VALID database backup", blaming the
|
||||
# backup for a missing interpreter.
|
||||
# * backup_current halts when it cannot snapshot, so the same boxes could
|
||||
# never update at all.
|
||||
# Prefer the install's own venv interpreter: on a real box it is guaranteed
|
||||
# present, guaranteed to have the module, and independent of what is on PATH.
|
||||
locate_sqlite_python() {
|
||||
local c
|
||||
for c in "$@" python3.12 python3.11 python3 python; do
|
||||
[ -n "$c" ] || continue
|
||||
command -v "$c" >/dev/null 2>&1 || continue
|
||||
"$c" -c 'import sqlite3' >/dev/null 2>&1 || continue
|
||||
printf '%s' "$c"
|
||||
return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
copy_sqlite_db() {
|
||||
local src="$1" dest="$2" py
|
||||
py="$(locate_python)" || { warn "No Python 3.11/3.12 available for a consistent DB snapshot"; return 1; }
|
||||
local src="$1" dest="$2" py slot
|
||||
# The DB lives at <slot>/backend/instance/serverkit.db — derive that slot's
|
||||
# interpreter as the preferred candidate. A src outside a slot leaves the
|
||||
# path unchanged, yielding a non-executable candidate that is simply skipped.
|
||||
slot="${src%/backend/instance/*}"
|
||||
py="$(locate_sqlite_python "$slot/venv/bin/python")" \
|
||||
|| { warn "No Python with the sqlite3 module available for a consistent DB snapshot"; return 1; }
|
||||
"$py" - "$src" "$dest" <<'PYEOF'
|
||||
import sqlite3, sys
|
||||
src, dest = sys.argv[1], sys.argv[2]
|
||||
@@ -860,9 +891,15 @@ PYEOF
|
||||
# A backup that was never verified is a hope, not a safety net. Verify every
|
||||
# artifact BEFORE it is allowed to justify proceeding with the update.
|
||||
verify_sqlite_db() {
|
||||
local db="$1" py
|
||||
local db="$1" py active hint=""
|
||||
[ -s "$db" ] || return 1
|
||||
py="$(locate_python)" || return 1
|
||||
# Backups live in BACKUP_DIR, outside any slot, so hint at the active
|
||||
# install's interpreter instead of deriving one from the file's path.
|
||||
active="$(active_real_dir 2>/dev/null || true)"
|
||||
if [ -n "$active" ]; then
|
||||
hint="$active/venv/bin/python"
|
||||
fi
|
||||
py="$(locate_sqlite_python "$hint")" || return 1
|
||||
[ "$("$py" -c "import sqlite3,sys;print(sqlite3.connect(sys.argv[1]).execute('PRAGMA integrity_check').fetchone()[0])" "$db" 2>/dev/null || true)" = "ok" ]
|
||||
}
|
||||
verify_pg_dump() {
|
||||
|
||||
Reference in new issue
Block a user