diff --git a/workspaces/backend/api/suite_test.go b/workspaces/backend/api/suite_test.go index faf349621..b3ef540c3 100644 --- a/workspaces/backend/api/suite_test.go +++ b/workspaces/backend/api/suite_test.go @@ -77,6 +77,8 @@ func TestAPI(t *testing.T) { RunSpecs(t, "API Suite") } +const namespaceName = "default" + var _ = BeforeSuite(func() { logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) ctx, cancel = context.WithCancel(context.Background()) @@ -221,8 +223,9 @@ func NewExampleWorkspaceKind(name string) *kubefloworgv1beta1.WorkspaceKind { }, Logo: kubefloworgv1beta1.WorkspaceKindIcon{ ConfigMap: &kubefloworgv1beta1.WorkspaceKindConfigMap{ - Name: "my-logos", - Key: "apple-touch-icon-152x152.png", + Name: "my-logos", + Namespace: namespaceName, + Key: "apple-touch-icon-152x152.png", }, }, }, diff --git a/workspaces/controller/api/v1beta1/workspace_types.go b/workspaces/controller/api/v1beta1/workspace_types.go index 972d72f42..c7a61ff5d 100644 --- a/workspaces/controller/api/v1beta1/workspace_types.go +++ b/workspaces/controller/api/v1beta1/workspace_types.go @@ -43,11 +43,12 @@ type WorkspaceSpec struct { DeferUpdates *bool `json:"deferUpdates,omitempty"` // the WorkspaceKind to use - // +kubebuilder:validation:MinLength:=2 - // +kubebuilder:validation:MaxLength:=63 - // +kubebuilder:validation:Pattern:=^[a-z0-9][-a-z0-9]*[a-z0-9]$ - // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Workspace 'kind' is immutable" - // +kubebuilder:example="jupyterlab" + //+kubebuilder:validation:MinLength:=2 + //+kubebuilder:validation:MaxLength:=63 + //+kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + //+kubebuilder:validation:XValidation:rule="self == oldSelf",message="Workspace 'kind' is immutable" + //+kubebuilder:example="jupyterlab" + Kind string `json:"kind"` // options for "podTemplate"-type WorkspaceKinds @@ -82,11 +83,12 @@ type WorkspacePodVolumes struct { // - this PVC must be RWX (ReadWriteMany, ReadWriteOnce) // - the mount path is defined in the WorkspaceKind under // `spec.podTemplate.volumeMounts.home` - // +kubebuilder:validation:Optional - // +kubebuilder:validation:MinLength:=2 - // +kubebuilder:validation:MaxLength:=63 - // +kubebuilder:validation:Pattern:=^[a-z0-9][-a-z0-9]*[a-z0-9]$ - // +kubebuilder:example="my-home-pvc" + + //+kubebuilder:validation:Optional + //+kubebuilder:validation:MinLength:=2 + //+kubebuilder:validation:MaxLength:=63 + //+kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + //+kubebuilder:example="my-home-pvc" Home *string `json:"home,omitempty"` // additional PVCs to mount @@ -102,10 +104,10 @@ type WorkspacePodVolumes struct { type PodVolumeMount struct { // the name of the PVC to mount - // +kubebuilder:validation:MinLength:=2 - // +kubebuilder:validation:MaxLength:=63 - // +kubebuilder:validation:Pattern:=^[a-z0-9][-a-z0-9]*[a-z0-9]$ - // +kubebuilder:example="my-data-pvc" + //+kubebuilder:validation:MinLength:=2 + //+kubebuilder:validation:MaxLength:=63 + //+kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + //+kubebuilder:example="my-data-pvc" PVCName string `json:"pvcName"` // the mount path for the PVC diff --git a/workspaces/controller/api/v1beta1/workspacekind_types.go b/workspaces/controller/api/v1beta1/workspacekind_types.go index 2d846237d..96cc04a9e 100644 --- a/workspaces/controller/api/v1beta1/workspacekind_types.go +++ b/workspaces/controller/api/v1beta1/workspacekind_types.go @@ -89,9 +89,24 @@ type WorkspaceKindIcon struct { } type WorkspaceKindConfigMap struct { - // +kubebuilder:example="my-logos" + + //+kubebuilder:validation:MinLength:=1 + //+kubebuilder:validation:MaxLength:=253 + //+kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + //+kubebuilder:example="my-logos" Name string `json:"name"` + //+kubebuilder:validation:MinLength:=1 + //+kubebuilder:validation:MaxLength:=63 + //+kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + Namespace string `json:"namespace"` + + //+kubebuilder:validation:MinLength:=1 + //+kubebuilder:validation:MaxLength:=253 + //+kubebuilder:validation:Pattern:=^[-._a-zA-Z0-9]+$ + //+kubebuilder:example="apple-touch-icon-152x152.png" + + // +kubebuilder:example="apple-touch-icon-152x152.png" Key string `json:"key"` } diff --git a/workspaces/controller/config/crd/bases/kubeflow.org_workspacekinds.yaml b/workspaces/controller/config/crd/bases/kubeflow.org_workspacekinds.yaml index 9fea44636..69f1214dc 100644 --- a/workspaces/controller/config/crd/bases/kubeflow.org_workspacekinds.yaml +++ b/workspaces/controller/config/crd/bases/kubeflow.org_workspacekinds.yaml @@ -4479,13 +4479,25 @@ spec: properties: key: example: apple-touch-icon-152x152.png + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ type: string name: example: my-logos + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string required: - key - name + - namespace type: object url: example: https://jupyter.org/assets/favicons/apple-touch-icon-152x152.png @@ -4504,13 +4516,25 @@ spec: properties: key: example: apple-touch-icon-152x152.png + maxLength: 253 + minLength: 1 + pattern: ^[-._a-zA-Z0-9]+$ type: string name: example: my-logos + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + namespace: + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string required: - key - name + - namespace type: object url: example: https://jupyter.org/assets/favicons/apple-touch-icon-152x152.png diff --git a/workspaces/controller/config/crd/bases/kubeflow.org_workspaces.yaml b/workspaces/controller/config/crd/bases/kubeflow.org_workspaces.yaml index e57a13a4a..a210ef91d 100644 --- a/workspaces/controller/config/crd/bases/kubeflow.org_workspaces.yaml +++ b/workspaces/controller/config/crd/bases/kubeflow.org_workspaces.yaml @@ -55,7 +55,7 @@ spec: example: jupyterlab maxLength: 63 minLength: 2 - pattern: ^[a-z0-9][-a-z0-9]*[a-z0-9]$ + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string x-kubernetes-validations: - message: Workspace 'kind' is immutable @@ -130,7 +130,7 @@ spec: example: my-data-pvc maxLength: 63 minLength: 2 - pattern: ^[a-z0-9][-a-z0-9]*[a-z0-9]$ + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string readOnly: default: false @@ -154,7 +154,7 @@ spec: example: my-home-pvc maxLength: 63 minLength: 2 - pattern: ^[a-z0-9][-a-z0-9]*[a-z0-9]$ + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string type: object required: diff --git a/workspaces/controller/internal/controller/suite_test.go b/workspaces/controller/internal/controller/suite_test.go index f89afed2e..ecca604e3 100644 --- a/workspaces/controller/internal/controller/suite_test.go +++ b/workspaces/controller/internal/controller/suite_test.go @@ -59,6 +59,8 @@ var ( cancel context.CancelFunc ) +const namespaceName = "default" + func TestControllers(t *testing.T) { RegisterFailHandler(Fail) @@ -197,8 +199,9 @@ func NewExampleWorkspaceKind1(name string) *kubefloworgv1beta1.WorkspaceKind { }, Logo: kubefloworgv1beta1.WorkspaceKindIcon{ ConfigMap: &kubefloworgv1beta1.WorkspaceKindConfigMap{ - Name: "my-logos", - Key: "apple-touch-icon-152x152.png", + Name: "my-logos", + Namespace: namespaceName, + Key: "apple-touch-icon-152x152.png", }, }, }, diff --git a/workspaces/controller/internal/controller/workspacekind_controller_test.go b/workspaces/controller/internal/controller/workspacekind_controller_test.go index 93bad2cea..62541f682 100644 --- a/workspaces/controller/internal/controller/workspacekind_controller_test.go +++ b/workspaces/controller/internal/controller/workspacekind_controller_test.go @@ -119,8 +119,9 @@ var _ = Describe("WorkspaceKind Controller", func() { newWorkspaceKind.Spec.Spawner.Icon = kubefloworgv1beta1.WorkspaceKindIcon{ Url: ptr.To("https://example.com/icon.png"), ConfigMap: &kubefloworgv1beta1.WorkspaceKindConfigMap{ - Name: "my-logos", - Key: "icon.png", + Name: "my-logos", + Namespace: namespaceName, + Key: "icon.png", }, } Expect(k8sClient.Patch(ctx, newWorkspaceKind, patch)).NotTo(Succeed()) diff --git a/workspaces/controller/internal/webhook/suite_test.go b/workspaces/controller/internal/webhook/suite_test.go index ba438e761..8e5f26174 100644 --- a/workspaces/controller/internal/webhook/suite_test.go +++ b/workspaces/controller/internal/webhook/suite_test.go @@ -62,6 +62,8 @@ var ( cancel context.CancelFunc ) +const namespaceName = "default" + func TestAPIs(t *testing.T) { RegisterFailHandler(Fail) @@ -185,8 +187,9 @@ func NewExampleWorkspaceKind(name string) *kubefloworgv1beta1.WorkspaceKind { }, Logo: kubefloworgv1beta1.WorkspaceKindIcon{ ConfigMap: &kubefloworgv1beta1.WorkspaceKindConfigMap{ - Name: "my-logos", - Key: "apple-touch-icon-152x152.png", + Name: "my-logos", + Namespace: namespaceName, + Key: "apple-touch-icon-152x152.png", }, }, },