Skip to content

Commit e075efd

Browse files
committed
chore: tweak CI and fix file_manager error
Signed-off-by: mkornfield <mkornfield@nvidia.com>
1 parent 266afd0 commit e075efd

5 files changed

Lines changed: 65 additions & 11 deletions

File tree

.github/actions/setup-docker-buildx/action.yaml

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
name: Set up Docker Buildx
22
description: >
3-
Relocates Docker storage to /mnt for additional disk headroom on
4-
GitHub-hosted runners, then creates a buildx docker-container builder.
3+
Optionally relocates Docker storage to /mnt when that path is on a separate
4+
larger partition, then creates a buildx docker-container builder.
55
66
inputs:
77
builder_name:
88
description: Name of the buildx builder instance
99
required: false
1010
default: nmp-builder
1111
relocate_docker_root:
12-
description: Move Docker data-root to /mnt before creating the builder
12+
description: >
13+
Docker relocation strategy. auto relocates only when /mnt is on a
14+
separate device from /; always forces relocation to /mnt; never skips.
1315
required: false
14-
default: "true"
16+
default: auto
1517

1618
runs:
1719
using: composite
@@ -24,10 +26,29 @@ runs:
2426
builder_name="${{ inputs.builder_name }}"
2527
relocate="${{ inputs.relocate_docker_root }}"
2628
27-
if [ "$relocate" = "true" ] && [ -d /mnt ]; then
28-
echo "=== Disk before Docker relocation ==="
29-
df -h / /mnt || true
29+
echo "=== Disk layout ==="
30+
df -h / /mnt 2>/dev/null || df -h /
31+
32+
should_relocate=false
33+
if [ "$relocate" = "never" ]; then
34+
echo "Docker relocation disabled (relocate_docker_root=never)"
35+
elif [ ! -d /mnt ]; then
36+
echo "Skipping Docker relocation: /mnt does not exist"
37+
elif [ "$relocate" = "always" ]; then
38+
should_relocate=true
39+
echo "Docker relocation forced (relocate_docker_root=always)"
40+
else
41+
root_dev="$(df --output=source / | tail -1 | tr -d ' ')"
42+
mnt_dev="$(df --output=source /mnt | tail -1 | tr -d ' ')"
43+
if [ "$root_dev" != "$mnt_dev" ]; then
44+
should_relocate=true
45+
echo "Relocating Docker storage: /mnt is on ${mnt_dev}, / is on ${root_dev}"
46+
else
47+
echo "Skipping Docker relocation: /mnt shares device ${root_dev} with /"
48+
fi
49+
fi
3050
51+
if [ "$should_relocate" = "true" ]; then
3152
sudo systemctl stop docker.socket docker.service 2>/dev/null || sudo service docker stop || true
3253
sudo mkdir -p /mnt/docker
3354
if [ -d /var/lib/docker ] && [ ! -L /var/lib/docker ]; then
@@ -47,5 +68,5 @@ runs:
4768
docker buildx inspect --bootstrap
4869
4970
echo "=== Disk after Buildx bootstrap ==="
50-
df -h / /mnt || true
71+
df -h / /mnt 2>/dev/null || df -h /
5172
docker system df || true

docker/Dockerfile.safe-synthesizer-tasks

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ LABEL org.opencontainers.image.title="Safe Synthesizer Tasks" \
8282

8383
# Install the Safe Synthesizer engine/CUDA runtime before copying Platform
8484
# sources, so plugin-only edits do not invalidate the large dependency layers.
85+
COPY plugins/nemo-safe-synthesizer/constraints.txt /tmp/safe-synthesizer-constraints.txt
8586
RUN uv venv /opt/venv
8687
RUN printf '%s\n' \
8788
flashinfer-cubin \
@@ -123,6 +124,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
123124
--index-strategy unsafe-best-match \
124125
--torch-backend cu129 \
125126
--overrides /tmp/safe-synthesizer-overrides.txt \
127+
--constraints /tmp/safe-synthesizer-constraints.txt \
126128
--excludes /tmp/exclude-flashinfer-torch-vllm.txt \
127129
--requirements /tmp/safe-synthesizer-runtime.txt
128130

@@ -134,6 +136,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
134136
--index-strategy unsafe-best-match \
135137
--torch-backend cu129 \
136138
--overrides /tmp/safe-synthesizer-overrides.txt \
139+
--constraints /tmp/safe-synthesizer-constraints.txt \
137140
--excludes /tmp/exclude-torch-vllm.txt \
138141
--requirements /tmp/safe-synthesizer-runtime.txt
139142

@@ -145,6 +148,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
145148
--index-strategy unsafe-best-match \
146149
--torch-backend cu129 \
147150
--overrides /tmp/safe-synthesizer-overrides.txt \
151+
--constraints /tmp/safe-synthesizer-constraints.txt \
148152
--excludes /tmp/exclude-vllm.txt \
149153
--requirements /tmp/safe-synthesizer-runtime.txt
150154

@@ -156,6 +160,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
156160
--index-strategy unsafe-best-match \
157161
--torch-backend cu129 \
158162
--overrides /tmp/safe-synthesizer-overrides.txt \
163+
--constraints /tmp/safe-synthesizer-constraints.txt \
159164
--requirements /tmp/safe-synthesizer-runtime.txt \
160165
--requirements /tmp/vllm-cu129.txt
161166

packages/nemo_platform_plugin/src/nemo_platform_plugin/jobs/file_manager.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import tempfile
77
from abc import abstractmethod
88
from dataclasses import dataclass, field
9+
from inspect import isawaitable
910
from pathlib import Path
1011
from typing import Protocol
1112

@@ -163,7 +164,9 @@ async def _validate_storage(self) -> None:
163164
except FileNotFoundError:
164165
if self.ensure_fileset_exists:
165166
logger.info(f"Creating new fileset: [{self.fileset_name}] in workspace [{self.workspace}]")
166-
await self._fs._sdk.files.filesets.create(name=self.fileset_name, workspace=self.workspace)
167+
result = self.sdk.files.filesets.create(name=self.fileset_name, workspace=self.workspace)
168+
if isawaitable(result):
169+
await result
167170
else:
168171
raise FileStorageDoesNotExist(
169172
f"Fileset [{self.fileset_name}] in workspace [{self.workspace}] does not exist."

packages/nmp_common/tests/jobs/test_file_manager.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ def test_fileset_validate_storage_creates(fileset_manager, mock_fileset_fs, mock
133133
"""Test validate_storage creates fileset when missing."""
134134
mock_fileset_fs._info.side_effect = FileNotFoundError("not found")
135135
fileset_manager.validate_storage()
136-
# The async version uses _fs._sdk.files.filesets.create
137-
mock_fileset_fs._sdk.files.filesets.create.assert_called_once()
136+
mock_sdk.files.filesets.create.assert_called_once_with(name="job-results-jobid-123", workspace="default")
138137

139138

140139
def test_fileset_upload_file(tmp_path, fileset_manager, mock_fileset_fs):
@@ -148,6 +147,31 @@ def test_fileset_upload_file(tmp_path, fileset_manager, mock_fileset_fs):
148147
assert result == "default/job-results-jobid-123#remote/test.txt"
149148

150149

150+
async def test_async_fileset_validate_storage_creates(mock_async_nmp_sdk, mock_fileset_fs):
151+
"""Test async validate_storage creates fileset when missing."""
152+
from unittest import mock
153+
154+
from nmp.common.entities import DEFAULT_WORKSPACE
155+
from nmp.common.jobs.file_manager import AsyncFilesetFileManager
156+
157+
mock_fileset_fs._info.side_effect = FileNotFoundError("not found")
158+
159+
with mock.patch("nemo_platform_plugin.jobs.file_manager.FilesetFileSystem") as mock_fs_class:
160+
mock_fs_class.return_value = mock_fileset_fs
161+
async_manager = AsyncFilesetFileManager(
162+
workspace=DEFAULT_WORKSPACE,
163+
fileset_name="job-results-jobid-123",
164+
sdk=mock_async_nmp_sdk,
165+
)
166+
167+
await async_manager.validate_storage()
168+
169+
mock_async_nmp_sdk.files.filesets.create.assert_awaited_once_with(
170+
name="job-results-jobid-123",
171+
workspace="default",
172+
)
173+
174+
151175
def test_fileset_upload_directory(tmp_path, fileset_manager, mock_fileset_fs):
152176
"""Test uploading a directory."""
153177
test_dir = tmp_path / "mydir"

plugins/nemo-safe-synthesizer/constraints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ tornado>=6.5.5
3030
# Runtime compatibility constraints.
3131
boto3>=1.40.46,<1.40.62
3232
botocore>=1.40.46,<1.40.62
33+
gliner<0.2.27

0 commit comments

Comments
 (0)