Files
serverAppConfigs/tests/comfyui_rocm.bats
T
Frank 88dcd3cc0f ComfyUI: rootless-correct GPU group config (video only)
Rootless podman cannot map the 'render' gid (990) into the container
namespace (dank's subgid range is 100000+), so --group-add render fails to
start the container. GPU access actually comes from the /dev/kfd + /dev/dri
passthrough, checked host-side (the run user is already in 'render' on the
host). So add only the 'video' group (which resolves) and drop 'render'.

Update the group test to assert video present and render ABSENT (with the
rootless rationale), per the approved rootless config.
2026-08-19 15:50:28 -07:00

83 lines
3.4 KiB
Bash

#!/usr/bin/env bats
# Seam: ComfyUI ROCm GPU configuration on Dankclaw.
# The gfx1151-enabled PyTorch build is the only verified GPU path on Strix
# Halo. The compose must:
# - build from a Containerfile based on the gfx1151 ROCm torch image
# - pass /dev/kfd and /dev/dri to the container
# - NOT pass --cpu
# - add the video and render groups
#
# STATUS (2026-08-19): the GPU migration is applied. The compose builds
# comfyui-rocm:gfx1151 from Containerfile.comfyui (AMD's gfx1151 torch base),
# passes /dev/kfd + /dev/dri, adds the video group (render is unmappable in
# rootless), and drops --cpu.
# The four compose-wiring tests below are active (un-skipped). See
# docs/Research/ComfyUI ROCm and Vulkan.md.
load helpers
@test "comfyui builds from the gfx1151 ROCm Containerfile" {
local compose="$REPO_ROOT/dankclaw/compose.yaml"
python3 - "$compose" <<'PYEOF'
import sys, yaml
with open(sys.argv[1]) as fh:
data = yaml.safe_load(fh)
svc = data["services"]["comfyui"]
assert svc.get("build"), "comfyui must have a build: section (Containerfile)"
assert svc.get("image", "").startswith("comfyui-rocm"), \
"comfyui image must be tagged comfyui-rocm:*"
print("comfyui build OK:", svc["build"], svc.get("image"))
PYEOF
}
@test "comfyui Containerfile is based on the gfx1151 torch image" {
local cf
cf=$(find "$REPO_ROOT/dankclaw" -name 'Containerfile*' 2>/dev/null | head -1)
[ -n "$cf" ] || { echo "no Containerfile under dankclaw/"; return 1; }
grep -q "gfx1151" "$cf" || { echo "$cf does not reference gfx1151"; return 1; }
grep -q "FROM" "$cf" || { echo "$cf has no FROM"; return 1; }
}
@test "comfyui passes /dev/kfd and /dev/dri to the container" {
python3 - "$REPO_ROOT/dankclaw/compose.yaml" <<'PYEOF'
import sys, yaml
with open(sys.argv[1]) as fh:
data = yaml.safe_load(fh)
devices = data["services"]["comfyui"].get("devices", [])
joined = "\n".join(devices)
for need in ("/dev/kfd", "/dev/dri"):
assert need in joined, f"comfyui devices must include {need}; got: {devices}"
print("device passthrough OK:", devices)
PYEOF
}
@test "comfyui does not run with --cpu" {
python3 - "$REPO_ROOT/dankclaw/compose.yaml" <<'PYEOF'
import sys, yaml
with open(sys.argv[1]) as fh:
data = yaml.safe_load(fh)
cmd = data["services"]["comfyui"].get("command", [])
joined = " ".join(cmd) if isinstance(cmd, list) else str(cmd)
assert "--cpu" not in joined, "comfyui must not pass --cpu (ROCm GPU build)"
assert "--listen" in joined, "comfyui must listen on 0.0.0.0"
print("command OK:", cmd)
PYEOF
}
@test "comfyui adds the video group (render is unmappable in rootless)" {
python3 - "$REPO_ROOT/dankclaw/compose.yaml" <<'PYEOF'
import sys, yaml
with open(sys.argv[1]) as fh:
data = yaml.safe_load(fh)
groups = data["services"]["comfyui"].get("group_add", [])
# 'video' is added (it resolves in the rootless namespace). 'render' (gid 990)
# is intentionally ABSENT: rootless podman cannot map it into the container
# namespace (the subgid range is 100000+), so --group-add render fails to start.
# GPU access comes from the /dev/kfd + /dev/dri passthrough, checked host-side
# (the run user is already a member of 'render' on the host).
assert "video" in groups, f"comfyui group_add must include video; got: {groups}"
assert "render" not in groups, f"comfyui group_add must NOT include render (unmappable in rootless); got: {groups}"
print("groups OK:", groups)
PYEOF
}