Skip to content

feat: Add new apiVersion with redesigned DGDR - #6095

Closed
Jont828 wants to merge 8 commits into
ai-dynamo:mainfrom
Jont828:v1beta1-apiversion
Closed

feat: Add new apiVersion with redesigned DGDR#6095
Jont828 wants to merge 8 commits into
ai-dynamo:mainfrom
Jont828:v1beta1-apiversion

Conversation

@Jont828

@Jont828 Jont828 commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Overview:

Work in progress following this proposal by @hhzhang16 .

Details:

Where should the reviewer start?

Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)

Signed-off-by: Jont828 <jt572@cornell.edu>
Signed-off-by: Jont828 <jt572@cornell.edu>
@copy-pr-bot

copy-pr-bot Bot commented Feb 9, 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 commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

👋 Hi Jont828! Thank you for contributing to ai-dynamo/dynamo.

Just a reminder: The NVIDIA Test Github Validation CI runs an essential subset of the testing framework to quickly catch errors.Your PR reviewers may elect to test the changes comprehensively before approving your changes.

🚀

@github-actions github-actions Bot added external-contribution Pull request is from an external contributor deployment::k8s Relates to dynamo deployment in kubernetes labels Feb 9, 2026
…conditions, and print cols to DGDR status

Signed-off-by: Jont828 <jt572@cornell.edu>
Comment on lines +33 to +35
DGDRPhaseReady DGDRPhase = "Ready"
DGDRPhaseDeploying DGDRPhase = "Deploying"
DGDRPhaseDeployed DGDRPhase = "Deployed"

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.

After looking at this, I think Ready isn't the best name for "successful profiling". Maybe we should change the phases:

  • Pending
  • Profiling
  • ProfilingComplete (this is where it stops with autoApply: false)
  • Deploying
  • Deployed (this is where it stops with autoApply: true)
  • Failed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think "ProfilingSucceeded" or "ProfilingComplete" is a good name. Should there be a planner phase, or is Deploying/Deployed enough?

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.

It's a DynamoDeployment, may or may not have Planner. So I don't think any phase should explicitly mention planner. Also DynamoDeploymentDeploying sounds kinda weird to me lol

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Oh I see, I didn't realize the planner was a component instead of a step in DGDR controller. Should we have some kind of aggregate/overall terminal phase similar to the "succeeded" condition? I think that would make it more clear that it's done and we can check against that value if we're deploying or not.

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.

Yes down

// ConditionTypeSucceeded is the aggregate condition for the DGDR lifecycle.
// True = pipeline completed successfully; False = in progress or failed.
// Reason and Message reflect the current stage or error.
ConditionTypeSucceeded = "Succeeded"

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.

For the records: this will happen if ProfilingComplete and autoApply: false or Deployed and autoApply: true

EventReasonValidationFailed = "ValidationFailed"
EventReasonProfilingJobCreated = "ProfilingJobCreated"
EventReasonProfilingJobFailed = "ProfilingJobFailed"
EventReasonAIConfiguratorFailed = "AIConfiguratorFailed"

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.

Not sure if this should be tied into/part of ProfilingJobFailed? Does the user need to know abt AIConfigurator explicitly

ProfilingPhaseDone ProfilingPhase = "Done"
)

// Profiling condition Reasons.

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.

Should these be a bit more explanatory? @tedzhouhk

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.

agreed, is it possible to show more details, like sweeping prefill 2/4

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The 'Reason' needs to be a hard coded string. But each condition will have a message too, so I was thinking we could expose it in the message part, that way we don't need to say how many GPUs we're targeting for ex. Does that work?

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.

That works for me

Signed-off-by: Jont828 <jt572@cornell.edu>
Move the +kubebuilder:storageversion marker from v1alpha1 to v1beta1
for all CRDs and regenerate manifests so v1beta1 is the version
persisted in etcd going forward.

Signed-off-by: Jont828 <jt572@cornell.edu>

@julienmancuso julienmancuso 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.

hi @Jont828 what justifies the switch to using a new CRD version ?
internally we are having discussions but we are leaning towards keeping v1alpha1 for now.
let's hold on this change

Implement the controller-runtime conversion interface for 5 CRDs:
DynamoCheckpoint, DynamoComponentDeployment, DynamoGraphDeployment,
DynamoGraphDeploymentScalingAdapter, and DynamoModel.

