fix(frank-dragoon): stage the NPU lane inside the payload mount
The lane's first boot died at container init, not at the engine:
runc create failed: ... create mountpoint for /models/npu mount:
mkdirat .../merged/models/npu: read-only file system
The image ships no /models, and the serve script binds the payload dir
there read-only, so a nested `-v $NPU_DIR:/models/npu:ro` had to create
its own mountpoint underneath a read-only parent — impossible. The
engine's own entrypoint confirms the container path is fixed: it rejects
HALOGEN_NPU_DIR outright ("our NPU models live under /models/npu/<id>/").
Fix is the mount shape, not the engine: FRANK_DRAGOON_NPU_DIR now lives
inside FRANK_DRAGOON_MODEL_DIR, so the payload's single read-only mount
puts the files at /models/npu/<id>/ by itself and the nested bind is
gone. Verified on the running container: after the move, `podman exec
frank-dragoon-halogen ls /models/npu/qwen3-embedding-0.6b` answers with
the staged tree while the lane is still armed off.
Both gates refuse the old shape by name (serve + deployer parity) so a
future payload swap that moves the model dir cannot reintroduce a crash
that lands after the deployer has already stopped the running unit.
This commit is contained in:
@@ -469,7 +469,12 @@ $(cat "$TEST_TMP/serve.log")"
|
||||
run_with_log
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"--device $TEST_TMP/accel0"* ]]
|
||||
[[ "$output" == *"-v $TEST_TMP/npu:/models/npu:ro"* ]]
|
||||
# The lane's files ride the payload mount: /models is a read-only bind and
|
||||
# runc cannot mkdir a nested /models/npu mountpoint through it (measured
|
||||
# 2026-10-19), so the staging dir lives INSIDE the payload dir and gets no
|
||||
# -v of its own.
|
||||
[[ "$output" == *"-v $TEST_TMP:/models:ro"* ]]
|
||||
[[ "$output" != *":/models/npu"* ]]
|
||||
[[ "$output" == *"-e HALOGEN_NPU_MODELS=qwen3-embedding-0.6b"* ]]
|
||||
for l in libxrt_coreutil.so.2 libxrt_core.so.2 libxrt_driver_xdna.so.2; do
|
||||
[[ "$output" == *"-v $TEST_TMP/xrt/$l:/opt/xilinx/xrt/lib/$l:ro"* ]]
|
||||
@@ -479,6 +484,20 @@ $(cat "$TEST_TMP/serve.log")"
|
||||
[[ "$output" == *"-e HALOGEN_CHECKPOINT=/models/qwen.hgn"* ]]
|
||||
}
|
||||
|
||||
@test "the lane refuses a staging dir outside the payload dir and says why" {
|
||||
# A staging dir outside the payload dir needs a nested bind the read-only
|
||||
# /models mount cannot host: runc dies at container init, which is AFTER the
|
||||
# deployer has stopped the old unit — so the shape is refused here, before
|
||||
# anything is rendered.
|
||||
podman_stub
|
||||
good_env
|
||||
npu_fixture
|
||||
run_with_log FRANK_DRAGOON_NPU_DIR=/elsewhere/npu
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"/elsewhere/npu"*"outside the payload dir"* ]]
|
||||
[[ "$output" != *"--device"* ]]
|
||||
}
|
||||
|
||||
@test "the lane refuses a model that is not staged and names the fetch script" {
|
||||
# The engine cannot fetch these at boot here (/models is read-only and
|
||||
# HALOGEN_DOWNLOAD stays unset), so an un-staged name must stop the unit
|
||||
@@ -560,6 +579,9 @@ $(cat "$TEST_TMP/serve.log")"
|
||||
grep -qE 'download-frank-dragoon-npu\.sh' "$DEPLOYER"
|
||||
# The lane's own health gate is a real embedding, not a 200 on /health.
|
||||
grep -qE '/v1/embeddings' "$DEPLOYER"
|
||||
# Parity with the serve gate: a staging dir outside the payload dir is
|
||||
# refused before the restart, not left to runc.
|
||||
grep -qE 'outside the payload dir' "$DEPLOYER"
|
||||
}
|
||||
|
||||
@test "the fabric-clock host unit is the vendor shape and boots on its own" {
|
||||
|
||||
Reference in New Issue
Block a user