chore(deploy): provision l4d2-sandbox + bubblewrap; drop globals refresh timer
deploy-test-server.sh: provisions the l4d2-sandbox system user (no home,
nologin shell) and installs the bubblewrap apt/dnf package; copies the
left4me-script-sandbox helper into /usr/local/libexec/left4me with mode
0755. Drops the global_overlay_cache directory provisioning, the
refresh-global-overlays unit installation, and the timer enable.
Deletes the orphaned left4me-refresh-global-overlays.{service,timer}
files. Trims the matching paragraph from deploy/README.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
75e703e1a4
commit
e51a4d58a4
5 changed files with 39 additions and 55 deletions
|
|
@ -42,10 +42,6 @@ deploy/deploy-test-server.sh deploy-user@example-host
|
||||||
|
|
||||||
The SSH user must be able to run `sudo` on the target host. The deployment configures system packages, directories, environment files, helper scripts, sudoers rules, Python dependencies, and systemd units.
|
The SSH user must be able to run `sudo` on the target host. The deployment configures system packages, directories, environment files, helper scripts, sudoers rules, Python dependencies, and systemd units.
|
||||||
|
|
||||||
## Scheduled Jobs
|
|
||||||
|
|
||||||
`left4me-refresh-global-overlays.timer` runs daily with `Persistent=true`. It invokes `flask refresh-global-overlays`, which only enqueues a `refresh_global_overlays` job; downloads and rebuilds run in the web worker and are visible in the normal job log UI.
|
|
||||||
|
|
||||||
## Admin Bootstrap
|
## Admin Bootstrap
|
||||||
|
|
||||||
Set the bootstrap credentials in the environment when creating the first admin user:
|
Set the bootstrap credentials in the environment when creating the first admin user:
|
||||||
|
|
|
||||||
|
|
@ -77,11 +77,17 @@ if ! id left4me >/dev/null 2>&1; then
|
||||||
$sudo_cmd useradd --system --home-dir /var/lib/left4me --create-home --shell /usr/sbin/nologin left4me
|
$sudo_cmd useradd --system --home-dir /var/lib/left4me --create-home --shell /usr/sbin/nologin left4me
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Sandbox uid for script-overlay builds. No home, no login shell — the bwrap
|
||||||
|
# invocation uses --uid/--gid to drop to it.
|
||||||
|
if ! id l4d2-sandbox >/dev/null 2>&1; then
|
||||||
|
$sudo_cmd useradd --system --no-create-home --shell /usr/sbin/nologin l4d2-sandbox
|
||||||
|
fi
|
||||||
|
|
||||||
if command -v apt-get >/dev/null 2>&1; then
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
$sudo_cmd apt-get update
|
$sudo_cmd apt-get update
|
||||||
$sudo_cmd apt-get install -y python3 python3-venv python3-pip curl ca-certificates tar gzip util-linux sudo
|
$sudo_cmd apt-get install -y python3 python3-venv python3-pip curl ca-certificates tar gzip util-linux sudo bubblewrap
|
||||||
elif command -v dnf >/dev/null 2>&1; then
|
elif command -v dnf >/dev/null 2>&1; then
|
||||||
$sudo_cmd dnf install -y python3 python3-pip curl ca-certificates tar gzip util-linux sudo
|
$sudo_cmd dnf install -y python3 python3-pip curl ca-certificates tar gzip util-linux sudo bubblewrap
|
||||||
else
|
else
|
||||||
printf 'Unsupported package manager: expected apt-get or dnf\n' >&2
|
printf 'Unsupported package manager: expected apt-get or dnf\n' >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|
@ -97,7 +103,6 @@ $sudo_cmd mkdir -p \
|
||||||
/var/lib/left4me/instances \
|
/var/lib/left4me/instances \
|
||||||
/var/lib/left4me/runtime \
|
/var/lib/left4me/runtime \
|
||||||
/var/lib/left4me/workshop_cache \
|
/var/lib/left4me/workshop_cache \
|
||||||
/var/lib/left4me/global_overlay_cache \
|
|
||||||
/var/lib/left4me/tmp
|
/var/lib/left4me/tmp
|
||||||
|
|
||||||
$sudo_cmd chown left4me:left4me \
|
$sudo_cmd chown left4me:left4me \
|
||||||
|
|
@ -107,7 +112,6 @@ $sudo_cmd chown left4me:left4me \
|
||||||
/var/lib/left4me/instances \
|
/var/lib/left4me/instances \
|
||||||
/var/lib/left4me/runtime \
|
/var/lib/left4me/runtime \
|
||||||
/var/lib/left4me/workshop_cache \
|
/var/lib/left4me/workshop_cache \
|
||||||
/var/lib/left4me/global_overlay_cache \
|
|
||||||
/var/lib/left4me/tmp
|
/var/lib/left4me/tmp
|
||||||
$sudo_cmd chown -R left4me:left4me /opt/left4me
|
$sudo_cmd chown -R left4me:left4me /opt/left4me
|
||||||
|
|
||||||
|
|
@ -126,12 +130,11 @@ $sudo_cmd chown -R left4me:left4me /opt/left4me
|
||||||
|
|
||||||
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/lib/systemd/system/left4me-web.service /usr/local/lib/systemd/system/left4me-web.service
|
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/lib/systemd/system/left4me-web.service /usr/local/lib/systemd/system/left4me-web.service
|
||||||
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/lib/systemd/system/left4me-server@.service /usr/local/lib/systemd/system/left4me-server@.service
|
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/lib/systemd/system/left4me-server@.service /usr/local/lib/systemd/system/left4me-server@.service
|
||||||
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/lib/systemd/system/left4me-refresh-global-overlays.service /usr/local/lib/systemd/system/left4me-refresh-global-overlays.service
|
|
||||||
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/lib/systemd/system/left4me-refresh-global-overlays.timer /usr/local/lib/systemd/system/left4me-refresh-global-overlays.timer
|
|
||||||
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/libexec/left4me/left4me-systemctl /usr/local/libexec/left4me/left4me-systemctl
|
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/libexec/left4me/left4me-systemctl /usr/local/libexec/left4me/left4me-systemctl
|
||||||
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/libexec/left4me/left4me-journalctl /usr/local/libexec/left4me/left4me-journalctl
|
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/libexec/left4me/left4me-journalctl /usr/local/libexec/left4me/left4me-journalctl
|
||||||
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/libexec/left4me/left4me-overlay /usr/local/libexec/left4me/left4me-overlay
|
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/libexec/left4me/left4me-overlay /usr/local/libexec/left4me/left4me-overlay
|
||||||
$sudo_cmd chmod 0755 /usr/local/libexec/left4me/left4me-systemctl /usr/local/libexec/left4me/left4me-journalctl /usr/local/libexec/left4me/left4me-overlay
|
$sudo_cmd cp /opt/left4me/deploy/files/usr/local/libexec/left4me/left4me-script-sandbox /usr/local/libexec/left4me/left4me-script-sandbox
|
||||||
|
$sudo_cmd chmod 0755 /usr/local/libexec/left4me/left4me-systemctl /usr/local/libexec/left4me/left4me-journalctl /usr/local/libexec/left4me/left4me-overlay /usr/local/libexec/left4me/left4me-script-sandbox
|
||||||
$sudo_cmd cp /opt/left4me/deploy/files/etc/sudoers.d/left4me /etc/sudoers.d/left4me
|
$sudo_cmd cp /opt/left4me/deploy/files/etc/sudoers.d/left4me /etc/sudoers.d/left4me
|
||||||
$sudo_cmd chmod 0440 /etc/sudoers.d/left4me
|
$sudo_cmd chmod 0440 /etc/sudoers.d/left4me
|
||||||
$sudo_cmd visudo -cf /etc/sudoers.d/left4me
|
$sudo_cmd visudo -cf /etc/sudoers.d/left4me
|
||||||
|
|
@ -197,7 +200,6 @@ fi
|
||||||
$sudo_cmd systemctl daemon-reload
|
$sudo_cmd systemctl daemon-reload
|
||||||
$sudo_cmd systemctl enable --now left4me-web.service
|
$sudo_cmd systemctl enable --now left4me-web.service
|
||||||
$sudo_cmd systemctl restart left4me-web.service
|
$sudo_cmd systemctl restart left4me-web.service
|
||||||
$sudo_cmd systemctl enable --now left4me-refresh-global-overlays.timer
|
|
||||||
for attempt in 1 2 3 4 5 6 7 8 9 10; do
|
for attempt in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
if curl -fsS http://127.0.0.1:8000/health; then
|
if curl -fsS http://127.0.0.1:8000/health; then
|
||||||
exit 0
|
exit 0
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
[Unit]
|
|
||||||
Description=left4me refresh global map overlays
|
|
||||||
After=network-online.target left4me-web.service
|
|
||||||
Wants=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=oneshot
|
|
||||||
User=left4me
|
|
||||||
Group=left4me
|
|
||||||
WorkingDirectory=/opt/left4me
|
|
||||||
Environment=HOME=/var/lib/left4me
|
|
||||||
Environment=PATH=/opt/left4me/.venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
|
||||||
EnvironmentFile=/etc/left4me/host.env
|
|
||||||
EnvironmentFile=/etc/left4me/web.env
|
|
||||||
ExecStart=/opt/left4me/.venv/bin/flask --app l4d2web.app:create_app refresh-global-overlays
|
|
||||||
ProtectSystem=full
|
|
||||||
ReadWritePaths=/var/lib/left4me
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
[Unit]
|
|
||||||
Description=Daily left4me global map overlay refresh
|
|
||||||
|
|
||||||
[Timer]
|
|
||||||
OnCalendar=daily
|
|
||||||
Persistent=true
|
|
||||||
Unit=left4me-refresh-global-overlays.service
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=timers.target
|
|
||||||
|
|
@ -11,6 +11,7 @@ WEB_UNIT = DEPLOY / "files/usr/local/lib/systemd/system/left4me-web.service"
|
||||||
SERVER_UNIT = DEPLOY / "files/usr/local/lib/systemd/system/left4me-server@.service"
|
SERVER_UNIT = DEPLOY / "files/usr/local/lib/systemd/system/left4me-server@.service"
|
||||||
GLOBAL_REFRESH_SERVICE = DEPLOY / "files/usr/local/lib/systemd/system/left4me-refresh-global-overlays.service"
|
GLOBAL_REFRESH_SERVICE = DEPLOY / "files/usr/local/lib/systemd/system/left4me-refresh-global-overlays.service"
|
||||||
GLOBAL_REFRESH_TIMER = DEPLOY / "files/usr/local/lib/systemd/system/left4me-refresh-global-overlays.timer"
|
GLOBAL_REFRESH_TIMER = DEPLOY / "files/usr/local/lib/systemd/system/left4me-refresh-global-overlays.timer"
|
||||||
|
SANDBOX_UNIT_DIR = DEPLOY / "files/usr/local/lib/systemd/system"
|
||||||
SYSTEMCTL_HELPER = DEPLOY / "files/usr/local/libexec/left4me/left4me-systemctl"
|
SYSTEMCTL_HELPER = DEPLOY / "files/usr/local/libexec/left4me/left4me-systemctl"
|
||||||
JOURNALCTL_HELPER = DEPLOY / "files/usr/local/libexec/left4me/left4me-journalctl"
|
JOURNALCTL_HELPER = DEPLOY / "files/usr/local/libexec/left4me/left4me-journalctl"
|
||||||
OVERLAY_HELPER = DEPLOY / "files/usr/local/libexec/left4me/left4me-overlay"
|
OVERLAY_HELPER = DEPLOY / "files/usr/local/libexec/left4me/left4me-overlay"
|
||||||
|
|
@ -270,26 +271,38 @@ 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)
|
||||||
|
|
||||||
|
|
||||||
def test_global_refresh_timer_units_exist_and_enqueue_only():
|
def test_globals_refresh_units_removed():
|
||||||
service = GLOBAL_REFRESH_SERVICE.read_text()
|
"""Global-overlays subsystem deleted in favor of script overlays."""
|
||||||
timer = GLOBAL_REFRESH_TIMER.read_text()
|
assert not GLOBAL_REFRESH_SERVICE.exists()
|
||||||
|
assert not GLOBAL_REFRESH_TIMER.exists()
|
||||||
assert "User=left4me" in service
|
|
||||||
assert "EnvironmentFile=/etc/left4me/host.env" in service
|
|
||||||
assert "EnvironmentFile=/etc/left4me/web.env" in service
|
|
||||||
assert "flask --app l4d2web.app:create_app refresh-global-overlays" in service
|
|
||||||
assert "OnCalendar=daily" in timer
|
|
||||||
assert "Persistent=true" in timer
|
|
||||||
assert "WantedBy=timers.target" in timer
|
|
||||||
|
|
||||||
|
|
||||||
def test_deploy_script_installs_and_enables_global_refresh_timer():
|
def test_deploy_script_does_not_reference_globals_subsystem():
|
||||||
script = DEPLOY_SCRIPT.read_text()
|
script = DEPLOY_SCRIPT.read_text()
|
||||||
|
|
||||||
assert "/var/lib/left4me/global_overlay_cache" in script
|
assert "/var/lib/left4me/global_overlay_cache" not in script
|
||||||
assert "left4me-refresh-global-overlays.service" in script
|
assert "left4me-refresh-global-overlays" not in script
|
||||||
assert "left4me-refresh-global-overlays.timer" in script
|
|
||||||
assert "systemctl enable --now left4me-refresh-global-overlays.timer" in script
|
|
||||||
|
def test_deploy_script_provisions_sandbox_user():
|
||||||
|
script = DEPLOY_SCRIPT.read_text()
|
||||||
|
assert "useradd --system --no-create-home --shell /usr/sbin/nologin l4d2-sandbox" in script
|
||||||
|
|
||||||
|
|
||||||
|
def test_deploy_script_installs_bubblewrap():
|
||||||
|
install_lines = [
|
||||||
|
line for line in DEPLOY_SCRIPT.read_text().splitlines()
|
||||||
|
if ("apt-get install" in line or "dnf install" in line)
|
||||||
|
]
|
||||||
|
assert install_lines, "expected at least one apt/dnf install line"
|
||||||
|
for line in install_lines:
|
||||||
|
assert "bubblewrap" in line, f"missing bubblewrap in install line: {line}"
|
||||||
|
|
||||||
|
|
||||||
|
def test_deploy_script_installs_script_sandbox_helper():
|
||||||
|
script = DEPLOY_SCRIPT.read_text()
|
||||||
|
assert "/usr/local/libexec/left4me/left4me-script-sandbox" in script
|
||||||
|
assert "chmod 0755" in script and "left4me-script-sandbox" in script
|
||||||
|
|
||||||
|
|
||||||
def test_script_sandbox_helper_present():
|
def test_script_sandbox_helper_present():
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue