From 031033f98f2363c1107f962f11721c4b0df2a1d6 Mon Sep 17 00:00:00 2001 From: Matthew Grossman Date: Fri, 12 Jun 2026 08:35:53 -0700 Subject: [PATCH 1/9] fix(jobs): Fix e2e tests to use the nmp-api image by default Signed-off-by: Matthew Grossman --- docs/set-up/config-reference.mdx | 8 ++++++ e2e/test_jobs.py | 27 ++++--------------- .../types/jobs/container_spec.py | 2 +- .../types/jobs/container_spec_param.py | 2 +- .../jobs/src/nmp/core/jobs/app/providers.py | 4 +-- .../core/jobs/controllers/backends/base.py | 26 ++++++++++++++++++ .../core/jobs/controllers/backends/docker.py | 6 ++++- .../controllers/backends/kubernetes/common.py | 7 ++++- .../core/jobs/tests/controllers/test_base.py | 20 +++++++++++++- 9 files changed, 73 insertions(+), 29 deletions(-) diff --git a/docs/set-up/config-reference.mdx b/docs/set-up/config-reference.mdx index bbd4cd1d95..b20bb2fec1 100644 --- a/docs/set-up/config-reference.mdx +++ b/docs/set-up/config-reference.mdx @@ -224,6 +224,8 @@ jobs: cleanup_completed_jobs_immediately: true # Path to the jobs launcher tool | default: '/tools/jobs-launcher' launcher_tool_path: /tools/jobs-launcher + # Default container image for job task pods. Used when a job step omits container.image. On Kubernetes this is typically the platform API image. When unset, container.image is required. + default_task_image: # Optional env vars applied to all jobs (e.g. HOME=/tmp). Keys must not conflict with platform-reserved names. Job steps may override these variables. env: {} # Docker storage configuration @@ -250,6 +252,8 @@ jobs: cleanup_completed_jobs_immediately: true # Path to the jobs launcher tool | default: '/tools/jobs-launcher' launcher_tool_path: /tools/jobs-launcher + # Default container image for job task pods. Used when a job step omits container.image. On Kubernetes this is typically the platform API image. When unset, container.image is required. + default_task_image: # Optional env vars applied to all jobs (e.g. HOME=/tmp). Keys must not conflict with platform-reserved names. Job steps may override these variables. env: {} # Kubernetes namespace to submit the job to. If not set, it will be determined from the environment. @@ -322,6 +326,8 @@ jobs: cleanup_completed_jobs_immediately: true # Path to the jobs launcher tool | default: '/tools/jobs-launcher' launcher_tool_path: /tools/jobs-launcher + # Default container image for job task pods. Used when a job step omits container.image. On Kubernetes this is typically the platform API image. When unset, container.image is required. + default_task_image: # Optional env vars applied to all jobs (e.g. HOME=/tmp). Keys must not conflict with platform-reserved names. Job steps may override these variables. env: {} # Kubernetes namespace to submit the job to. If not set, it will be determined from the environment. @@ -402,6 +408,8 @@ jobs: cleanup_completed_jobs_immediately: false # Path to the jobs launcher tool | default: '/tools/jobs-launcher' launcher_tool_path: /tools/jobs-launcher + # Default container image for job task pods. Used when a job step omits container.image. On Kubernetes this is typically the platform API image. When unset, container.image is required. + default_task_image: # Optional env vars applied to all jobs (e.g. HOME=/tmp). Keys must not conflict with platform-reserved names. Job steps may override these variables. env: {} # Root directory for subprocess job state, config, storage, and logs. | default: '/tmp/nmp-subprocess-jobs' diff --git a/e2e/test_jobs.py b/e2e/test_jobs.py index 12255b52df..2bffe386c4 100644 --- a/e2e/test_jobs.py +++ b/e2e/test_jobs.py @@ -1,9 +1,9 @@ -"""E2E tests for platform jobs via the subprocess executor. +"""E2E tests for platform jobs. -These tests submit jobs with CPUExecutionProviderSpec (container image + command). -In subprocess mode, the jobs service translates cpu/default steps to subprocess -steps automatically — the container image is discarded and the command runs -directly on the host. +These tests submit jobs with CPUExecutionProviderSpec (container + command). +The container image is omitted so that: +- On subprocess mode, the cpu→subprocess translation discards it anyway. +- On Kubernetes/Docker, the execution profile's default_task_image is used. Ported from Platform-Deploy e2e/test_jobs.py, adapted for the SDK's TypedDict param types and filtered to tests that work without Docker. @@ -17,10 +17,6 @@ JOB_SOURCE = "e2e-test-jobs" -# The image is discarded by the cpu→subprocess translation, but must be -# syntactically valid for the API to accept the CPUExecutionProvider. -PLACEHOLDER_IMAGE = "placeholder:unused" - pytestmark = [pytest.mark.timeout(600)] @@ -62,7 +58,6 @@ def test_basic_platform_job_lifecycle(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": ["echo", "Hello from e2e test!"], }, }, @@ -106,7 +101,6 @@ def test_job_logs_across_multiple_batches(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": ["sh", "-c", log_command], }, }, @@ -146,7 +140,6 @@ def test_job_config_is_readable(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": ["sh", "-c", "echo 'Step config:'; cat $NEMO_JOB_STEP_CONFIG_FILE_PATH;"], }, }, @@ -181,7 +174,6 @@ def test_job_passing_data_between_steps(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": [ "sh", "-c", @@ -195,7 +187,6 @@ def test_job_passing_data_between_steps(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": [ "sh", "-c", @@ -237,7 +228,6 @@ def test_job_using_secret_environment_variable(sdk: NeMoPlatform, workspace: str "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": ["sh", "-c", 'echo "Secret value is: $SECRET_ENV_VAR"'], }, }, @@ -275,7 +265,6 @@ def test_job_with_expected_failure(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": ["sh", "-c", "echo 'This step will fail'; exit 1;"], }, }, @@ -305,7 +294,6 @@ def test_job_cancel_immediately(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": ["sh", "-c", "sleep 60"], }, }, @@ -335,7 +323,6 @@ def test_job_cancel_once_active(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": ["sh", "-c", "sleep 300"], }, }, @@ -376,7 +363,6 @@ def test_job_pause_resume(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": ["sh", "-c", "sleep 300"], }, }, @@ -418,7 +404,6 @@ def test_job_pause_and_cancel(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": ["sh", "-c", "sleep 300"], }, }, @@ -455,7 +440,6 @@ def test_job_using_additional_volume(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": [ "sh", "-c", @@ -470,7 +454,6 @@ def test_job_using_additional_volume(sdk: NeMoPlatform, workspace: str): "executor": { "provider": "cpu", "container": { - "image": PLACEHOLDER_IMAGE, "command": [ "sh", "-c", diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec.py b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec.py index 266b0f06ed..ad9948abf0 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec.py @@ -28,7 +28,7 @@ class ContainerSpec(BaseModel): Defines the container image and related configuration for job execution. """ - image: str + image: Optional[str] = None command: Optional[List[str]] = None diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec_param.py b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec_param.py index 5497499027..06347f4c0e 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec_param.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec_param.py @@ -30,7 +30,7 @@ class ContainerSpecParam(TypedDict, total=False): Defines the container image and related configuration for job execution. """ - image: Required[str] + image: str command: SequenceNotStr[str] diff --git a/services/core/jobs/src/nmp/core/jobs/app/providers.py b/services/core/jobs/src/nmp/core/jobs/app/providers.py index 6d5c5486a9..0bd23036f9 100644 --- a/services/core/jobs/src/nmp/core/jobs/app/providers.py +++ b/services/core/jobs/src/nmp/core/jobs/app/providers.py @@ -18,8 +18,8 @@ class ContainerSpec(BaseModel): Defines the container image and related configuration for job execution. """ - image: str - """The container image to use for execution""" + image: str | None = None + """The container image to use for execution. When omitted, the execution profile's default_task_image is used.""" entrypoint: list[str] = Field(default_factory=list) """The entrypoint for the container as a list of strings (e.g., ['python', 'script.py']). This overrides a container's default entrypoint (e.g. ENTRYPOINT in Docker) if provided.""" diff --git a/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py b/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py index 54404b11d7..8ada071782 100644 --- a/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py +++ b/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py @@ -91,6 +91,11 @@ class JobExecutionProfileConfig(BaseModel): ttl_seconds_after_finished: int = 60 * 60 # 1 hour cleanup_completed_jobs_immediately: bool = True launcher_tool_path: str = Field(default="/tools/jobs-launcher", description="Path to the jobs launcher tool") + default_task_image: str | None = Field( + default=None, + description="Default container image for job task pods. Used when a job step omits container.image. " + "On Kubernetes this is typically the platform API image. When unset, container.image is required.", + ) env: dict[str, str] = Field( default_factory=dict, description="Optional env vars applied to all jobs (e.g. HOME=/tmp). Keys must not conflict with platform-reserved names. Job steps may override these variables.", @@ -106,6 +111,27 @@ def validate_env_no_reserved_names(self) -> JobExecutionProfileConfig: return self +_PLATFORM_API_IMAGE_NAME = "nmp-api" + + +def resolve_task_image(container_image: str | None, default_task_image: str | None) -> str: + """Resolve the container image for a job task. + + Priority: + 1. Explicit container.image from the job step + 2. default_task_image from the execution profile config + 3. Platform API image derived from platform.image_registry / image_tag + """ + if container_image: + return container_image + if default_task_image: + return default_task_image + + from nemo_platform_plugin.jobs.image import get_qualified_image + + return get_qualified_image(_PLATFORM_API_IMAGE_NAME) + + def resolve_gpu_job_shm_size( executor_resources: ComputeResources | None, profile_resources: ComputeResources | None, diff --git a/services/core/jobs/src/nmp/core/jobs/controllers/backends/docker.py b/services/core/jobs/src/nmp/core/jobs/controllers/backends/docker.py index cd85caa5d1..4ee170bc53 100644 --- a/services/core/jobs/src/nmp/core/jobs/controllers/backends/docker.py +++ b/services/core/jobs/src/nmp/core/jobs/controllers/backends/docker.py @@ -73,6 +73,7 @@ JobUpdate, get_logs_endpoint_from_fileset, resolve_gpu_job_shm_size, + resolve_task_image, staleness_error_message, ) from nmp.core.jobs.controllers.backends.exceptions import ( @@ -679,11 +680,14 @@ def schedule_single_container( else: labels[JOB_USES_PERSISTENT_STORAGE_LABEL] = "false" + task_image = resolve_task_image( + executor_config.container.image, self._execution_profile_config.default_task_image + ) container_args = { "name": self.name_for_step(step), "entrypoint": executor_config.container.entrypoint or [], "command": executor_config.container.command or [], - "image": executor_config.container.image, + "image": task_image, "labels": labels, "log_config": log_config, "environment": env, diff --git a/services/core/jobs/src/nmp/core/jobs/controllers/backends/kubernetes/common.py b/services/core/jobs/src/nmp/core/jobs/controllers/backends/kubernetes/common.py index d1465d1f56..e17700dce3 100644 --- a/services/core/jobs/src/nmp/core/jobs/controllers/backends/kubernetes/common.py +++ b/services/core/jobs/src/nmp/core/jobs/controllers/backends/kubernetes/common.py @@ -56,6 +56,7 @@ JobExecutionProfileConfig, get_logs_endpoint_from_fileset, resolve_gpu_job_shm_size, + resolve_task_image, ) from nmp.core.jobs.controllers.backends.exceptions import FailedToScheduleError, JobStorageError from pydantic import BaseModel, Field, model_validator @@ -1102,10 +1103,14 @@ def create_pod_template_spec( for cmd in container.entrypoint or []: command.append(cmd) + # Resolve the task image: explicit container.image takes precedence, + # then the profile's default_task_image, then error. + task_image = resolve_task_image(container.image, config.default_task_image) + # Main job container job_container = client.V1Container( name=NEMO_JOB_TASK_CONTAINER_NAME, - image=container.image, + image=task_image, command=command, args=container.command, env=env, diff --git a/services/core/jobs/tests/controllers/test_base.py b/services/core/jobs/tests/controllers/test_base.py index 759e1e5f81..6915101d97 100644 --- a/services/core/jobs/tests/controllers/test_base.py +++ b/services/core/jobs/tests/controllers/test_base.py @@ -11,7 +11,7 @@ from nmp.core.jobs.api.v2.jobs.schemas import PlatformJobStepWithContext from nmp.core.jobs.app.providers import ContainerSpec, CPUExecutionProvider from nmp.core.jobs.app.schemas import PlatformJobStepSpec, StepLifecycle -from nmp.core.jobs.controllers.backends.base import get_logs_endpoint_from_fileset +from nmp.core.jobs.controllers.backends.base import get_logs_endpoint_from_fileset, resolve_task_image from nmp.core.jobs.controllers.backends.test import MockKubernetesCPUJobBackend @@ -316,3 +316,21 @@ def test_returns_false_when_task_missing_updated_at(self): ) assert backend.check_step_is_stale(step) is False + + +class TestResolveTaskImage: + """Tests for resolve_task_image.""" + + def test_explicit_image_takes_precedence(self): + assert resolve_task_image("my-image:v1", "default-image:latest") == "my-image:v1" + + def test_falls_back_to_default_task_image(self): + assert resolve_task_image(None, "default-image:latest") == "default-image:latest" + + def test_explicit_image_without_default(self): + assert resolve_task_image("my-image:v1", None) == "my-image:v1" + + def test_falls_back_to_platform_image_when_both_none(self): + with patch("nemo_platform_plugin.jobs.image.get_platform_config") as mock_config: + mock_config.return_value = MagicMock(image_registry="my-registry", image_tag="v1.0") + assert resolve_task_image(None, None) == "my-registry/nmp-api:v1.0" From 840dfc9df52a87e50b08208a26dc133c2793f572 Mon Sep 17 00:00:00 2001 From: Matthew Grossman Date: Fri, 12 Jun 2026 09:17:59 -0700 Subject: [PATCH 2/9] use nmp-cpu-tasks iamge Signed-off-by: Matthew Grossman --- .../jobs/src/nmp/core/jobs/controllers/backends/base.py | 6 +++--- services/core/jobs/tests/controllers/test_base.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py b/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py index 8ada071782..c042cadc90 100644 --- a/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py +++ b/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py @@ -111,7 +111,7 @@ def validate_env_no_reserved_names(self) -> JobExecutionProfileConfig: return self -_PLATFORM_API_IMAGE_NAME = "nmp-api" +_DEFAULT_TASK_IMAGE_NAME = "nmp-cpu-tasks" def resolve_task_image(container_image: str | None, default_task_image: str | None) -> str: @@ -120,7 +120,7 @@ def resolve_task_image(container_image: str | None, default_task_image: str | No Priority: 1. Explicit container.image from the job step 2. default_task_image from the execution profile config - 3. Platform API image derived from platform.image_registry / image_tag + 3. Platform CPU tasks image derived from platform.image_registry / image_tag """ if container_image: return container_image @@ -129,7 +129,7 @@ def resolve_task_image(container_image: str | None, default_task_image: str | No from nemo_platform_plugin.jobs.image import get_qualified_image - return get_qualified_image(_PLATFORM_API_IMAGE_NAME) + return get_qualified_image(_DEFAULT_TASK_IMAGE_NAME) def resolve_gpu_job_shm_size( diff --git a/services/core/jobs/tests/controllers/test_base.py b/services/core/jobs/tests/controllers/test_base.py index 6915101d97..6d85637939 100644 --- a/services/core/jobs/tests/controllers/test_base.py +++ b/services/core/jobs/tests/controllers/test_base.py @@ -330,7 +330,7 @@ def test_falls_back_to_default_task_image(self): def test_explicit_image_without_default(self): assert resolve_task_image("my-image:v1", None) == "my-image:v1" - def test_falls_back_to_platform_image_when_both_none(self): + def test_falls_back_to_platform_cpu_tasks_image_when_both_none(self): with patch("nemo_platform_plugin.jobs.image.get_platform_config") as mock_config: mock_config.return_value = MagicMock(image_registry="my-registry", image_tag="v1.0") - assert resolve_task_image(None, None) == "my-registry/nmp-api:v1.0" + assert resolve_task_image(None, None) == "my-registry/nmp-cpu-tasks:v1.0" From 177487440893223630272def4d7971e5d9a65a1d Mon Sep 17 00:00:00 2001 From: Matthew Grossman Date: Fri, 12 Jun 2026 09:29:44 -0700 Subject: [PATCH 3/9] make update-sdk Signed-off-by: Matthew Grossman --- docs/set-up/config-reference.mdx | 8 ++--- openapi/ga/individual/platform.openapi.yaml | 34 +++++++++++++++++-- openapi/ga/openapi.yaml | 34 +++++++++++++++++-- openapi/openapi.yaml | 34 +++++++++++++++++-- .../nemo-platform/.nmpcontext/openapi.yaml | 34 +++++++++++++++++-- sdk/python/nemo-platform/api.md | 1 - .../src/nemo_platform/resources/files/api.md | 2 +- .../nemo_platform/resources/files/filesets.py | 11 +++--- .../nemo_platform/resources/guardrail/api.md | 5 +++ .../src/nemo_platform/resources/jobs/api.md | 5 +++ .../src/nemo_platform/resources/jobs/jobs.py | 1 + .../src/nemo_platform/types/__init__.py | 1 - .../src/nemo_platform/types/files/__init__.py | 2 ++ .../src/nemo_platform/types/files/fileset.py | 2 +- .../types/files/fileset_create_params.py | 4 +-- .../{shared => files}/fileset_metadata.py | 4 +-- .../fileset_metadata_param.py} | 8 ++--- .../types/files/fileset_update_params.py | 4 +-- .../types/jobs/container_spec.py | 4 +-- .../types/jobs/container_spec_param.py | 6 ++-- .../docker_job_execution_profile_config.py | 8 +++++ .../jobs/job_execution_profile_config.py | 8 +++++ ...kubernetes_job_execution_profile_config.py | 8 +++++ ...subprocess_job_execution_profile_config.py | 8 +++++ .../volcano_job_execution_profile_config.py | 8 +++++ .../nemo_platform/types/shared/__init__.py | 1 - .../types/shared_params/__init__.py | 1 - .../tests/api_resources/test_jobs.py | 20 +++++------ .../jobs/src/nmp/core/jobs/app/providers.py | 2 +- .../core/jobs/controllers/backends/base.py | 2 +- 30 files changed, 216 insertions(+), 54 deletions(-) rename sdk/python/nemo-platform/src/nemo_platform/types/{shared => files}/fileset_metadata.py (91%) rename sdk/python/nemo-platform/src/nemo_platform/types/{shared_params/fileset_metadata.py => files/fileset_metadata_param.py} (85%) diff --git a/docs/set-up/config-reference.mdx b/docs/set-up/config-reference.mdx index b20bb2fec1..61b857bcc5 100644 --- a/docs/set-up/config-reference.mdx +++ b/docs/set-up/config-reference.mdx @@ -224,7 +224,7 @@ jobs: cleanup_completed_jobs_immediately: true # Path to the jobs launcher tool | default: '/tools/jobs-launcher' launcher_tool_path: /tools/jobs-launcher - # Default container image for job task pods. Used when a job step omits container.image. On Kubernetes this is typically the platform API image. When unset, container.image is required. + # Default container image for job task pods. Used when a job step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). default_task_image: # Optional env vars applied to all jobs (e.g. HOME=/tmp). Keys must not conflict with platform-reserved names. Job steps may override these variables. env: {} @@ -252,7 +252,7 @@ jobs: cleanup_completed_jobs_immediately: true # Path to the jobs launcher tool | default: '/tools/jobs-launcher' launcher_tool_path: /tools/jobs-launcher - # Default container image for job task pods. Used when a job step omits container.image. On Kubernetes this is typically the platform API image. When unset, container.image is required. + # Default container image for job task pods. Used when a job step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). default_task_image: # Optional env vars applied to all jobs (e.g. HOME=/tmp). Keys must not conflict with platform-reserved names. Job steps may override these variables. env: {} @@ -326,7 +326,7 @@ jobs: cleanup_completed_jobs_immediately: true # Path to the jobs launcher tool | default: '/tools/jobs-launcher' launcher_tool_path: /tools/jobs-launcher - # Default container image for job task pods. Used when a job step omits container.image. On Kubernetes this is typically the platform API image. When unset, container.image is required. + # Default container image for job task pods. Used when a job step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). default_task_image: # Optional env vars applied to all jobs (e.g. HOME=/tmp). Keys must not conflict with platform-reserved names. Job steps may override these variables. env: {} @@ -408,7 +408,7 @@ jobs: cleanup_completed_jobs_immediately: false # Path to the jobs launcher tool | default: '/tools/jobs-launcher' launcher_tool_path: /tools/jobs-launcher - # Default container image for job task pods. Used when a job step omits container.image. On Kubernetes this is typically the platform API image. When unset, container.image is required. + # Default container image for job task pods. Used when a job step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). default_task_image: # Optional env vars applied to all jobs (e.g. HOME=/tmp). Keys must not conflict with platform-reserved names. Job steps may override these variables. env: {} diff --git a/openapi/ga/individual/platform.openapi.yaml b/openapi/ga/individual/platform.openapi.yaml index dba0e62e51..0d8c7cb527 100644 --- a/openapi/ga/individual/platform.openapi.yaml +++ b/openapi/ga/individual/platform.openapi.yaml @@ -8597,8 +8597,8 @@ components: ContainerSpec: properties: image: - type: string title: Image + type: string entrypoint: items: type: string @@ -8610,8 +8610,6 @@ components: type: array title: Command type: object - required: - - image title: ContainerSpec description: 'Specification for a container configuration. @@ -9355,6 +9353,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -11790,6 +11794,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -11907,6 +11917,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -16571,6 +16587,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -17587,6 +17609,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string diff --git a/openapi/ga/openapi.yaml b/openapi/ga/openapi.yaml index dba0e62e51..0d8c7cb527 100644 --- a/openapi/ga/openapi.yaml +++ b/openapi/ga/openapi.yaml @@ -8597,8 +8597,8 @@ components: ContainerSpec: properties: image: - type: string title: Image + type: string entrypoint: items: type: string @@ -8610,8 +8610,6 @@ components: type: array title: Command type: object - required: - - image title: ContainerSpec description: 'Specification for a container configuration. @@ -9355,6 +9353,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -11790,6 +11794,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -11907,6 +11917,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -16571,6 +16587,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -17587,6 +17609,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index dba0e62e51..0d8c7cb527 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -8597,8 +8597,8 @@ components: ContainerSpec: properties: image: - type: string title: Image + type: string entrypoint: items: type: string @@ -8610,8 +8610,6 @@ components: type: array title: Command type: object - required: - - image title: ContainerSpec description: 'Specification for a container configuration. @@ -9355,6 +9353,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -11790,6 +11794,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -11907,6 +11917,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -16571,6 +16587,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -17587,6 +17609,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string diff --git a/sdk/python/nemo-platform/.nmpcontext/openapi.yaml b/sdk/python/nemo-platform/.nmpcontext/openapi.yaml index dba0e62e51..0d8c7cb527 100644 --- a/sdk/python/nemo-platform/.nmpcontext/openapi.yaml +++ b/sdk/python/nemo-platform/.nmpcontext/openapi.yaml @@ -8597,8 +8597,8 @@ components: ContainerSpec: properties: image: - type: string title: Image + type: string entrypoint: items: type: string @@ -8610,8 +8610,6 @@ components: type: array title: Command type: object - required: - - image title: ContainerSpec description: 'Specification for a container configuration. @@ -9355,6 +9353,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -11790,6 +11794,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -11907,6 +11917,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -16571,6 +16587,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string @@ -17587,6 +17609,12 @@ components: title: Launcher Tool Path description: Path to the jobs launcher tool default: /tools/jobs-launcher + default_task_image: + title: Default Task Image + description: Default container image for job task pods. Used when a job + step omits container.image. When unset, falls back to the platform CPU + tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + type: string env: additionalProperties: type: string diff --git a/sdk/python/nemo-platform/api.md b/sdk/python/nemo-platform/api.md index 271d51d2df..a0e07c72cd 100644 --- a/sdk/python/nemo-platform/api.md +++ b/sdk/python/nemo-platform/api.md @@ -10,7 +10,6 @@ from nemo_platform.types import ( DatetimeFilter, DeleteResponse, FileStorageType, - FilesetMetadata, FinetuningType, GenericSortField, HTTPValidationError, diff --git a/sdk/python/nemo-platform/src/nemo_platform/resources/files/api.md b/sdk/python/nemo-platform/src/nemo_platform/resources/files/api.md index 72e7b5ca66..882f649add 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/resources/files/api.md +++ b/sdk/python/nemo-platform/src/nemo_platform/resources/files/api.md @@ -33,7 +33,7 @@ Methods: Types: ```python -from nemo_platform.types.files import FilesetFilter +from nemo_platform.types.files import FilesetFilter, FilesetMetadata, FilesetMetadataParam ``` Methods: diff --git a/sdk/python/nemo-platform/src/nemo_platform/resources/files/filesets.py b/sdk/python/nemo-platform/src/nemo_platform/resources/files/filesets.py index f8fb167cf2..018acd45b4 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/resources/files/filesets.py +++ b/sdk/python/nemo-platform/src/nemo_platform/resources/files/filesets.py @@ -34,6 +34,7 @@ from ...pagination import SyncDefaultPagination, AsyncDefaultPagination from ...types.files import ( FilesetPurpose, + FilesetMetadataParam, fileset_list_params, fileset_create_params, fileset_update_params, @@ -43,7 +44,7 @@ from ...types.files.fileset_purpose import FilesetPurpose from ...types.shared.generic_sort_field import GenericSortField from ...types.files.fileset_filter_param import FilesetFilterParam -from ...types.shared_params.fileset_metadata import FilesetMetadata +from ...types.files.fileset_metadata_param import FilesetMetadataParam from ..._exceptions import ConflictError __all__ = ["FilesetsResource", "AsyncFilesetsResource"] @@ -77,7 +78,7 @@ def create( cache: bool | Omit = omit, custom_fields: Dict[str, object] | Omit = omit, description: str | Omit = omit, - metadata: FilesetMetadata | Omit = omit, + metadata: FilesetMetadataParam | Omit = omit, project: str | Omit = omit, purpose: FilesetPurpose | Omit = omit, storage: fileset_create_params.Storage | Omit = omit, @@ -206,7 +207,7 @@ def update( workspace: str | None = None, custom_fields: Dict[str, object] | Omit = omit, description: str | Omit = omit, - metadata: FilesetMetadata | Omit = omit, + metadata: FilesetMetadataParam | Omit = omit, project: str | Omit = omit, purpose: FilesetPurpose | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -402,7 +403,7 @@ async def create( cache: bool | Omit = omit, custom_fields: Dict[str, object] | Omit = omit, description: str | Omit = omit, - metadata: FilesetMetadata | Omit = omit, + metadata: FilesetMetadataParam | Omit = omit, project: str | Omit = omit, purpose: FilesetPurpose | Omit = omit, storage: fileset_create_params.Storage | Omit = omit, @@ -531,7 +532,7 @@ async def update( workspace: str | None = None, custom_fields: Dict[str, object] | Omit = omit, description: str | Omit = omit, - metadata: FilesetMetadata | Omit = omit, + metadata: FilesetMetadataParam | Omit = omit, project: str | Omit = omit, purpose: FilesetPurpose | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/sdk/python/nemo-platform/src/nemo_platform/resources/guardrail/api.md b/sdk/python/nemo-platform/src/nemo_platform/resources/guardrail/api.md index 52c2cf31fd..4fe014901d 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/resources/guardrail/api.md +++ b/sdk/python/nemo-platform/src/nemo_platform/resources/guardrail/api.md @@ -60,14 +60,19 @@ from nemo_platform.types.guardrail import ( PangeaRailOptions, PatronusEvaluateAPIParams, PatronusEvaluateConfig, + PatronusEvaluateConfigParam, PatronusEvaluationSuccessStrategy, PatronusRailConfig, + PatronusRailConfigParam, PrivateAIDetection, PrivateAIDetectionOptions, RailStatus, Rails, RailsConfig, RailsConfigData, + RailsConfigDataParam, + RailsConfigParam, + RailsParam, ReasoningConfig, RegexDetection, RegexDetectionOptions, diff --git a/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/api.md b/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/api.md index 99f688895d..f5bfd41e0c 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/api.md +++ b/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/api.md @@ -8,8 +8,10 @@ from nemo_platform.types.jobs import ( ComputeResources, ContainerSpec, CPUExecutionProvider, + CPUExecutionProviderParam, CreatePlatformJobRequest, DistributedGPUExecutionProvider, + DistributedGPUExecutionProviderParam, DockerJobExecutionProfile, DockerJobExecutionProfileConfig, DockerJobNetworkConfig, @@ -17,6 +19,7 @@ from nemo_platform.types.jobs import ( DockerVolumeMount, E2EJobExecutionProfile, GPUExecutionProvider, + GPUExecutionProviderParam, ImagePullSecret, JobExecutionProfileConfig, KubernetesEmptyDirVolume, @@ -33,7 +36,9 @@ from nemo_platform.types.jobs import ( PlatformJobSecretEnvironmentVariableRef, PlatformJobSortField, PlatformJobSpec, + PlatformJobSpecParam, PlatformJobStepSpec, + PlatformJobStepSpecParam, PlatformJobsListFilter, StepLifecycle, SubprocessExecutionProvider, diff --git a/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/jobs.py b/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/jobs.py index 3a7aff2408..9c5652b216 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/jobs.py +++ b/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/jobs.py @@ -58,6 +58,7 @@ from ...pagination import SyncLogsPagination, AsyncLogsPagination, SyncDefaultPagination, AsyncDefaultPagination from ...types.jobs import ( PlatformJobSortField, + PlatformJobSpecParam, job_list_params, job_create_params, job_get_logs_params, diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/__init__.py b/sdk/python/nemo-platform/src/nemo_platform/types/__init__.py index 2d670dadaf..fafcd134f4 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/__init__.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/__init__.py @@ -32,7 +32,6 @@ PlatformJobLog as PlatformJobLog, ToolCallConfig as ToolCallConfig, APIEndpointData as APIEndpointData, - FilesetMetadata as FilesetMetadata, FileStorageType as FileStorageType, InferenceParams as InferenceParams, LinearLayerSpec as LinearLayerSpec, diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/files/__init__.py b/sdk/python/nemo-platform/src/nemo_platform/types/files/__init__.py index 3833c1d785..b76dd4a694 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/files/__init__.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/files/__init__.py @@ -22,6 +22,7 @@ from .cache_status import CacheStatus as CacheStatus from .fileset_file import FilesetFile as FilesetFile from .fileset_purpose import FilesetPurpose as FilesetPurpose +from .fileset_metadata import FilesetMetadata as FilesetMetadata from .s3_storage_config import S3StorageConfig as S3StorageConfig from .ngc_storage_config import NGCStorageConfig as NGCStorageConfig from .fileset_list_params import FilesetListParams as FilesetListParams @@ -32,6 +33,7 @@ from .fileset_create_params import FilesetCreateParams as FilesetCreateParams from .fileset_update_params import FilesetUpdateParams as FilesetUpdateParams from .file_list_files_params import FileListFilesParams as FileListFilesParams +from .fileset_metadata_param import FilesetMetadataParam as FilesetMetadataParam from .file_upload_file_params import FileUploadFileParams as FileUploadFileParams from .s3_storage_config_param import S3StorageConfigParam as S3StorageConfigParam from .ngc_storage_config_param import NGCStorageConfigParam as NGCStorageConfigParam diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset.py b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset.py index 810d5ce990..e6d9642b7a 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset.py @@ -20,10 +20,10 @@ from ..._models import BaseModel from .fileset_purpose import FilesetPurpose +from .fileset_metadata import FilesetMetadata from .s3_storage_config import S3StorageConfig from .ngc_storage_config import NGCStorageConfig from .local_storage_config import LocalStorageConfig -from ..shared.fileset_metadata import FilesetMetadata from .huggingface_storage_config import HuggingfaceStorageConfig __all__ = ["Fileset", "Storage"] diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_create_params.py b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_create_params.py index 06715b1c74..ccab3462e8 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_create_params.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_create_params.py @@ -21,10 +21,10 @@ from typing_extensions import Required, TypeAlias, TypedDict from .fileset_purpose import FilesetPurpose +from .fileset_metadata_param import FilesetMetadataParam from .s3_storage_config_param import S3StorageConfigParam from .ngc_storage_config_param import NGCStorageConfigParam from .local_storage_config_param import LocalStorageConfigParam -from ..shared_params.fileset_metadata import FilesetMetadata from .huggingface_storage_config_param import HuggingfaceStorageConfigParam __all__ = ["FilesetCreateParams", "Storage"] @@ -49,7 +49,7 @@ class FilesetCreateParams(TypedDict, total=False): description: str """The description of the fileset.""" - metadata: FilesetMetadata + metadata: FilesetMetadataParam """Tagged metadata container - the key indicates the type. Example: metadata = FilesetMetadata( dataset=DatasetMetadataContent( diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/shared/fileset_metadata.py b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata.py similarity index 91% rename from sdk/python/nemo-platform/src/nemo_platform/types/shared/fileset_metadata.py rename to sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata.py index b35b6d8ecc..36573bd374 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/shared/fileset_metadata.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata.py @@ -18,8 +18,8 @@ from typing import Optional from ..._models import BaseModel -from .model_metadata_content import ModelMetadataContent -from .dataset_metadata_content import DatasetMetadataContent +from ..shared.model_metadata_content import ModelMetadataContent +from ..shared.dataset_metadata_content import DatasetMetadataContent __all__ = ["FilesetMetadata"] diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/shared_params/fileset_metadata.py b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata_param.py similarity index 85% rename from sdk/python/nemo-platform/src/nemo_platform/types/shared_params/fileset_metadata.py rename to sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata_param.py index d53a643b0d..66f37de921 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/shared_params/fileset_metadata.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata_param.py @@ -19,13 +19,13 @@ from typing_extensions import TypedDict -from .model_metadata_content import ModelMetadataContent -from .dataset_metadata_content import DatasetMetadataContent +from ..shared_params.model_metadata_content import ModelMetadataContent +from ..shared_params.dataset_metadata_content import DatasetMetadataContent -__all__ = ["FilesetMetadata"] +__all__ = ["FilesetMetadataParam"] -class FilesetMetadata(TypedDict, total=False): +class FilesetMetadataParam(TypedDict, total=False): """Tagged metadata container - the key indicates the type. Example: diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_update_params.py b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_update_params.py index 3f8699dda8..0b389fd318 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_update_params.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_update_params.py @@ -21,7 +21,7 @@ from typing_extensions import TypedDict from .fileset_purpose import FilesetPurpose -from ..shared_params.fileset_metadata import FilesetMetadata +from .fileset_metadata_param import FilesetMetadataParam __all__ = ["FilesetUpdateParams"] @@ -35,7 +35,7 @@ class FilesetUpdateParams(TypedDict, total=False): description: str """The description of the fileset.""" - metadata: FilesetMetadata + metadata: FilesetMetadataParam """Tagged metadata container - the key indicates the type. Example: metadata = FilesetMetadata( dataset=DatasetMetadataContent( diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec.py b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec.py index ad9948abf0..6d2de8677e 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec.py @@ -28,8 +28,8 @@ class ContainerSpec(BaseModel): Defines the container image and related configuration for job execution. """ - image: Optional[str] = None - command: Optional[List[str]] = None entrypoint: Optional[List[str]] = None + + image: Optional[str] = None diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec_param.py b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec_param.py index 06347f4c0e..23ac07cc30 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec_param.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/container_spec_param.py @@ -17,7 +17,7 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing_extensions import TypedDict from ..._types import SequenceNotStr @@ -30,8 +30,8 @@ class ContainerSpecParam(TypedDict, total=False): Defines the container image and related configuration for job execution. """ - image: str - command: SequenceNotStr[str] entrypoint: SequenceNotStr[str] + + image: str diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/docker_job_execution_profile_config.py b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/docker_job_execution_profile_config.py index 1a6d2602ad..cdce4354fa 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/docker_job_execution_profile_config.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/docker_job_execution_profile_config.py @@ -29,6 +29,14 @@ class DockerJobExecutionProfileConfig(BaseModel): cleanup_completed_jobs_immediately: Optional[bool] = None + default_task_image: Optional[str] = None + """Default container image for job task pods. + + Used when a job step omits container.image. When unset, falls back to the + platform CPU tasks image + (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + """ + env: Optional[Dict[str, str]] = None """Optional env vars applied to all jobs (e.g. diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/job_execution_profile_config.py b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/job_execution_profile_config.py index f368ee1589..d30d547c45 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/job_execution_profile_config.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/job_execution_profile_config.py @@ -25,6 +25,14 @@ class JobExecutionProfileConfig(BaseModel): cleanup_completed_jobs_immediately: Optional[bool] = None + default_task_image: Optional[str] = None + """Default container image for job task pods. + + Used when a job step omits container.image. When unset, falls back to the + platform CPU tasks image + (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + """ + env: Optional[Dict[str, str]] = None """Optional env vars applied to all jobs (e.g. diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/kubernetes_job_execution_profile_config.py b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/kubernetes_job_execution_profile_config.py index 34ff6d5ca9..81f5941f63 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/kubernetes_job_execution_profile_config.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/kubernetes_job_execution_profile_config.py @@ -34,6 +34,14 @@ class KubernetesJobExecutionProfileConfig(BaseModel): cleanup_completed_jobs_immediately: Optional[bool] = None + default_task_image: Optional[str] = None + """Default container image for job task pods. + + Used when a job step omits container.image. When unset, falls back to the + platform CPU tasks image + (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + """ + env: Optional[Dict[str, str]] = None """Optional env vars applied to all jobs (e.g. diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/subprocess_job_execution_profile_config.py b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/subprocess_job_execution_profile_config.py index b48dd4350d..8969bb951f 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/subprocess_job_execution_profile_config.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/subprocess_job_execution_profile_config.py @@ -26,6 +26,14 @@ class SubprocessJobExecutionProfileConfig(BaseModel): cleanup_completed_jobs_immediately: Optional[bool] = None """Keep subprocess working directories by default so runs remain inspectable.""" + default_task_image: Optional[str] = None + """Default container image for job task pods. + + Used when a job step omits container.image. When unset, falls back to the + platform CPU tasks image + (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + """ + env: Optional[Dict[str, str]] = None """Optional env vars applied to all jobs (e.g. diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/volcano_job_execution_profile_config.py b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/volcano_job_execution_profile_config.py index 0c04f84278..c4ace352c0 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/jobs/volcano_job_execution_profile_config.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/jobs/volcano_job_execution_profile_config.py @@ -34,6 +34,14 @@ class VolcanoJobExecutionProfileConfig(BaseModel): cleanup_completed_jobs_immediately: Optional[bool] = None + default_task_image: Optional[str] = None + """Default container image for job task pods. + + Used when a job step omits container.image. When unset, falls back to the + platform CPU tasks image + (platform.image_registry/nmp-cpu-tasks:platform.image_tag). + """ + enable_multi_node_networking: Optional[bool] = None """Enable multi-node networking injection. diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/shared/__init__.py b/sdk/python/nemo-platform/src/nemo_platform/types/shared/__init__.py index e0178b4f49..7a667ef8b5 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/shared/__init__.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/shared/__init__.py @@ -26,7 +26,6 @@ from .delete_response import DeleteResponse as DeleteResponse from .finetuning_type import FinetuningType as FinetuningType from .pagination_data import PaginationData as PaginationData -from .fileset_metadata import FilesetMetadata as FilesetMetadata from .inference_params import InferenceParams as InferenceParams from .platform_job_log import PlatformJobLog as PlatformJobLog from .tool_call_config import ToolCallConfig as ToolCallConfig diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/shared_params/__init__.py b/sdk/python/nemo-platform/src/nemo_platform/types/shared_params/__init__.py index 449d6c5e14..f78dae8e90 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/shared_params/__init__.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/shared_params/__init__.py @@ -23,7 +23,6 @@ from .backend_format import BackendFormat as BackendFormat from .datetime_filter import DatetimeFilter as DatetimeFilter from .finetuning_type import FinetuningType as FinetuningType -from .fileset_metadata import FilesetMetadata as FilesetMetadata from .inference_params import InferenceParams as InferenceParams from .tool_call_config import ToolCallConfig as ToolCallConfig from .api_endpoint_data import APIEndpointData as APIEndpointData diff --git a/sdk/python/nemo-platform/tests/api_resources/test_jobs.py b/sdk/python/nemo-platform/tests/api_resources/test_jobs.py index dce491ed23..537f366757 100644 --- a/sdk/python/nemo-platform/tests/api_resources/test_jobs.py +++ b/sdk/python/nemo-platform/tests/api_resources/test_jobs.py @@ -52,7 +52,7 @@ def test_method_create(self, client: NeMoPlatform) -> None: "steps": [ { "executor": { - "container": {"image": "image"}, + "container": {}, "provider": "cpu", }, "name": "preprocess", @@ -74,9 +74,9 @@ def test_method_create_with_all_params(self, client: NeMoPlatform) -> None: { "executor": { "container": { - "image": "image", "command": ["string"], "entrypoint": ["string"], + "image": "image", }, "profile": "profile", "provider": "cpu", @@ -126,7 +126,7 @@ def test_raw_response_create(self, client: NeMoPlatform) -> None: "steps": [ { "executor": { - "container": {"image": "image"}, + "container": {}, "provider": "cpu", }, "name": "preprocess", @@ -151,7 +151,7 @@ def test_streaming_response_create(self, client: NeMoPlatform) -> None: "steps": [ { "executor": { - "container": {"image": "image"}, + "container": {}, "provider": "cpu", }, "name": "preprocess", @@ -179,7 +179,7 @@ def test_path_params_create(self, client: NeMoPlatform) -> None: "steps": [ { "executor": { - "container": {"image": "image"}, + "container": {}, "provider": "cpu", }, "name": "preprocess", @@ -746,7 +746,7 @@ async def test_method_create(self, async_client: AsyncNeMoPlatform) -> None: "steps": [ { "executor": { - "container": {"image": "image"}, + "container": {}, "provider": "cpu", }, "name": "preprocess", @@ -768,9 +768,9 @@ async def test_method_create_with_all_params(self, async_client: AsyncNeMoPlatfo { "executor": { "container": { - "image": "image", "command": ["string"], "entrypoint": ["string"], + "image": "image", }, "profile": "profile", "provider": "cpu", @@ -820,7 +820,7 @@ async def test_raw_response_create(self, async_client: AsyncNeMoPlatform) -> Non "steps": [ { "executor": { - "container": {"image": "image"}, + "container": {}, "provider": "cpu", }, "name": "preprocess", @@ -845,7 +845,7 @@ async def test_streaming_response_create(self, async_client: AsyncNeMoPlatform) "steps": [ { "executor": { - "container": {"image": "image"}, + "container": {}, "provider": "cpu", }, "name": "preprocess", @@ -873,7 +873,7 @@ async def test_path_params_create(self, async_client: AsyncNeMoPlatform) -> None "steps": [ { "executor": { - "container": {"image": "image"}, + "container": {}, "provider": "cpu", }, "name": "preprocess", diff --git a/services/core/jobs/src/nmp/core/jobs/app/providers.py b/services/core/jobs/src/nmp/core/jobs/app/providers.py index 0bd23036f9..40e9ef366a 100644 --- a/services/core/jobs/src/nmp/core/jobs/app/providers.py +++ b/services/core/jobs/src/nmp/core/jobs/app/providers.py @@ -19,7 +19,7 @@ class ContainerSpec(BaseModel): """ image: str | None = None - """The container image to use for execution. When omitted, the execution profile's default_task_image is used.""" + """The container image to use for execution. When omitted, resolved from the execution profile's default_task_image or the platform CPU tasks image.""" entrypoint: list[str] = Field(default_factory=list) """The entrypoint for the container as a list of strings (e.g., ['python', 'script.py']). This overrides a container's default entrypoint (e.g. ENTRYPOINT in Docker) if provided.""" diff --git a/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py b/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py index c042cadc90..f8bd176728 100644 --- a/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py +++ b/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py @@ -94,7 +94,7 @@ class JobExecutionProfileConfig(BaseModel): default_task_image: str | None = Field( default=None, description="Default container image for job task pods. Used when a job step omits container.image. " - "On Kubernetes this is typically the platform API image. When unset, container.image is required.", + "When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag).", ) env: dict[str, str] = Field( default_factory=dict, From a51b41878381c183b936cd5d4a9280512c251538 Mon Sep 17 00:00:00 2001 From: Matthew Grossman Date: Fri, 12 Jun 2026 10:57:54 -0700 Subject: [PATCH 4/9] code review Signed-off-by: Matthew Grossman --- .../jobs/src/nmp/core/jobs/controllers/backends/base.py | 7 +------ .../integration/test_model_entity_service_integration.py | 3 +-- .../models/tests/unit/test_model_entity_service_unit.py | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py b/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py index f8bd176728..4eabda8dff 100644 --- a/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py +++ b/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py @@ -122,14 +122,9 @@ def resolve_task_image(container_image: str | None, default_task_image: str | No 2. default_task_image from the execution profile config 3. Platform CPU tasks image derived from platform.image_registry / image_tag """ - if container_image: - return container_image - if default_task_image: - return default_task_image - from nemo_platform_plugin.jobs.image import get_qualified_image - return get_qualified_image(_DEFAULT_TASK_IMAGE_NAME) + return container_image or default_task_image or get_qualified_image(_DEFAULT_TASK_IMAGE_NAME) def resolve_gpu_job_shm_size( diff --git a/services/core/models/tests/integration/test_model_entity_service_integration.py b/services/core/models/tests/integration/test_model_entity_service_integration.py index 6611a27e82..ab008ccbc8 100644 --- a/services/core/models/tests/integration/test_model_entity_service_integration.py +++ b/services/core/models/tests/integration/test_model_entity_service_integration.py @@ -8,8 +8,7 @@ import pytest from nemo_platform import AsyncNeMoPlatform from nemo_platform.filesets import ListFilesResponse -from nemo_platform.types.files import Fileset, FilesetFile, LocalStorageConfig -from nemo_platform.types.shared import FilesetMetadata +from nemo_platform.types.files import Fileset, FilesetFile, FilesetMetadata, LocalStorageConfig from nmp.common.api.filter import ComparisonOperation, FilterOperator, LogicalOperation from nmp.common.api.parsed_filter import ParsedFilter from nmp.common.entities.client import EntityClient diff --git a/services/core/models/tests/unit/test_model_entity_service_unit.py b/services/core/models/tests/unit/test_model_entity_service_unit.py index 63b7c264be..821525be83 100644 --- a/services/core/models/tests/unit/test_model_entity_service_unit.py +++ b/services/core/models/tests/unit/test_model_entity_service_unit.py @@ -14,11 +14,11 @@ from nemo_platform.types.files import ( Fileset, FilesetFile, + FilesetMetadata, HuggingfaceStorageConfig, LocalStorageConfig, NGCStorageConfig, ) -from nemo_platform.types.shared import FilesetMetadata from nmp.common.api.common import Page, PaginationData from nmp.common.api.filter import ComparisonOperation, FilterOperator, LogicalOperation from nmp.common.api.parsed_filter import ParsedFilter From 934d11c815a7b884bbdac60eaacbb742e3a07007 Mon Sep 17 00:00:00 2001 From: Matthew Grossman Date: Fri, 12 Jun 2026 11:03:47 -0700 Subject: [PATCH 5/9] merge fixes Signed-off-by: Matthew Grossman --- .../src/nemo_platform/resources/files/api.md | 2 +- .../src/nemo_platform/types/__init__.py | 1 + .../src/nemo_platform/types/files/__init__.py | 2 - .../src/nemo_platform/types/files/fileset.py | 2 +- .../types/files/fileset_create_params.py | 1 - .../types/files/fileset_metadata_param.py | 47 ------------------- .../nemo_platform/types/shared/__init__.py | 1 + .../{files => shared}/fileset_metadata.py | 4 +- .../shared_params/fileset_metadata_param.py | 4 +- 9 files changed, 8 insertions(+), 56 deletions(-) delete mode 100644 sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata_param.py rename sdk/python/nemo-platform/src/nemo_platform/types/{files => shared}/fileset_metadata.py (91%) diff --git a/sdk/python/nemo-platform/src/nemo_platform/resources/files/api.md b/sdk/python/nemo-platform/src/nemo_platform/resources/files/api.md index 882f649add..72e7b5ca66 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/resources/files/api.md +++ b/sdk/python/nemo-platform/src/nemo_platform/resources/files/api.md @@ -33,7 +33,7 @@ Methods: Types: ```python -from nemo_platform.types.files import FilesetFilter, FilesetMetadata, FilesetMetadataParam +from nemo_platform.types.files import FilesetFilter ``` Methods: diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/__init__.py b/sdk/python/nemo-platform/src/nemo_platform/types/__init__.py index 571b87927b..eb3af5c4f7 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/__init__.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/__init__.py @@ -32,6 +32,7 @@ PlatformJobLog as PlatformJobLog, ToolCallConfig as ToolCallConfig, APIEndpointData as APIEndpointData, + FilesetMetadata as FilesetMetadata, FileStorageType as FileStorageType, InferenceParams as InferenceParams, LinearLayerSpec as LinearLayerSpec, diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/files/__init__.py b/sdk/python/nemo-platform/src/nemo_platform/types/files/__init__.py index b76dd4a694..3833c1d785 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/files/__init__.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/files/__init__.py @@ -22,7 +22,6 @@ from .cache_status import CacheStatus as CacheStatus from .fileset_file import FilesetFile as FilesetFile from .fileset_purpose import FilesetPurpose as FilesetPurpose -from .fileset_metadata import FilesetMetadata as FilesetMetadata from .s3_storage_config import S3StorageConfig as S3StorageConfig from .ngc_storage_config import NGCStorageConfig as NGCStorageConfig from .fileset_list_params import FilesetListParams as FilesetListParams @@ -33,7 +32,6 @@ from .fileset_create_params import FilesetCreateParams as FilesetCreateParams from .fileset_update_params import FilesetUpdateParams as FilesetUpdateParams from .file_list_files_params import FileListFilesParams as FileListFilesParams -from .fileset_metadata_param import FilesetMetadataParam as FilesetMetadataParam from .file_upload_file_params import FileUploadFileParams as FileUploadFileParams from .s3_storage_config_param import S3StorageConfigParam as S3StorageConfigParam from .ngc_storage_config_param import NGCStorageConfigParam as NGCStorageConfigParam diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset.py b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset.py index e6d9642b7a..810d5ce990 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset.py @@ -20,10 +20,10 @@ from ..._models import BaseModel from .fileset_purpose import FilesetPurpose -from .fileset_metadata import FilesetMetadata from .s3_storage_config import S3StorageConfig from .ngc_storage_config import NGCStorageConfig from .local_storage_config import LocalStorageConfig +from ..shared.fileset_metadata import FilesetMetadata from .huggingface_storage_config import HuggingfaceStorageConfig __all__ = ["Fileset", "Storage"] diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_create_params.py b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_create_params.py index ea3cb763f7..9836fcb477 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_create_params.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_create_params.py @@ -21,7 +21,6 @@ from typing_extensions import Required, TypeAlias, TypedDict from .fileset_purpose import FilesetPurpose -from .fileset_metadata_param import FilesetMetadataParam from .s3_storage_config_param import S3StorageConfigParam from .ngc_storage_config_param import NGCStorageConfigParam from .local_storage_config_param import LocalStorageConfigParam diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata_param.py b/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata_param.py deleted file mode 100644 index 66f37de921..0000000000 --- a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata_param.py +++ /dev/null @@ -1,47 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -from ..shared_params.model_metadata_content import ModelMetadataContent -from ..shared_params.dataset_metadata_content import DatasetMetadataContent - -__all__ = ["FilesetMetadataParam"] - - -class FilesetMetadataParam(TypedDict, total=False): - """Tagged metadata container - the key indicates the type. - - Example: - metadata = FilesetMetadata( - dataset=DatasetMetadataContent( - schema={"columns": ["id", "name"]}, - ) - ) - """ - - dataset: DatasetMetadataContent - """Content for dataset-type filesets.""" - - model: ModelMetadataContent - """Content for model-type filesets. - - Contains tool calling configuration that is merged into the ModelSpec during - checkpoint analysis. - """ diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/shared/__init__.py b/sdk/python/nemo-platform/src/nemo_platform/types/shared/__init__.py index 70ea9bdc92..d16fead87f 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/shared/__init__.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/shared/__init__.py @@ -26,6 +26,7 @@ from .delete_response import DeleteResponse as DeleteResponse from .finetuning_type import FinetuningType as FinetuningType from .pagination_data import PaginationData as PaginationData +from .fileset_metadata import FilesetMetadata as FilesetMetadata from .inference_params import InferenceParams as InferenceParams from .platform_job_log import PlatformJobLog as PlatformJobLog from .tool_call_config import ToolCallConfig as ToolCallConfig diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata.py b/sdk/python/nemo-platform/src/nemo_platform/types/shared/fileset_metadata.py similarity index 91% rename from sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata.py rename to sdk/python/nemo-platform/src/nemo_platform/types/shared/fileset_metadata.py index 36573bd374..b35b6d8ecc 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/files/fileset_metadata.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/shared/fileset_metadata.py @@ -18,8 +18,8 @@ from typing import Optional from ..._models import BaseModel -from ..shared.model_metadata_content import ModelMetadataContent -from ..shared.dataset_metadata_content import DatasetMetadataContent +from .model_metadata_content import ModelMetadataContent +from .dataset_metadata_content import DatasetMetadataContent __all__ = ["FilesetMetadata"] diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/shared_params/fileset_metadata_param.py b/sdk/python/nemo-platform/src/nemo_platform/types/shared_params/fileset_metadata_param.py index 66f37de921..e3f510ca6e 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/shared_params/fileset_metadata_param.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/shared_params/fileset_metadata_param.py @@ -19,8 +19,8 @@ from typing_extensions import TypedDict -from ..shared_params.model_metadata_content import ModelMetadataContent -from ..shared_params.dataset_metadata_content import DatasetMetadataContent +from .model_metadata_content import ModelMetadataContent +from .dataset_metadata_content import DatasetMetadataContent __all__ = ["FilesetMetadataParam"] From 850c83a65e6c2e3f2277e0ab7e6989b97b2b4633 Mon Sep 17 00:00:00 2001 From: Matthew Grossman Date: Fri, 12 Jun 2026 11:47:36 -0700 Subject: [PATCH 6/9] fixes Signed-off-by: Matthew Grossman --- .../tests/integration/test_model_entity_service_integration.py | 3 ++- .../core/models/tests/unit/test_model_entity_service_unit.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/services/core/models/tests/integration/test_model_entity_service_integration.py b/services/core/models/tests/integration/test_model_entity_service_integration.py index ab008ccbc8..6611a27e82 100644 --- a/services/core/models/tests/integration/test_model_entity_service_integration.py +++ b/services/core/models/tests/integration/test_model_entity_service_integration.py @@ -8,7 +8,8 @@ import pytest from nemo_platform import AsyncNeMoPlatform from nemo_platform.filesets import ListFilesResponse -from nemo_platform.types.files import Fileset, FilesetFile, FilesetMetadata, LocalStorageConfig +from nemo_platform.types.files import Fileset, FilesetFile, LocalStorageConfig +from nemo_platform.types.shared import FilesetMetadata from nmp.common.api.filter import ComparisonOperation, FilterOperator, LogicalOperation from nmp.common.api.parsed_filter import ParsedFilter from nmp.common.entities.client import EntityClient diff --git a/services/core/models/tests/unit/test_model_entity_service_unit.py b/services/core/models/tests/unit/test_model_entity_service_unit.py index 821525be83..63b7c264be 100644 --- a/services/core/models/tests/unit/test_model_entity_service_unit.py +++ b/services/core/models/tests/unit/test_model_entity_service_unit.py @@ -14,11 +14,11 @@ from nemo_platform.types.files import ( Fileset, FilesetFile, - FilesetMetadata, HuggingfaceStorageConfig, LocalStorageConfig, NGCStorageConfig, ) +from nemo_platform.types.shared import FilesetMetadata from nmp.common.api.common import Page, PaginationData from nmp.common.api.filter import ComparisonOperation, FilterOperator, LogicalOperation from nmp.common.api.parsed_filter import ParsedFilter From d6d9952af252a80b87e466bdbe764cddfb1165c1 Mon Sep 17 00:00:00 2001 From: Matthew Grossman Date: Fri, 12 Jun 2026 11:58:25 -0700 Subject: [PATCH 7/9] remove Signed-off-by: Matthew Grossman --- docs/k8s-dev-guide.md | 350 ------------------------------------------ 1 file changed, 350 deletions(-) delete mode 100644 docs/k8s-dev-guide.md diff --git a/docs/k8s-dev-guide.md b/docs/k8s-dev-guide.md deleted file mode 100644 index 68ae22c8c4..0000000000 --- a/docs/k8s-dev-guide.md +++ /dev/null @@ -1,350 +0,0 @@ -# Kubernetes Developer Guide - -How to test, debug, and reproduce issues against NeMo Platform's Kubernetes environments. - -**Linear ticket:** [AIRCORE-765](https://linear.app/nvidia/issue/AIRCORE-765/k8s-dev-testing-and-release-readiness-for-nmpdev) - -## Environments - -| Environment | URL | Deploys on | -| -- | -- | -- | -| Merge-to-main | https://nmp.dev.aire.nvidia.com/ | Every merge to `main` | -| Nightly snapshot | https://nemo-platform-nightly.dev.aire.nvidia.com | Nightly release build | - -Both environments serve Studio at `/studio/` and expose the API at the root URL. The `/cluster-info` endpoint requires authentication: - -```bash -curl -s -H "Authorization: Bearer $(nemo auth token)" \ - https://nmp.dev.aire.nvidia.com/cluster-info | jq . -# {"platform_version":"0.0.1","revision":"a3e68a67..."} -``` - -## One-time CLI setup - -The NeMo CLI uses **contexts** (similar to `kubectl` contexts) to manage multiple environments. Set up all your contexts once and switch between them as needed. Config lives at `~/.config/nmp/config.yaml`. - -### Create your contexts - -Use `nemo config set --context --base-url ` to create a new context. This creates the context, a dedicated cluster entry, and a user entry all at once. Creating a new context automatically makes it the active context. - -```bash -# nmp.dev — merge-to-main K8s environment (OIDC auth required) -nemo config set --context tot --base-url https://nmp.dev.aire.nvidia.com - -# nmp.dev nightly — nightly snapshot release (OIDC auth required) -nemo config set --context nightly --base-url https://nemo-platform-nightly.dev.aire.nvidia.com - -# Local development — subprocess mode via `nemo services run` -nemo config set --context localdev --base-url http://localhost:8080 - -# Minikube — local K8s cluster -nemo config set --context minikube --base-url http://localhost:30080 - -# Dev-blue — GPU development box -nemo config set --context dev-blue --base-url https://.dev.aire.nvidia.com -``` - -After running these, switch back to whichever context you want to use: - -```bash -nemo config use-context localdev -``` - -### Switch between contexts - -```bash -nemo config use-context tot # nmp.dev merge-to-main -nemo config use-context nightly # nmp.dev nightly snapshot -nemo config use-context localdev # local subprocess -nemo config use-context minikube # local K8s -nemo config use-context dev-blue # GPU dev box -``` - -Check which context you're on: - -```bash -nemo config current-context -``` - -View all contexts: - -```bash -nemo config view --all-contexts -``` - -### Authenticate to nmp.dev - -The `tot` and `nightly` contexts require OIDC authentication via NVIDIA SSO (Microsoft). The local contexts (`localdev`, `minikube`) don't require auth. - -```bash -nemo config use-context tot -nemo auth login -``` - -This will: - -1. Discover the OIDC configuration from the cluster -2. Give you a device code and URL (`https://login.microsoft.com/device`) -3. Open your browser — enter the code and sign in with your NVIDIA account -4. Save credentials including a refresh token for automatic renewal - -Verify it worked: - -```bash -nemo auth status -nemo workspaces list -``` - -You should see at least `default` and `system` workspaces. - -### Workspaces - -* **default** — general-purpose workspace, all users have write access. Use this for testing. -* **system** — platform-provided resources, read-only for users. - -## Validated CLI commands - -The following commands have been tested against nmp.dev (with auth) and minikube (without auth): - -```bash -nemo workspaces list # list workspaces -nemo workspaces get default # get a specific workspace -nemo workspaces create # create a workspace -nemo plugins list # list loaded plugins -nemo inference models list # list available models -nemo auth status # check auth state -nemo auth token # print bearer token (for SDK/curl use) -``` - -## Using the SDK against nmp.dev - -If you need to use the Python SDK directly (e.g., in scripts or tests), you can construct a client using a CLI context or explicit token: - -```python -from nemo_platform import NeMoPlatform - -# Option 1: use a CLI context (recommended — handles token refresh) -client = NeMoPlatform(context_name="tot") - -# Option 2: explicit base URL + token -import os -client = NeMoPlatform( - base_url="https://nmp.dev.aire.nvidia.com", - access_token=os.environ["NMP_ACCESS_TOKEN"], -) -``` - -To get a token for curl or other tools: - -```bash -export NMP_ACCESS_TOKEN=$(nemo auth token) - -# Note: on K8s, API routes use the /apis/ prefix (e.g., /apis/entities/v2/...) -# The SDK handles this automatically, but for raw curl you need the right paths. -curl -s -H "Authorization: Bearer $NMP_ACCESS_TOKEN" \ - https://nmp.dev.aire.nvidia.com/cluster-info | jq . -``` - -## Running e2e tests - -### Against nmp.dev - -The e2e test harness supports pointing at an already-running instance via `NMP_BASE_URL`. This skips local service startup and runs tests directly against the cluster. - -Authentication can be provided via `NMP_ACCESS_TOKEN` (explicit token) or `NMP_CONTEXT_NAME` (reads credentials from CLI config): - -```bash -# Option 1: explicit token -NMP_BASE_URL=https://nmp.dev.aire.nvidia.com \ - NMP_ACCESS_TOKEN=$(nemo auth token) \ - uv run --frozen pytest e2e --run-e2e -v - -# Option 2: use a CLI context (reads token + refresh from config) -NMP_BASE_URL=https://nmp.dev.aire.nvidia.com \ - NMP_CONTEXT_NAME=tot \ - uv run --frozen pytest e2e --run-e2e -v -``` - -Note: you need to be in the appropriate context (or have recently run `nemo auth login`) for `nemo auth token` to return a valid token. - -### Against minikube - -No auth needed — just point at the local cluster: - -```bash -NMP_BASE_URL=http://localhost:30080 uv run --frozen pytest e2e --run-e2e -v -``` - -### Known issues - -**On nmp.dev (as of 2026-06-10):** 2 passed, 5 skipped, 52 failed. - -* **RBAC blocks entity operations (403 Forbidden)** ([AIRCORE-771](https://linear.app/nvidia/issue/AIRCORE-771)): Entity create/update/delete returns 403 for authenticated users, in all workspaces including `default`. This blocks entity, inference, files, and most other tests. **Confirmed not a code bug** — entity CRUD works on minikube without auth. The 403 is specific to nmp.dev's RBAC configuration. -* **Health/Studio/cluster-info tests use** `sdk._client.get()`: These tests access the internal httpx client directly, which has an empty base URL when auth bootstrap is active. -* **Mock inference provider unavailable**: Tests relying on `mock.local` fail because the mock provider is subprocess-only. - -**On minikube with locally built image (as of 2026-06-12):** 7 passed, 1 failed, 5 skipped. - -* All entity, workspace, secret, and job execution tests pass -* `test_job_passing_data_between_steps` fails — persistent storage env var not set (pre-existing) -* Health endpoint tests fail (not routed through ingress — known routing gap) - -**On minikube with stale GHCR image:** 9 passed, 9 failed — secrets tests fail due to API version skew, entity search filter has a minor mismatch. Use a locally built image to avoid this. - -## Observability and debugging - -Phil's team has observability flowing for both environments with more dashboards in progress. - -**Dashboards:** TBD — need Grafana URL and access instructions from Phil's team. - -**Logs:** TBD — need to confirm how devs access pod logs (Grafana/Loki? direct kubectl? dashboard only?). - -**Deployment notifications:** Deployment status is included in the nightly release Slack update. Deployment failure messages currently go to ops channels — may be surfaced to devs in the future. - -**Useful kubectl commands for debugging:** - -```bash -# Check pod status -kubectl get pods - -# Check logs for a crashing pod -kubectl logs --tail=50 - -# Attach a debug container to a running pod -POD=$(kubectl get pod | awk '/nemo-platform-api/{print $1; exit}') && \ - kubectl debug -it $POD --image=ghcr.io/astral-sh/uv:debian --target=nmp-api --profile=sysadmin -- bash - -# Profile with py-spy -POD=$(kubectl get pod | awk '/nemo-platform-api/{print $1; exit}') && \ - kubectl debug -i $POD --image=ghcr.io/astral-sh/uv:debian --target=nmp-api --profile=sysadmin -- \ - sh -c 'uvx py-spy record --pid 1 --format speedscope --duration 5 -o /tmp/profile.json >/dev/null 2>&1 && cat /tmp/profile.json' | tee profile.json -``` - -## Reproducing failures locally - -When you find a failure on nmp.dev, use the lightest environment that can reproduce it: - -### 1. Subprocess mode - -Fastest option. No containers. Good for API logic and plugin behavior issues. Won't catch container or networking issues. - -```bash -nemo config use-context localdev -nemo services run -``` - -### 2. Docker backend - -*TODO: document Docker backend setup* - -### 3. Minikube / kind - -Local single-node K8s cluster. Deploy using the same Helm chart used in production. Catches K8s-specific issues: ingress, service discovery, persistent volumes, RBAC. - -The Dockerfiles and `docker-bake.hcl` live in the nemo-platform repo. The Helm chart and minikube setup scripts live in the **Platform-Deploy** repo ([NVIDIA-NeMo/Platform-Deploy](https://github.com/NVIDIA-NeMo/Platform-Deploy)). - -#### Prerequisites - -* Docker Desktop running with at least 6GB memory allocated (Settings > Resources > Memory) -* `minikube`, `kubectl`, `helm` installed -* Platform-Deploy repo cloned (e.g., `~/dev/Platform-Deploy`) -* `NGC_API_KEY` env var set (needed for Helm chart dependencies from NGC) -* GitHub CLI (`gh`) authenticated with `read:packages` scope (needed to pull base-of-base images from GHCR) - -#### Setup - -First, choose your image configuration: - -```bash -# Option A: Build locally (for testing code changes) -NMP_REGISTRY=my-registry -NMP_TAG=local -NMP_PULL_POLICY=Never - -# Option B: Pre-built from GHCR (faster, no local build) -# NMP_REGISTRY=ghcr.io/nvidia-nemo/platform -# NMP_TAG=latest -# NMP_PULL_POLICY=IfNotPresent - -NMP_IMAGE=${NMP_REGISTRY}/nmp-api -``` - -Then run the setup: - -```bash -# 1. Start minikube cluster -bash ~/dev/Platform-Deploy/e2e/k8s/scripts/setup_local_minikube_cpu.sh - -# 2. Point Docker at minikube's daemon -eval $(minikube -p minikube-auth docker-env) - -# 3. One-time GHCR auth (needed for pulling base images during build, or for Option B) -gh auth refresh -h github.com -s read:packages -gh auth token | docker login ghcr.io -u $(gh api user --jq .login) --password-stdin - -# 4. Build images locally (skip this step if using Option B) -# BUILD_ARCH: set to linux/arm64 on Apple Silicon, linux/amd64 on Intel -BUILD_ARCH=linux/arm64 \ - BAKE_REGISTRY_IMAGE=${NMP_REGISTRY} BAKE_TAG=${NMP_TAG} \ - docker buildx bake --progress=plain --load docker-cpu - -# 5. Add the NGC Helm repo (needed for chart dependencies) -helm repo add nvidia https://helm.ngc.nvidia.com/nvidia \ - --username='$oauthtoken' --password="${NGC_API_KEY}" - -# 6. Build chart dependencies and install via Helm -(cd ~/dev/Platform-Deploy && \ - helm dependency build helm/platform && \ - helm upgrade -i nemo-platform helm/platform \ - -f e2e/k8s/values/minikube.yaml \ - --set "api.image.repository=${NMP_IMAGE}" \ - --set "api.image.tag=${NMP_TAG}" \ - --set "api.image.pullPolicy=${NMP_PULL_POLICY}" \ - --set "core.image.repository=${NMP_IMAGE}" \ - --set "core.image.tag=${NMP_TAG}" \ - --set "core.image.pullPolicy=${NMP_PULL_POLICY}" \ - --set "platformConfig.platform.image_registry=${NMP_REGISTRY}" \ - --set "platformConfig.platform.image_tag=${NMP_TAG}" \ - --timeout 10m \ - --wait) -``` - -Step 4 builds `nmp-api`, `nmp-core`, and `nmp-cpu-tasks` directly into minikube's Docker daemon. The Python base is built automatically as a dependency. Skip this step if using pre-built GHCR images (Option B). - -The `platformConfig.platform.image_registry` and `image_tag` tell the platform which container images to use when launching job task pods. Without these, the platform defaults to `nvcr.io/nvidia/nemo-microservices` which won't match your local images. - -Note: the GHCR `latest` image may be behind current source — the core controller may crash, secrets API may have version skew, and entity search filters may differ. Building locally avoids this. - -#### Connect nemo CLI to minikube - -```bash -nemo config use-context minikube -# minikube context points at http://localhost:30080 (no auth needed) -nemo workspaces list -``` - -#### Values files - -Platform-Deploy provides several values files for different scenarios: - -| File | Use case | -| -- | -- | -| `e2e/k8s/values/minikube.yaml` | Basic minikube (NIM operator, local storage, mock inference) | -| `e2e/k8s/values/minikube-auth.yaml` | Auth enabled, embedded policy decision point | -| `e2e/k8s/values/default.yaml` | E2E test defaults (NIM disabled, local-path storage) | -| `e2e/k8s/values/s3-rustfs.yaml` | S3-compatible storage via RustFS | - -Important: use `minikube.yaml` (not `default.yaml`) for minikube — the default values reference `oci-nfs` storage class which doesn't exist on minikube and will cause PVC creation to fail. - -#### Teardown - -```bash -helm uninstall nemo-platform -kubectl delete pvc --all -# Or nuclear: -minikube -p minikube-auth delete -``` - -### 4. Dev-blue box - -*TODO: document dev-blue setup and access* From 55fd1beef12f96248ce621cc9657c2b0e0069068 Mon Sep 17 00:00:00 2001 From: Matthew Grossman Date: Fri, 12 Jun 2026 12:21:46 -0700 Subject: [PATCH 8/9] lint Signed-off-by: Matthew Grossman --- services/core/jobs/src/nmp/core/jobs/app/providers.py | 2 +- .../core/jobs/src/nmp/core/jobs/controllers/backends/base.py | 1 + .../src/nmp/core/jobs/controllers/backends/kubernetes/common.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/services/core/jobs/src/nmp/core/jobs/app/providers.py b/services/core/jobs/src/nmp/core/jobs/app/providers.py index 40e9ef366a..c57f6c08bd 100644 --- a/services/core/jobs/src/nmp/core/jobs/app/providers.py +++ b/services/core/jobs/src/nmp/core/jobs/app/providers.py @@ -18,7 +18,7 @@ class ContainerSpec(BaseModel): Defines the container image and related configuration for job execution. """ - image: str | None = None + image: str | None = Field(default=None, min_length=1) """The container image to use for execution. When omitted, resolved from the execution profile's default_task_image or the platform CPU tasks image.""" entrypoint: list[str] = Field(default_factory=list) diff --git a/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py b/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py index 4eabda8dff..0bf9088313 100644 --- a/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py +++ b/services/core/jobs/src/nmp/core/jobs/controllers/backends/base.py @@ -93,6 +93,7 @@ class JobExecutionProfileConfig(BaseModel): launcher_tool_path: str = Field(default="/tools/jobs-launcher", description="Path to the jobs launcher tool") default_task_image: str | None = Field( default=None, + min_length=1, description="Default container image for job task pods. Used when a job step omits container.image. " "When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag).", ) diff --git a/services/core/jobs/src/nmp/core/jobs/controllers/backends/kubernetes/common.py b/services/core/jobs/src/nmp/core/jobs/controllers/backends/kubernetes/common.py index e17700dce3..30f24e4991 100644 --- a/services/core/jobs/src/nmp/core/jobs/controllers/backends/kubernetes/common.py +++ b/services/core/jobs/src/nmp/core/jobs/controllers/backends/kubernetes/common.py @@ -1104,7 +1104,7 @@ def create_pod_template_spec( command.append(cmd) # Resolve the task image: explicit container.image takes precedence, - # then the profile's default_task_image, then error. + # then the profile's default_task_image, then platform CPU tasks image fallback. task_image = resolve_task_image(container.image, config.default_task_image) # Main job container From 3a68eb646d9a3f9ac03472875485a7ec15914b44 Mon Sep 17 00:00:00 2001 From: Matthew Grossman Date: Fri, 12 Jun 2026 12:34:35 -0700 Subject: [PATCH 9/9] lint Signed-off-by: Matthew Grossman --- openapi/ga/individual/platform.openapi.yaml | 6 ++++++ openapi/ga/openapi.yaml | 6 ++++++ openapi/openapi.yaml | 6 ++++++ sdk/python/nemo-platform/.nmpcontext/openapi.yaml | 6 ++++++ sdk/python/nemo-platform/tests/api_resources/test_jobs.py | 4 ++-- 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/openapi/ga/individual/platform.openapi.yaml b/openapi/ga/individual/platform.openapi.yaml index 863d6ef1a0..5b4f4b0bcd 100644 --- a/openapi/ga/individual/platform.openapi.yaml +++ b/openapi/ga/individual/platform.openapi.yaml @@ -8599,6 +8599,7 @@ components: image: title: Image type: string + minLength: 1 entrypoint: items: type: string @@ -9359,6 +9360,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -11781,6 +11783,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -11904,6 +11907,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -16559,6 +16563,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -17581,6 +17586,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string diff --git a/openapi/ga/openapi.yaml b/openapi/ga/openapi.yaml index 863d6ef1a0..5b4f4b0bcd 100644 --- a/openapi/ga/openapi.yaml +++ b/openapi/ga/openapi.yaml @@ -8599,6 +8599,7 @@ components: image: title: Image type: string + minLength: 1 entrypoint: items: type: string @@ -9359,6 +9360,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -11781,6 +11783,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -11904,6 +11907,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -16559,6 +16563,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -17581,6 +17586,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 863d6ef1a0..5b4f4b0bcd 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -8599,6 +8599,7 @@ components: image: title: Image type: string + minLength: 1 entrypoint: items: type: string @@ -9359,6 +9360,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -11781,6 +11783,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -11904,6 +11907,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -16559,6 +16563,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -17581,6 +17586,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string diff --git a/sdk/python/nemo-platform/.nmpcontext/openapi.yaml b/sdk/python/nemo-platform/.nmpcontext/openapi.yaml index 863d6ef1a0..5b4f4b0bcd 100644 --- a/sdk/python/nemo-platform/.nmpcontext/openapi.yaml +++ b/sdk/python/nemo-platform/.nmpcontext/openapi.yaml @@ -8599,6 +8599,7 @@ components: image: title: Image type: string + minLength: 1 entrypoint: items: type: string @@ -9359,6 +9360,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -11781,6 +11783,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -11904,6 +11907,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -16559,6 +16563,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string @@ -17581,6 +17586,7 @@ components: step omits container.image. When unset, falls back to the platform CPU tasks image (platform.image_registry/nmp-cpu-tasks:platform.image_tag). type: string + minLength: 1 env: additionalProperties: type: string diff --git a/sdk/python/nemo-platform/tests/api_resources/test_jobs.py b/sdk/python/nemo-platform/tests/api_resources/test_jobs.py index 537f366757..16c770f140 100644 --- a/sdk/python/nemo-platform/tests/api_resources/test_jobs.py +++ b/sdk/python/nemo-platform/tests/api_resources/test_jobs.py @@ -76,7 +76,7 @@ def test_method_create_with_all_params(self, client: NeMoPlatform) -> None: "container": { "command": ["string"], "entrypoint": ["string"], - "image": "image", + "image": "x", }, "profile": "profile", "provider": "cpu", @@ -770,7 +770,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncNeMoPlatfo "container": { "command": ["string"], "entrypoint": ["string"], - "image": "image", + "image": "x", }, "profile": "profile", "provider": "cpu",