Skip to content

fix(operator): align and document v1beta2 DGDR defaults - #17191

Open
sttts wants to merge 17 commits into
mainfrom
sttts-dgdr-v1beta2-defaulting-docs
Open

sttts wants to merge 17 commits into
mainfrom
sttts-dgdr-v1beta2-defaulting-docs

Conversation

@sttts

@sttts sttts commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

This PR is blocked by the admission PR #16661.

Summary

Document the complete nvidia.com/v1beta2 DGDR admission contract at the Go API types that generate the CRD and Kubernetes API reference. This also aligns the implemented model-only objective with the accepted API contract: Optimize / ThroughputPerGPU with ttftMs: 2000 and itlMs: 30.

Admission remains the single owner of Request defaults. The CRD carries their descriptions but no duplicate default markers. The comments now specify:

  • exact backend, workload, objective, recommendation, hardware, and AISimulate artifact defaults;
  • the difference between an omitted or empty parent and the nested workload.static: {} / objective.sla: {} opt-outs;
  • create and update behavior for cluster-derived hardware, including the 32-GPU cap on discovered budgets and authoritative explicit budgets;
  • image and versionOverride ownership as one operator-provided pair; and
  • spec.aisimulate.parameters as the opaque, final RFC 7386 Merge Patch over the typed and derived underlay.

This PR is stacked on #16661 and includes its current commits so the resulting API contract can be reviewed now. Once #16661 merges, this PR reduces to commit 9e0c1ed7e5.

Relates to #13545 and DGH-1426.

API examples

A model-only Request remains the minimal input:

apiVersion: nvidia.com/v1beta2
kind: DynamoGraphDeploymentRequest
metadata:
  name: llama-8b
spec:
  model:
    name: meta-llama/Llama-3.1-8B-Instruct

Admission persists a resolved Request with this shape. The hardware and AISimulate artifact values depend on the cluster and operator configuration:

spec:
  model:
    name: meta-llama/Llama-3.1-8B-Instruct
  backends: [vllm, sglang, trtllm]
  hardware:
    gpu:
      sku: h200_sxm
      budget: 8 # min(matching cluster GPUs, 32)
  workload:
    static:
      isl: 1024
      osl: 128
      concurrency: 10
  objective:
    mode: Optimize
    metric: ThroughputPerGPU
    sla:
      ttftMs: 2000
      itlMs: 30
  aisimulate:
    image: registry.example.com/aisimulate:nightly
    versionOverride: "0.13.0"
  recommendation:
    maxCandidates: 1

The nested empty objects opt out of only their whole-object defaults. objective still receives its mode and metric defaults:

spec:
  model:
    name: meta-llama/Llama-3.1-8B-Instruct
  workload:
    static: {}
  objective:
    sla: {}
  aisimulate:
    parameters:
      workload:
        isl: 4096
        osl: 512
        concurrency: 32
      goal:
        sla: null # JSON Merge Patch deletion; native parameters win last

Hardware fields are independently optional:

# Discover SKU and persist budget=min(matching GPUs, 32).
hardware: {}

# Preserve the SKU; discover and cap only the budget.
hardware:
  gpu:
    sku: h200_sxm

# Discover only the SKU; preserve the explicit budget without capping it.
hardware:
  gpu:
    budget: 64

# Preserve both fields and do not access the cluster.
hardware:
  gpu:
    sku: h200_sxm
    budget: 64

On update, unchanged hardware is not rediscovered. A hardware-changing update resolves only newly missing fields. Admission rejects discovery failures, unknown or ambiguous GPU types, and a missing budget when no matching GPUs exist. Native parameters remains opaque during admission and may override the persisted typed hardware during controller lowering.

The API field shapes are unchanged, so conversion code and conversion tests are unaffected. CRDs and both committed Kubernetes API references are regenerated from the Go comments.

