77948ef56c
The per-agent companion container (the egress/git-gate/supervise data plane run once per bottle) is the pre-consolidation architecture. Remove it and disable the backends that still depend on it, per the #385 thread. - Delete `backend/docker/sidecar_bundle.py`; docker's live path uses the consolidated shared gateway, not a per-bottle bundle. - Disable the firecracker and macos-container backends: their `launch()` fails closed (they launched a per-bottle companion; firecracker's consolidated relaunch is #354, macos follows). Their `enumerate` return empty and `cleanup` drop the companion-container discovery (firecracker keeps VMM/run-dir cleanup). - Fail-close both backends' `egress_apply` reload (it signalled the per-bottle container); consolidated egress policy resolves per-request against the orchestrator, so gateway-side apply is a follow-up. - Rename `egress_sidecar_env_entries` → `egress_gateway_env_entries`, `SIDECAR_PORTS` → `GATEWAY_PORTS`. - Move the shared DockerBottlePlan fixture to `tests/unit/_docker_bottle_plan.py`; delete tests for the removed launch paths; update cleanup/egress-apply tests. Docker consolidated launch verified end-to-end (multitenant isolation integration test passes). macos/firecracker are intentionally disabled. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck
70 lines
1.8 KiB
Python
70 lines
1.8 KiB
Python
"""Cleanup for the Firecracker backend.
|
|
|
|
Orphans are: firecracker VMM processes whose config lives under our run
|
|
dir, and the per-bottle run dirs. TAP slots free themselves (the flock
|
|
drops when the launcher exits), so there is nothing to reclaim there.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import shutil
|
|
import signal
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
from ...log import info
|
|
from . import util
|
|
from .bottle_cleanup_plan import FirecrackerBottleCleanupPlan
|
|
|
|
|
|
def _run_root() -> Path:
|
|
return util.cache_dir() / "run"
|
|
|
|
|
|
def _orphan_vm_pids() -> list[int]:
|
|
"""firecracker processes whose --config-file is under our run dir."""
|
|
run_root = str(_run_root())
|
|
result = subprocess.run(
|
|
["pgrep", "-a", "firecracker"],
|
|
capture_output=True, text=True, check=False,
|
|
)
|
|
if result.returncode != 0:
|
|
return []
|
|
pids: list[int] = []
|
|
for line in result.stdout.splitlines():
|
|
parts = line.split(None, 1)
|
|
if len(parts) != 2 or run_root not in parts[1]:
|
|
continue
|
|
try:
|
|
pids.append(int(parts[0]))
|
|
except ValueError:
|
|
continue
|
|
return pids
|
|
|
|
|
|
def _run_dirs() -> list[str]:
|
|
run_root = _run_root()
|
|
if not run_root.is_dir():
|
|
return []
|
|
return sorted(str(p) for p in run_root.iterdir() if p.is_dir())
|
|
|
|
|
|
def prepare_cleanup() -> FirecrackerBottleCleanupPlan:
|
|
return FirecrackerBottleCleanupPlan(
|
|
vm_pids=tuple(_orphan_vm_pids()),
|
|
run_dirs=tuple(_run_dirs()),
|
|
)
|
|
|
|
|
|
def cleanup(plan: FirecrackerBottleCleanupPlan) -> None:
|
|
for pid in plan.vm_pids:
|
|
info(f"kill firecracker VM pid {pid}")
|
|
try:
|
|
os.kill(pid, signal.SIGTERM)
|
|
except ProcessLookupError:
|
|
pass
|
|
for path in plan.run_dirs:
|
|
info(f"rm -rf {path}")
|
|
shutil.rmtree(path, ignore_errors=True)
|