Skip to content

feat(models): deployments_plugin backend (AIRCORE-759 PR1)#663

Merged
tylersbray merged 5 commits into
mainfrom
759-models-adopts-deployments-plugin/tbray
Jul 14, 2026
Merged

feat(models): deployments_plugin backend (AIRCORE-759 PR1)#663
tylersbray merged 5 commits into
mainfrom
759-models-adopts-deployments-plugin/tbray

Conversation

@tylersbray

@tylersbray tylersbray commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a selectable models deployments_plugin ServiceBackend that compiles NIM/vLLM/generic deployments into deployments-plugin entities: Volume + OnFailure puller + Always server with prerequisite: succeeded.
  • Projects plugin Deployment status onto ModelDeployment (trust READY; substrate details in error_details); missing server after READY → LOST.
  • Keeps existing docker / nim_operator / none backends for dual-path rollout. Enable via models.controller.backends.deployments_plugin.enabled: true (and disable the other backend).

Linear: AIRCORE-759

This is PR1 of 2. PR2 (delete backends + drop k8s-nim-operator) waits for this to merge.

Resolved open questions

# Question Decision
1 Asymmetric projection Models sole writer of ModelDeployment (spec/status/status_message/error_details/model_provider_id/host_url). Plugin owns Deployment/Volume/DeploymentConfig. Models projects plugin status with Layer-3 enrichment; raw substrate in error_details.
2 In-flight upgrade No alembic. Stale READYLOST for manual recreate. No auto-orphan cleanup of old docker containers / NIMService CRs / PVCs.
3 Executor selection docker_executor / k8s_executor / default_executor on the new backend config; map platform.runtime → named executor. No per-ModelDeployment executor field.
4 LoRA sidecar Models-owned. k8s: init_containers native-sidecar (restart_policy: Always). docker: second container emitted (plugin docker v1 is still single-container — LoRA-on-docker via plugin needs a follow-up).

Test plan

  • Unit: pytest services/core/models/tests/unit/controllers/backends/deployments_plugin/ -v (17 tests)
  • Registry/config unit tests still green
  • ty check on new package; ruff clean
  • Enable deployments_plugin against a local platform with deployments executors and deploy a vLLM (and NIM) model end-to-end
  • Confirm READY → LOST when plugin server Deployment is deleted under a READY ModelDeployment
  • Confirm delete ordering leaves ModelDeployment until plugin Deployments are gone

Enablement sketch

models:
  controller:
    backends:
      docker:
        enabled: false
      deployments_plugin:
        enabled: true
        docker_executor: local-docker   # or k8s_executor: local-k8s

Summary by CodeRabbit

  • New Features
    • Added an optional Deployments Plugin backend for creating, monitoring, and removing model deployments.
    • Supports Docker and Kubernetes execution, vLLM and NIM serving, optional weight pulling, and LoRA integrations.
  • Documentation
    • Expanded the configuration reference with deployments-plugin settings (timeouts, images/tags, storage defaults, and LoRA controls), including an enablement switch.
  • Bug Fixes
    • Added fail-fast validation for unsupported Docker+LoRA combinations.
    • Improved drift recovery/teardown behavior and pending-timeout escalation.
  • Tests
    • Added unit coverage for backend execution, compilation, naming, status mapping, and edge cases.

…ject

Introduce a selectable ServiceBackend that compiles model deployments into
Volume + OnFailure puller + Always server plugin entities and projects
plugin status onto ModelDeployment. Old docker/nim_operator backends remain
for dual-path rollout (AIRCORE-759 PR1).

Signed-off-by: Tyler Bray <tbray@nvidia.com>
@tylersbray
tylersbray requested review from a team as code owners July 13, 2026 22:09
@github-actions github-actions Bot added the feat label Jul 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

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: af4efad7-f3a7-4d36-98bd-15f9f32bfa20

📥 Commits

Reviewing files that changed from the base of the PR and between e33d680 and ab967b0.

📒 Files selected for processing (11)
  • docs/set-up/config-reference.mdx
  • services/core/models/src/nmp/core/models/config.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/__init__.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/backend.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/compiler.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/config.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/executor.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/resolve.py
  • services/core/models/src/nmp/core/models/controllers/backends/registry.py
  • services/core/models/tests/unit/controllers/backends/deployments_plugin/test_compiler.py
  • services/core/models/tests/unit/controllers/test_backend_registry.py