Validation

  • go test ./internal/webhook/defaulting -count=1
  • KUBEBUILDER_ASSETS=<repo-pinned-1.30.0-assets> go test ./internal/webhook/validation -run '^TestDynamoGraphDeploymentRequestValidator_Validate$' -count=1
  • make -C deploy/operator manifests
  • make -C deploy/operator generate-api-docs
  • python3 docs/fern/scripts/gen_kubernetes_api.py --check
  • staged pre-commit hooks

Summary by CodeRabbit

  • New Features

    • v1beta2 Requests now receive defaults for backends, workload settings, objectives, recommendations, and AISimulate configuration. Empty nested objects can opt out of selected defaults.
    • GPU hardware can be discovered automatically; unsupported or ambiguous hardware is rejected. Discovered GPU budgets are capped at 32.
    • AISimulate inputs combine typed Request settings with a parameter merge patch. Resolved inputs are saved to Runs, which do not receive Request defaults.
    • Helm settings let operators configure default AISimulate images and version overrides.
  • Bug Fixes

    • Invalid two-value KV load-ratio ranges are rejected.
  • Documentation

    • Updated API references to explain defaults, hardware discovery, and Run behavior.

devivasudevan and others added 17 commits October 21, 2026 21:39
Defaulting and validation for native v1beta2 DynamoGraphDeploymentRequests, on top of the
conversion API (#13744).

Admission runs through the shared v1beta1 webhooks (matchPolicy: Equivalent) and is routed by
the original request's API version: a native v1beta2 request is decoded from spec.v1beta2,
defaulted, validated and re-encoded; a foreign-version carrier is never mutated, direct carrier
creates are rejected, and an unchanged foreign view can still be updated.

Defaults: backends, workload (static ISL 1024, OSL 128, concurrency 10), objective (Optimize,
Throughput), recommendation (maxCandidates 1), hardware discovery on CREATE only, and the
operator's AISimulate image. The structural defaults are applied in admission, not the CRD
schema, because a schema default would also be applied to an object that carries spec.v1beta1
and conversion would then reject it; only nested defaults stay in the schema. Explicit empty
objects (workload.static: {}, objective.sla: {}) are kept.

The AISimulate input is derived from the typed spec with derived defaults (request_count,
sweep.max_trials, strict_sla) computed first and spec.aisimulate.parameters merged last, once.
The base's early returns for requests carrying spec.v1beta2 are removed so those requests are
validated. internal/runtimeversion is renamed internal/versionoverride.

Tests: defaulting and routing unit tests, a CRD drift test (no top-level defaults; nested
defaults equal the webhook's), admission envtest rows, an API-server test that carrier objects
stay writable through every served version, and a Helm unit test for matchPolicy.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
…unchanged carrier

Objective.metric: the Optimize default is Throughput, not ThroughputPerGPU. Workload: the
fixed-concurrency default creates neither sweep.max_trials nor a KV-load ratio search.

The carrier test now also writes the unchanged foreign view back with a full update and
requires the spec to be byte-stable and the generation unchanged, in both directions.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
…ssion

Validate the lowered input, so hardware given only in spec.aisimulate.parameters
counts and a null that deletes discovered hardware does not. Updates validate only
when the spec changed. Rewrite the aisimulate package contract to match.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
…dline

Split the flag description (lll). Drop the constant kind parameter of the test helper
(unparam). Match the lowercased error text for the DCGM-not-enabled reason, which
never matched. Give the DCGM phase of GPU discovery half of the remaining deadline
so the node-label fallback keeps time to run.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
…a deadline

The DCGM phase reserved time for the fallback by calling NodeLabels() before DCGM ran.
Callers without a deadline, such as the v1beta1 reconciler, never needed that and could
hit a callback that was not configured for them. Evaluate it only when there is a
deadline to share, and test that it is not asked otherwise.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
…ssion

Admission validates the typed spec and the image/version selection only. Drop
the parameters object check and the effective-hardware validation; hardware
discovery reads spec.hardware alone. A Request whose discovery fails is
admitted and reported as Accepted=False/InvalidSpec by the Request controller.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
…aults

Remove the +kubebuilder:default markers for workload.static, objective.mode
and recommendation.maxCandidates, and the test that compared them with the
webhook constants. Default in the order of the Go API types: each parent
creates its documented default child and fills its own scalars, and
workload.static: {} stays an opt-out.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
…ange spec.hardware

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
…re the GPU discoverer

Default through the NativeSpec and NativeSearchInput types in declaration
order. Make the aisimulate native paths package-private and drop the unused
ones. HardwareDiscoverer now has the signature of gpu.Discoverer, so the
shared discoverer satisfies it directly and the catalog mapping lives in
resolveHardware.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
…nd CEL

Backend uniqueness is +listType=set and the kvLoadRatio range order is CEL on
the type. Native model presence and the model name length were already
enforced by the representation CEL and MinLength, so the webhook no longer
repeats any of them. The operatorenv table covers the exact error paths.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
…ssion table

Move the externally observable defaulting cases into the admission table and
delete v1beta2SchemaDefaulted and the direct-function matrix. The unit tests
that remain cover resolver and envelope internals.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
…dary

Resolve the admission request once in Validate and ValidateUpdate and fail when
it is absent. Compare the requested version with the spec.v1beta2 carrier
directly and drop RequestUsesV1Beta2, RequestIsNative and requestIsNative. The
mutating handler returns the missing-request error instead of skipping defaulting.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
An operator-configured default image whose tag is not a semantic version was
admitted without a versionOverride, and validation then rejected every
Request that received it. Add --dgdr-aisimulate-default-version-override
and the matching Helm value, and persist the pair together: the override
follows the image, so a caller's own image derives its own version or brings
its own override. Reject at startup a default image that validation would
always reject.

Also register the v1beta2 types once, make the versionoverride comments
domain-neutral, and regenerate the API reference.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
Admission now guarantees complete typed hardware for a v1beta2 Request
instead of leaving gaps for AISimulate's implicit defaults. An omitted SKU is
discovered, an omitted budget becomes min(matching GPUs, 32), and an
explicit budget is authoritative and never capped. A failed discovery, a GPU
model the AISimulate catalog does not know, no GPU of the pinned SKU, and an
omitted SKU in a cluster with several GPU types are rejected on the field
that fixes them. gpu.GPUInfo reports the models unfiltered discovery left
out so that case can be detected. spec.aisimulate.parameters stays opaque.

Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
@sttts
sttts requested review from a team as code owners October 23, 2026 16:23
@copy-pr-bot

copy-pr-bot Bot commented Oct 23, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions github-actions Bot added fix documentation Improvements or additions to documentation deployment::k8s Relates to dynamo deployment in kubernetes labels Oct 23, 2026
@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between c3b7504 and 9e0c1ed.

📒 Files selected for processing: 60
  • deploy/helm/charts/platform/components/operator/templates/deployment.yaml
  • deploy/helm/charts/platform/components/operator/templates/webhook-configuration.yaml
  • deploy/helm/charts/platform/components/operator/values.yaml
  • deploy/helm/charts/platform/tests/namespace_restriction_webhooks_test.yaml
  • deploy/operator/api/v1beta2/dynamographdeploymentrequest_types.go
  • deploy/operator/api/v1beta2/dynamographdeploymentrun_types.go
  • deploy/operator/cmd/main.go
  • deploy/operator/config/crd/bases/nvidia.com_dynamographdeploymentrequests.yaml
  • deploy/operator/config/crd/bases/nvidia.com_dynamographdeploymentruns.yaml
  • deploy/operator/internal/controller/aisimulate/defaults.go
  • deploy/operator/internal/controller/aisimulate/doc.go
  • deploy/operator/internal/controller/aisimulate/image.go
  • deploy/operator/internal/controller/aisimulate/image_test.go
  • deploy/operator/internal/controller/aisimulate/input.go
  • deploy/operator/internal/controller/aisimulate/input_test.go
  • deploy/operator/internal/controller/aisimulate/paths.go
  • deploy/operator/internal/controller/dynamographdeploymentrequest_controller.go
  • deploy/operator/internal/controller/suite_envtest_test.go
  • deploy/operator/internal/dynamo/component_common.go
  • deploy/operator/internal/dynamo/component_frontend_test.go
  • deploy/operator/internal/dynamo/component_namespace_test.go
  • deploy/operator/internal/dynamo/component_worker_test.go
  • deploy/operator/internal/dynamo/graph.go
  • deploy/operator/internal/dynamo/hash.go
  • deploy/operator/internal/features/runtime/gate.go
  • deploy/operator/internal/features/runtime/gate_test.go
  • deploy/operator/internal/features/runtime/gates.go
  • deploy/operator/internal/gpu/dcgm_phase_context_test.go
  • deploy/operator/internal/gpu/discovery.go
  • deploy/operator/internal/gpu/hardware_discoverer.go
  • deploy/operator/internal/gpu/hardware_discoverer_test.go
  • deploy/operator/internal/gpu/heterogeneous.go
  • deploy/operator/internal/gpu/heterogeneous_test.go
  • deploy/operator/internal/versionoverride/versionoverride.go
  • deploy/operator/internal/versionoverride/versionoverride_test.go
  • deploy/operator/internal/webhook/defaulting/dynamographdeploymentrequest_handler.go
  • deploy/operator/internal/webhook/defaulting/dynamographdeploymentrequest_handler_test.go
  • deploy/operator/internal/webhook/defaulting/dynamographdeploymentrequest_routing_test.go
  • deploy/operator/internal/webhook/defaulting/dynamographdeploymentrequest_v1beta1_options.go
  • deploy/operator/internal/webhook/defaulting/dynamographdeploymentrequest_v1beta2.go
  • deploy/operator/internal/webhook/defaulting/dynamographdeploymentrequest_v1beta2_artifact.go
  • deploy/operator/internal/webhook/defaulting/dynamographdeploymentrequest_v1beta2_artifact_test.go
  • deploy/operator/internal/webhook/defaulting/dynamographdeploymentrequest_v1beta2_hardware_test.go
  • deploy/operator/internal/webhook/defaulting/dynamographdeploymentrequest_v1beta2_helpers.go
  • deploy/operator/internal/webhook/defaulting/dynamographdeploymentrequest_v1beta2_test.go
  • deploy/operator/internal/webhook/request_version.go
  • deploy/operator/internal/webhook/request_version_test.go
  • deploy/operator/internal/webhook/setup/setup.go
  • deploy/operator/internal/webhook/validation/dynamographdeploymentrequest.go
  • deploy/operator/internal/webhook/validation/dynamographdeploymentrequest_boundary_test.go
  • deploy/operator/internal/webhook/validation/dynamographdeploymentrequest_carrier_envtest_test.go
  • deploy/operator/internal/webhook/validation/dynamographdeploymentrequest_routing.go
  • deploy/operator/internal/webhook/validation/dynamographdeploymentrequest_v1beta2.go
  • deploy/operator/internal/webhook/validation/dynamographdeploymentrequest_v1beta2_test.go
  • deploy/operator/internal/webhook/validation/dynamographdeploymentrequest_validation_envtest_test.go
  • deploy/operator/internal/webhook/validation/planner_runtime_features.go
  • deploy/operator/internal/webhook/validation/shared_helpers.go
  • deploy/operator/internal/webhook/validation/suite_envtest_test.go
  • docs/fern/pages/reference/kubernetes-api/additional-resources/api-reference-k8s.md
  • docs/fern/pages/reference/kubernetes-api/full-api-reference.mdx

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.

Walkthrough

The pull request adds v1beta2 Request admission defaults, GPU hardware discovery, and API-version-aware webhook routing and validation. It also adds AISimulate input lowering and merge-patch handling, updates Helm configuration and API references, and changes the shared compatibility-version package name.

Changes

DGDR v1beta2 Request flow

Layer / File(s) Summary
Request defaults and API contract
deploy/operator/api/v1beta2/*, deploy/operator/config/crd/bases/*dynamographdeployment*, docs/fern/pages/reference/kubernetes-api/*
The API descriptions and references document Request admission defaults, hardware resolution, AISimulate parameters, opt-outs, and resolved Run inputs. The CRDs remove selected schema defaults and add validation for two-value KV-load-ratio ranges.
GPU discovery and hardware data
deploy/operator/internal/gpu/*, deploy/operator/internal/controller/dynamographdeploymentrequest_controller.go
A shared discoverer tries DCGM and can use node-label discovery when enabled. GPU discovery reports other models and shared helpers resolve known SKUs and failure reasons. The Request controller uses the shared discoverer for hardware enrichment.
Admission defaults and deployment wiring
deploy/helm/charts/platform/components/operator/*, deploy/helm/charts/platform/tests/namespace_restriction_webhooks_test.yaml, deploy/operator/cmd/main.go, deploy/operator/internal/webhook/defaulting/*, deploy/operator/internal/webhook/setup/setup.go, deploy/operator/internal/controller/suite_envtest_test.go
The operator and Helm chart configure AISimulate image and version defaults, GPU discovery, and v1beta2 Request defaulting. Admission applies defaults for backends, hardware, workload, objective/SLA, AISimulate, and recommendations while retaining explicit values and empty-object opt-outs.
API-version routing and validation
deploy/operator/internal/webhook/request_version*, deploy/operator/internal/webhook/validation/*, deploy/operator/internal/versionoverride/*, deploy/operator/internal/dynamo/*, deploy/operator/internal/features/runtime/*
Webhooks route by requested API version, validate v1beta2 Request envelopes and AISimulate versions, and restrict changed writes through a non-owning API version. Compatibility-version types replace runtime-version types in the existing checks. Tests cover routing and cross-version carrier behavior.
AISimulate input lowering
deploy/operator/internal/controller/aisimulate/*
The controller maps typed Request fields into native AISimulate input, derives request-count, trial-count, and strict-SLA defaults, and applies Parameters as an RFC 7386 merge patch. Tests cover conversion, default derivation, and patch precedence.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~50 minutes

Merge Risk: ⚪ Minimal · up to 9e0c1

No actionable issue remains from this review; the PR is ready to merge after normal checks.

Pre-merge checks: Passed 4 · Inconclusive 1

Failed Failed checks: 1 inconclusive

Check name Status Explanation Resolution
Docstring Coverage Inconclusive Docstring coverage is 39.74% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 151 functions across 50 files. (10 skippe… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly summarizes the primary changes: aligning and documenting v1beta2 DGDR defaults.
Description check Passed The description provides a detailed overview, implementation details, API examples, validation steps, and issue references. It does not use the template headings for Overview, Details, reviewer starti…
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.
Full details: Description check

Explanation

The description provides a detailed overview, implementation details, API examples, validation steps, and issue references. It does not use the template headings for Overview, Details, reviewer starting point, or Related Issues, but it includes the required substantive information and is mostly complete.

Full details: Docstring Coverage

Explanation

Docstring coverage is 39.74% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 151 functions across 50 files. (10 skipped: 8 unsupported, 2 over the file limit.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

✨ Finishing Touches: 💡 1
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR

sttts added a commit that referenced this pull request Oct 26, 2026
Squashed from #17191.

Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
sttts added a commit that referenced this pull request Oct 26, 2026
Squashed from #17191.

Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
sttts added a commit that referenced this pull request Oct 27, 2026
Squashed from #17191.

Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
sttts added a commit that referenced this pull request Oct 27, 2026
Squashed from #17191.

Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
sttts added a commit that referenced this pull request Oct 27, 2026
Squashed from #17191.

Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
sttts added a commit that referenced this pull request Oct 27, 2026
Squashed from #17191.

Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deployment::k8s Relates to dynamo deployment in kubernetes documentation Improvements or additions to documentation fix size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants