Repository navigation
feat(operator): admission for v1beta2 DGDR requests - #16661
devivasudevan wants to merge 17 commits into
Conversation
|
/ok to test 79d7fde |
✅ Dynamo PR CI passed — run 39753620443 (attempt 1) on
|
sttts
left a comment
There was a problem hiding this comment.
Detailed re-review findings for the v1beta2 DGDR admission implementation.
|
/ok to test c3058df |
|
/ok to test ea4eb12 |
|
/ok to test 7a00fc2 |
…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>
…uest controller Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VnCXbx7DMQHVwxwN8Dnutz Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
CI is currently blocked before admission envtests runAt HEAD Please regenerate and commit the CRD/API documentation from the source definitions rather than editing generated files manually. Because that check fails first, the later operator Go/Python integration step is skipped; consequently the new admission/operatorenv table has not actually run in CI on this HEAD. After updating the generated artifacts, please rerun the |
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>
…amo#16661 Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
sttts
left a comment
There was a problem hiding this comment.
The mixed-node count is now tracked as a shared v1beta1/v1beta2 follow-up. The AISimulate compatibility version still needs an explicit planner-version mapping in this PR.
Decision: AISimulate execution is operator-owned and version-lockedWe resolved the compatibility question by removing per-Request AISimulate artifact selection. A DGDR is not a supported compatibility boundary to an independently versioned or skewed AISimulate installation. The operator will always run the AISimulate version contained in the planner image configured for that operator release. The later Job reconciler reads that image directly from operator/Helm configuration; it does not copy the image or an AISimulate version into the Request or Run API. 1. Fixed release bundleThe two-container Job topology remains. What changes is ownership of the versions: both containers are selected by the running operator release, rather than one of them being selected by the DGDR. flowchart LR
HELM["Helm/operator configuration<br/>operator release + matching planner image"]
OP["Running operator<br/>admission + controllers"]
DGDR["DGDR v1beta2<br/>typed search intent<br/>aisimulate.inputOverrides"]
RUN["Immutable DGDRRun<br/>accepted native input snapshot"]
JOB["Fixed two-container Job"]
PUB["Publisher/helper container<br/>operator-owned image"]
EXEC["AISimulate execution container<br/>operator-configured planner image"]
BUNDLE["One tested release bundle<br/>Python host<br/>AISimulate<br/>Dynamo simulator/providers<br/>DGD generator/output adapter"]
STATUS["Run status<br/>aisimulate.input"]
CAND["Candidate resources<br/>DGD + metrics"]
HELM --> OP
HELM --> JOB
DGDR --> OP
OP --> RUN
RUN --> JOB
JOB --> PUB
JOB --> EXEC
EXEC --> BUNDLE
BUNDLE --> STATUS
BUNDLE --> CAND
The output adapter may eventually be consumed natively from the planner image or be exported by the publisher container. Because the whole Job is version-locked to one Dynamo/operator release, that choice is a reconciler packaging detail, not a cross-version compatibility feature and not a DGDR API option. 2. Kubernetes API contractThe user-facing AISimulate field contains only an optional native-input override: spec:
model:
name: meta-llama/Llama-3.1-8B-Instruct
aisimulate:
inputOverrides:
workload:
request_count: 2000
The immutable Run preserves the accepted typed input and the override. The exact document used to invoke AISimulate is observable separately: status:
aisimulate:
input:
model:
name: meta-llama/Llama-3.1-8B-Instruct
workload:
request_count: 2000
# ...the complete effective native input...
3. Lowering contractThese are the intentional boundaries:
Private AISimulate structures such as 4. Removed API and admission behaviorThis decision removes:
The generic runtime-version resolver remains specific to Dynamo runtime images; AISimulate is not a Dynamo runtime. 5. Follow-up ownershipThe Job reconciler must consume the planner image from operator/Helm configuration directly, lower the immutable Run input exactly once, write the resulting document to Validation of 6. ImplementationImplemented in devivasudevan/dynamo#4. |
…sion Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
Automatic CI Approval SkippedAutomatic approval requires every commit to have a signature that GitHub reports as verified. The following commits do not meet that requirement:
To use automatic approval, sign the listed commits and push again. Alternatively, a maintainer can review this head and comment |
|
For the |
Squashed from #16661. Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
Squashed from #16661. Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
Squashed from #16661. Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
Squashed from #16661. Signed-off-by: devivasudevan <49675305+devivasudevan@users.noreply.github.com>
Summary
Adds admission for native v1beta2
DynamoGraphDeploymentRequestobjects: defaulting (mutating) and validation (validating) webhooks. After conversion, a v1beta2 Request reaches both webhooks as a v1beta1 hub object carryingspec.v1beta2.Design
Defaults have one owner: admission. Backends,
workload.static,objective.modeand the scalar metric,recommendation.maxCandidates, cluster hardware and the AISimulate image are all defaulted by the webhook. The CRD carries no default markers for them, because the hub holds v1beta2 as an opaque envelope and the API server defaults in the webhook's version. The traversal mirrors the Go API tree (Spec→NativeSpec→NativeSearchInput→ children, in declaration order). It preserves explicit values including empty objects, is idempotent, and treatsworkload.static: {}as an opt-out.Hardware discovery uses the shared
gpu.Discovererthrough a consumer-owned interface with its exact signature. The AISimulate catalog mapping (unknown GPU model → empty SKU) happens at the v1beta2 boundary.spec.hardwareunchanged does not contact the cluster or mutate the spec, metadata-only updates included.spec.hardwarediscovers only the missing fields.spec.aisimulate.parametersis never consulted.Validation covers the typed API and the image and version selection: an AISimulate image is required, and
versionOverrideis required when the image tag has no parseable version. It runs on every CREATE and UPDATE, with no whole-spec equality shortcut. Rules the source schema can express stay with the schema: model presence (representation CEL),model.namelength, backend uniqueness (+listType=set) and thekvLoadRatiorange order (CEL).spec.aisimulate.parametersis opaque to admission. It is stored untouched and never decides a default. Lowering (typed values and derived defaults as the underlay,parametersas an RFC 7386 merge patch applied last) happens in the reconciler (#17097), which freezes the result into the Run.Conversion carriers. The requested version is resolved once from the admission request, and a missing request fails the call. A foreign-version view is read-only: an unchanged spec round-trips, any change is rejected.
Supporting changes
Tests
workload,workload.static,objective,sla,recommendation), Pareto objective, hardware lifecycle (failed discovery, recovery, metadata-only update, removing budget, SKU or all hardware), schema and CEL error paths, a stored invalid spec rejected again on updatematchPolicytestsBehaviour changes to review
workload.static,objective.modeandrecommendation.maxCandidatesare removed, so the Run CRD loses them too. This is harmless because the controller always writes a fully resolved Run.parameters; this surfaces when the Run executes.model.namenow passes, because the schema enforces only a minimum length of 1.Out of scope
_v1beta2files and calls nothing that PR changes