mirror of
https://github.com/hansjone/netx.git
synced 2026-10-15 04:53:20 +08:00
- packaging/linux: netx-<ver>-linux-x86_64.tar.gz with bundled Python 3.12, PostgreSQL 16 and web/dist (glibc >= 2.17). install.sh (install/update/ reinstall), netxctl (start/stop/status/logs, set-port, set-bind, set-pg-port, reconfigure-db, check-update/update/auto-update, backup, uninstall), systemd units, nohup fallback without systemd. Privilege drop, detaching and tar go through the bundled Python, so bare images without su/runuser/setsid/tar work. - Updates: same GitHub/Forgejo/manifest sources as Windows, sha256 verified, pre-update pg_dump, automatic rollback when the new version does not come up. - Non-loopback bind: generated bootstrap admin password and NETX_UME_VERIFY_TLS=true, as security_bootstrap requires. - Build in manylinux2014 + check_bundle.sh (GLIBC <= 2.17, no missing libs); release-linux.yml builds on v* tags and smoke-tests offline on CentOS 7, Rocky 9, Ubuntu 18.04/24.04, Debian 12, openSUSE Leap 15 and openEuler 22.03 before attaching to the release. - Windows: Setup DB page gets a bundled PG port field and /BundledPgPort=; set_pg_port.ps1 + tray "Built-in database port"; reconfigure keeps the configured port; postgresql.conf is written without a BOM (PS 5.1 Set-Content -Encoding utf8 broke postgres). - Forgejo/GitHub publish scripts include the Linux package. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
109 lines
4.9 KiB
Bash
Executable file
109 lines
4.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Offline install smoke test, run inside a bare distro container as root:
|
|
# docker run --rm --network none -v "$PWD/packaging/release:/pkg:ro" \
|
|
# -v "$PWD/packaging/linux/smoke_test.sh:/smoke.sh:ro" centos:7 bash /smoke.sh /pkg/netx-X-linux-x86_64.tar.gz
|
|
# Exercises: install (custom ports) -> login -> set-port -> set-pg-port -> update
|
|
# (same package, with backup) -> data survives -> stop -> uninstall --purge.
|
|
set -euo pipefail
|
|
TARBALL="$1"
|
|
PKGDIR="${2:-}" # pre-extracted package (minimal images may lack tar)
|
|
PORT1=18890 PORT2=18891 PG1=25432 PG2=25433
|
|
|
|
step() { printf '\n\033[36m### %s\033[0m\n' "$*"; }
|
|
fail() { printf '\033[31m[SMOKE FAIL] %s\033[0m\n' "$*" >&2; tail -n 60 /var/lib/netx/logs/*.log 2>/dev/null >&2 || true; exit 1; }
|
|
|
|
PY() { /opt/netx/current/python/bin/python3 -I -c "$@"; }
|
|
|
|
login() { # login <port> -> prints access token
|
|
PY "
|
|
import json, urllib.request
|
|
req = urllib.request.Request('http://127.0.0.1:$1/v1/auth/login',
|
|
data=json.dumps({'username': 'admin', 'password': open('/var/lib/netx/.env').read().split('NETX_BOOTSTRAP_ADMIN_PASSWORD=')[1].split()[0]}).encode(),
|
|
headers={'Content-Type': 'application/json'})
|
|
import time
|
|
for attempt in range(3):
|
|
try:
|
|
body = json.load(urllib.request.urlopen(req, timeout=60))
|
|
break
|
|
except Exception:
|
|
if attempt == 2:
|
|
raise
|
|
time.sleep(5)
|
|
print(body.get('access_token') or body['token'])
|
|
"
|
|
}
|
|
|
|
health() { PY "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:$1/health', timeout=5).status == 200 else 1)" 2>/dev/null; }
|
|
|
|
listening() { # listening <port> -> 0 when something accepts on 127.0.0.1:<port>
|
|
PY "import socket,sys; s=socket.socket(); s.settimeout(1); sys.exit(s.connect_ex(('127.0.0.1', $1)))"
|
|
}
|
|
|
|
step "environment: $(. /etc/os-release && echo "${PRETTY_NAME}") / $(getconf GNU_LIBC_VERSION)"
|
|
if [[ -n "${PKGDIR}" ]]; then
|
|
work="$(mktemp -d)"
|
|
cp -a "${PKGDIR}" "${work}/"
|
|
else
|
|
work="$(mktemp -d)"
|
|
tar xzf "${TARBALL}" -C "${work}"
|
|
fi
|
|
pkg="$(echo "${work}"/netx-*)"
|
|
|
|
step "install (bundled PG ${PG1}, API ${PORT1})"
|
|
"${pkg}/install.sh" --yes --no-service --db bundled --port "${PORT1}" --pg-port "${PG1}" || fail "install"
|
|
health "${PORT1}" || fail "health after install"
|
|
listening "${PG1}" || fail "PG not on ${PG1}"
|
|
token="$(login "${PORT1}")" || fail "login"
|
|
[[ -n "${token}" ]] || fail "empty token"
|
|
netxctl status || fail "status"
|
|
|
|
step "marker row survives update"
|
|
PGPASSWORD="$(grep '^NETX_DATABASE_URL=' /var/lib/netx/.env | sed 's#.*://netx:\([^@]*\)@.*#\1#')" \
|
|
/opt/netx/current/pgsql/bin/psql -h 127.0.0.1 -p "${PG1}" -U netx -d netx -v ON_ERROR_STOP=1 \
|
|
-c "CREATE TABLE IF NOT EXISTS smoke_marker(v text); INSERT INTO smoke_marker VALUES ('kept');" || fail "marker"
|
|
|
|
step "set-port ${PORT2}"
|
|
netxctl set-port "${PORT2}" || fail "set-port"
|
|
health "${PORT2}" || fail "health after set-port"
|
|
|
|
step "set-pg-port ${PG2}"
|
|
netxctl set-pg-port "${PG2}" || fail "set-pg-port"
|
|
health "${PORT2}" || fail "health after set-pg-port"
|
|
listening "${PG2}" || fail "PG not on ${PG2}"
|
|
listening "${PG1}" && fail "PG still on ${PG1}"
|
|
|
|
step "set-pg-port to a busy port is refused"
|
|
if netxctl set-pg-port "${PORT2}"; then fail "busy port accepted"; fi
|
|
health "${PORT2}" || fail "health after refused port change"
|
|
|
|
step "update with the same package (--force path via install.sh --mode update)"
|
|
"${pkg}/install.sh" --mode update --yes || fail "update"
|
|
health "${PORT2}" || fail "health after update"
|
|
ls /var/lib/netx/backups/pre-*.dump >/dev/null || fail "no pre-update dump"
|
|
out="$(PGPASSWORD="$(grep '^NETX_DATABASE_URL=' /var/lib/netx/.env | sed 's#.*://netx:\([^@]*\)@.*#\1#')" \
|
|
/opt/netx/current/pgsql/bin/psql -h 127.0.0.1 -p "${PG2}" -U netx -d netx -tAc "SELECT v FROM smoke_marker")"
|
|
[[ "${out}" == "kept" ]] || fail "marker lost: ${out}"
|
|
login "${PORT2}" >/dev/null || fail "login after update"
|
|
|
|
step "offline update via netxctl update --file (same version needs --force)"
|
|
if netxctl update --file "${TARBALL}" --yes; then fail "same-version update without --force accepted"; fi
|
|
netxctl update --file "${TARBALL}" --yes --force || fail "netxctl update --file --force"
|
|
health "${PORT2}" || fail "health after netxctl update"
|
|
|
|
step "backup"
|
|
netxctl backup /tmp/netx-backup.tar.gz || fail "backup"
|
|
netxctl_admin_list="$(/opt/netx/current/python/bin/python3 -I /opt/netx/current/packaging/linux/netx_admin.py tar-list /tmp/netx-backup.tar.gz)"
|
|
[[ "${netxctl_admin_list}" == *netx.dump* ]] || fail "backup content"
|
|
|
|
step "stop"
|
|
netxctl stop || fail "stop"
|
|
health "${PORT2}" && fail "still healthy after stop"
|
|
listening "${PG2}" && fail "PG still running after stop"
|
|
pgrep -f netx_api >/dev/null 2>&1 && fail "netx_api processes left" || true
|
|
|
|
step "start again + uninstall --purge"
|
|
netxctl start || fail "restart"
|
|
netxctl uninstall --purge --yes || fail "uninstall"
|
|
[[ ! -e /opt/netx && ! -e /var/lib/netx && ! -e /usr/bin/netxctl ]] || fail "leftovers after purge"
|
|
|
|
printf '\n\033[32m[SMOKE OK] %s\033[0m\n' "$(. /etc/os-release && echo "${PRETTY_NAME}")"
|