From c6136ea19d95e34f70d14215fd3c1ef758a7abe6 Mon Sep 17 00:00:00 2001 From: Chung-Hsuan Tsai Date: Sat, 28 Feb 2026 23:36:35 +0800 Subject: [PATCH] feat: update ModelArtifact CRD to include registry field and improve validation - Added 'registry' field to the ModelArtifact CRD for specifying the OCI registry host. - Renamed 'repository' field in HuggingFaceSource to 'model' for clarity. - Updated descriptions and validation patterns for 'repository' and 'model' fields to enhance understanding and enforce naming conventions. - Adjusted required fields in the CRD to include the new 'registry' field. --- .../model.otterscale.io_modelartifacts.yaml | 21 +++++++++++++---- model/v1alpha1/modelartifact_types.go | 23 ++++++++++++++----- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/config/crd/bases/model.otterscale.io_modelartifacts.yaml b/config/crd/bases/model.otterscale.io_modelartifacts.yaml index 00fa5e1..0b3259d 100644 --- a/config/crd/bases/model.otterscale.io_modelartifacts.yaml +++ b/config/crd/bases/model.otterscale.io_modelartifacts.yaml @@ -21,6 +21,9 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .spec.target.registry + name: Registry + type: string - jsonPath: .spec.target.repository name: Repository type: string @@ -75,9 +78,9 @@ spec: description: HuggingFace specifies a HuggingFace Hub repository as the model source. properties: - repository: + model: description: |- - Repository is the HuggingFace model repository identifier (e.g. "microsoft/phi-4"). + Model is the HuggingFace model identifier (e.g. "microsoft/phi-4", "facebook/opt-125m"). Must contain only alphanumerics, dots, underscores, hyphens, and slashes. maxLength: 253 minLength: 1 @@ -109,7 +112,7 @@ spec: - name type: object required: - - repository + - model type: object type: object x-kubernetes-validations: @@ -160,10 +163,17 @@ spec: Insecure uses an unencrypted connection to the registry instead of TLS. Only use for development or air-gapped environments. type: boolean + registry: + description: Registry is the OCI registry host, optionally with + port (e.g. "ghcr.io", "registry.local:5001"). + maxLength: 253 + minLength: 1 + pattern: ^[a-zA-Z0-9][a-zA-Z0-9._/:-]*$ + type: string repository: description: |- - Repository is the full OCI registry path (e.g. "ghcr.io/myorg/models/phi-4"). - Must contain only alphanumerics, dots, underscores, hyphens, and slashes. + Repository is the OCI repository path within the registry (e.g. "myorg/models/phi-4", "facebook/opt-125m"). + Must not include the registry host. Must contain only alphanumerics, dots, underscores, hyphens, and slashes. maxLength: 253 minLength: 1 pattern: ^[a-zA-Z0-9][a-zA-Z0-9._/-]*$ @@ -176,6 +186,7 @@ spec: pattern: ^[a-zA-Z0-9._/-]*$ type: string required: + - registry - repository type: object required: diff --git a/model/v1alpha1/modelartifact_types.go b/model/v1alpha1/modelartifact_types.go index 9d8321e..c526ba5 100644 --- a/model/v1alpha1/modelartifact_types.go +++ b/model/v1alpha1/modelartifact_types.go @@ -40,10 +40,13 @@ type ArtifactPhase string const ( // PhasePending indicates the pipeline has not yet started. PhasePending ArtifactPhase = "Pending" + // PhaseRunning indicates the import/pack/push Job is in progress. PhaseRunning ArtifactPhase = "Running" + // PhaseSucceeded indicates the artifact was successfully pushed to the registry. PhaseSucceeded ArtifactPhase = "Succeeded" + // PhaseFailed indicates the pipeline encountered an error. PhaseFailed ArtifactPhase = "Failed" ) @@ -83,16 +86,16 @@ type ModelSource struct { // HuggingFaceSource configures model retrieval from HuggingFace Hub. // -// SECURITY: Repository and Revision are passed to shell scripts. Only users who can +// SECURITY: Model and Revision are passed to shell scripts. Only users who can // create ModelArtifacts should have access; they already have equivalent privileges. type HuggingFaceSource struct { - // Repository is the HuggingFace model repository identifier (e.g. "microsoft/phi-4"). + // Model is the HuggingFace model identifier (e.g. "microsoft/phi-4", "facebook/opt-125m"). // Must contain only alphanumerics, dots, underscores, hyphens, and slashes. // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=253 // +kubebuilder:validation:Pattern="^[a-zA-Z0-9][a-zA-Z0-9._/-]*$" // +required - Repository string `json:"repository"` + Model string `json:"model"` // Revision pins a specific branch, tag, or commit hash. // If not specified, the default branch is used. @@ -110,11 +113,18 @@ type HuggingFaceSource struct { // OCITarget defines the destination OCI registry for the packaged artifact. // -// SECURITY: Repository and Tag are passed to shell scripts. Only users who can +// SECURITY: Registry, Repository, and Tag are passed to shell scripts. Only users who can // create ModelArtifacts should have access; they already have equivalent privileges. type OCITarget struct { - // Repository is the full OCI registry path (e.g. "ghcr.io/myorg/models/phi-4"). - // Must contain only alphanumerics, dots, underscores, hyphens, and slashes. + // Registry is the OCI registry host, optionally with port (e.g. "ghcr.io", "registry.local:5001"). + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:Pattern="^[a-zA-Z0-9][a-zA-Z0-9._/:-]*$" + // +required + Registry string `json:"registry"` + + // Repository is the OCI repository path within the registry (e.g. "myorg/models/phi-4", "facebook/opt-125m"). + // Must not include the registry host. Must contain only alphanumerics, dots, underscores, hyphens, and slashes. // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=253 // +kubebuilder:validation:Pattern="^[a-zA-Z0-9][a-zA-Z0-9._/-]*$" @@ -228,6 +238,7 @@ type ModelArtifactStatus struct { // +kubebuilder:resource:scope=Namespaced // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` // +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status` +// +kubebuilder:printcolumn:name="Registry",type=string,JSONPath=`.spec.target.registry` // +kubebuilder:printcolumn:name="Repository",type=string,JSONPath=`.spec.target.repository` // +kubebuilder:printcolumn:name="Digest",type=string,JSONPath=`.status.digest`,priority=1 // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"