"""A service netOrk no longer ships is removed from the host (NetOrk/netork#763). `docker compose up` never removes a container whose service has left the compose file, so it would keep running on every host until somebody removed it by hand. The first of these is the bundled `registry:2`: it held only an old satellite image, nothing had pulled from it in 30 days, and it accepted anonymous pushes on port 5000 of every instance. The remote side is a fake `ssh` that records every command it is given. """ from __future__ import annotations import os import subprocess from pathlib import Path DEPLOY = Path(__file__).resolve().parent.parent / "deploy.sh" _FAKE_SSH = """#!/bin/sh for arg in "$@"; do cmd="$arg"; done # The host lock's holder runs for real, here (test_deploy_host_lock.py). case "$cmd" in *.deploy.lock*) exec sh -c "$cmd" ;; esac cat > /dev/null printf '%s\\n----\\n' "$cmd" >> "{state}/commands" exit 0 """ def _deploy(tmp_path: Path) -> tuple[subprocess.CompletedProcess[str], list[str]]: bin_dir = tmp_path / "bin" bin_dir.mkdir() fake = bin_dir / "ssh" fake.write_text(_FAKE_SSH.replace("{state}", str(tmp_path))) fake.chmod(0o755) result = subprocess.run( ["bash", str(DEPLOY), "testhost"], env={ "PATH": f"{bin_dir}:{os.environ['PATH']}", "HOME": str(tmp_path), "DEPLOY_ENV_FILE": "/dev/null", "REGISTRY_HOST": "registry.example", "NETORK_VERSION": "latest-dev", }, stdin=subprocess.DEVNULL, capture_output=True, text=True, timeout=60, check=False, ) commands = (tmp_path / "commands").read_text().split("\n----\n") return result, commands def test_a_deploy_removes_the_retired_registry_and_its_volume(tmp_path: Path) -> None: result, commands = _deploy(tmp_path) assert result.returncode == 0, result.stderr removal = [c for c in commands if "netork-registry-1" in c] assert removal, "no command removes the netork-registry-1 container" assert "docker rm -f" in removal[0] assert "docker volume rm" in removal[0] and "netork_registry_data" in removal[0] # The container goes first: a volume still in use cannot be removed. assert removal[0].index("docker rm -f") < removal[0].index("docker volume rm") def test_the_infrastructure_reconcile_no_longer_starts_the_registry(tmp_path: Path) -> None: result, commands = _deploy(tmp_path) assert result.returncode == 0, result.stderr reconcile = [c for c in commands if "up -d --no-deps" in c and "--force-recreate" not in c] assert reconcile, "the infrastructure reconcile step is missing" assert " registry" not in reconcile[0].split("up -d --no-deps", 1)[1]