feat(firecracker): portable systemd-unit install for the network pool
Make the network pool a persistent, distro-uniform resource instead of a non-persistent per-distro shell command. systemd is the common denominator across Debian/Ubuntu/Fedora/RHEL/Arch/… (and NixOS), so `backend setup` on any systemd host now installs one bot-bottle-owned oneshot unit (bot-bottle-firecracker-netpool.service): params pinned via Environment= (so it doesn't depend on $SUDO_USER at boot), ExecStart/Stop delegating to the bundled bring-up script (single source of logic). - render_systemd_unit() in netpool.py (derived from the same constants as the shell script + nix module). - backend setup: install + enable the unit directly when run as root, else print a self-contained copy-paste block. NixOS keeps its declarative module (which produces the same-named unit); non-systemd hosts fall back to the raw imperative script. - backend teardown: symmetric — disable + remove the unit. - backend status: report the unit's active/inactive state so you can tell a persistent install from an imperative one. Net: one install path (`backend setup`), persistent, identical across distros; per-distro variance shrinks to installing nft + iproute2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck
This commit is contained in:
@@ -73,6 +73,21 @@ class TestNetpoolRenderers(unittest.TestCase):
|
||||
self.assertIn("BOT_BOTTLE_FC_POOL_SIZE=3", out)
|
||||
self.assertIn("firecracker-netpool.sh up", out)
|
||||
|
||||
def test_systemd_unit_pins_params_and_calls_script(self):
|
||||
# The portable install: one oneshot unit, params pinned via
|
||||
# Environment= (must not depend on $SUDO_USER at boot), delegating
|
||||
# bring-up/teardown to the bundled script.
|
||||
script = "/opt/bb/scripts/firecracker-netpool.sh"
|
||||
with patch.dict(os.environ, {"BOT_BOTTLE_FC_POOL_SIZE": "4"}):
|
||||
unit = netpool.render_systemd_unit("alice", script)
|
||||
self.assertIn("Type=oneshot", unit)
|
||||
self.assertIn("BOT_BOTTLE_FC_POOL_SIZE=4", unit)
|
||||
self.assertIn("BOT_BOTTLE_FC_OWNER=alice", unit)
|
||||
self.assertIn(f"BOT_BOTTLE_FC_IP_BASE={netpool.ip_base()}", unit)
|
||||
self.assertIn(f"ExecStart={script} up", unit)
|
||||
self.assertIn(f"ExecStop={script} down", unit)
|
||||
self.assertIn("WantedBy=multi-user.target", unit)
|
||||
|
||||
|
||||
class TestFirecrackerStatus(unittest.TestCase):
|
||||
"""`status()` gates launch: ready == TAP pool present + no overlap.
|
||||
|
||||
Reference in New Issue
Block a user