Skip to content

fix(models): lora model revision re-pull logic - #508

Merged
benmccown merged 4 commits into
mainfrom
models-generic-engine-followups/bmccown
Jun 30, 2026
Merged

fix(models): lora model revision re-pull logic#508
benmccown merged 4 commits into
mainfrom
models-generic-engine-followups/bmccown

Conversation

@benmccown

@benmccown benmccown commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Follow-ups to generic engine support (#476)

Addresses two items deferred from the generic engine PR review.

1. Fix stale-weights bug in the k8s re-pull check (fix)

_existing_model_source() only read the model-source annotation off the weight-puller Job, but that Job is deleted at P3 once weights are pulled. For an already-serving deployment the lookup returned None, so a later model_revision change skipped the re-pull and served stale weights.

Now reads the Job first, then falls back to the (long-lived) PVC annotation, and propagates non-404 API errors instead of swallowing them. Pre-existing bug in the vLLM weighted path; surfaced more broadly now that weight-aware generic deployments ride the same path.

2. Configurable run_as_user / run_as_group (feat)

Adds executor_config.run_as_user / run_as_group to override the serving pod's securityContext uid/gid on the k8s backend. An explicit value wins over the engine default (vLLM pins its image's 2000/0; generic runs as the image's own user). Applied to both the serving container and the puller Job so pulled weights are owned by the same user the server reads them as. Ignored by the docker backend (it sets no container user).

Includes OpenAPI + Python SDK regeneration.

Summary by CodeRabbit

  • New Features

    • Added optional run_as_user and run_as_group settings to container executor configuration.
    • When using the Kubernetes backend, these fields map to the serving container’s pod securityContext (k8s only; docker ignores them).
  • Bug Fixes

    • Improved rollout/update behavior when model puller jobs or annotations are missing, including a safer fallback to PVC-stored metadata.
    • Non-recoverable Kubernetes API errors are no longer silently swallowed, improving reliability during updates.

The k8s direct-emission reconciler stamps the model source on both the
weight-puller Job and the PVC, but _existing_model_source() only read the
Job. At P3 the Job is deleted to release the RWO volume, so for an
already-serving deployment the Job is gone and the lookup returned None --
causing a later model-revision change to skip the re-pull branch and serve
stale weights.

Read the source from the Job first, then fall back to the (long-lived) PVC
annotation, and propagate non-404 API errors instead of swallowing them.

Signed-off-by: Ben McCown <bmccown@nvidia.com>
Add executor_config.run_as_user / run_as_group to override the serving pod's
securityContext uid/gid on the k8s backend. An explicit value wins over the
engine default (vLLM pins its image's 2000/0; generic runs as the image's own
user). Applied to both the serving container and the weight-puller Job so
pulled weights are owned by the same user the server reads them as. Ignored by
the docker backend, which does not set a container user.

Regenerates the OpenAPI spec for the new fields. (SDK regeneration via the
Stainless flow is a separate maintainer/CI step.)

Signed-off-by: Ben McCown <bmccown@nvidia.com>
Stainless regeneration picks up the new ContainerExecutorConfig.run_as_user /
run_as_group fields added in the prior commit.

Note: the TypeScript web SDK (web/packages/sdk) was not regenerated here because
node_modules are not installed in this worktree; `make update-web-sdk` (pnpm)
should be run before merge to keep the web SDK in sync.

Signed-off-by: Ben McCown <bmccown@nvidia.com>
@benmccown
benmccown requested review from a team as code owners June 29, 2026 20:01
@benmccown
benmccown requested a review from mckornfield June 29, 2026 20:01
@github-actions github-actions Bot added the fix label Jun 29, 2026
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b435da59-d83b-4a8f-a31b-1fc3681123dc

📥 Commits

Reviewing files that changed from the base of the PR and between 56f3799 and c348d0a.

📒 Files selected for processing (1)
  • services/core/models/tests/unit/controllers/test_k8s_nim_operator_backend.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • services/core/models/tests/unit/controllers/test_k8s_nim_operator_backend.py

📝 Walkthrough

Walkthrough

Adds optional run_as_user and run_as_group fields to ContainerExecutorConfig, threads them through DeploymentConfigView into the K8s reconciler, and changes _existing_model_source to fall back to PVC annotation when the puller Job is gone.

Changes

Pod securityContext UID/GID overrides and model-source PVC fallback

Layer / File(s) Summary
ContainerExecutorConfig schema and DeploymentConfigView fields
services/core/models/src/nmp/core/models/schemas.py, openapi/openapi.yaml, openapi/ga/openapi.yaml, openapi/ga/individual/platform.openapi.yaml, services/core/models/src/nmp/core/models/controllers/backends/common.py
Adds run_as_user and run_as_group optional non-negative integer fields to ContainerExecutorConfig across schema/OpenAPI, and adds matching optional fields to DeploymentConfigView populated from the executor config.
_pod_user override logic and call-site wiring
services/core/models/src/nmp/core/models/controllers/backends/k8s_nim_operator/reconcilers/k8s.py
_pod_user now accepts DeploymentConfigView and uses explicit run_as_user/run_as_group when set, otherwise falls back to vLLM backend defaults or None; create() and _serving_spec() use the new signature.
_existing_model_source PVC fallback
services/core/models/src/nmp/core/models/controllers/backends/k8s_nim_operator/reconcilers/k8s.py
_existing_model_source now reads the Job annotation first, falls back to the PVC on 404, and re-raises non-404 API errors.
Unit tests
services/core/models/tests/unit/controllers/test_k8s_nim_operator_backend.py
Updates test helpers for the new executor fields and adds coverage for generic/vLLM securityContext behavior plus PVC-fallback and no-repull update paths.

Sequence Diagram(s)

sequenceDiagram
  participant Schema as ContainerExecutorConfig
  participant View as DeploymentConfigView
  participant Reconciler as K8sReconciler
  participant Job as puller Job
  participant PVC as PVC

  Schema->>View: run_as_user/run_as_group
  View->>Reconciler: flattened overrides
  Reconciler->>Reconciler: _pod_user(view)
  Reconciler->>Job: read model-source annotation
  Job-->>Reconciler: annotation or 404
  Reconciler->>PVC: read annotation on 404
  PVC-->>Reconciler: annotation or none
Loading

Suggested labels

feat

Suggested reviewers

  • mckornfield
  • tylersbray
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main K8s model re-pull fix, though it omits the new run_as_user/run_as_group work.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch models-generic-engine-followups/bmccown

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
services/core/models/tests/unit/controllers/test_k8s_nim_operator_backend.py (2)

2514-2595: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a non-404 ApiException regression test.

These additions only exercise the 404 fallback path. The source change also promises that non-404 errors from read_namespaced_job and read_namespaced_persistent_volume_claim are re-raised, and that behavior is still untested here.

Possible test shape
+def test_existing_model_source_reraises_job_api_errors(k8s_backend):
+    backend = _vllm_backend(k8s_backend)
+    backend._batch_v1.read_namespaced_job.side_effect = _api_exception(500)
+
+    _sync_reconcilers(backend)
+    with pytest.raises(k8s_client.exceptions.ApiException):
+        backend._k8s_reconciler._existing_model_source("md-default-qwen")
+
+
+def test_existing_model_source_reraises_pvc_api_errors(k8s_backend):
+    backend = _vllm_backend(k8s_backend)
+    backend._batch_v1.read_namespaced_job.side_effect = _api_exception(404)
+    backend._core_v1.read_namespaced_persistent_volume_claim.side_effect = _api_exception(500)
+
+    _sync_reconcilers(backend)
+    with pytest.raises(k8s_client.exceptions.ApiException):
+        backend._k8s_reconciler._existing_model_source("md-default-qwen")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/core/models/tests/unit/controllers/test_k8s_nim_operator_backend.py`
around lines 2514 - 2595, The new tests cover only the 404 fallback path, but
they do not verify that non-404 ApiException failures are propagated. Add a
regression test around _existing_model_source in
test_k8s_nim_operator_backend.py that makes read_namespaced_job or
read_namespaced_persistent_volume_claim raise an ApiException with a non-404
status and asserts the exception is re-raised instead of falling back to PVC or
returning None. Use the existing _vllm_backend, _sync_reconcilers, and
_existing_model_source setup patterns to keep the test aligned with the current
behavior.

1937-1937: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add concrete types for the new helper params.

run_as_user and run_as_group are nullable ints in the production contract, but both helpers leave them untyped. Annotate them as int | None so these fixtures stay aligned with the config shape.

As per coding guidelines, **/*.py: Always prefer concrete type hints over string-based ones in Python code; do not import types under TYPE_CHECKING, instead import types as regular imports when possible.

Also applies to: 2005-2012

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/core/models/tests/unit/controllers/test_k8s_nim_operator_backend.py`
at line 1937, The helper _vllm_config in the k8s nim operator backend tests
leaves run_as_user and run_as_group untyped even though they model nullable
integers in the production config. Update the helper signature (and the related
fixture helpers around the same area) to use concrete type hints of int | None
for these parameters so the test helpers stay aligned with the config contract
and follow the Python typing guideline.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@services/core/models/tests/unit/controllers/test_k8s_nim_operator_backend.py`:
- Around line 2514-2595: The new tests cover only the 404 fallback path, but
they do not verify that non-404 ApiException failures are propagated. Add a
regression test around _existing_model_source in
test_k8s_nim_operator_backend.py that makes read_namespaced_job or
read_namespaced_persistent_volume_claim raise an ApiException with a non-404
status and asserts the exception is re-raised instead of falling back to PVC or
returning None. Use the existing _vllm_backend, _sync_reconcilers, and
_existing_model_source setup patterns to keep the test aligned with the current
behavior.
- Line 1937: The helper _vllm_config in the k8s nim operator backend tests
leaves run_as_user and run_as_group untyped even though they model nullable
integers in the production config. Update the helper signature (and the related
fixture helpers around the same area) to use concrete type hints of int | None
for these parameters so the test helpers stay aligned with the config contract
and follow the Python typing guideline.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3b791391-20b3-488c-ab4b-498b7bce8065

📥 Commits

Reviewing files that changed from the base of the PR and between 9a05e42 and 56f3799.

⛔ Files ignored due to path filters (4)
  • sdk/python/nemo-platform/.nmpcontext/openapi.yaml is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/types/inference/container_executor_config.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/types/inference/container_executor_config_param.py is excluded by !sdk/**
  • sdk/python/nemo-platform/tests/api_resources/inference/test_deployment_configs.py is excluded by !sdk/**
📒 Files selected for processing (7)
  • openapi/ga/individual/platform.openapi.yaml
  • openapi/ga/openapi.yaml
  • openapi/openapi.yaml
  • services/core/models/src/nmp/core/models/controllers/backends/common.py
  • services/core/models/src/nmp/core/models/controllers/backends/k8s_nim_operator/reconcilers/k8s.py
  • services/core/models/src/nmp/core/models/schemas.py
  • services/core/models/tests/unit/controllers/test_k8s_nim_operator_backend.py

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 21936/28740 76.3% 61.1%
Integration Tests 12599/27420 46.0% 19.3%

Address PR review nits:
- Add regression tests asserting _existing_model_source re-raises non-404
  ApiException from both the Job and PVC reads (only the 404 fallback was
  covered before).
- Add concrete int | None type hints to the run_as_user/run_as_group params
  on the _vllm_config / _generic_config test helpers.

Signed-off-by: Ben McCown <bmccown@nvidia.com>
@benmccown

Copy link
Copy Markdown
Contributor Author

Response from claude session: Addressed both CodeRabbit nitpicks in c348d0a:

  • Added regression tests asserting _existing_model_source re-raises a non-404 ApiException from both the Job read and the PVC read (previously only the 404 fallback path was covered).
  • Added concrete int | None type hints to the run_as_user / run_as_group params on the _vllm_config / _generic_config test helpers, per the repo typing guideline.

@benmccown
benmccown added this pull request to the merge queue Jun 30, 2026
Merged via the queue into main with commit b8f3452 Jun 30, 2026
54 checks passed
@benmccown
benmccown deleted the models-generic-engine-followups/bmccown branch June 30, 2026 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants