Repository navigation
Conversation
✅ Dynamo PR CI passed — run 41139800682 (attempt 1) on
|
d8d5ee2 to
e2d17ad
Compare
e2d17ad to
a3d4cf8
Compare
Port the standalone CI fix from ai-dynamo#17483 without its DGDR changes. Original fix by hongkuanz in 934ceb3. Ignore only the unset fixture-loop-scope notice so pytest 9.2 can configure plugins under filterwarnings=error while preserving existing fixture scopes. (cherry picked from commit 934ceb3) Signed-off-by: Pranjul Gupta <pranjulgupta0203@gmail.com>
a3d4cf8 to
30884c7
Compare
Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
…evan#7] Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
Signed-off-by: Dr. Stefan Schimanski <sschimanski@nvidia.com>
e22e256 to
a2f69a0
Compare
Squash of hzhou/dgdr-trace-pvc at 410f5dd onto sttts-dgdr-v1beta2-integration (a2f69a0). The branch history carried a copy of the integration stack for every force-push of the base, which put the pull request over the 250-commit limit of the GitHub API that the DCO app and copy-pr-bot read. The tree is identical to 410f5dd. Signed-off-by: hongkuanz <hongkuanz@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
410f5dd to
ab4b32b
Compare
…le marker The integration base built every Run Job with fsGroup 65532 and the merged Job validation required none, so an operator upgrade would fail an in-flight non-trace sweep as InvalidExecution and delete its Job. Validation now accepts that legacy fsGroup for a Run without a trace; a trace Run still must request none, and any other fsGroup is still skew. Also cover the optimistic lock on the permanent-failure marker: a stale pass that sees a second Run-controlled Job after the trace failure was recorded must conflict rather than overwrite TraceSourceUnavailable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
#17308 squash-merged sttts-dgdr-v1beta2-integration into main as dff7c99, and this pull request now targets main. The merge uses the integration head a2f69a0 this branch was built on as its base, so it carries only this branch's changes onto main. Main has not changed deploy/operator or the Kubernetes API reference since a2f69a0. Signed-off-by: hongkuanz <hongkuanz@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Trace workload API and schema deploy/operator/api/*, deploy/operator/config/crd/bases/*, docs/fern/pages/reference/kubernetes-api/*, docs/fern/scripts/tests/test_gen_kubernetes_api.py |
The API and CRD schemas add a Dynamo-format trace source backed by a PVC, optional arrival speedup, and static-versus-trace exclusivity. The references, examples, generated deep-copy methods, and fuzz tests cover the new workload. |
Admission defaults and validation deploy/operator/internal/webhook/defaulting/*, deploy/operator/internal/webhook/validation/*, deploy/operator/internal/controller/dynamographdeploymentrequest_v1beta2_controller* |
Defaulting skips static traffic defaults for trace workloads. Validation checks trace fields, PVC paths, override restrictions, and conversion-carried workloads. Request reconciliation records rejected Run creation as InvalidSpec. |
Trace input lowering deploy/operator/internal/aisimulate/*, deploy/operator/internal/controller/testdata/dgdr-v1beta2/vllm-trace/* |
AISimulate lowering sets trace source and timestamp-based load fields. It maps source paths to fixed mount filenames and omits the request-count default for trace traffic. Tests and fixtures cover lowered trace input and a vLLM trace candidate. |
Run trace mounting and failure handling deploy/operator/internal/controller/dynamographdeploymentrun_v1beta2_controller*, deploy/operator/internal/controller/dgdr_v1beta2_trace_clustertest_test.go, deploy/operator/internal/controller/clusterenv_test.go |
The Run controller mounts the source file read-only in the sweeper, watches PVC and Job-pod events, and records trace-source failures. It deletes unfinished Jobs after those failures. Controller and cluster tests cover claim availability, mount errors, overrides, and file integrity. |
Estimated code review effort: 4 (Complex) | ~60 minutes
Merge Risk: 
Minimal · up to ad3bd
-
This change adds PVC-backed recorded-trace replay for DGDR v1beta2. No remaining merge-blocking risk was found in the supplied evidence. Cluster-level behavior is reported as verified only by CI's Operator Integration, which is normal validation uncertainty and not a concrete defect.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 warning Passed checks: 4 passed-
Full details: Description check
-
Explanation
The description is complete and follows the required template. It includes Overview, Key Changes, Validation, and Issues and Ongoing Work sections, with detailed scope, testing, limitations, and follow-up work. The checklist is present but remains unchecked, and no closing issue link is provided; these are non-critical for this description check.
-
Full details: Docstring Coverage
-
Explanation
Docstring coverage is 39.39% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 66 functions across 25 files. (8 skipped: 8 unsupported.)
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.
The only conflict was the generated full-api-reference.mdx. It is resolved by regenerating with make generate manifests generate-api-docs generate-helm-docs. Regenerating the other generated files left them unchanged from the automatic merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
sttts
left a comment
There was a problem hiding this comment.
Three follow-up comments on trace-PVC lifetime/cancellation, diagnostic-only Pod errors, and exercising the default AIC renderer. Source review only; no tests were executed.
…deletion Give the trace PersistentVolumeClaim an operator-owned lifetime tied to the Runs that read it, and stop deriving Run outcomes from cached pod startup state or kubelet messages. - Before a Run creates its Job it patches its own finalizer, nvidia.com/dgdr-run-<run-uid>, onto the claim with an optimistic lock, so a stale cache or a claim being deleted never gets a Job. Patch errors are retryable; the API server reports a refused finalizer as Invalid, which would otherwise fail the Run permanently. - A claim with a deletionTimestamp, or one gone after the Run created its Job, cancels the Run whatever its pod has started: the Job is stopped through the foreground stop path shared with Request supersession (stopAndCompleteRun), and only after the API server confirms it is gone does the Run fail with TraceSourceDeleted. A Job that already has JobComplete or JobFailed decides the Run itself. - A completed Run stops any unfinished Job a stale pass created and then releases its finalizer after an uncached confirmation. A claim-keyed reconciler releases the finalizers of deleted Runs once no Job they control exists, so release converges after Run deletion, namespace deletion and operator restarts. - A missing claim keeps the Run open with TraceSourceMissing; a Block or Lost claim fails it with TraceSourceUnavailable through the durable permanent-failure marker, and only before the first Job. - Waiting containers are diagnostics only: the Run stays open with ContainerWaiting and the container's reason and message verbatim. The message-based trace mount classification, the scheduled/started inference, and the operator-initiated Job deletion are removed. - Grant patch/update on persistentvolumeclaims through the RBAC marker, pin the pod cache fields the diagnostic reads, verify the API server fencing in envtest, and document the lifecycle and manual finalizer removal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
…erator The vllm-trace ClusterEnv scenario forced dgdr_run.generator: direct, so it could pass while an ordinary trace Request failed to render its Candidate through the default AIC generator. The AIC renderer forwards the trace workload since #17474 and #17523, so drop the override and keep the scenario on the default path. The pinned AISimulate still rejects a candidate without an explicit block size (#17581), so the scenario takes the same TODO(#17581) block-size workaround as the static vllm scenario. The Candidate golden is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
…op a Job on a stale read A Job the operator foreground-deletes for a deleted trace claim can be marked JobFailed by the Job controller while its pod is removed. The finished-Job exemption then took that failure as the Job's own outcome and the Run never reported TraceSourceDeleted. The exemption now applies only to a Job that finished while nothing was deleting it. stopOwnedJobs now fences each deletion with the UID and resourceVersion of the Job as it was read. A Job that finished after the cache last showed it is no longer stopped on that stale view: the API server reports a Conflict and the next pass decides again from the finished Job, which keeps its outcome. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
Brings the branch to current main so the live retune pull requests stacked on it share one base. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
jthomson04
left a comment
There was a problem hiding this comment.
Reviewed at 6e8087d. The finalizer and cancellation lifecycle holds up: every finalizer and status write is resourceVersion-fenced, finalizers are keyed by Run UID, and Job absence is confirmed through the uncached reader. Five nits inline, none blocking.
| // +kubebuilder:rbac:groups=nvidia.com,resources=dynamographdeploymentcandidates/status,verbs=get;update;patch | ||
| // +kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;watch;create;delete | ||
| // +kubebuilder:rbac:groups="",resources=pods,verbs=get;list;watch | ||
| // +kubebuilder:rbac:groups="",resources=persistentvolumeclaims,verbs=get;list;watch;patch;update |
There was a problem hiding this comment.
Nothing calls Update on a PVC; every write here and in the claim reconciler is a Patch. Drop update so the generated role.yaml doesn't grant it cluster-wide.
| source *nvidiacomv1beta2.TracePVCSource, | ||
| ) (ctrl.Result, error) { | ||
| if len(jobs) == 0 { | ||
| live, err := r.uncachedOwnedJobs(ctx, run) |
There was a problem hiding this comment.
When the cache shows no Jobs, this lists every Job in the namespace from the API, then stopOwnedJobs (:363) lists them all again because jobs is still empty, once per dgdrRunExecutionCacheRetry. Pass the confirmed result through. A Run-UID label on the Job would let this and runHoldsClaim use a selector instead of an unfiltered list.
|
|
||
| // runsForTraceClaim maps a claim event to the Runs in the claim's namespace that read their trace | ||
| // from it. | ||
| func (r *DynamoGraphDeploymentRunV1beta2Reconciler) runsForTraceClaim(ctx context.Context, claim client.Object) []reconcile.Request { |
There was a problem hiding this comment.
Every claim event re-queues every Run on the claim, completed ones included. With live retune (#17562) all Runs share one claim, so each finalizer add or remove fans out to all of them: O(N²) reconciles. Enqueue only Runs that aren't Completed or still hold a finalizer on the claim.
| } | ||
| } | ||
|
|
||
| // A Job of the Run, as the cache and then the API server show it. |
There was a problem hiding this comment.
On this path no Job doesn't mean no pod. A Run deleted directly has no finalizer, so GC deletes its Jobs with background propagation and the release can land while the pod still has the subPath mounted. kubernetes.io/pvc-protection keeps the object, so nothing breaks, but the claimName doc's "until its execution stops" overstates it. Either foreground-delete the gone Run's Jobs here or narrow the doc.
| return true, nil | ||
| } | ||
| live := &batchv1.JobList{} | ||
| if err := r.APIReader.List(ctx, live, client.InNamespace(claim.Namespace)); err != nil { |
There was a problem hiding this comment.
This uncached, unfiltered namespace Job list runs once per stale finalizer. Hoist it out of the loop, or select on a Run-UID label.
Overview
A DGDR v1beta2 search can now replay a recorded request trace instead of synthetic static traffic. This is the input side of a planner retune in a live deployment: the frontend records traces to a shared claim, and a Request evaluates candidates against one recorded window. The planner side is out of scope here.
Key Changes
API (
api/v1beta2)spec.workload.trace{format, source.pvc{claimName, path}, replay.arrivalSpeedupRatio}, exclusive withstatic. The shape follows the trace workload in DEP DEP: Evolve DGDR for replay-backed multi-candidate search #13092;formatis limited todynamo, which can widen compatibly later.claimNameis a DNS-1123 subdomain;pathis relative, has no empty,.or..segment, no NUL, and at most 1024 characters; the speedup is greater than 0.workload.static, now acceptsstaticortrace.Validation (
internal/webhook/validation)shared_v1beta2.gomirror the CRD rules. They matter for a v1beta1 carrier stored without admission, whose unchanged trace CEL ratchets on the next v1beta2 write.inputOverridescannot settraffic.source.type,formatorpaths, or replacetrafficortraffic.sourcewith a non-object. Every other traffic override,traffic.stopincluded, is AISimulate input that AISimulate validates.InvalidSpecfor that generation instead of retrying.Lowering (
internal/aisimulate)traffic.source{type: trace, format, paths: [<fixed mount path>]}andtraffic.load.type: trace_timestamps, plustraffic.load.speedupwhen set. Notraffic.stop.requestsis added. The Run controller restores the typed source after the override merge.Run controller and Job
subPathat/var/run/aisimulate/trace/trace.jsonl.gz(ortrace.jsonl), into the sweeper alone. The kubelet resolves the path inside the claim and refuses an absolute symlink or one that leaves the claim.fsGroup, so neither kubelet nor a CSI driver changes the claim's ownership or permissions. A trace Job's pod gets group 65532 as a supplemental group. The base'srunAsNonRoot, seccomp profile and numeric sweeper UID are kept.nvidia.com/dgdr-run-<run-uid>to the claim with an optimistic-lock patch, so a stale cache gets a Conflict instead of a Job. No Job is created for a claim that is being deleted.stopAndCompleteRun, which replacescancelSupersededRun). The Run fails withCompleted=True/TraceSourceDeletedonly after the API server confirms the Job is gone, and then releases its finalizer. A Job that reachedJobCompleteorJobFailedon its own keeps its result. Stop deletes carry UID and resourceVersion preconditions, so a stale read never stops a Job that has since finished.Pending,Completed=False/TraceSourceMissing), and a claim event wakes it when the claim appears. A block or lost claim fails the Run withTraceSourceUnavailable, through the existing durable permanent-failure marker.ContainerCreatingorPodInitializingsetsCompleted=False/ContainerWaitingwith the kubelet's reason and message copied verbatim. It never ends the Run or deletes the Job.DynamoGraphDeploymentRunTraceClaimReconciler, releases the finalizer of a Run that is gone once no Job of that Run is left, so release converges after Run deletion and operator restarts.persistentvolumeclaimsget;list;watch;patch;update,podsget;list;watch,jobsdelete. The generatedrole.yamlchanges; the chart's hand-written operator rules already grant these.Generated files and docs
test_gen_kubernetes_api.pygoes from 35 to 40.ContainerWaitingdiagnostic and how to recover or cancel, and removing leftover finalizers by hand.Validation
On head
f73f4bbd0b:Build and lint
golangci-lint v2.15.0 run ./...: 0 issues.go vetwith no tags,clustertest, andclustertest,upgradecontract: clean.make generate manifests generate-api-docs generate-helm-docsleaves the tree unchanged.pre-commit runon the changed files andgit diff --checkpass.Go tests (envtest on k8s 1.30.0):
go test ./internal/... ./api/...passes (48 packages). Coverage includes:Cluster (
clustertest, only in CI's Operator Integration): the vllm-trace candidate scenario, now through the default AIC generator, and the escaping-symlink test, which now expectsContainerWaitingand cleans up by deleting the claim. Not run locally.AIC renderer: the vllm-trace scenario's Run Job command, run in the CI planner image with AISimulate
0.13.0.dev202610290000000087, reachesphase: Succeededthrough the default AIC generator and renders--block-size 64with theTODO(#17581)workaround. Without the workaround it fails on #17581.Development cluster: before this lifecycle change, at
ad3bd3050e, this PR ran with #17562 on an H200 development cluster. Frontends recorded traces to the claim, and every Run Job read its window file and succeeded. #17562's description has the details.Not verified: real foreground garbage collection of the Job and its Pods on claim deletion, release across a live operator restart, and RBAC in a non-
system:mastersinstall.Issues and Ongoing Work
ContainerWaitingdiagnostic until the cause is fixed or the Run is cancelled by deleting the claim or changing the Request.Terminatingthrough the upstreamkubernetes.io/pvc-protectionfinalizer until their Runs are retired.nvidia.com/dgdr-run-*finalizers stay on the claim; the DGDR reference shows how to remove them.engine.workers.<role>.kv_cache.block_sizefails in the default AIC renderer, trace or static. The trace scenario carries the sameTODO(#17581)workaround as the static vllm scenario.Pull Request Checklist
/pr-checklistskill.🤖 Generated with Claude Code
Summary by CodeRabbit