v1beta1 is marked as the Hub and v1alpha1 implements ConvertTo/ConvertFrom
with field-by-field mapping. DGDR is excluded because the two versions
have fundamentally different schemas that cannot be losslessly converted.

Signed-off-by: Jont828 <jt572@cornell.edu>
@tedzhouhk

Copy link
Copy Markdown
Contributor

currently we have two different definitions on the DGDR fields. One version is defined in this PR, another version is defined for the shim python layer #6285. We need to manually sync between them now. However, we should automate this in the future.

type OptimizationType string

const (
OptimizationTypeHybrid OptimizationType = "hybrid"

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.

Let's get rid of this option and make "throughput" the default

Align the Go CRD types with the Python profiler's pydantic models so
that JSON serialized between operator and profiler is structurally
consistent:

- Introduce ModelSpec (modelName + modelCache) replacing flat model
  string and top-level modelCache field
- Introduce BackendSpec (backend + dynamoImage) replacing flat backend
  enum and top-level image field
- Rename ModelCacheSpec.PVCPath to ModelPathInPVC (json: modelPathInPvc)
- Add WorkloadSpec.Concurrency and RequestRate fields
- Add SLASpec.E2ELatency field
- Replace FeaturesSpec.Planner *bool with *PlannerSpec (enabled,
  plannerPreDeploymentSweeping, plannerArgsList)
- Replace FeaturesSpec.Mocker *bool with *MockerSpec (enabled)
- Add HardwareSpec with gpuSku, vramMb, totalGpus, numGpusPerNode
- Add PlannerPreDeploymentSweepMode enum (none, rapid, thorough)
- Remove OptimizationType "hybrid" value
- Update printcolumn JSONPaths for new nesting
- Update deepcopy methods for new and changed types

Signed-off-by: Jonathan Zhou <hongkuanz@nvidia.com>
Signed-off-by: Jont828 <jt572@cornell.edu>
@Jont828

Jont828 commented Feb 14, 2026

Copy link
Copy Markdown
Contributor Author

@tedzhouhk I pushed some changes to sync it based on your Python code. Here's a summary of what I changed. Does this look right to you? There's some Go types that aren't in the Python for your PR so not sure if you want to add them or not.

  Go struct changes (dynamographdeploymentrequest_types.go)

  New struct: ModelSpec
  Wraps the model name and cache into a single nested object, replacing the old flat Model string + top-level ModelCache *ModelCacheSpec.
  ┌────────────┬────────────┬────────────────────────────┐
  │   Field    │  JSON tag  │            Type            │
  ├────────────┼────────────┼────────────────────────────┤
  │ ModelName  │ modelName  │ string (required)          │
  ├────────────┼────────────┼────────────────────────────┤
  │ ModelCache │ modelCache │ *ModelCacheSpec (optional) │
  └────────────┴────────────┴────────────────────────────┘
  → Python counterpart: class ModelSpec(BaseModel) — model_name: str, model_cache: Optional[ModelCacheSpec]

  ---
  New struct: BackendSpec
  Wraps the backend enum and image into a single nested object, replacing the old flat Backend BackendType + Image string.
  ┌─────────────┬─────────────┬─────────────────────────────┐
  │    Field    │  JSON tag   │            Type             │
  ├─────────────┼─────────────┼─────────────────────────────┤
  │ Backend     │ backend     │ BackendType (default: auto) │
  ├─────────────┼─────────────┼─────────────────────────────┤
  │ DynamoImage │ dynamoImage │ string (optional)           │
  └─────────────┴─────────────┴─────────────────────────────┘
  → Python counterpart: class BackendSpec(BaseModel) — backend: Backend, dynamo_image: str

  ---
  Changed struct: ModelCacheSpec
  Renamed one field:
  ┌────────────────┬───────────────────────┬──────────────────────────┐
  │     Before     │         After         │         JSON tag         │
  ├────────────────┼───────────────────────┼──────────────────────────┤
  │ PVCPath string │ ModelPathInPVC string │ pvcPath → modelPathInPvc │
  └────────────────┴───────────────────────┴──────────────────────────┘
  Other fields (PVCName, PVCMountPath) unchanged.

  → Python counterpart: class ModelCacheSpec(BaseModel) — pvc_name, model_path_in_pvc, pvc_mount_path

  ---
  Changed struct: DynamoGraphDeploymentRequestSpec
  ┌────────────────────────────────────────┬──────────────────────────────────────────────┐
  │                 Before                 │                    After                     │
  ├────────────────────────────────────────┼──────────────────────────────────────────────┤
  │ Model string (flat)                    │ Model ModelSpec (nested struct)              │
  ├────────────────────────────────────────┼──────────────────────────────────────────────┤
  │ Backend BackendType (flat enum)        │ Backend *BackendSpec (nested struct)         │
  ├────────────────────────────────────────┼──────────────────────────────────────────────┤
  │ Image string (flat)                    │ Removed — now inside BackendSpec.DynamoImage │
  ├────────────────────────────────────────┼──────────────────────────────────────────────┤
  │ ModelCache *ModelCacheSpec (top-level) │ Removed — now inside ModelSpec.ModelCache    │
  └────────────────────────────────────────┴──────────────────────────────────────────────┘
  All other fields unchanged: Hardware, Workload, SLA, Overrides, Features, SearchStrategy, AutoApply.

  → Python counterpart: class AugmentedDGDR(BaseModel) — model: ModelSpec, backend: BackendSpec, hardware, workload, sla, features, search_strategy, auto_apply

  ---
  Updated printcolumn JSONPaths:
  - .spec.model → .spec.model.modelName
  - .spec.backend → .spec.backend.backend

  ---
  Updated zz_generated.deepcopy.go:
  - DynamoGraphDeploymentRequestSpec.DeepCopyInto updated for new Model/Backend field shapes
  - Added ModelSpec.DeepCopyInto / DeepCopy
  - Added BackendSpec.DeepCopyInto / DeepCopy

  ---
  Unchanged structs (already in sync)
  ┌──────────────┬──────────────┬──────────────────────────────────────────────────────────────────────┐
  │  Go struct   │ Python class │                                Fields                                │
  ├──────────────┼──────────────┼──────────────────────────────────────────────────────────────────────┤
  │ HardwareSpec │ HardwareSpec │ gpuSku, vramMb, totalGpus, numGpusPerNode                            │
  ├──────────────┼──────────────┼──────────────────────────────────────────────────────────────────────┤
  │ WorkloadSpec │ WorkloadSpec │ isl, osl, concurrency, requestRate                                   │
  ├──────────────┼──────────────┼──────────────────────────────────────────────────────────────────────┤
  │ SLASpec      │ SLASpec      │ ttft, itl, e2eLatency (Go also has optimizationType — not in Python) │
  ├──────────────┼──────────────┼──────────────────────────────────────────────────────────────────────┤
  │ PlannerSpec  │ PlannerSpec  │ enabled, plannerPreDeploymentSweeping, plannerArgsList               │
  ├──────────────┼──────────────┼──────────────────────────────────────────────────────────────────────┤
  │ MockerSpec   │ MockerSpec   │ enabled                                                              │
  ├──────────────┼──────────────┼──────────────────────────────────────────────────────────────────────┤
  │ FeaturesSpec │ FeaturesSpec │ planner, mocker (Go also has kvRouter — not in Python)               │
  └──────────────┴──────────────┴──────────────────────────────────────────────────────────────────────┘
  Go-only types (no Python counterpart yet)

  - OverridesSpec (profilingJob, dgd)
  - SLASpec.OptimizationType (latency/throughput)
  - FeaturesSpec.KVRouter (*bool)

Add v1alpha1 ↔ v1beta1 conversion for DynamoGraphDeploymentRequest
(DGDR) and split the monolithic conversion.go into per-type files
matching the existing *_types.go naming convention.

Hub marker: add DynamoGraphDeploymentRequest to v1beta1/hub.go.

DGDR conversion handles three categories of field mappings:
- Simple renames (Model, Backend, AutoApply, UseMocker, WorkersImage)
- JSON blob ↔ structured fields (SLA ttft/itl, Workload isl/osl,
  ModelCache) with full-blob annotation for round-trip preservation
- Annotation-based storage for v1alpha1 fields with no v1beta1
  equivalent (ProfilerImage, ConfigMapRef, OutputPVC, etc.)

State ↔ Phase mapping accounts for v1alpha1 "Ready" mapping to either
Ready or Deployed depending on Deployment.Created context.

Signed-off-by: Jont828 <jt572@cornell.edu>
@hhzhang16

Copy link
Copy Markdown
Contributor

Closing as covered in #6352

@hhzhang16 hhzhang16 closed this Feb 20, 2026
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 external-contribution Pull request is from an external contributor feat size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants