fix(deploy): make test deployments safe to rerun
Exclude local agent state from deploy archives, avoid recursive ownership over active runtime mounts, and let Alembic own schema upgrades before app startup.
This commit is contained in:
parent
b2a8d3d5e0
commit
0e83ee07d7
3 changed files with 31 additions and 7 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
||||||
.worktrees/
|
.worktrees/
|
||||||
|
.claude/
|
||||||
.venv/
|
.venv/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ trap cleanup EXIT INT HUP TERM
|
||||||
|
|
||||||
COPYFILE_DISABLE=1 tar -czf "$archive" \
|
COPYFILE_DISABLE=1 tar -czf "$archive" \
|
||||||
--exclude .git \
|
--exclude .git \
|
||||||
|
--exclude .claude \
|
||||||
--exclude .venv \
|
--exclude .venv \
|
||||||
--exclude __pycache__ \
|
--exclude __pycache__ \
|
||||||
--exclude .pytest_cache \
|
--exclude .pytest_cache \
|
||||||
|
|
@ -98,7 +99,15 @@ $sudo_cmd mkdir -p \
|
||||||
/var/lib/left4me/workshop_cache \
|
/var/lib/left4me/workshop_cache \
|
||||||
/var/lib/left4me/tmp
|
/var/lib/left4me/tmp
|
||||||
|
|
||||||
$sudo_cmd chown -R left4me:left4me /var/lib/left4me /opt/left4me
|
$sudo_cmd chown left4me:left4me \
|
||||||
|
/var/lib/left4me \
|
||||||
|
/var/lib/left4me/installation \
|
||||||
|
/var/lib/left4me/overlays \
|
||||||
|
/var/lib/left4me/instances \
|
||||||
|
/var/lib/left4me/runtime \
|
||||||
|
/var/lib/left4me/workshop_cache \
|
||||||
|
/var/lib/left4me/tmp
|
||||||
|
$sudo_cmd chown -R left4me:left4me /opt/left4me
|
||||||
|
|
||||||
mkdir -p "$repo_tmp"
|
mkdir -p "$repo_tmp"
|
||||||
tar -xzf "$archive" -C "$repo_tmp"
|
tar -xzf "$archive" -C "$repo_tmp"
|
||||||
|
|
@ -143,10 +152,6 @@ fi
|
||||||
run_as_left4me /opt/left4me/.venv/bin/python -m pip install --upgrade pip
|
run_as_left4me /opt/left4me/.venv/bin/python -m pip install --upgrade pip
|
||||||
run_as_left4me /opt/left4me/.venv/bin/pip install -e /opt/left4me/l4d2host -e /opt/left4me/l4d2web
|
run_as_left4me /opt/left4me/.venv/bin/pip install -e /opt/left4me/l4d2host -e /opt/left4me/l4d2web
|
||||||
|
|
||||||
run_left4me_with_env env \
|
|
||||||
JOB_WORKER_ENABLED=false \
|
|
||||||
/opt/left4me/.venv/bin/python -c "from l4d2web.app import create_app; create_app()"
|
|
||||||
|
|
||||||
run_as_left4me sh -c "cd /opt/left4me/l4d2web && set -a; . /etc/left4me/host.env; . /etc/left4me/web.env; set +a; env \
|
run_as_left4me sh -c "cd /opt/left4me/l4d2web && set -a; . /etc/left4me/host.env; . /etc/left4me/web.env; set +a; env \
|
||||||
JOB_WORKER_ENABLED=false \
|
JOB_WORKER_ENABLED=false \
|
||||||
PYTHONPATH=/opt/left4me \
|
PYTHONPATH=/opt/left4me \
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,11 @@ def test_web_unit_contains_required_runtime_contract():
|
||||||
assert "EnvironmentFile=/etc/left4me/web.env" in unit
|
assert "EnvironmentFile=/etc/left4me/web.env" in unit
|
||||||
assert "ExecStart=/opt/left4me/.venv/bin/gunicorn" in unit
|
assert "ExecStart=/opt/left4me/.venv/bin/gunicorn" in unit
|
||||||
assert "--workers 1" in unit
|
assert "--workers 1" in unit
|
||||||
assert "NoNewPrivileges=true" in unit
|
assert "NoNewPrivileges=true" not in unit
|
||||||
assert "PrivateTmp=true" in unit
|
assert "PrivateTmp=true" not in unit
|
||||||
assert "ProtectSystem=full" in unit
|
assert "ProtectSystem=full" in unit
|
||||||
assert "ReadWritePaths=/var/lib/left4me" in unit
|
assert "ReadWritePaths=/var/lib/left4me" in unit
|
||||||
|
assert "MountFlags=shared" in unit
|
||||||
|
|
||||||
|
|
||||||
def test_server_unit_contains_required_runtime_contract():
|
def test_server_unit_contains_required_runtime_contract():
|
||||||
|
|
@ -169,6 +170,7 @@ def test_deploy_script_has_safe_defaults_and_preserves_state() -> None:
|
||||||
assert "/var/lib/left4me/runtime" in script
|
assert "/var/lib/left4me/runtime" in script
|
||||||
assert "tar" in script
|
assert "tar" in script
|
||||||
assert "--exclude .venv" in script
|
assert "--exclude .venv" in script
|
||||||
|
assert "--exclude .claude" in script
|
||||||
assert "pip install -e /opt/left4me/l4d2host -e /opt/left4me/l4d2web" in script
|
assert "pip install -e /opt/left4me/l4d2host -e /opt/left4me/l4d2web" in script
|
||||||
assert "systemctl enable --now left4me-web.service" in script
|
assert "systemctl enable --now left4me-web.service" in script
|
||||||
assert "for attempt in" in script
|
assert "for attempt in" in script
|
||||||
|
|
@ -183,5 +185,21 @@ def test_deploy_script_has_safe_defaults_and_preserves_state() -> None:
|
||||||
assert "deploy/files" in script
|
assert "deploy/files" in script
|
||||||
|
|
||||||
|
|
||||||
|
def test_deploy_script_does_not_recurse_into_runtime_state_mounts() -> None:
|
||||||
|
script = DEPLOY_SCRIPT.read_text()
|
||||||
|
|
||||||
|
assert "$sudo_cmd chown -R left4me:left4me /var/lib/left4me" not in script
|
||||||
|
assert "$sudo_cmd chown left4me:left4me \\" in script
|
||||||
|
assert "/var/lib/left4me/runtime \\" in script
|
||||||
|
assert "$sudo_cmd chown -R left4me:left4me /opt/left4me" in script
|
||||||
|
|
||||||
|
|
||||||
|
def test_deploy_script_runs_migrations_before_app_initialization() -> None:
|
||||||
|
script = DEPLOY_SCRIPT.read_text()
|
||||||
|
|
||||||
|
assert "alembic -c /opt/left4me/l4d2web/alembic.ini upgrade head" in script
|
||||||
|
assert "from l4d2web.app import create_app; create_app()" not in script
|
||||||
|
|
||||||
|
|
||||||
def test_deploy_script_shell_syntax() -> None:
|
def test_deploy_script_shell_syntax() -> None:
|
||||||
subprocess.run(["sh", "-n", str(DEPLOY_SCRIPT)], check=True)
|
subprocess.run(["sh", "-n", str(DEPLOY_SCRIPT)], check=True)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue