From 26f3d270b0434707316656af9a920704c6f41f99 Mon Sep 17 00:00:00 2001 From: mwiegand Date: Sun, 10 May 2026 01:04:12 +0200 Subject: [PATCH] feat(deploy): wire nft marking + CAKE shaper into deploy script Installs nftables via apt/dnf, copies left4me-mark.nft and left4me-apply-cake helper into system paths, conditionally seeds cake.env (preserving operator edits), and enables left4me-nft-mark.service + left4me-cake.service on deploy. Co-Authored-By: Claude Opus 4.7 (1M context) --- deploy/deploy-test-server.sh | 28 ++++++++++++++++++++--- deploy/tests/test_deploy_artifacts.py | 32 +++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/deploy/deploy-test-server.sh b/deploy/deploy-test-server.sh index ff92dca..01c70c9 100755 --- a/deploy/deploy-test-server.sh +++ b/deploy/deploy-test-server.sh @@ -85,9 +85,9 @@ fi if command -v apt-get >/dev/null 2>&1; then $sudo_cmd apt-get update - $sudo_cmd apt-get install -y python3 python3-venv python3-pip curl ca-certificates tar gzip util-linux sudo coreutils p7zip-full + $sudo_cmd apt-get install -y python3 python3-venv python3-pip curl ca-certificates tar gzip util-linux sudo coreutils p7zip-full nftables 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 coreutils p7zip p7zip-plugins + $sudo_cmd dnf install -y python3 python3-pip curl ca-certificates tar gzip util-linux sudo coreutils p7zip p7zip-plugins nftables else printf 'Unsupported package manager: expected apt-get or dnf\n' >&2 exit 1 @@ -98,6 +98,7 @@ $sudo_cmd mkdir -p \ /opt/left4me \ /usr/local/lib/systemd/system \ /usr/local/libexec/left4me \ + /usr/local/lib/left4me/nft \ /var/lib/left4me/installation \ /var/lib/left4me/overlays \ /var/lib/left4me/instances \ @@ -138,6 +139,8 @@ $sudo_cmd cp /opt/left4me/deploy/files/usr/local/lib/systemd/system/left4me-web. $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/l4d2-game.slice /usr/local/lib/systemd/system/l4d2-game.slice $sudo_cmd cp /opt/left4me/deploy/files/usr/local/lib/systemd/system/l4d2-build.slice /usr/local/lib/systemd/system/l4d2-build.slice +$sudo_cmd cp /opt/left4me/deploy/files/usr/local/lib/systemd/system/left4me-nft-mark.service /usr/local/lib/systemd/system/left4me-nft-mark.service +$sudo_cmd cp /opt/left4me/deploy/files/usr/local/lib/systemd/system/left4me-cake.service /usr/local/lib/systemd/system/left4me-cake.service # CPU isolation via cgroup-v2 AllowedCPUs= drop-ins. Pin everything that # isn't a live game server to core 0; give game servers cores 1..N-1. @@ -176,7 +179,8 @@ $sudo_cmd cp /opt/left4me/deploy/files/usr/local/libexec/left4me/left4me-systemc $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-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/usr/local/libexec/left4me/left4me-apply-cake /usr/local/libexec/left4me/left4me-apply-cake +$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 /usr/local/libexec/left4me/left4me-apply-cake $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 visudo -cf /etc/sudoers.d/left4me @@ -190,6 +194,12 @@ $sudo_cmd install -m 0644 -o root -g root \ /opt/left4me/deploy/files/etc/left4me/sandbox-resolv.conf \ /etc/left4me/sandbox-resolv.conf +# Network packet marking + shaping. See spec +# docs/superpowers/specs/2026-05-10-l4d2-network-shaping-design.md. +$sudo_cmd install -m 0644 -o root -g root \ + /opt/left4me/deploy/files/usr/local/lib/left4me/nft/left4me-mark.nft \ + /usr/local/lib/left4me/nft/left4me-mark.nft + # Host perf-baseline sysctls. Apply with `sysctl --system` so values # take effect this deploy, not on next reboot. $sudo_cmd install -m 0644 -o root -g root \ @@ -197,6 +207,16 @@ $sudo_cmd install -m 0644 -o root -g root \ /etc/sysctl.d/99-left4me.conf $sudo_cmd sysctl --system >/dev/null +# CAKE config: ship the template only if the operator hasn't created one +# (their LEFT4ME_UPLINK_MBIT value must survive re-deploys). +if [ -e /etc/left4me/cake.env ]; then + : # operator file present; leave it intact +else + $sudo_cmd install -m 0644 -o root -g root \ + /opt/left4me/deploy/files/etc/left4me/cake.env \ + /etc/left4me/cake.env +fi + # Stomp the file every deploy so newly added vars reach existing boxes. # SECRET_KEY is derived from /etc/machine-id so it stays stable across # redeploys (no session invalidation) without persisting state in /etc. @@ -313,6 +333,8 @@ run_left4me_with_env env \ seed-script-overlays /opt/left4me/examples/script-overlays $sudo_cmd systemctl daemon-reload +$sudo_cmd systemctl enable --now left4me-nft-mark.service +$sudo_cmd systemctl enable --now left4me-cake.service $sudo_cmd systemctl enable --now left4me-web.service $sudo_cmd systemctl restart left4me-web.service for attempt in 1 2 3 4 5 6 7 8 9 10; do diff --git a/deploy/tests/test_deploy_artifacts.py b/deploy/tests/test_deploy_artifacts.py index bdc1edb..55be1a6 100644 --- a/deploy/tests/test_deploy_artifacts.py +++ b/deploy/tests/test_deploy_artifacts.py @@ -823,3 +823,35 @@ def test_cake_unit_runs_helper_in_apply_and_clear_modes(): "ExecStop=/usr/local/libexec/left4me/left4me-apply-cake clear" in text ) assert "WantedBy=multi-user.target" in text + + +def test_deploy_script_installs_network_shaping_artifacts(): + script = DEPLOY_SCRIPT.read_text() + + # nftables: package install on both apt and dnf paths. + apt_lines = [l for l in script.splitlines() if "apt-get install" in l] + dnf_lines = [l for l in script.splitlines() if "dnf install" in l] + assert apt_lines and dnf_lines + for line in apt_lines: + assert "nftables" in line, line + for line in dnf_lines: + assert "nftables" in line, line + + # nft rules + unit copied to system paths. + assert "/usr/local/lib/left4me/nft/left4me-mark.nft" in script + assert ( + "/usr/local/lib/systemd/system/left4me-nft-mark.service" in script + ) + assert "systemctl enable --now left4me-nft-mark.service" in script + + # CAKE helper + unit copied; helper made executable. + assert "/usr/local/libexec/left4me/left4me-apply-cake" in script + assert ( + "/usr/local/lib/systemd/system/left4me-cake.service" in script + ) + assert "chmod 0755" in script and "left4me-apply-cake" in script + assert "systemctl enable --now left4me-cake.service" in script + + # cake.env: copied only if absent (operator edits survive re-deploys). + assert "/etc/left4me/cake.env" in script + assert "[ -e /etc/left4me/cake.env ]" in script