🚧 Files skipped from review as they are similar to previous changes (9)
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/executor.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/config.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/resolve.py
  • docs/set-up/config-reference.mdx
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/compiler.py
  • services/core/models/tests/unit/controllers/backends/deployments_plugin/test_compiler.py
  • services/core/models/src/nmp/core/models/controllers/backends/registry.py
  • services/core/models/src/nmp/core/models/config.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/backend.py

📝 Walkthrough

Walkthrough

Adds a configurable deployments_plugin backend for model deployments, including model resolution, engine-specific entity compilation, lifecycle orchestration, status projection, registry integration, dependencies, documentation, and unit tests.

Changes

Deployments Plugin Integration

Layer / File(s) Summary
Configuration and backend registration
services/core/models/pyproject.toml, services/core/models/src/nmp/core/models/config.py, services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/*, services/core/models/src/nmp/core/models/controllers/backends/registry.py, packages/nemo_platform/pyproject.toml, docs/set-up/config-reference.mdx, services/core/models/tests/unit/controllers/backends/deployments_plugin/{test_executor.py,test_naming.py}, services/core/models/tests/unit/controllers/test_backend_registry.py
Registers the backend, defines configuration defaults, adds dependencies, supports lazy resolution, and defines stable entity names.
Deployment resolution and entity compilation
services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/{resolve.py,compiler.py}, services/core/models/tests/unit/controllers/backends/deployments_plugin/test_compiler.py
Resolves model sources and runtime inputs, then compiles puller, server, volume, scratch, and LoRA entities.
Deployment lifecycle operations
services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/backend.py, services/core/models/tests/unit/controllers/backends/deployments_plugin/test_backend.py
Creates entities in dependency order, performs rollback and drift recovery, reports status, rejects updates, lists managed deployments, and polls teardown completion.
Substrate status projection
services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/status.py, services/core/models/tests/unit/controllers/backends/deployments_plugin/test_status.py
Maps plugin states, projects READY endpoint URLs, detects LOST deployments, escalates stalled pending states, and reports substrate failures with structured details.

Sequence Diagram(s)

sequenceDiagram
  participant ModelsService
  participant DeploymentsPluginServiceBackend
  participant NemoEntitiesClient
  ModelsService->>DeploymentsPluginServiceBackend: resolve and create deployment
  DeploymentsPluginServiceBackend->>NemoEntitiesClient: create volume, puller, and server
  NemoEntitiesClient-->>DeploymentsPluginServiceBackend: return entity status and endpoints
  DeploymentsPluginServiceBackend-->>ModelsService: return DeploymentStatusUpdate
Loading

Possibly related PRs

Suggested labels: feat

Suggested reviewers: benmccown

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding the new deployments_plugin backend for models.
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 759-models-adopts-deployments-plugin/tbray

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.

Actionable comments posted: 3

🧹 Nitpick comments (3)
services/core/models/tests/unit/controllers/backends/deployments_plugin/test_status.py (2)

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

Add missing map_status cases.

_STATUS_MAP also defines UNKNOWN, DELETING, and SUCCEEDED, none of which are parametrized here.

♻️ Extend parametrize cases
     [("PENDING", "PENDING"), ("STARTING", "PENDING"), ("READY", "READY"), ("FAILED", "ERROR"), ("LOST", "LOST"),
+     ("UNKNOWN", "UNKNOWN"), ("DELETING", "DELETING"), ("SUCCEEDED", "PENDING")],
🤖 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/backends/deployments_plugin/test_status.py`
around lines 14 - 19, Extend the parameter list in test_map_status to cover the
UNKNOWN, DELETING, and SUCCEEDED statuses defined by _STATUS_MAP, using each
status’s mapped model value. Keep the existing map_status assertions and cases
unchanged.

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

No test for volume-FAILED or default-PENDING branches.

aggregate_status has a dedicated volume-FAILED → ERROR branch and a default PENDING fallback (status.py lines 76-86), neither of which is exercised here.

🤖 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/backends/deployments_plugin/test_status.py`
around lines 34 - 37, Extend
test_missing_ready_server_is_lost_and_failed_puller_is_error to cover
aggregate_status branches for a FAILED volume returning ERROR and for the
default PENDING fallback. Add focused assertions using suitable Deployment
inputs, while preserving the existing LOST and failed-puller ERROR assertions.
services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/compiler.py (1)

161-176: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Fail fast instead of compiling a known-broken Docker+LoRA spec.

The comment states create "will ERROR" for LoRA on Docker until the docker backend supports multi-container configs. Right now that failure surfaces later as an opaque plugin-level error. Raising a clear ValueError here (or in create_model_deployment) for runtime == Runtime.DOCKER and lora_enabled would give operators an actionable message instead.

🤖 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/src/nmp/core/models/controllers/backends/deployments_plugin/compiler.py`
around lines 161 - 176, Update the LoRA container handling in the compiler flow
to raise a clear ValueError when resolved.runtime is Runtime.DOCKER and
resolved.view.lora_enabled, before constructing or returning the known-invalid
multi-container deployment spec. Include an actionable message identifying that
Docker does not yet support LoRA or multi-container DeploymentConfigs, and
preserve the existing non-Docker container behavior.
🤖 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.

Inline comments:
In
`@services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/backend.py`:
- Around line 107-122: Update _rollback_create so each failed entities.delete
operation logs the exception and the entity type/name being cleaned up instead
of silently passing. Preserve the best-effort rollback behavior and continue
attempting subsequent deletions, using the module’s existing logging mechanism.

In
`@services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/config.py`:
- Around line 31-32: Update the delete_wait_seconds and delete_poll_seconds
fields in the deployment configuration model to enforce strictly positive values
using the model’s existing validation mechanism with gt=0, preventing zero or
negative deletion timing settings.

In
`@services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/status.py`:
- Around line 70-81: Update the deployment status handling around the puller and
volume failure checks to treat both LOST and UNKNOWN statuses as terminal ERROR
states, alongside FAILED. Preserve the existing status messages, fallback text,
and substrate error_details for each corresponding component, and ensure
aggregate_status no longer lets these statuses fall through to PENDING.

---

Nitpick comments:
In
`@services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/compiler.py`:
- Around line 161-176: Update the LoRA container handling in the compiler flow
to raise a clear ValueError when resolved.runtime is Runtime.DOCKER and
resolved.view.lora_enabled, before constructing or returning the known-invalid
multi-container deployment spec. Include an actionable message identifying that
Docker does not yet support LoRA or multi-container DeploymentConfigs, and
preserve the existing non-Docker container behavior.

In
`@services/core/models/tests/unit/controllers/backends/deployments_plugin/test_status.py`:
- Around line 14-19: Extend the parameter list in test_map_status to cover the
UNKNOWN, DELETING, and SUCCEEDED statuses defined by _STATUS_MAP, using each
status’s mapped model value. Keep the existing map_status assertions and cases
unchanged.
- Around line 34-37: Extend
test_missing_ready_server_is_lost_and_failed_puller_is_error to cover
aggregate_status branches for a FAILED volume returning ERROR and for the
default PENDING fallback. Add focused assertions using suitable Deployment
inputs, while preserving the existing LOST and failed-puller ERROR assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: bb6fc8d7-2fe2-465a-9109-69d8973c5a26

📥 Commits

Reviewing files that changed from the base of the PR and between 96b5c9e and 79d8bb3.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (18)
  • docs/set-up/config-reference.mdx
  • services/core/models/pyproject.toml
  • services/core/models/src/nmp/core/models/config.py
  • services/core/models/src/nmp/core/models/controllers/backends/__init__.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/__init__.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/backend.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/compiler.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/config.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/executor.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/naming.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/resolve.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/status.py
  • services/core/models/src/nmp/core/models/controllers/backends/registry.py
  • services/core/models/tests/unit/controllers/backends/deployments_plugin/test_backend.py
  • services/core/models/tests/unit/controllers/backends/deployments_plugin/test_compiler.py
  • services/core/models/tests/unit/controllers/backends/deployments_plugin/test_executor.py
  • services/core/models/tests/unit/controllers/backends/deployments_plugin/test_naming.py
  • services/core/models/tests/unit/controllers/backends/deployments_plugin/test_status.py

@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 24401/31577 77.3% 62.0%
Integration Tests 14024/30226 46.4% 19.3%

Teardown leftover substrate before recreate, use controlled delete on
rollback, and wire LoRA sidecar env/mounts/scratch volume so drift recovery
and adapters match existing backends.

Signed-off-by: Tyler Bray <tbray@nvidia.com>
Fix CI and CodeRabbit feedback on the deployments_plugin models backend:

- Lazy-import the backend so the core models service (and its standalone
  wheel) boots without the optional nemo_deployments_plugin package. The
  vendored models-service extra excludes plugins, so eager import broke the
  wheel build+test and Kind e2e jobs.
- Regenerate the vendored SDK metadata (adds nemo-platform-plugin to the
  models-service extra) to fix lint-sdk-vendored.
- Constrain delete_wait_seconds/delete_poll_seconds with gt=0.
- aggregate_status now surfaces LOST/UNKNOWN puller/volume substrate instead
  of hiding a dead prerequisite behind PENDING.
- Log rollback failures instead of swallowing them.
- Fail fast with an actionable error for LoRA on the docker runtime.
- Extend status/backend unit tests for the above.

Signed-off-by: Tyler Bray <tbray@nvidia.com>

@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 (1)
services/core/models/tests/unit/controllers/backends/deployments_plugin/test_backend.py (1)

151-169: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert that pending teardown prevents substrate creation.

This test only checks the returned status and message. Also assert _entities.create was not called; otherwise a regression could report PENDING while creating over substrate that is still being deleted.

🤖 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/backends/deployments_plugin/test_backend.py`
around lines 151 - 169, Update test_create_waits_when_prior_teardown_incomplete
to patch or mock _entities.create and assert it was not called after
create_model_deployment returns PENDING. Keep the existing status and
teardown-message assertions unchanged.
🤖 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/backends/deployments_plugin/test_backend.py`:
- Around line 151-169: Update test_create_waits_when_prior_teardown_incomplete
to patch or mock _entities.create and assert it was not called after
create_model_deployment returns PENDING. Keep the existing status and
teardown-message assertions unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d20e2c3c-b9e8-42e2-90bb-312bb824b71b

📥 Commits

Reviewing files that changed from the base of the PR and between 4a66dd8 and 266f1f0.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • packages/nemo_platform/pyproject.toml
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/__init__.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/backend.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/compiler.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/config.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/status.py
  • services/core/models/src/nmp/core/models/controllers/backends/registry.py
  • services/core/models/tests/unit/controllers/backends/deployments_plugin/test_backend.py
  • services/core/models/tests/unit/controllers/backends/deployments_plugin/test_status.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/init.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/config.py
  • services/core/models/tests/unit/controllers/backends/deployments_plugin/test_status.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/compiler.py
  • services/core/models/src/nmp/core/models/controllers/backends/deployments_plugin/backend.py

Escalate stuck PENDING deployments to ERROR via pending_timeout_seconds,
fail fast when no executor is configured for the runtime, and extend unit
tests for teardown-wait, timeout, and executor validation.

Signed-off-by: Tyler Bray <tbray@nvidia.com>
Comment thread services/core/models/src/nmp/core/models/config.py
- Drop __getattr__ lazy export; registry imports backend directly with
  ImportError guidance when nemo-deployments-plugin is missing
- Document none backend as intentional no-op for platform.runtime none
- Use ModelEntity | None, extract files URL vars, structured rollback logs
- Make LoRA busybox init image configurable (docker.io/library/busybox)
- Clarify executor_for_runtime misconfiguration scenario in docstring

Signed-off-by: Tyler Bray <tbray@nvidia.com>
@tylersbray
tylersbray enabled auto-merge July 14, 2026 23:01
@tylersbray
tylersbray added this pull request to the merge queue Jul 14, 2026
Merged via the queue into main with commit 13407da Jul 14, 2026
59 checks passed
@tylersbray
tylersbray deleted the 759-models-adopts-deployments-plugin/tbray branch July 14, 2026 23:15
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