import subprocess import time from collections.abc import Generator import pytest CONTAINER = "cli-tools-test" IMAGE = "images:debian/bookworm" REPO_ROOT = "/home/jev/projects/cli-tools" def _lxc(*args: str, capture: bool = False) -> subprocess.CompletedProcess: return subprocess.run( ["lxc", *args], check=True, capture_output=capture, text=capture, ) def _wait_for_network(container: str, retries: int = 20, delay: float = 2.0) -> None: print("[container] Waiting for network...", flush=True) for _ in range(retries): result = subprocess.run( ["lxc", "exec", container, "--", "bash", "-c", "ping -c1 8.8.8.8 &>/dev/null"], capture_output=True, ) if result.returncode == 0: print("[container] Network ready", flush=True) return time.sleep(delay) raise RuntimeError(f"Container {container!r} did not get network access") @pytest.fixture(scope="session") def container() -> Generator[str, None, None]: # Clean up any stale container from a previous run subprocess.run(["lxc", "delete", "--force", CONTAINER], capture_output=True) print(f"\n[container] Launching {CONTAINER}...", flush=True) _lxc("launch", IMAGE, CONTAINER) time.sleep(3) _wait_for_network(CONTAINER) print("[container] Installing sudo and python3-pip...", flush=True) _lxc( "exec", CONTAINER, "--", "bash", "-c", """ apt-get update -qq DEBIAN_FRONTEND=noninteractive apt-get install -y -qq sudo python3-pip """, ) print("[container] Creating jev user...", flush=True) _lxc( "exec", CONTAINER, "--", "bash", "-c", """ useradd -m -s /bin/bash -u 1000 jev usermod -aG sudo jev echo 'jev ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/jev chmod 440 /etc/sudoers.d/jev """, ) print("[container] Installing invoke...", flush=True) _lxc( "exec", CONTAINER, "--", "bash", "-c", "pip3 install invoke --quiet --break-system-packages", ) print("[container] Mounting repo...", flush=True) _lxc("config", "device", "add", CONTAINER, "repo", "disk", f"source={REPO_ROOT}", "path=/home/jev/cli-tools") print("[container] Ready\n", flush=True) yield CONTAINER print(f"\n[container] Destroying {CONTAINER}...", flush=True) _lxc("delete", "--force", CONTAINER)