core: GPU containers, bind sub-paths, and stop containers on unit stop

- container launcher: `gpus:` passes through as docker `--gpus`.
- requires: `path:` is appended to the bound URL, for consumers that want a
  sub-path as their base (e.g. an OpenAI-compatible server's /v1).
- container services now get `ExecStop=-docker stop wildpc-<name>`. SIGTERM
  only reached the `docker run` client, so a stop/restart left the container
  running unsupervised and holding its name, and the next start failed with
  a name conflict until systemd gave up.
This commit is contained in:
2026-10-16 03:10:01 -07:00
parent 8a9843658c
commit 55c2f269ec
6 changed files with 90 additions and 4 deletions

View File

@@ -205,3 +205,24 @@ def test_compose_stop_cmd_is_down(tmp_path: Path) -> None:
def test_non_compose_runner_has_no_stop_cmd(tmp_path: Path) -> None:
run = RunPython(launcher="python", program="svc")
assert _build_stop_cmd("svc", run, tmp_path) == []
def test_container_gpus_flag() -> None:
"""`gpus` passes through as docker `--gpus`; omitted → no GPU access."""
run = RunContainer(launcher="container", image="img:latest", gpus="all")
with patch("wildpc_core.deploy.shutil.which", return_value="/usr/bin/docker"):
cmd = _build_run_cmd("svc", run, {}, [])
assert cmd[cmd.index("--gpus") + 1] == "all"
assert cmd.index("--gpus") < cmd.index("img:latest")
plain = RunContainer(launcher="container", image="img:latest")
with patch("wildpc_core.deploy.shutil.which", return_value="/usr/bin/docker"):
assert "--gpus" not in _build_run_cmd("svc", plain, {}, [])
def test_container_stop_cmd_stops_named_container() -> None:
"""Stopping the unit must stop the container itself, not just the docker client."""
run = RunContainer(launcher="container", image="img:latest")
with patch("wildpc_core.deploy.shutil.which", return_value="/usr/bin/docker"):
stop = _build_stop_cmd("svc", run, None)
assert stop == ["-/usr/bin/docker", "stop", "wildpc-svc"]