diff --git a/Makefile b/Makefile index 9fdf869a51b..7ba0b5047ed 100644 --- a/Makefile +++ b/Makefile @@ -180,9 +180,16 @@ api-docs: crd-ref-docs ## Creates API docs using https://github.com/elastic/crd- build: generate fmt vet ## Build manager binary. go build -o bin/manager main.go +RUN_ARGS = --log-mode=devel +GO_RUN_MAIN = OPERATOR_NAMESPACE=$(OPERATOR_NAMESPACE) DEFAULT_MANIFESTS_PATH=$(DEFAULT_MANIFESTS_PATH) go run $(GO_RUN_ARGS) ./main.go $(RUN_ARGS) .PHONY: run run: manifests generate fmt vet ## Run a controller from your host. - OPERATOR_NAMESPACE=$(OPERATOR_NAMESPACE) DEFAULT_MANIFESTS_PATH=${DEFAULT_MANIFESTS_PATH} go run ./main.go --log-mode=devel + $(GO_RUN_MAIN) + +.PHONY: run-nowebhook +run-nowebhook: GO_RUN_ARGS += -tags nowebhook +run-nowebhook: manifests generate fmt vet ## Run a controller from your host without webhook enabled + $(GO_RUN_MAIN) .PHONY: image-build image-build: # unit-test ## Build image with the manager. diff --git a/PROJECT b/PROJECT index e321d617330..29b72f8cff8 100644 --- a/PROJECT +++ b/PROJECT @@ -37,4 +37,114 @@ resources: defaulting: true validation: true webhookVersion: v1 +- api: + crdVersion: v1 + controller: true + domain: opendatahub.io + group: components + kind: Dashboard + path: github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1 + version: v1 + webhooks: + validation: false +- api: + crdVersion: v1 + controller: true + domain: opendatahub.io + group: components + kind: Workbenches + path: github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1 + version: v1 + webhooks: + validation: false +- api: + crdVersion: v1 + controller: true + domain: opendatahub.io + group: components + kind: ModelMeshServing + path: github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1 + version: v1 + webhooks: + validation: false +- api: + crdVersion: v1 + controller: true + domain: opendatahub.io + group: components + kind: DataSciencePipelines + path: github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1 + version: v1 + webhooks: + validation: false +- api: + crdVersion: v1 + controller: true + domain: opendatahub.io + group: components + kind: Kserve + path: github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1 + version: v1 + webhooks: + validation: false +- api: + crdVersion: v1 + controller: true + domain: opendatahub.io + group: components + kind: Kueue + path: github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1 + version: v1 + webhooks: + validation: false +- api: + crdVersion: v1 + controller: true + domain: opendatahub.io + group: components + kind: CodeFlare + path: github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1 + version: v1 + webhooks: + validation: false +- api: + crdVersion: v1 + controller: true + domain: opendatahub.io + group: components + kind: Ray + path: github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1 + version: v1 + webhooks: + validation: false +- api: + crdVersion: v1 + controller: true + domain: opendatahub.io + group: components + kind: TrustyAI + path: github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1 + version: v1 + webhooks: + validation: false +- api: + crdVersion: v1 + controller: true + domain: opendatahub.io + group: components + kind: ModelRegistry + path: github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1 + version: v1 + webhooks: + validation: false +- api: + crdVersion: v1 + controller: true + domain: opendatahub.io + group: components + kind: TrainingOperator + path: github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1 + version: v1 + webhooks: + validation: false version: "3" diff --git a/apis/components/component.go b/apis/components/component.go new file mode 100644 index 00000000000..0555e208a95 --- /dev/null +++ b/apis/components/component.go @@ -0,0 +1,68 @@ +// +groupName=datasciencecluster.opendatahub.io +package components + +import ( + operatorv1 "github.com/openshift/api/operator/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Component struct defines the basis for each OpenDataHub component configuration. +// +kubebuilder:object:generate=true +type Component struct { + // Set to one of the following values: + // + // - "Managed" : the operator is actively managing the component and trying to keep it active. + // It will only upgrade the component if it is safe to do so + // + // - "Removed" : the operator is actively managing the component and will not install it, + // or if it is installed, the operator will try to remove it + // + // +kubebuilder:validation:Enum=Managed;Removed + ManagementState operatorv1.ManagementState `json:"managementState,omitempty"` + // Add any other common fields across components below + + // Add developer fields + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,order=2 + DevFlags *DevFlags `json:"devFlags,omitempty"` +} + +// DevFlags defines list of fields that can be used by developers to test customizations. This is not recommended +// to be used in production environment. +// +kubebuilder:object:generate=true +type DevFlags struct { + // List of custom manifests for the given component + // +optional + Manifests []ManifestsConfig `json:"manifests,omitempty"` +} + +type ManifestsConfig struct { + // uri is the URI point to a git repo with tag/branch. e.g. https://github.com/org/repo/tarball/ + // +optional + // +kubebuilder:default:="" + // +operator-sdk:csv:customresourcedefinitions:type=spec,order=1 + URI string `json:"uri,omitempty"` + + // contextDir is the relative path to the folder containing manifests in a repository, default value "manifests" + // +optional + // +kubebuilder:default:="manifests" + // +operator-sdk:csv:customresourcedefinitions:type=spec,order=2 + ContextDir string `json:"contextDir,omitempty"` + + // sourcePath is the subpath within contextDir where kustomize builds start. Examples include any sub-folder or path: `base`, `overlays/dev`, `default`, `odh` etc. + // +optional + // +kubebuilder:default:="" + // +operator-sdk:csv:customresourcedefinitions:type=spec,order=3 + SourcePath string `json:"sourcePath,omitempty"` +} + +// +kubebuilder:object:generate=true +type Status struct { + Phase string `json:"phase"` + Conditions []metav1.Condition `json:"conditions,omitempty"` + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +type WithStatus interface { + GetStatus() *Status +} diff --git a/apis/components/v1/codeflare_types.go b/apis/components/v1/codeflare_types.go new file mode 100644 index 00000000000..554074b19dc --- /dev/null +++ b/apis/components/v1/codeflare_types.go @@ -0,0 +1,69 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// CodeFlareSpec defines the desired state of CodeFlare +type CodeFlareSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of CodeFlare. Edit codeflare_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// CodeFlareStatus defines the observed state of CodeFlare +type CodeFlareStatus struct { + components.Status `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// CodeFlare is the Schema for the codeflares API +type CodeFlare struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CodeFlareSpec `json:"spec,omitempty"` + Status CodeFlareStatus `json:"status,omitempty"` +} + +func (c *CodeFlare) GetStatus() *components.Status { + return &c.Status.Status +} + +// +kubebuilder:object:root=true + +// CodeFlareList contains a list of CodeFlare +type CodeFlareList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CodeFlare `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CodeFlare{}, &CodeFlareList{}) +} diff --git a/apis/components/v1/dashboard_types.go b/apis/components/v1/dashboard_types.go new file mode 100644 index 00000000000..6ba973bc3e8 --- /dev/null +++ b/apis/components/v1/dashboard_types.go @@ -0,0 +1,78 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + DashboardInstanceName = "default-dashboard" +) + +// DashboardSpec defines the desired state of Dashboard +type DashboardSpec struct { + // dashboard spec exposed to DSC api + DSCDashboard `json:""` + // dashboard spec exposed only to internal api +} + +// DashboardStatus defines the observed state of Dashboard +type DashboardStatus struct { + components.Status `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster +// +kubebuilder:validation:XValidation:rule="self.metadata.name == 'default-dashboard'",message="Dashboard name must be default-dashboard" +// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`,description="Ready" +// +kubebuilder:printcolumn:name="Reason",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`,description="Reason" + +// Dashboard is the Schema for the dashboards API +type Dashboard struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec DashboardSpec `json:"spec,omitempty"` + Status DashboardStatus `json:"status,omitempty"` +} + +func (c *Dashboard) GetStatus() *components.Status { + return &c.Status.Status +} + +// +kubebuilder:object:root=true + +// DashboardList contains a list of Dashboard +type DashboardList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Dashboard `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Dashboard{}, &DashboardList{}) +} + +// DSCDashboard contains all the configuration exposed in DSC instance for Dashboard component +type DSCDashboard struct { + // configuration fields common across components + components.Component `json:""` + // configuration fields specific to the dashboard component +} diff --git a/apis/components/v1/datasciencepipelines_types.go b/apis/components/v1/datasciencepipelines_types.go new file mode 100644 index 00000000000..35e413a79ee --- /dev/null +++ b/apis/components/v1/datasciencepipelines_types.go @@ -0,0 +1,69 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// DataSciencePipelinesSpec defines the desired state of DataSciencePipelines +type DataSciencePipelinesSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of DataSciencePipelines. Edit datasciencepipelines_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// DataSciencePipelinesStatus defines the observed state of DataSciencePipelines +type DataSciencePipelinesStatus struct { + components.Status `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// DataSciencePipelines is the Schema for the datasciencepipelines API +type DataSciencePipelines struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec DataSciencePipelinesSpec `json:"spec,omitempty"` + Status DataSciencePipelinesStatus `json:"status,omitempty"` +} + +func (c *DataSciencePipelines) GetStatus() *components.Status { + return &c.Status.Status +} + +// +kubebuilder:object:root=true + +// DataSciencePipelinesList contains a list of DataSciencePipelines +type DataSciencePipelinesList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []DataSciencePipelines `json:"items"` +} + +func init() { + SchemeBuilder.Register(&DataSciencePipelines{}, &DataSciencePipelinesList{}) +} diff --git a/apis/components/v1/groupversion_info.go b/apis/components/v1/groupversion_info.go new file mode 100644 index 00000000000..727c3cab6c8 --- /dev/null +++ b/apis/components/v1/groupversion_info.go @@ -0,0 +1,36 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1 contains API Schema definitions for the components v1 API group +// +kubebuilder:object:generate=true +// +groupName=components.opendatahub.io +package v1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "components.opendatahub.io", Version: "v1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/apis/components/v1/kserve_types.go b/apis/components/v1/kserve_types.go new file mode 100644 index 00000000000..1ca4112dfc4 --- /dev/null +++ b/apis/components/v1/kserve_types.go @@ -0,0 +1,69 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// KserveSpec defines the desired state of Kserve +type KserveSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of Kserve. Edit kserve_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// KserveStatus defines the observed state of Kserve +type KserveStatus struct { + components.Status `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// Kserve is the Schema for the kserves API +type Kserve struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec KserveSpec `json:"spec,omitempty"` + Status KserveStatus `json:"status,omitempty"` +} + +func (c *Kserve) GetStatus() *components.Status { + return &c.Status.Status +} + +// +kubebuilder:object:root=true + +// KserveList contains a list of Kserve +type KserveList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Kserve `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Kserve{}, &KserveList{}) +} diff --git a/apis/components/v1/kueue_types.go b/apis/components/v1/kueue_types.go new file mode 100644 index 00000000000..61850634f6c --- /dev/null +++ b/apis/components/v1/kueue_types.go @@ -0,0 +1,69 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// KueueSpec defines the desired state of Kueue +type KueueSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of Kueue. Edit kueue_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// KueueStatus defines the observed state of Kueue +type KueueStatus struct { + components.Status `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// Kueue is the Schema for the kueues API +type Kueue struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec KueueSpec `json:"spec,omitempty"` + Status KueueStatus `json:"status,omitempty"` +} + +func (c *Kueue) GetStatus() *components.Status { + return &c.Status.Status +} + +// +kubebuilder:object:root=true + +// KueueList contains a list of Kueue +type KueueList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Kueue `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Kueue{}, &KueueList{}) +} diff --git a/apis/components/v1/modelmeshserving_types.go b/apis/components/v1/modelmeshserving_types.go new file mode 100644 index 00000000000..94cdb6bee65 --- /dev/null +++ b/apis/components/v1/modelmeshserving_types.go @@ -0,0 +1,69 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ModelMeshServingSpec defines the desired state of ModelMeshServing +type ModelMeshServingSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ModelMeshServing. Edit modelmeshserving_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// ModelMeshServingStatus defines the observed state of ModelMeshServing +type ModelMeshServingStatus struct { + components.Status `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// ModelMeshServing is the Schema for the modelmeshservings API +type ModelMeshServing struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ModelMeshServingSpec `json:"spec,omitempty"` + Status ModelMeshServingStatus `json:"status,omitempty"` +} + +func (c *ModelMeshServing) GetStatus() *components.Status { + return &c.Status.Status +} + +// +kubebuilder:object:root=true + +// ModelMeshServingList contains a list of ModelMeshServing +type ModelMeshServingList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ModelMeshServing `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ModelMeshServing{}, &ModelMeshServingList{}) +} diff --git a/apis/components/v1/modelregistry_types.go b/apis/components/v1/modelregistry_types.go new file mode 100644 index 00000000000..e7563643cc4 --- /dev/null +++ b/apis/components/v1/modelregistry_types.go @@ -0,0 +1,69 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ModelRegistrySpec defines the desired state of ModelRegistry +type ModelRegistrySpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ModelRegistry. Edit modelregistry_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// ModelRegistryStatus defines the observed state of ModelRegistry +type ModelRegistryStatus struct { + components.Status `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// ModelRegistry is the Schema for the modelregistries API +type ModelRegistry struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ModelRegistrySpec `json:"spec,omitempty"` + Status ModelRegistryStatus `json:"status,omitempty"` +} + +func (c *ModelRegistry) GetStatus() *components.Status { + return &c.Status.Status +} + +// +kubebuilder:object:root=true + +// ModelRegistryList contains a list of ModelRegistry +type ModelRegistryList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ModelRegistry `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ModelRegistry{}, &ModelRegistryList{}) +} diff --git a/apis/components/v1/ray_types.go b/apis/components/v1/ray_types.go new file mode 100644 index 00000000000..012cba22cf1 --- /dev/null +++ b/apis/components/v1/ray_types.go @@ -0,0 +1,69 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// RaySpec defines the desired state of Ray +type RaySpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of Ray. Edit ray_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// RayStatus defines the observed state of Ray +type RayStatus struct { + components.Status `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// Ray is the Schema for the rays API +type Ray struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec RaySpec `json:"spec,omitempty"` + Status RayStatus `json:"status,omitempty"` +} + +func (c *Ray) GetStatus() *components.Status { + return &c.Status.Status +} + +// +kubebuilder:object:root=true + +// RayList contains a list of Ray +type RayList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Ray `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Ray{}, &RayList{}) +} diff --git a/apis/components/v1/trainingoperator_types.go b/apis/components/v1/trainingoperator_types.go new file mode 100644 index 00000000000..5e7fd6e7463 --- /dev/null +++ b/apis/components/v1/trainingoperator_types.go @@ -0,0 +1,69 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// TrainingOperatorSpec defines the desired state of TrainingOperator +type TrainingOperatorSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of TrainingOperator. Edit trainingoperator_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// TrainingOperatorStatus defines the observed state of TrainingOperator +type TrainingOperatorStatus struct { + components.Status `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// TrainingOperator is the Schema for the trainingoperators API +type TrainingOperator struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec TrainingOperatorSpec `json:"spec,omitempty"` + Status TrainingOperatorStatus `json:"status,omitempty"` +} + +func (c *TrainingOperator) GetStatus() *components.Status { + return &c.Status.Status +} + +// +kubebuilder:object:root=true + +// TrainingOperatorList contains a list of TrainingOperator +type TrainingOperatorList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TrainingOperator `json:"items"` +} + +func init() { + SchemeBuilder.Register(&TrainingOperator{}, &TrainingOperatorList{}) +} diff --git a/apis/components/v1/trustyai_types.go b/apis/components/v1/trustyai_types.go new file mode 100644 index 00000000000..873f35b3490 --- /dev/null +++ b/apis/components/v1/trustyai_types.go @@ -0,0 +1,69 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// TrustyAISpec defines the desired state of TrustyAI +type TrustyAISpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of TrustyAI. Edit trustyai_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// TrustyAIStatus defines the observed state of TrustyAI +type TrustyAIStatus struct { + components.Status `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// TrustyAI is the Schema for the trustyais API +type TrustyAI struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec TrustyAISpec `json:"spec,omitempty"` + Status TrustyAIStatus `json:"status,omitempty"` +} + +func (c *TrustyAI) GetStatus() *components.Status { + return &c.Status.Status +} + +// +kubebuilder:object:root=true + +// TrustyAIList contains a list of TrustyAI +type TrustyAIList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TrustyAI `json:"items"` +} + +func init() { + SchemeBuilder.Register(&TrustyAI{}, &TrustyAIList{}) +} diff --git a/apis/components/v1/workbenches_types.go b/apis/components/v1/workbenches_types.go new file mode 100644 index 00000000000..3b8856781c0 --- /dev/null +++ b/apis/components/v1/workbenches_types.go @@ -0,0 +1,69 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// WorkbenchesSpec defines the desired state of Workbenches +type WorkbenchesSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of Workbenches. Edit workbenches_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// WorkbenchesStatus defines the observed state of Workbenches +type WorkbenchesStatus struct { + components.Status `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// Workbenches is the Schema for the workbenches API +type Workbenches struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec WorkbenchesSpec `json:"spec,omitempty"` + Status WorkbenchesStatus `json:"status,omitempty"` +} + +func (c *Workbenches) GetStatus() *components.Status { + return &c.Status.Status +} + +// +kubebuilder:object:root=true + +// WorkbenchesList contains a list of Workbenches +type WorkbenchesList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Workbenches `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Workbenches{}, &WorkbenchesList{}) +} diff --git a/apis/components/v1/zz_generated.deepcopy.go b/apis/components/v1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..c94e9e65d01 --- /dev/null +++ b/apis/components/v1/zz_generated.deepcopy.go @@ -0,0 +1,1032 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CodeFlare) DeepCopyInto(out *CodeFlare) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CodeFlare. +func (in *CodeFlare) DeepCopy() *CodeFlare { + if in == nil { + return nil + } + out := new(CodeFlare) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CodeFlare) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CodeFlareList) DeepCopyInto(out *CodeFlareList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CodeFlare, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CodeFlareList. +func (in *CodeFlareList) DeepCopy() *CodeFlareList { + if in == nil { + return nil + } + out := new(CodeFlareList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CodeFlareList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CodeFlareSpec) DeepCopyInto(out *CodeFlareSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CodeFlareSpec. +func (in *CodeFlareSpec) DeepCopy() *CodeFlareSpec { + if in == nil { + return nil + } + out := new(CodeFlareSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CodeFlareStatus) DeepCopyInto(out *CodeFlareStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CodeFlareStatus. +func (in *CodeFlareStatus) DeepCopy() *CodeFlareStatus { + if in == nil { + return nil + } + out := new(CodeFlareStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DSCDashboard) DeepCopyInto(out *DSCDashboard) { + *out = *in + in.Component.DeepCopyInto(&out.Component) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DSCDashboard. +func (in *DSCDashboard) DeepCopy() *DSCDashboard { + if in == nil { + return nil + } + out := new(DSCDashboard) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Dashboard) DeepCopyInto(out *Dashboard) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Dashboard. +func (in *Dashboard) DeepCopy() *Dashboard { + if in == nil { + return nil + } + out := new(Dashboard) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Dashboard) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DashboardList) DeepCopyInto(out *DashboardList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Dashboard, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardList. +func (in *DashboardList) DeepCopy() *DashboardList { + if in == nil { + return nil + } + out := new(DashboardList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DashboardList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DashboardSpec) DeepCopyInto(out *DashboardSpec) { + *out = *in + in.DSCDashboard.DeepCopyInto(&out.DSCDashboard) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardSpec. +func (in *DashboardSpec) DeepCopy() *DashboardSpec { + if in == nil { + return nil + } + out := new(DashboardSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DashboardStatus) DeepCopyInto(out *DashboardStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardStatus. +func (in *DashboardStatus) DeepCopy() *DashboardStatus { + if in == nil { + return nil + } + out := new(DashboardStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataSciencePipelines) DeepCopyInto(out *DataSciencePipelines) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataSciencePipelines. +func (in *DataSciencePipelines) DeepCopy() *DataSciencePipelines { + if in == nil { + return nil + } + out := new(DataSciencePipelines) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DataSciencePipelines) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataSciencePipelinesList) DeepCopyInto(out *DataSciencePipelinesList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]DataSciencePipelines, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataSciencePipelinesList. +func (in *DataSciencePipelinesList) DeepCopy() *DataSciencePipelinesList { + if in == nil { + return nil + } + out := new(DataSciencePipelinesList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DataSciencePipelinesList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataSciencePipelinesSpec) DeepCopyInto(out *DataSciencePipelinesSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataSciencePipelinesSpec. +func (in *DataSciencePipelinesSpec) DeepCopy() *DataSciencePipelinesSpec { + if in == nil { + return nil + } + out := new(DataSciencePipelinesSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataSciencePipelinesStatus) DeepCopyInto(out *DataSciencePipelinesStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataSciencePipelinesStatus. +func (in *DataSciencePipelinesStatus) DeepCopy() *DataSciencePipelinesStatus { + if in == nil { + return nil + } + out := new(DataSciencePipelinesStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Kserve) DeepCopyInto(out *Kserve) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Kserve. +func (in *Kserve) DeepCopy() *Kserve { + if in == nil { + return nil + } + out := new(Kserve) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Kserve) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KserveList) DeepCopyInto(out *KserveList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Kserve, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KserveList. +func (in *KserveList) DeepCopy() *KserveList { + if in == nil { + return nil + } + out := new(KserveList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KserveList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KserveSpec) DeepCopyInto(out *KserveSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KserveSpec. +func (in *KserveSpec) DeepCopy() *KserveSpec { + if in == nil { + return nil + } + out := new(KserveSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KserveStatus) DeepCopyInto(out *KserveStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KserveStatus. +func (in *KserveStatus) DeepCopy() *KserveStatus { + if in == nil { + return nil + } + out := new(KserveStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Kueue) DeepCopyInto(out *Kueue) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Kueue. +func (in *Kueue) DeepCopy() *Kueue { + if in == nil { + return nil + } + out := new(Kueue) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Kueue) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KueueList) DeepCopyInto(out *KueueList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Kueue, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KueueList. +func (in *KueueList) DeepCopy() *KueueList { + if in == nil { + return nil + } + out := new(KueueList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KueueList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KueueSpec) DeepCopyInto(out *KueueSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KueueSpec. +func (in *KueueSpec) DeepCopy() *KueueSpec { + if in == nil { + return nil + } + out := new(KueueSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KueueStatus) DeepCopyInto(out *KueueStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KueueStatus. +func (in *KueueStatus) DeepCopy() *KueueStatus { + if in == nil { + return nil + } + out := new(KueueStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ModelMeshServing) DeepCopyInto(out *ModelMeshServing) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelMeshServing. +func (in *ModelMeshServing) DeepCopy() *ModelMeshServing { + if in == nil { + return nil + } + out := new(ModelMeshServing) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ModelMeshServing) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ModelMeshServingList) DeepCopyInto(out *ModelMeshServingList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ModelMeshServing, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelMeshServingList. +func (in *ModelMeshServingList) DeepCopy() *ModelMeshServingList { + if in == nil { + return nil + } + out := new(ModelMeshServingList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ModelMeshServingList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ModelMeshServingSpec) DeepCopyInto(out *ModelMeshServingSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelMeshServingSpec. +func (in *ModelMeshServingSpec) DeepCopy() *ModelMeshServingSpec { + if in == nil { + return nil + } + out := new(ModelMeshServingSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ModelMeshServingStatus) DeepCopyInto(out *ModelMeshServingStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelMeshServingStatus. +func (in *ModelMeshServingStatus) DeepCopy() *ModelMeshServingStatus { + if in == nil { + return nil + } + out := new(ModelMeshServingStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ModelRegistry) DeepCopyInto(out *ModelRegistry) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelRegistry. +func (in *ModelRegistry) DeepCopy() *ModelRegistry { + if in == nil { + return nil + } + out := new(ModelRegistry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ModelRegistry) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ModelRegistryList) DeepCopyInto(out *ModelRegistryList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ModelRegistry, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelRegistryList. +func (in *ModelRegistryList) DeepCopy() *ModelRegistryList { + if in == nil { + return nil + } + out := new(ModelRegistryList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ModelRegistryList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ModelRegistrySpec) DeepCopyInto(out *ModelRegistrySpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelRegistrySpec. +func (in *ModelRegistrySpec) DeepCopy() *ModelRegistrySpec { + if in == nil { + return nil + } + out := new(ModelRegistrySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ModelRegistryStatus) DeepCopyInto(out *ModelRegistryStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelRegistryStatus. +func (in *ModelRegistryStatus) DeepCopy() *ModelRegistryStatus { + if in == nil { + return nil + } + out := new(ModelRegistryStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ray) DeepCopyInto(out *Ray) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ray. +func (in *Ray) DeepCopy() *Ray { + if in == nil { + return nil + } + out := new(Ray) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Ray) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RayList) DeepCopyInto(out *RayList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Ray, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RayList. +func (in *RayList) DeepCopy() *RayList { + if in == nil { + return nil + } + out := new(RayList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RayList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RaySpec) DeepCopyInto(out *RaySpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RaySpec. +func (in *RaySpec) DeepCopy() *RaySpec { + if in == nil { + return nil + } + out := new(RaySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RayStatus) DeepCopyInto(out *RayStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RayStatus. +func (in *RayStatus) DeepCopy() *RayStatus { + if in == nil { + return nil + } + out := new(RayStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrainingOperator) DeepCopyInto(out *TrainingOperator) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrainingOperator. +func (in *TrainingOperator) DeepCopy() *TrainingOperator { + if in == nil { + return nil + } + out := new(TrainingOperator) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TrainingOperator) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrainingOperatorList) DeepCopyInto(out *TrainingOperatorList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TrainingOperator, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrainingOperatorList. +func (in *TrainingOperatorList) DeepCopy() *TrainingOperatorList { + if in == nil { + return nil + } + out := new(TrainingOperatorList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TrainingOperatorList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrainingOperatorSpec) DeepCopyInto(out *TrainingOperatorSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrainingOperatorSpec. +func (in *TrainingOperatorSpec) DeepCopy() *TrainingOperatorSpec { + if in == nil { + return nil + } + out := new(TrainingOperatorSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrainingOperatorStatus) DeepCopyInto(out *TrainingOperatorStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrainingOperatorStatus. +func (in *TrainingOperatorStatus) DeepCopy() *TrainingOperatorStatus { + if in == nil { + return nil + } + out := new(TrainingOperatorStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrustyAI) DeepCopyInto(out *TrustyAI) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrustyAI. +func (in *TrustyAI) DeepCopy() *TrustyAI { + if in == nil { + return nil + } + out := new(TrustyAI) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TrustyAI) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrustyAIList) DeepCopyInto(out *TrustyAIList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TrustyAI, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrustyAIList. +func (in *TrustyAIList) DeepCopy() *TrustyAIList { + if in == nil { + return nil + } + out := new(TrustyAIList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TrustyAIList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrustyAISpec) DeepCopyInto(out *TrustyAISpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrustyAISpec. +func (in *TrustyAISpec) DeepCopy() *TrustyAISpec { + if in == nil { + return nil + } + out := new(TrustyAISpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrustyAIStatus) DeepCopyInto(out *TrustyAIStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrustyAIStatus. +func (in *TrustyAIStatus) DeepCopy() *TrustyAIStatus { + if in == nil { + return nil + } + out := new(TrustyAIStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Workbenches) DeepCopyInto(out *Workbenches) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Workbenches. +func (in *Workbenches) DeepCopy() *Workbenches { + if in == nil { + return nil + } + out := new(Workbenches) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Workbenches) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkbenchesList) DeepCopyInto(out *WorkbenchesList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Workbenches, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchesList. +func (in *WorkbenchesList) DeepCopy() *WorkbenchesList { + if in == nil { + return nil + } + out := new(WorkbenchesList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *WorkbenchesList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkbenchesSpec) DeepCopyInto(out *WorkbenchesSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchesSpec. +func (in *WorkbenchesSpec) DeepCopy() *WorkbenchesSpec { + if in == nil { + return nil + } + out := new(WorkbenchesSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkbenchesStatus) DeepCopyInto(out *WorkbenchesStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchesStatus. +func (in *WorkbenchesStatus) DeepCopy() *WorkbenchesStatus { + if in == nil { + return nil + } + out := new(WorkbenchesStatus) + in.DeepCopyInto(out) + return out +} diff --git a/apis/components/zz_generated.deepcopy.go b/apis/components/zz_generated.deepcopy.go new file mode 100644 index 00000000000..569c6049163 --- /dev/null +++ b/apis/components/zz_generated.deepcopy.go @@ -0,0 +1,87 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package components + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Component) DeepCopyInto(out *Component) { + *out = *in + if in.DevFlags != nil { + in, out := &in.DevFlags, &out.DevFlags + *out = new(DevFlags) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Component. +func (in *Component) DeepCopy() *Component { + if in == nil { + return nil + } + out := new(Component) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DevFlags) DeepCopyInto(out *DevFlags) { + *out = *in + if in.Manifests != nil { + in, out := &in.Manifests, &out.Manifests + *out = make([]ManifestsConfig, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevFlags. +func (in *DevFlags) DeepCopy() *DevFlags { + if in == nil { + return nil + } + out := new(DevFlags) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Status) DeepCopyInto(out *Status) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Status. +func (in *Status) DeepCopy() *Status { + if in == nil { + return nil + } + out := new(Status) + in.DeepCopyInto(out) + return out +} diff --git a/apis/datasciencecluster/v1/datasciencecluster_types.go b/apis/datasciencecluster/v1/datasciencecluster_types.go index 39166651ac1..b4a799e8586 100644 --- a/apis/datasciencecluster/v1/datasciencecluster_types.go +++ b/apis/datasciencecluster/v1/datasciencecluster_types.go @@ -24,9 +24,9 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" "github.com/opendatahub-io/opendatahub-operator/v2/components" "github.com/opendatahub-io/opendatahub-operator/v2/components/codeflare" - "github.com/opendatahub-io/opendatahub-operator/v2/components/dashboard" "github.com/opendatahub-io/opendatahub-operator/v2/components/datasciencepipelines" "github.com/opendatahub-io/opendatahub-operator/v2/components/kserve" "github.com/opendatahub-io/opendatahub-operator/v2/components/kueue" @@ -49,7 +49,7 @@ type DataScienceClusterSpec struct { type Components struct { // Dashboard component configuration. - Dashboard dashboard.Dashboard `json:"dashboard,omitempty"` + Dashboard componentsv1.DSCDashboard `json:"dashboard,omitempty"` // Workbenches component configuration. Workbenches workbenches.Workbenches `json:"workbenches,omitempty"` diff --git a/bundle/manifests/components.opendatahub.io_codeflares.yaml b/bundle/manifests/components.opendatahub.io_codeflares.yaml new file mode 100644 index 00000000000..f1aa641fd76 --- /dev/null +++ b/bundle/manifests/components.opendatahub.io_codeflares.yaml @@ -0,0 +1,124 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + creationTimestamp: null + name: codeflares.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: CodeFlare + listKind: CodeFlareList + plural: codeflares + singular: codeflare + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: CodeFlare is the Schema for the codeflares API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: CodeFlareSpec defines the desired state of CodeFlare + properties: + foo: + description: Foo is an example field of CodeFlare. Edit codeflare_types.go + to remove/update + type: string + type: object + status: + description: CodeFlareStatus defines the observed state of CodeFlare + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/components.opendatahub.io_dashboards.yaml b/bundle/manifests/components.opendatahub.io_dashboards.yaml new file mode 100644 index 00000000000..3dd7f3e4fc1 --- /dev/null +++ b/bundle/manifests/components.opendatahub.io_dashboards.yaml @@ -0,0 +1,160 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + creationTimestamp: null + name: dashboards.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: Dashboard + listKind: DashboardList + plural: dashboards + singular: dashboard + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Dashboard is the Schema for the dashboards API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: DashboardSpec defines the desired state of Dashboard + properties: + devFlags: + description: Add developer fields + properties: + manifests: + description: List of custom manifests for the given component + items: + properties: + contextDir: + default: manifests + description: contextDir is the relative path to the folder + containing manifests in a repository, default value "manifests" + type: string + sourcePath: + default: "" + description: 'sourcePath is the subpath within contextDir + where kustomize builds start. Examples include any sub-folder + or path: `base`, `overlays/dev`, `default`, `odh` etc.' + type: string + uri: + default: "" + description: uri is the URI point to a git repo with tag/branch. + e.g. https://github.com/org/repo/tarball/ + type: string + type: object + type: array + type: object + managementState: + description: |- + Set to one of the following values: + + - "Managed" : the operator is actively managing the component and trying to keep it active. + It will only upgrade the component if it is safe to do so + + - "Removed" : the operator is actively managing the component and will not install it, + or if it is installed, the operator will try to remove it + enum: + - Managed + - Removed + pattern: ^(Managed|Unmanaged|Force|Removed)$ + type: string + type: object + status: + description: DashboardStatus defines the observed state of Dashboard + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/components.opendatahub.io_datasciencepipelines.yaml b/bundle/manifests/components.opendatahub.io_datasciencepipelines.yaml new file mode 100644 index 00000000000..93d5ba1b43f --- /dev/null +++ b/bundle/manifests/components.opendatahub.io_datasciencepipelines.yaml @@ -0,0 +1,126 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + creationTimestamp: null + name: datasciencepipelines.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: DataSciencePipelines + listKind: DataSciencePipelinesList + plural: datasciencepipelines + singular: datasciencepipelines + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: DataSciencePipelines is the Schema for the datasciencepipelines + API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: DataSciencePipelinesSpec defines the desired state of DataSciencePipelines + properties: + foo: + description: Foo is an example field of DataSciencePipelines. Edit + datasciencepipelines_types.go to remove/update + type: string + type: object + status: + description: DataSciencePipelinesStatus defines the observed state of + DataSciencePipelines + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/components.opendatahub.io_kserves.yaml b/bundle/manifests/components.opendatahub.io_kserves.yaml new file mode 100644 index 00000000000..3fe65ca3b1c --- /dev/null +++ b/bundle/manifests/components.opendatahub.io_kserves.yaml @@ -0,0 +1,124 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + creationTimestamp: null + name: kserves.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: Kserve + listKind: KserveList + plural: kserves + singular: kserve + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Kserve is the Schema for the kserves API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: KserveSpec defines the desired state of Kserve + properties: + foo: + description: Foo is an example field of Kserve. Edit kserve_types.go + to remove/update + type: string + type: object + status: + description: KserveStatus defines the observed state of Kserve + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/components.opendatahub.io_kueues.yaml b/bundle/manifests/components.opendatahub.io_kueues.yaml new file mode 100644 index 00000000000..acd8e620a91 --- /dev/null +++ b/bundle/manifests/components.opendatahub.io_kueues.yaml @@ -0,0 +1,124 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + creationTimestamp: null + name: kueues.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: Kueue + listKind: KueueList + plural: kueues + singular: kueue + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Kueue is the Schema for the kueues API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: KueueSpec defines the desired state of Kueue + properties: + foo: + description: Foo is an example field of Kueue. Edit kueue_types.go + to remove/update + type: string + type: object + status: + description: KueueStatus defines the observed state of Kueue + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/components.opendatahub.io_modelmeshservings.yaml b/bundle/manifests/components.opendatahub.io_modelmeshservings.yaml new file mode 100644 index 00000000000..cbac4fe7a21 --- /dev/null +++ b/bundle/manifests/components.opendatahub.io_modelmeshservings.yaml @@ -0,0 +1,124 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + creationTimestamp: null + name: modelmeshservings.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: ModelMeshServing + listKind: ModelMeshServingList + plural: modelmeshservings + singular: modelmeshserving + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: ModelMeshServing is the Schema for the modelmeshservings API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ModelMeshServingSpec defines the desired state of ModelMeshServing + properties: + foo: + description: Foo is an example field of ModelMeshServing. Edit modelmeshserving_types.go + to remove/update + type: string + type: object + status: + description: ModelMeshServingStatus defines the observed state of ModelMeshServing + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/components.opendatahub.io_modelregistries.yaml b/bundle/manifests/components.opendatahub.io_modelregistries.yaml new file mode 100644 index 00000000000..86a3b1cdf16 --- /dev/null +++ b/bundle/manifests/components.opendatahub.io_modelregistries.yaml @@ -0,0 +1,124 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + creationTimestamp: null + name: modelregistries.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: ModelRegistry + listKind: ModelRegistryList + plural: modelregistries + singular: modelregistry + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: ModelRegistry is the Schema for the modelregistries API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ModelRegistrySpec defines the desired state of ModelRegistry + properties: + foo: + description: Foo is an example field of ModelRegistry. Edit modelregistry_types.go + to remove/update + type: string + type: object + status: + description: ModelRegistryStatus defines the observed state of ModelRegistry + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/components.opendatahub.io_rays.yaml b/bundle/manifests/components.opendatahub.io_rays.yaml new file mode 100644 index 00000000000..b28a1562a78 --- /dev/null +++ b/bundle/manifests/components.opendatahub.io_rays.yaml @@ -0,0 +1,124 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + creationTimestamp: null + name: rays.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: Ray + listKind: RayList + plural: rays + singular: ray + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Ray is the Schema for the rays API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: RaySpec defines the desired state of Ray + properties: + foo: + description: Foo is an example field of Ray. Edit ray_types.go to + remove/update + type: string + type: object + status: + description: RayStatus defines the observed state of Ray + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/components.opendatahub.io_trainingoperators.yaml b/bundle/manifests/components.opendatahub.io_trainingoperators.yaml new file mode 100644 index 00000000000..d10ce68a29a --- /dev/null +++ b/bundle/manifests/components.opendatahub.io_trainingoperators.yaml @@ -0,0 +1,124 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + creationTimestamp: null + name: trainingoperators.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: TrainingOperator + listKind: TrainingOperatorList + plural: trainingoperators + singular: trainingoperator + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: TrainingOperator is the Schema for the trainingoperators API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TrainingOperatorSpec defines the desired state of TrainingOperator + properties: + foo: + description: Foo is an example field of TrainingOperator. Edit trainingoperator_types.go + to remove/update + type: string + type: object + status: + description: TrainingOperatorStatus defines the observed state of TrainingOperator + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/components.opendatahub.io_trustyais.yaml b/bundle/manifests/components.opendatahub.io_trustyais.yaml new file mode 100644 index 00000000000..2cb03cfdfbd --- /dev/null +++ b/bundle/manifests/components.opendatahub.io_trustyais.yaml @@ -0,0 +1,124 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + creationTimestamp: null + name: trustyais.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: TrustyAI + listKind: TrustyAIList + plural: trustyais + singular: trustyai + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: TrustyAI is the Schema for the trustyais API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TrustyAISpec defines the desired state of TrustyAI + properties: + foo: + description: Foo is an example field of TrustyAI. Edit trustyai_types.go + to remove/update + type: string + type: object + status: + description: TrustyAIStatus defines the observed state of TrustyAI + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/components.opendatahub.io_workbenches.yaml b/bundle/manifests/components.opendatahub.io_workbenches.yaml new file mode 100644 index 00000000000..826196a136c --- /dev/null +++ b/bundle/manifests/components.opendatahub.io_workbenches.yaml @@ -0,0 +1,124 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + creationTimestamp: null + name: workbenches.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: Workbenches + listKind: WorkbenchesList + plural: workbenches + singular: workbenches + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Workbenches is the Schema for the workbenches API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: WorkbenchesSpec defines the desired state of Workbenches + properties: + foo: + description: Foo is an example field of Workbenches. Edit workbenches_types.go + to remove/update + type: string + type: object + status: + description: WorkbenchesStatus defines the observed state of Workbenches + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/opendatahub-operator.clusterserviceversion.yaml b/bundle/manifests/opendatahub-operator.clusterserviceversion.yaml index 1519a9ef8ca..3f67e150e8d 100644 --- a/bundle/manifests/opendatahub-operator.clusterserviceversion.yaml +++ b/bundle/manifests/opendatahub-operator.clusterserviceversion.yaml @@ -103,9 +103,15 @@ metadata: categories: AI/Machine Learning, Big Data certified: "False" containerImage: quay.io/opendatahub/opendatahub-operator:v2.19.0 - createdAt: "2024-10-09T14:46:54Z" + createdAt: "2024-10-15T03:57:32Z" olm.skipRange: '>=1.0.0 <2.19.0' operators.operatorframework.io/builder: operator-sdk-v1.31.0 + operators.operatorframework.io/internal-objects: '["featuretrackers.features.opendatahub.io", + "codeflares.components.opendatahub.io", "dashboards.components.opendatahub.io", + "datasciencepipelines.components.opendatahub.io", "kserves.components.opendatahub.io", + "kueues.components.opendatahub.io", "modelmeshservings.components.opendatahub.io", + "modelregistries.components.opendatahub.io", "rays.components.opendatahub.io", + "trainingoperators.components.opendatahub.io", "trustyais.components.opendatahub.io", "workbenches.components.opendatahub.io"]' operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/opendatahub-io/opendatahub-operator name: opendatahub-operator.v2.19.0 @@ -114,6 +120,20 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: + - description: CodeFlare is the Schema for the codeflares API + displayName: Code Flare + kind: CodeFlare + name: codeflares.components.opendatahub.io + version: v1 + - description: Dashboard is the Schema for the dashboards API + displayName: Dashboard + kind: Dashboard + name: dashboards.components.opendatahub.io + specDescriptors: + - description: Add developer fields + displayName: Dev Flags + path: devFlags + version: v1 - description: DataScienceCluster is the Schema for the datascienceclusters API. displayName: Data Science Cluster kind: DataScienceCluster @@ -123,6 +143,12 @@ spec: displayName: Components path: components version: v1 + - description: DataSciencePipelines is the Schema for the datasciencepipelines + API + displayName: Data Science Pipelines + kind: DataSciencePipelines + name: datasciencepipelines.components.opendatahub.io + version: v1 - description: DSCInitialization is the Schema for the dscinitializations API. displayName: DSC Initialization kind: DSCInitialization @@ -161,6 +187,46 @@ spec: - kind: FeatureTracker name: featuretrackers.features.opendatahub.io version: v1 + - description: Kserve is the Schema for the kserves API + displayName: Kserve + kind: Kserve + name: kserves.components.opendatahub.io + version: v1 + - description: Kueue is the Schema for the kueues API + displayName: Kueue + kind: Kueue + name: kueues.components.opendatahub.io + version: v1 + - description: ModelMeshServing is the Schema for the modelmeshservings API + displayName: Model Mesh Serving + kind: ModelMeshServing + name: modelmeshservings.components.opendatahub.io + version: v1 + - description: ModelRegistry is the Schema for the modelregistries API + displayName: Model Registry + kind: ModelRegistry + name: modelregistries.components.opendatahub.io + version: v1 + - description: Ray is the Schema for the rays API + displayName: Ray + kind: Ray + name: rays.components.opendatahub.io + version: v1 + - description: TrainingOperator is the Schema for the trainingoperators API + displayName: Training Operator + kind: TrainingOperator + name: trainingoperators.components.opendatahub.io + version: v1 + - description: TrustyAI is the Schema for the trustyais API + displayName: Trusty AI + kind: TrustyAI + name: trustyais.components.opendatahub.io + version: v1 + - description: Workbenches is the Schema for the workbenches API + displayName: Workbenches + kind: Workbenches + name: workbenches.components.opendatahub.io + version: v1 description: "The Open Data Hub is a machine-learning-as-a-service platform built on Red Hat's Kubernetes-based OpenShift® Container Platform. Open Data Hub integrates multiple AI/ML open source components into one operator that can easily be downloaded @@ -354,6 +420,62 @@ spec: verbs: - create - patch + - apiGroups: + - components.opendatahub.io + resources: + - codeflares + - dashboards + - datasciencepipelines + - kserves + - kueues + - modelmeshservings + - modelregistries + - rays + - trainingoperators + - trustyais + - workbenches + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - components.opendatahub.io + resources: + - codeflares/finalizers + - dashboards/finalizers + - datasciencepipelines/finalizers + - kserves/finalizers + - kueues/finalizers + - modelmeshservings/finalizers + - modelregistries/finalizers + - rays/finalizers + - trainingoperators/finalizers + - trustyais/finalizers + - workbenches/finalizers + verbs: + - update + - apiGroups: + - components.opendatahub.io + resources: + - codeflares/status + - dashboards/status + - datasciencepipelines/status + - kserves/status + - kueues/status + - modelmeshservings/status + - modelregistries/status + - rays/status + - trainingoperators/status + - trustyais/status + - workbenches/status + verbs: + - get + - patch + - update - apiGroups: - config.openshift.io resources: diff --git a/components/component.go b/components/component.go index c43cef7ac92..7b53477d541 100644 --- a/components/component.go +++ b/components/component.go @@ -13,6 +13,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" ) @@ -57,7 +58,7 @@ func (c *Component) Cleanup(_ context.Context, _ client.Client, _ metav1.Object, type DevFlags struct { // List of custom manifests for the given component // +optional - Manifests []ManifestsConfig `json:"manifests,omitempty"` + Manifests []components.ManifestsConfig `json:"manifests,omitempty"` } type ManifestsConfig struct { diff --git a/components/dashboard/dashboard.go b/components/dashboard/dashboard.go index d2ed096b3bd..c0bb1ed37c5 100644 --- a/components/dashboard/dashboard.go +++ b/components/dashboard/dashboard.go @@ -1,244 +1,245 @@ -// Package dashboard provides utility functions to config Open Data Hub Dashboard: A web dashboard that displays -// installed Open Data Hub components with easy access to component UIs and documentation -// +groupName=datasciencecluster.opendatahub.io +// // Package dashboard provides utility functions to config Open Data Hub Dashboard: A web dashboard that displays +// // installed Open Data Hub components with easy access to component UIs and documentation +// // +groupName=datasciencecluster.opendatahub.io package dashboard -import ( - "context" - "errors" - "fmt" - "path/filepath" - - "github.com/go-logr/logr" - operatorv1 "github.com/openshift/api/operator/v1" - corev1 "k8s.io/api/core/v1" - k8serr "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - logf "sigs.k8s.io/controller-runtime/pkg/log" - - dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" - "github.com/opendatahub-io/opendatahub-operator/v2/components" - "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" - "github.com/opendatahub-io/opendatahub-operator/v2/pkg/deploy" -) - -var ( - ComponentNameUpstream = "dashboard" - PathUpstream = deploy.DefaultManifestPath + "/" + ComponentNameUpstream + "/odh" - - ComponentNameDownstream = "rhods-dashboard" - PathDownstream = deploy.DefaultManifestPath + "/" + ComponentNameUpstream + "/rhoai" - PathSelfDownstream = PathDownstream + "/onprem" - PathManagedDownstream = PathDownstream + "/addon" - OverridePath = "" - DefaultPath = "" -) - -// Verifies that Dashboard implements ComponentInterface. -var _ components.ComponentInterface = (*Dashboard)(nil) - -// Dashboard struct holds the configuration for the Dashboard component. -// +kubebuilder:object:generate=true -type Dashboard struct { - components.Component `json:""` -} - -func (d *Dashboard) Init(ctx context.Context, platform cluster.Platform) error { - log := logf.FromContext(ctx).WithName(ComponentNameUpstream) - - imageParamMap := map[string]string{ - "odh-dashboard-image": "RELATED_IMAGE_ODH_DASHBOARD_IMAGE", - } - DefaultPath = map[cluster.Platform]string{ - cluster.SelfManagedRhods: PathDownstream + "/onprem", - cluster.ManagedRhods: PathDownstream + "/addon", - cluster.OpenDataHub: PathUpstream, - cluster.Unknown: PathUpstream, - }[platform] - - if err := deploy.ApplyParams(DefaultPath, imageParamMap); err != nil { - log.Error(err, "failed to update image", "path", DefaultPath) - } - - return nil -} - -func (d *Dashboard) OverrideManifests(ctx context.Context, platform cluster.Platform) error { - // If devflags are set, update default manifests path - if len(d.DevFlags.Manifests) != 0 { - manifestConfig := d.DevFlags.Manifests[0] - if err := deploy.DownloadManifests(ctx, ComponentNameUpstream, manifestConfig); err != nil { - return err - } - if manifestConfig.SourcePath != "" { - OverridePath = filepath.Join(deploy.DefaultManifestPath, ComponentNameUpstream, manifestConfig.SourcePath) - } - } - return nil -} - -func (d *Dashboard) GetComponentName() string { - return ComponentNameUpstream -} - -func (d *Dashboard) ReconcileComponent(ctx context.Context, - cli client.Client, - l logr.Logger, - owner metav1.Object, - dscispec *dsciv1.DSCInitializationSpec, - platform cluster.Platform, - currentComponentExist bool, -) error { - entryPath := DefaultPath - enabled := d.GetManagementState() == operatorv1.Managed - monitoringEnabled := dscispec.Monitoring.ManagementState == operatorv1.Managed - - if enabled { - // 1. cleanup OAuth client related secret and CR if dashboard is in 'installed false' status - if err := d.cleanOauthClient(ctx, cli, dscispec, currentComponentExist, l); err != nil { - return err - } - if d.DevFlags != nil && len(d.DevFlags.Manifests) != 0 { - // Download manifests and update paths - if err := d.OverrideManifests(ctx, platform); err != nil { - return err - } - if OverridePath != "" { - entryPath = OverridePath - } - } - - // 2. platform specific RBAC - if platform == cluster.OpenDataHub || platform == "" { - if err := cluster.UpdatePodSecurityRolebinding(ctx, cli, dscispec.ApplicationsNamespace, "odh-dashboard"); err != nil { - return err - } - } else { - if err := cluster.UpdatePodSecurityRolebinding(ctx, cli, dscispec.ApplicationsNamespace, "rhods-dashboard"); err != nil { - return err - } - } - - // 3. Append or Update variable for component to consume - extraParamsMap, err := updateKustomizeVariable(ctx, cli, platform, dscispec) - if err != nil { - return errors.New("failed to set variable for extraParamsMap") - } - - // 4. update params.env regardless devFlags is provided of not - if err := deploy.ApplyParams(entryPath, nil, extraParamsMap); err != nil { - return fmt.Errorf("failed to update params.env from %s : %w", entryPath, err) - } - } - - // common: Deploy odh-dashboard manifests - // TODO: check if we can have the same component name odh-dashboard for both, or still keep rhods-dashboard for RHOAI - switch platform { - case cluster.SelfManagedRhods, cluster.ManagedRhods: - // anaconda - if err := cluster.CreateSecret(ctx, cli, "anaconda-ce-access", dscispec.ApplicationsNamespace); err != nil { - return fmt.Errorf("failed to create access-secret for anaconda: %w", err) - } - // Deploy RHOAI manifests - if err := deploy.DeployManifestsFromPath(ctx, cli, owner, entryPath, dscispec.ApplicationsNamespace, ComponentNameDownstream, enabled); err != nil { - return fmt.Errorf("failed to apply manifests from %s: %w", PathDownstream, err) - } - l.Info("apply manifests done") - - if enabled { - if err := cluster.WaitForDeploymentAvailable(ctx, cli, ComponentNameDownstream, dscispec.ApplicationsNamespace, 20, 3); err != nil { - return fmt.Errorf("deployment for %s is not ready to server: %w", ComponentNameDownstream, err) - } - } - - // CloudService Monitoring handling - if platform == cluster.ManagedRhods { - if err := d.UpdatePrometheusConfig(cli, l, enabled && monitoringEnabled, ComponentNameDownstream); err != nil { - return err - } - if err := deploy.DeployManifestsFromPath(ctx, cli, owner, - filepath.Join(deploy.DefaultManifestPath, "monitoring", "prometheus", "apps"), - dscispec.Monitoring.Namespace, - "prometheus", true); err != nil { - return err - } - l.Info("updating SRE monitoring done") - } - return nil - - default: - // Deploy ODH manifests - if err := deploy.DeployManifestsFromPath(ctx, cli, owner, entryPath, dscispec.ApplicationsNamespace, ComponentNameUpstream, enabled); err != nil { - return err - } - l.Info("apply manifests done") - if enabled { - if err := cluster.WaitForDeploymentAvailable(ctx, cli, ComponentNameUpstream, dscispec.ApplicationsNamespace, 20, 3); err != nil { - return fmt.Errorf("deployment for %s is not ready to server: %w", ComponentNameUpstream, err) - } - } - - return nil - } -} - -func updateKustomizeVariable(ctx context.Context, cli client.Client, platform cluster.Platform, dscispec *dsciv1.DSCInitializationSpec) (map[string]string, error) { - adminGroups := map[cluster.Platform]string{ - cluster.SelfManagedRhods: "rhods-admins", - cluster.ManagedRhods: "dedicated-admins", - cluster.OpenDataHub: "odh-admins", - cluster.Unknown: "odh-admins", - }[platform] - - sectionTitle := map[cluster.Platform]string{ - cluster.SelfManagedRhods: "OpenShift Self Managed Services", - cluster.ManagedRhods: "OpenShift Managed Services", - cluster.OpenDataHub: "OpenShift Open Data Hub", - cluster.Unknown: "OpenShift Open Data Hub", - }[platform] - - consoleLinkDomain, err := cluster.GetDomain(ctx, cli) - if err != nil { - return nil, fmt.Errorf("error getting console route URL %s : %w", consoleLinkDomain, err) - } - consoleURL := map[cluster.Platform]string{ - cluster.SelfManagedRhods: "https://rhods-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, - cluster.ManagedRhods: "https://rhods-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, - cluster.OpenDataHub: "https://odh-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, - cluster.Unknown: "https://odh-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, - }[platform] - - return map[string]string{ - "admin_groups": adminGroups, - "dashboard-url": consoleURL, - "section-title": sectionTitle, - }, nil -} - -func (d *Dashboard) cleanOauthClient(ctx context.Context, cli client.Client, dscispec *dsciv1.DSCInitializationSpec, currentComponentExist bool, l logr.Logger) error { - // Remove previous oauth-client secrets - // Check if component is going from state of `Not Installed --> Installed` - // Assumption: Component is currently set to enabled - name := "dashboard-oauth-client" - if !currentComponentExist { - l.Info("Cleanup any left secret") - // Delete client secrets from previous installation - oauthClientSecret := &corev1.Secret{} - err := cli.Get(ctx, client.ObjectKey{ - Namespace: dscispec.ApplicationsNamespace, - Name: name, - }, oauthClientSecret) - if err != nil { - if !k8serr.IsNotFound(err) { - return fmt.Errorf("error getting secret %s: %w", name, err) - } - } else { - if err := cli.Delete(ctx, oauthClientSecret); err != nil { - return fmt.Errorf("error deleting secret %s: %w", name, err) - } - l.Info("successfully deleted secret", "secret", name) - } - } - return nil -} +// +// import ( +// "context" +// "errors" +// "fmt" +// "path/filepath" +// +// "github.com/go-logr/logr" +// operatorv1 "github.com/openshift/api/operator/v1" +// corev1 "k8s.io/api/core/v1" +// k8serr "k8s.io/apimachinery/pkg/api/errors" +// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +// "sigs.k8s.io/controller-runtime/pkg/client" +// logf "sigs.k8s.io/controller-runtime/pkg/log" +// +// dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" +// "github.com/opendatahub-io/opendatahub-operator/v2/components" +// "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" +// "github.com/opendatahub-io/opendatahub-operator/v2/pkg/deploy" +//) +// +// var ( +// ComponentNameUpstream = "dashboard" +// PathUpstream = deploy.DefaultManifestPath + "/" + ComponentNameUpstream + "/odh" +// +// ComponentNameDownstream = "rhods-dashboard" +// PathDownstream = deploy.DefaultManifestPath + "/" + ComponentNameUpstream + "/rhoai" +// PathSelfDownstream = PathDownstream + "/onprem" +// PathManagedDownstream = PathDownstream + "/addon" +// OverridePath = "" +// DefaultPath = "" +//) +// +//// Verifies that Dashboard implements ComponentInterface. +// var _ components.ComponentInterface = (*Dashboard)(nil) +// +//// Dashboard struct holds the configuration for the Dashboard component. +//// +kubebuilder:object:generate=true +// type Dashboard struct { +// components.Component `json:""` +//} +// +// func (d *Dashboard) Init(ctx context.Context, platform cluster.Platform) error { +// log := logf.FromContext(ctx).WithName(ComponentNameUpstream) +// +// imageParamMap := map[string]string{ +// "odh-dashboard-image": "RELATED_IMAGE_ODH_DASHBOARD_IMAGE", +// } +// DefaultPath = map[cluster.Platform]string{ +// cluster.SelfManagedRhods: PathDownstream + "/onprem", +// cluster.ManagedRhods: PathDownstream + "/addon", +// cluster.OpenDataHub: PathUpstream, +// cluster.Unknown: PathUpstream, +// }[platform] +// +// if err := deploy.ApplyParams(DefaultPath, imageParamMap); err != nil { +// log.Error(err, "failed to update image", "path", DefaultPath) +// } +// +// return nil +//} +// +// func (d *Dashboard) OverrideManifests(ctx context.Context, platform cluster.Platform) error { +// // If devflags are set, update default manifests path +// if len(d.DevFlags.Manifests) != 0 { +// manifestConfig := d.DevFlags.Manifests[0] +// if err := deploy.DownloadManifests(ctx, ComponentNameUpstream, manifestConfig); err != nil { +// return err +// } +// if manifestConfig.SourcePath != "" { +// OverridePath = filepath.Join(deploy.DefaultManifestPath, ComponentNameUpstream, manifestConfig.SourcePath) +// } +// } +// return nil +//} +// +// func (d *Dashboard) GetComponentName() string { +// return ComponentNameUpstream +//} +// +// func (d *Dashboard) ReconcileComponent(ctx context.Context, +// cli client.Client, +// l logr.Logger, +// owner metav1.Object, +// dscispec *dsciv1.DSCInitializationSpec, +// platform cluster.Platform, +// currentComponentExist bool, +// ) error { +// entryPath := DefaultPath +// enabled := d.GetManagementState() == operatorv1.Managed +// monitoringEnabled := dscispec.Monitoring.ManagementState == operatorv1.Managed +// +// if enabled { +// // 1. cleanup OAuth client related secret and CR if dashboard is in 'installed false' status +// if err := d.cleanOauthClient(ctx, cli, dscispec, currentComponentExist, l); err != nil { +// return err +// } +// if d.DevFlags != nil && len(d.DevFlags.Manifests) != 0 { +// // Download manifests and update paths +// if err := d.OverrideManifests(ctx, platform); err != nil { +// return err +// } +// if OverridePath != "" { +// entryPath = OverridePath +// } +// } +// +// // 2. platform specific RBAC +// if platform == cluster.OpenDataHub || platform == "" { +// if err := cluster.UpdatePodSecurityRolebinding(ctx, cli, dscispec.ApplicationsNamespace, "odh-dashboard"); err != nil { +// return err +// } +// } else { +// if err := cluster.UpdatePodSecurityRolebinding(ctx, cli, dscispec.ApplicationsNamespace, "rhods-dashboard"); err != nil { +// return err +// } +// } +// +// // 3. Append or Update variable for component to consume +// extraParamsMap, err := updateKustomizeVariable(ctx, cli, platform, dscispec) +// if err != nil { +// return errors.New("failed to set variable for extraParamsMap") +// } +// +// // 4. update params.env regardless devFlags is provided of not +// if err := deploy.ApplyParams(entryPath, nil, extraParamsMap); err != nil { +// return fmt.Errorf("failed to update params.env from %s : %w", entryPath, err) +// } +// } +// +// // common: Deploy odh-dashboard manifests +// // TODO: check if we can have the same component name odh-dashboard for both, or still keep rhods-dashboard for RHOAI +// switch platform { +// case cluster.SelfManagedRhods, cluster.ManagedRhods: +// // anaconda +// if err := cluster.CreateSecret(ctx, cli, "anaconda-ce-access", dscispec.ApplicationsNamespace); err != nil { +// return fmt.Errorf("failed to create access-secret for anaconda: %w", err) +// } +// // Deploy RHOAI manifests +// if err := deploy.DeployManifestsFromPath(ctx, cli, owner, entryPath, dscispec.ApplicationsNamespace, ComponentNameDownstream, enabled); err != nil { +// return fmt.Errorf("failed to apply manifests from %s: %w", PathDownstream, err) +// } +// l.Info("apply manifests done") +// +// if enabled { +// if err := cluster.WaitForDeploymentAvailable(ctx, cli, ComponentNameDownstream, dscispec.ApplicationsNamespace, 20, 3); err != nil { +// return fmt.Errorf("deployment for %s is not ready to server: %w", ComponentNameDownstream, err) +// } +// } +// +// // CloudService Monitoring handling +// if platform == cluster.ManagedRhods { +// if err := d.UpdatePrometheusConfig(cli, l, enabled && monitoringEnabled, ComponentNameDownstream); err != nil { +// return err +// } +// if err := deploy.DeployManifestsFromPath(ctx, cli, owner, +// filepath.Join(deploy.DefaultManifestPath, "monitoring", "prometheus", "apps"), +// dscispec.Monitoring.Namespace, +// "prometheus", true); err != nil { +// return err +// } +// l.Info("updating SRE monitoring done") +// } +// return nil +// +// default: +// // Deploy ODH manifests +// if err := deploy.DeployManifestsFromPath(ctx, cli, owner, entryPath, dscispec.ApplicationsNamespace, ComponentNameUpstream, enabled); err != nil { +// return err +// } +// l.Info("apply manifests done") +// if enabled { +// if err := cluster.WaitForDeploymentAvailable(ctx, cli, ComponentNameUpstream, dscispec.ApplicationsNamespace, 20, 3); err != nil { +// return fmt.Errorf("deployment for %s is not ready to server: %w", ComponentNameUpstream, err) +// } +// } +// +// return nil +// } +//} +// +// func updateKustomizeVariable(ctx context.Context, cli client.Client, platform cluster.Platform, dscispec *dsciv1.DSCInitializationSpec) (map[string]string, error) { +// adminGroups := map[cluster.Platform]string{ +// cluster.SelfManagedRhods: "rhods-admins", +// cluster.ManagedRhods: "dedicated-admins", +// cluster.OpenDataHub: "odh-admins", +// cluster.Unknown: "odh-admins", +// }[platform] +// +// sectionTitle := map[cluster.Platform]string{ +// cluster.SelfManagedRhods: "OpenShift Self Managed Services", +// cluster.ManagedRhods: "OpenShift Managed Services", +// cluster.OpenDataHub: "OpenShift Open Data Hub", +// cluster.Unknown: "OpenShift Open Data Hub", +// }[platform] +// +// consoleLinkDomain, err := cluster.GetDomain(ctx, cli) +// if err != nil { +// return nil, fmt.Errorf("error getting console route URL %s : %w", consoleLinkDomain, err) +// } +// consoleURL := map[cluster.Platform]string{ +// cluster.SelfManagedRhods: "https://rhods-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, +// cluster.ManagedRhods: "https://rhods-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, +// cluster.OpenDataHub: "https://odh-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, +// cluster.Unknown: "https://odh-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, +// }[platform] +// +// return map[string]string{ +// "admin_groups": adminGroups, +// "dashboard-url": consoleURL, +// "section-title": sectionTitle, +// }, nil +//} +// +// func (d *Dashboard) cleanOauthClient(ctx context.Context, cli client.Client, dscispec *dsciv1.DSCInitializationSpec, currentComponentExist bool, l logr.Logger) error { +// // Remove previous oauth-client secrets +// // Check if component is going from state of `Not Installed --> Installed` +// // Assumption: Component is currently set to enabled +// name := "dashboard-oauth-client" +// if !currentComponentExist { +// l.Info("Cleanup any left secret") +// // Delete client secrets from previous installation +// oauthClientSecret := &corev1.Secret{} +// err := cli.Get(ctx, client.ObjectKey{ +// Namespace: dscispec.ApplicationsNamespace, +// Name: name, +// }, oauthClientSecret) +// if err != nil { +// if !k8serr.IsNotFound(err) { +// return fmt.Errorf("error getting secret %s: %w", name, err) +// } +// } else { +// if err := cli.Delete(ctx, oauthClientSecret); err != nil { +// return fmt.Errorf("error deleting secret %s: %w", name, err) +// } +// l.Info("successfully deleted secret", "secret", name) +// } +// } +// return nil +//} diff --git a/components/dashboard/zz_generated.deepcopy.go b/components/dashboard/zz_generated.deepcopy.go index 9e4b4fc3a9d..69b406105a1 100644 --- a/components/dashboard/zz_generated.deepcopy.go +++ b/components/dashboard/zz_generated.deepcopy.go @@ -20,20 +20,21 @@ limitations under the License. package dashboard -import () - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Dashboard) DeepCopyInto(out *Dashboard) { - *out = *in - in.Component.DeepCopyInto(&out.Component) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Dashboard. -func (in *Dashboard) DeepCopy() *Dashboard { - if in == nil { - return nil - } - out := new(Dashboard) - in.DeepCopyInto(out) - return out -} +// +//import () +// +//// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +//func (in *Dashboard) DeepCopyInto(out *Dashboard) { +// *out = *in +// in.Component.DeepCopyInto(&out.Component) +//} +// +//// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Dashboard. +//func (in *Dashboard) DeepCopy() *Dashboard { +// if in == nil { +// return nil +// } +// out := new(Dashboard) +// in.DeepCopyInto(out) +// return out +//} diff --git a/components/zz_generated.deepcopy.go b/components/zz_generated.deepcopy.go index 92a766ebc26..245aa470b3b 100644 --- a/components/zz_generated.deepcopy.go +++ b/components/zz_generated.deepcopy.go @@ -20,7 +20,9 @@ limitations under the License. package components -import () +import ( + apiscomponents "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" +) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Component) DeepCopyInto(out *Component) { @@ -47,7 +49,7 @@ func (in *DevFlags) DeepCopyInto(out *DevFlags) { *out = *in if in.Manifests != nil { in, out := &in.Manifests, &out.Manifests - *out = make([]ManifestsConfig, len(*in)) + *out = make([]apiscomponents.ManifestsConfig, len(*in)) copy(*out, *in) } } diff --git a/config/crd/bases/components.opendatahub.io_codeflares.yaml b/config/crd/bases/components.opendatahub.io_codeflares.yaml new file mode 100644 index 00000000000..c45d5fcbfaa --- /dev/null +++ b/config/crd/bases/components.opendatahub.io_codeflares.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: codeflares.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: CodeFlare + listKind: CodeFlareList + plural: codeflares + singular: codeflare + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: CodeFlare is the Schema for the codeflares API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: CodeFlareSpec defines the desired state of CodeFlare + properties: + foo: + description: Foo is an example field of CodeFlare. Edit codeflare_types.go + to remove/update + type: string + type: object + status: + description: CodeFlareStatus defines the observed state of CodeFlare + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/components.opendatahub.io_dashboards.yaml b/config/crd/bases/components.opendatahub.io_dashboards.yaml new file mode 100644 index 00000000000..4763fb1b8ec --- /dev/null +++ b/config/crd/bases/components.opendatahub.io_dashboards.yaml @@ -0,0 +1,166 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: dashboards.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: Dashboard + listKind: DashboardList + plural: dashboards + singular: dashboard + scope: Cluster + versions: + - additionalPrinterColumns: + - description: Ready + jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - description: Reason + jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Reason + type: string + name: v1 + schema: + openAPIV3Schema: + description: Dashboard is the Schema for the dashboards API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: DashboardSpec defines the desired state of Dashboard + properties: + devFlags: + description: Add developer fields + properties: + manifests: + description: List of custom manifests for the given component + items: + properties: + contextDir: + default: manifests + description: contextDir is the relative path to the folder + containing manifests in a repository, default value "manifests" + type: string + sourcePath: + default: "" + description: 'sourcePath is the subpath within contextDir + where kustomize builds start. Examples include any sub-folder + or path: `base`, `overlays/dev`, `default`, `odh` etc.' + type: string + uri: + default: "" + description: uri is the URI point to a git repo with tag/branch. + e.g. https://github.com/org/repo/tarball/ + type: string + type: object + type: array + type: object + managementState: + description: |- + Set to one of the following values: + + - "Managed" : the operator is actively managing the component and trying to keep it active. + It will only upgrade the component if it is safe to do so + + - "Removed" : the operator is actively managing the component and will not install it, + or if it is installed, the operator will try to remove it + enum: + - Managed + - Removed + pattern: ^(Managed|Unmanaged|Force|Removed)$ + type: string + type: object + status: + description: DashboardStatus defines the observed state of Dashboard + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + x-kubernetes-validations: + - message: Dashboard name must be default-dashboard + rule: self.metadata.name == 'default-dashboard' + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/components.opendatahub.io_datasciencepipelines.yaml b/config/crd/bases/components.opendatahub.io_datasciencepipelines.yaml new file mode 100644 index 00000000000..fb4b6899735 --- /dev/null +++ b/config/crd/bases/components.opendatahub.io_datasciencepipelines.yaml @@ -0,0 +1,120 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: datasciencepipelines.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: DataSciencePipelines + listKind: DataSciencePipelinesList + plural: datasciencepipelines + singular: datasciencepipelines + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: DataSciencePipelines is the Schema for the datasciencepipelines + API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: DataSciencePipelinesSpec defines the desired state of DataSciencePipelines + properties: + foo: + description: Foo is an example field of DataSciencePipelines. Edit + datasciencepipelines_types.go to remove/update + type: string + type: object + status: + description: DataSciencePipelinesStatus defines the observed state of + DataSciencePipelines + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/components.opendatahub.io_kserves.yaml b/config/crd/bases/components.opendatahub.io_kserves.yaml new file mode 100644 index 00000000000..d69b9879bc0 --- /dev/null +++ b/config/crd/bases/components.opendatahub.io_kserves.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: kserves.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: Kserve + listKind: KserveList + plural: kserves + singular: kserve + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Kserve is the Schema for the kserves API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: KserveSpec defines the desired state of Kserve + properties: + foo: + description: Foo is an example field of Kserve. Edit kserve_types.go + to remove/update + type: string + type: object + status: + description: KserveStatus defines the observed state of Kserve + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/components.opendatahub.io_kueues.yaml b/config/crd/bases/components.opendatahub.io_kueues.yaml new file mode 100644 index 00000000000..1c979f917db --- /dev/null +++ b/config/crd/bases/components.opendatahub.io_kueues.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: kueues.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: Kueue + listKind: KueueList + plural: kueues + singular: kueue + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Kueue is the Schema for the kueues API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: KueueSpec defines the desired state of Kueue + properties: + foo: + description: Foo is an example field of Kueue. Edit kueue_types.go + to remove/update + type: string + type: object + status: + description: KueueStatus defines the observed state of Kueue + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/components.opendatahub.io_modelmeshservings.yaml b/config/crd/bases/components.opendatahub.io_modelmeshservings.yaml new file mode 100644 index 00000000000..f9fc51f2442 --- /dev/null +++ b/config/crd/bases/components.opendatahub.io_modelmeshservings.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: modelmeshservings.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: ModelMeshServing + listKind: ModelMeshServingList + plural: modelmeshservings + singular: modelmeshserving + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: ModelMeshServing is the Schema for the modelmeshservings API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ModelMeshServingSpec defines the desired state of ModelMeshServing + properties: + foo: + description: Foo is an example field of ModelMeshServing. Edit modelmeshserving_types.go + to remove/update + type: string + type: object + status: + description: ModelMeshServingStatus defines the observed state of ModelMeshServing + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/components.opendatahub.io_modelregistries.yaml b/config/crd/bases/components.opendatahub.io_modelregistries.yaml new file mode 100644 index 00000000000..ccf83ae4bd6 --- /dev/null +++ b/config/crd/bases/components.opendatahub.io_modelregistries.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: modelregistries.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: ModelRegistry + listKind: ModelRegistryList + plural: modelregistries + singular: modelregistry + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: ModelRegistry is the Schema for the modelregistries API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ModelRegistrySpec defines the desired state of ModelRegistry + properties: + foo: + description: Foo is an example field of ModelRegistry. Edit modelregistry_types.go + to remove/update + type: string + type: object + status: + description: ModelRegistryStatus defines the observed state of ModelRegistry + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/components.opendatahub.io_rays.yaml b/config/crd/bases/components.opendatahub.io_rays.yaml new file mode 100644 index 00000000000..9ef5113968c --- /dev/null +++ b/config/crd/bases/components.opendatahub.io_rays.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: rays.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: Ray + listKind: RayList + plural: rays + singular: ray + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Ray is the Schema for the rays API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: RaySpec defines the desired state of Ray + properties: + foo: + description: Foo is an example field of Ray. Edit ray_types.go to + remove/update + type: string + type: object + status: + description: RayStatus defines the observed state of Ray + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/components.opendatahub.io_trainingoperators.yaml b/config/crd/bases/components.opendatahub.io_trainingoperators.yaml new file mode 100644 index 00000000000..475ad90b607 --- /dev/null +++ b/config/crd/bases/components.opendatahub.io_trainingoperators.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: trainingoperators.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: TrainingOperator + listKind: TrainingOperatorList + plural: trainingoperators + singular: trainingoperator + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: TrainingOperator is the Schema for the trainingoperators API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TrainingOperatorSpec defines the desired state of TrainingOperator + properties: + foo: + description: Foo is an example field of TrainingOperator. Edit trainingoperator_types.go + to remove/update + type: string + type: object + status: + description: TrainingOperatorStatus defines the observed state of TrainingOperator + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/components.opendatahub.io_trustyais.yaml b/config/crd/bases/components.opendatahub.io_trustyais.yaml new file mode 100644 index 00000000000..e02caf6ee6e --- /dev/null +++ b/config/crd/bases/components.opendatahub.io_trustyais.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: trustyais.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: TrustyAI + listKind: TrustyAIList + plural: trustyais + singular: trustyai + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: TrustyAI is the Schema for the trustyais API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TrustyAISpec defines the desired state of TrustyAI + properties: + foo: + description: Foo is an example field of TrustyAI. Edit trustyai_types.go + to remove/update + type: string + type: object + status: + description: TrustyAIStatus defines the observed state of TrustyAI + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/components.opendatahub.io_workbenches.yaml b/config/crd/bases/components.opendatahub.io_workbenches.yaml new file mode 100644 index 00000000000..fbe5be0b249 --- /dev/null +++ b/config/crd/bases/components.opendatahub.io_workbenches.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: workbenches.components.opendatahub.io +spec: + group: components.opendatahub.io + names: + kind: Workbenches + listKind: WorkbenchesList + plural: workbenches + singular: workbenches + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Workbenches is the Schema for the workbenches API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: WorkbenchesSpec defines the desired state of Workbenches + properties: + foo: + description: Foo is an example field of Workbenches. Edit workbenches_types.go + to remove/update + type: string + type: object + status: + description: WorkbenchesStatus defines the observed state of Workbenches + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 4ae07b7fe22..d9e999fbe8d 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -5,6 +5,17 @@ resources: - bases/dscinitialization.opendatahub.io_dscinitializations.yaml - bases/datasciencecluster.opendatahub.io_datascienceclusters.yaml - bases/features.opendatahub.io_featuretrackers.yaml +- bases/components.opendatahub.io_dashboards.yaml +- bases/components.opendatahub.io_workbenches.yaml +- bases/components.opendatahub.io_modelmeshservings.yaml +- bases/components.opendatahub.io_datasciencepipelines.yaml +- bases/components.opendatahub.io_kserves.yaml +- bases/components.opendatahub.io_kueues.yaml +- bases/components.opendatahub.io_codeflares.yaml +- bases/components.opendatahub.io_rays.yaml +- bases/components.opendatahub.io_trustyais.yaml +- bases/components.opendatahub.io_modelregistries.yaml +- bases/components.opendatahub.io_trainingoperators.yaml #+kubebuilder:scaffold:crdkustomizeresource # patches: @@ -13,6 +24,17 @@ resources: #- patches/webhook_in_dscinitiatlizations.yaml #- patches/webhook_in_dscinitializations.yaml #- patches/webhook_in_datascienceclusters.yaml +#- patches/webhook_in_dashboards.yaml +#- patches/webhook_in_workbenches.yaml +#- patches/webhook_in_modelmeshservings.yaml +#- patches/webhook_in_datasciencepipelines.yaml +#- patches/webhook_in_kserves.yaml +#- patches/webhook_in_kueues.yaml +#- patches/webhook_in_codeflares.yaml +#- patches/webhook_in_rays.yaml +#- patches/webhook_in_trustyais.yaml +#- patches/webhook_in_modelregistries.yaml +#- patches/webhook_in_trainingoperators.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. @@ -20,6 +42,17 @@ resources: #- patches/cainjection_in_dscinitiatlizations.yaml #- patches/cainjection_in_dscinitializations.yaml #- patches/cainjection_in_datascienceclusters.yaml +#- patches/cainjection_in_dashboards.yaml +#- patches/cainjection_in_workbenches.yaml +#- patches/cainjection_in_modelmeshservings.yaml +#- patches/cainjection_in_datasciencepipelines.yaml +#- patches/cainjection_in_kserves.yaml +#- patches/cainjection_in_kueues.yaml +#- patches/cainjection_in_codeflares.yaml +#- patches/cainjection_in_rays.yaml +#- patches/cainjection_in_trustyais.yaml +#- patches/cainjection_in_modelregistries.yaml +#- patches/cainjection_in_trainingoperators.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/manifests/bases/opendatahub-operator.clusterserviceversion.yaml b/config/manifests/bases/opendatahub-operator.clusterserviceversion.yaml index 811770245b5..194052f9736 100644 --- a/config/manifests/bases/opendatahub-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/opendatahub-operator.clusterserviceversion.yaml @@ -9,6 +9,12 @@ metadata: containerImage: quay.io/opendatahub/opendatahub-operator:v2.19.0 createdAt: "2024-10-09T00:00:00Z" olm.skipRange: '>=1.0.0 <2.19.0' + operators.operatorframework.io/internal-objects: '["featuretrackers.features.opendatahub.io", + "codeflares.components.opendatahub.io", "dashboards.components.opendatahub.io", + "datasciencepipelines.components.opendatahub.io", "kserves.components.opendatahub.io", + "kueues.components.opendatahub.io", "modelmeshservings.components.opendatahub.io", + "modelregistries.components.opendatahub.io", "rays.components.opendatahub.io", + "trainingoperators.components.opendatahub.io", "trustyais.components.opendatahub.io", "workbenches.components.opendatahub.io"]' repository: https://github.com/opendatahub-io/opendatahub-operator name: opendatahub-operator.v2.19.0 namespace: placeholder @@ -16,6 +22,20 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: + - description: CodeFlare is the Schema for the codeflares API + displayName: Code Flare + kind: CodeFlare + name: codeflares.components.opendatahub.io + version: v1 + - description: Dashboard is the Schema for the dashboards API + displayName: Dashboard + kind: Dashboard + name: dashboards.components.opendatahub.io + specDescriptors: + - description: Add developer fields + displayName: Dev Flags + path: devFlags + version: v1 - description: DataScienceCluster is the Schema for the datascienceclusters API. displayName: Data Science Cluster kind: DataScienceCluster @@ -25,6 +45,12 @@ spec: displayName: Components path: components version: v1 + - description: DataSciencePipelines is the Schema for the datasciencepipelines + API + displayName: Data Science Pipelines + kind: DataSciencePipelines + name: datasciencepipelines.components.opendatahub.io + version: v1 - description: DSCInitialization is the Schema for the dscinitializations API. displayName: DSC Initialization kind: DSCInitialization @@ -60,6 +86,46 @@ spec: displayName: Conditions path: conditions version: v1 + - description: Kserve is the Schema for the kserves API + displayName: Kserve + kind: Kserve + name: kserves.components.opendatahub.io + version: v1 + - description: Kueue is the Schema for the kueues API + displayName: Kueue + kind: Kueue + name: kueues.components.opendatahub.io + version: v1 + - description: ModelMeshServing is the Schema for the modelmeshservings API + displayName: Model Mesh Serving + kind: ModelMeshServing + name: modelmeshservings.components.opendatahub.io + version: v1 + - description: ModelRegistry is the Schema for the modelregistries API + displayName: Model Registry + kind: ModelRegistry + name: modelregistries.components.opendatahub.io + version: v1 + - description: Ray is the Schema for the rays API + displayName: Ray + kind: Ray + name: rays.components.opendatahub.io + version: v1 + - description: TrainingOperator is the Schema for the trainingoperators API + displayName: Training Operator + kind: TrainingOperator + name: trainingoperators.components.opendatahub.io + version: v1 + - description: TrustyAI is the Schema for the trustyais API + displayName: Trusty AI + kind: TrustyAI + name: trustyais.components.opendatahub.io + version: v1 + - description: Workbenches is the Schema for the workbenches API + displayName: Workbenches + kind: Workbenches + name: workbenches.components.opendatahub.io + version: v1 description: This will be replaced by Kustomize displayName: Open Data Hub Operator icon: diff --git a/config/rbac/components_codeflare_editor_role.yaml b/config/rbac/components_codeflare_editor_role.yaml new file mode 100644 index 00000000000..0e8229f61cc --- /dev/null +++ b/config/rbac/components_codeflare_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit codeflares. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: codeflare-editor-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - codeflares + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - codeflares/status + verbs: + - get diff --git a/config/rbac/components_codeflare_viewer_role.yaml b/config/rbac/components_codeflare_viewer_role.yaml new file mode 100644 index 00000000000..8d28b7f20ca --- /dev/null +++ b/config/rbac/components_codeflare_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view codeflares. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: codeflare-viewer-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - codeflares + verbs: + - get + - list + - watch +- apiGroups: + - components.opendatahub.io + resources: + - codeflares/status + verbs: + - get diff --git a/config/rbac/components_dashboard_editor_role.yaml b/config/rbac/components_dashboard_editor_role.yaml new file mode 100644 index 00000000000..c0c20b200f5 --- /dev/null +++ b/config/rbac/components_dashboard_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit dashboards. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dashboard-editor-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - dashboards + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - dashboards/status + verbs: + - get diff --git a/config/rbac/components_dashboard_viewer_role.yaml b/config/rbac/components_dashboard_viewer_role.yaml new file mode 100644 index 00000000000..c5bf8c17e19 --- /dev/null +++ b/config/rbac/components_dashboard_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view dashboards. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dashboard-viewer-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - dashboards + verbs: + - get + - list + - watch +- apiGroups: + - components.opendatahub.io + resources: + - dashboards/status + verbs: + - get diff --git a/config/rbac/components_datasciencepipelines_editor_role.yaml b/config/rbac/components_datasciencepipelines_editor_role.yaml new file mode 100644 index 00000000000..904aadabc72 --- /dev/null +++ b/config/rbac/components_datasciencepipelines_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit datasciencepipelines. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: datasciencepipelines-editor-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - datasciencepipelines + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - datasciencepipelines/status + verbs: + - get diff --git a/config/rbac/components_datasciencepipelines_viewer_role.yaml b/config/rbac/components_datasciencepipelines_viewer_role.yaml new file mode 100644 index 00000000000..bcf46d95280 --- /dev/null +++ b/config/rbac/components_datasciencepipelines_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view datasciencepipelines. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: datasciencepipelines-viewer-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - datasciencepipelines + verbs: + - get + - list + - watch +- apiGroups: + - components.opendatahub.io + resources: + - datasciencepipelines/status + verbs: + - get diff --git a/config/rbac/components_kserve_editor_role.yaml b/config/rbac/components_kserve_editor_role.yaml new file mode 100644 index 00000000000..0f9a8592876 --- /dev/null +++ b/config/rbac/components_kserve_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit kserves. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kserve-editor-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - kserves + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - kserves/status + verbs: + - get diff --git a/config/rbac/components_kserve_viewer_role.yaml b/config/rbac/components_kserve_viewer_role.yaml new file mode 100644 index 00000000000..7e9da328177 --- /dev/null +++ b/config/rbac/components_kserve_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view kserves. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kserve-viewer-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - kserves + verbs: + - get + - list + - watch +- apiGroups: + - components.opendatahub.io + resources: + - kserves/status + verbs: + - get diff --git a/config/rbac/components_kueue_editor_role.yaml b/config/rbac/components_kueue_editor_role.yaml new file mode 100644 index 00000000000..062dd021ea6 --- /dev/null +++ b/config/rbac/components_kueue_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit kueues. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kueue-editor-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - kueues + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - kueues/status + verbs: + - get diff --git a/config/rbac/components_kueue_viewer_role.yaml b/config/rbac/components_kueue_viewer_role.yaml new file mode 100644 index 00000000000..5563cf423a7 --- /dev/null +++ b/config/rbac/components_kueue_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view kueues. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kueue-viewer-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - kueues + verbs: + - get + - list + - watch +- apiGroups: + - components.opendatahub.io + resources: + - kueues/status + verbs: + - get diff --git a/config/rbac/components_modelmeshserving_editor_role.yaml b/config/rbac/components_modelmeshserving_editor_role.yaml new file mode 100644 index 00000000000..eae2835f31d --- /dev/null +++ b/config/rbac/components_modelmeshserving_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit modelmeshservings. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: modelmeshserving-editor-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - modelmeshservings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - modelmeshservings/status + verbs: + - get diff --git a/config/rbac/components_modelmeshserving_viewer_role.yaml b/config/rbac/components_modelmeshserving_viewer_role.yaml new file mode 100644 index 00000000000..62e7014d2cd --- /dev/null +++ b/config/rbac/components_modelmeshserving_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view modelmeshservings. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: modelmeshserving-viewer-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - modelmeshservings + verbs: + - get + - list + - watch +- apiGroups: + - components.opendatahub.io + resources: + - modelmeshservings/status + verbs: + - get diff --git a/config/rbac/components_modelregistry_editor_role.yaml b/config/rbac/components_modelregistry_editor_role.yaml new file mode 100644 index 00000000000..1accc670789 --- /dev/null +++ b/config/rbac/components_modelregistry_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit modelregistries. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: modelregistry-editor-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - modelregistries + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - modelregistries/status + verbs: + - get diff --git a/config/rbac/components_modelregistry_viewer_role.yaml b/config/rbac/components_modelregistry_viewer_role.yaml new file mode 100644 index 00000000000..004a25d7e49 --- /dev/null +++ b/config/rbac/components_modelregistry_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view modelregistries. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: modelregistry-viewer-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - modelregistries + verbs: + - get + - list + - watch +- apiGroups: + - components.opendatahub.io + resources: + - modelregistries/status + verbs: + - get diff --git a/config/rbac/components_ray_editor_role.yaml b/config/rbac/components_ray_editor_role.yaml new file mode 100644 index 00000000000..5b8e4121403 --- /dev/null +++ b/config/rbac/components_ray_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit rays. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: ray-editor-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - rays + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - rays/status + verbs: + - get diff --git a/config/rbac/components_ray_viewer_role.yaml b/config/rbac/components_ray_viewer_role.yaml new file mode 100644 index 00000000000..e4a8314a61e --- /dev/null +++ b/config/rbac/components_ray_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view rays. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: ray-viewer-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - rays + verbs: + - get + - list + - watch +- apiGroups: + - components.opendatahub.io + resources: + - rays/status + verbs: + - get diff --git a/config/rbac/components_trainingoperator_editor_role.yaml b/config/rbac/components_trainingoperator_editor_role.yaml new file mode 100644 index 00000000000..899b19a319b --- /dev/null +++ b/config/rbac/components_trainingoperator_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit trainingoperators. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: trainingoperator-editor-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - trainingoperators + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - trainingoperators/status + verbs: + - get diff --git a/config/rbac/components_trainingoperator_viewer_role.yaml b/config/rbac/components_trainingoperator_viewer_role.yaml new file mode 100644 index 00000000000..adee308dc8b --- /dev/null +++ b/config/rbac/components_trainingoperator_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view trainingoperators. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: trainingoperator-viewer-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - trainingoperators + verbs: + - get + - list + - watch +- apiGroups: + - components.opendatahub.io + resources: + - trainingoperators/status + verbs: + - get diff --git a/config/rbac/components_trustyai_editor_role.yaml b/config/rbac/components_trustyai_editor_role.yaml new file mode 100644 index 00000000000..0e306303fa7 --- /dev/null +++ b/config/rbac/components_trustyai_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit trustyais. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: trustyai-editor-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - trustyais + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - trustyais/status + verbs: + - get diff --git a/config/rbac/components_trustyai_viewer_role.yaml b/config/rbac/components_trustyai_viewer_role.yaml new file mode 100644 index 00000000000..a601cdefa20 --- /dev/null +++ b/config/rbac/components_trustyai_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view trustyais. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: trustyai-viewer-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - trustyais + verbs: + - get + - list + - watch +- apiGroups: + - components.opendatahub.io + resources: + - trustyais/status + verbs: + - get diff --git a/config/rbac/components_workbenches_editor_role.yaml b/config/rbac/components_workbenches_editor_role.yaml new file mode 100644 index 00000000000..d2c595ffc89 --- /dev/null +++ b/config/rbac/components_workbenches_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit workbenches. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: workbenches-editor-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - workbenches + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - workbenches/status + verbs: + - get diff --git a/config/rbac/components_workbenches_viewer_role.yaml b/config/rbac/components_workbenches_viewer_role.yaml new file mode 100644 index 00000000000..c24917648e3 --- /dev/null +++ b/config/rbac/components_workbenches_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view workbenches. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: workbenches-viewer-role +rules: +- apiGroups: + - components.opendatahub.io + resources: + - workbenches + verbs: + - get + - list + - watch +- apiGroups: + - components.opendatahub.io + resources: + - workbenches/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index d81b97e1555..e0244c586ac 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -168,6 +168,62 @@ rules: verbs: - create - patch +- apiGroups: + - components.opendatahub.io + resources: + - codeflares + - dashboards + - datasciencepipelines + - kserves + - kueues + - modelmeshservings + - modelregistries + - rays + - trainingoperators + - trustyais + - workbenches + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - components.opendatahub.io + resources: + - codeflares/finalizers + - dashboards/finalizers + - datasciencepipelines/finalizers + - kserves/finalizers + - kueues/finalizers + - modelmeshservings/finalizers + - modelregistries/finalizers + - rays/finalizers + - trainingoperators/finalizers + - trustyais/finalizers + - workbenches/finalizers + verbs: + - update +- apiGroups: + - components.opendatahub.io + resources: + - codeflares/status + - dashboards/status + - datasciencepipelines/status + - kserves/status + - kueues/status + - modelmeshservings/status + - modelregistries/status + - rays/status + - trainingoperators/status + - trustyais/status + - workbenches/status + verbs: + - get + - patch + - update - apiGroups: - config.openshift.io resources: diff --git a/config/samples/components_v1_codeflare.yaml b/config/samples/components_v1_codeflare.yaml new file mode 100644 index 00000000000..e09ba6d116c --- /dev/null +++ b/config/samples/components_v1_codeflare.yaml @@ -0,0 +1,6 @@ +apiVersion: components.opendatahub.io/v1 +kind: CodeFlare +metadata: + name: codeflare-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/components_v1_dashboard.yaml b/config/samples/components_v1_dashboard.yaml new file mode 100644 index 00000000000..c104a16b924 --- /dev/null +++ b/config/samples/components_v1_dashboard.yaml @@ -0,0 +1,6 @@ +apiVersion: components.opendatahub.io/v1 +kind: Dashboard +metadata: + name: dashboard-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/components_v1_datasciencepipelines.yaml b/config/samples/components_v1_datasciencepipelines.yaml new file mode 100644 index 00000000000..1ce59519886 --- /dev/null +++ b/config/samples/components_v1_datasciencepipelines.yaml @@ -0,0 +1,6 @@ +apiVersion: components.opendatahub.io/v1 +kind: DataSciencePipelines +metadata: + name: datasciencepipelines-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/components_v1_kserve.yaml b/config/samples/components_v1_kserve.yaml new file mode 100644 index 00000000000..fedef048b54 --- /dev/null +++ b/config/samples/components_v1_kserve.yaml @@ -0,0 +1,6 @@ +apiVersion: components.opendatahub.io/v1 +kind: Kserve +metadata: + name: kserve-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/components_v1_kueue.yaml b/config/samples/components_v1_kueue.yaml new file mode 100644 index 00000000000..33c227b9c7d --- /dev/null +++ b/config/samples/components_v1_kueue.yaml @@ -0,0 +1,6 @@ +apiVersion: components.opendatahub.io/v1 +kind: Kueue +metadata: + name: kueue-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/components_v1_modelmeshserving.yaml b/config/samples/components_v1_modelmeshserving.yaml new file mode 100644 index 00000000000..79bb8575cdf --- /dev/null +++ b/config/samples/components_v1_modelmeshserving.yaml @@ -0,0 +1,6 @@ +apiVersion: components.opendatahub.io/v1 +kind: ModelMeshServing +metadata: + name: modelmeshserving-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/components_v1_modelregistry.yaml b/config/samples/components_v1_modelregistry.yaml new file mode 100644 index 00000000000..a02c88b9853 --- /dev/null +++ b/config/samples/components_v1_modelregistry.yaml @@ -0,0 +1,6 @@ +apiVersion: components.opendatahub.io/v1 +kind: ModelRegistry +metadata: + name: modelregistry-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/components_v1_ray.yaml b/config/samples/components_v1_ray.yaml new file mode 100644 index 00000000000..ce723da5119 --- /dev/null +++ b/config/samples/components_v1_ray.yaml @@ -0,0 +1,6 @@ +apiVersion: components.opendatahub.io/v1 +kind: Ray +metadata: + name: ray-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/components_v1_trainingoperator.yaml b/config/samples/components_v1_trainingoperator.yaml new file mode 100644 index 00000000000..3e3c0291692 --- /dev/null +++ b/config/samples/components_v1_trainingoperator.yaml @@ -0,0 +1,6 @@ +apiVersion: components.opendatahub.io/v1 +kind: TrainingOperator +metadata: + name: trainingoperator-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/components_v1_trustyai.yaml b/config/samples/components_v1_trustyai.yaml new file mode 100644 index 00000000000..a82e3b4b8b8 --- /dev/null +++ b/config/samples/components_v1_trustyai.yaml @@ -0,0 +1,6 @@ +apiVersion: components.opendatahub.io/v1 +kind: TrustyAI +metadata: + name: trustyai-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/components_v1_workbenches.yaml b/config/samples/components_v1_workbenches.yaml new file mode 100644 index 00000000000..7f0c179ecbf --- /dev/null +++ b/config/samples/components_v1_workbenches.yaml @@ -0,0 +1,6 @@ +apiVersion: components.opendatahub.io/v1 +kind: Workbenches +metadata: + name: workbenches-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index 51284dc78c5..339f92ae694 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -5,4 +5,15 @@ kind: Kustomization resources: - datasciencecluster_v1_datasciencecluster.yaml - dscinitialization_v1_dscinitialization.yaml +#- components_v1_dashboard.yaml +#- components_v1_workbenches.yaml +#- components_v1_modelmeshserving.yaml +#- components_v1_datasciencepipelines.yaml +#- components_v1_kserve.yaml +#- components_v1_kueue.yaml +#- components_v1_codeflare.yaml +#- components_v1_ray.yaml +#- components_v1_trustyai.yaml +#- components_v1_modelregistry.yaml +#- components_v1_trainingoperator.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/controllers/certconfigmapgenerator/certconfigmapgenerator_controller.go b/controllers/certconfigmapgenerator/certconfigmapgenerator_controller.go index a3ce257dcb3..a9565eb6d19 100644 --- a/controllers/certconfigmapgenerator/certconfigmapgenerator_controller.go +++ b/controllers/certconfigmapgenerator/certconfigmapgenerator_controller.go @@ -20,13 +20,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" + odhClient "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/client" annotation "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/annotations" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/trustedcabundle" ) // CertConfigmapGeneratorReconciler holds the controller configuration. type CertConfigmapGeneratorReconciler struct { - Client client.Client + *odhClient.Client Scheme *runtime.Scheme Log logr.Logger } diff --git a/controllers/components/codeflare/codeflare_controller.go b/controllers/components/codeflare/codeflare_controller.go new file mode 100644 index 00000000000..f1f1e7b2206 --- /dev/null +++ b/controllers/components/codeflare/codeflare_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package codeflare + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" +) + +// CodeFlareReconciler reconciles a CodeFlare object. +type CodeFlareReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=codeflares,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=codeflares/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=codeflares/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the CodeFlare object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *CodeFlareReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *CodeFlareReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&componentsv1.CodeFlare{}). + Complete(r) +} diff --git a/controllers/components/dashboard/dashboard_controller.go b/controllers/components/dashboard/dashboard_controller.go new file mode 100644 index 00000000000..d1e8027b970 --- /dev/null +++ b/controllers/components/dashboard/dashboard_controller.go @@ -0,0 +1,470 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package dashboard + +import ( + "context" + "errors" + "fmt" + "path/filepath" + + operatorv1 "github.com/openshift/api/operator/v1" + routev1 "github.com/openshift/api/route/v1" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + k8serr "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/handler" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" + dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" + dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/actions" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/predicates/dependent" + odhrec "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/reconciler" + odhtypes "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/types" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/deploy" + ctrlogger "github.com/opendatahub-io/opendatahub-operator/v2/pkg/logger" + annotation "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/annotations" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/labels" +) + +const ( + ComponentName = "dashboard" +) + +var ( + ComponentNameUpstream = ComponentName + PathUpstream = deploy.DefaultManifestPath + "/" + ComponentNameUpstream + "/odh" + + ComponentNameDownstream = "rhods-dashboard" + PathDownstream = deploy.DefaultManifestPath + "/" + ComponentNameUpstream + "/rhoai" + PathSelfDownstream = PathDownstream + "/onprem" + PathManagedDownstream = PathDownstream + "/addon" + OverridePath = "" + DefaultPath = "" + + dashboardID = types.NamespacedName{Name: componentsv1.DashboardInstanceName} +) + +func NewDashboardReconciler(ctx context.Context, mgr ctrl.Manager) error { + r, err := odhrec.NewComponentReconciler[*componentsv1.Dashboard](ctx, mgr, ComponentName) + if err != nil { + return err + } + + actionCtx := logf.IntoContext(ctx, r.Log) + // Add Dashboard-specific actions + r.AddAction(&InitializeAction{actions.BaseAction{Log: mgr.GetLogger().WithName("actions").WithName("initialize")}}) + r.AddAction(&SupportDevFlagsAction{actions.BaseAction{Log: mgr.GetLogger().WithName("actions").WithName("devFlags")}}) + r.AddAction(&CleanupOAuthClientAction{actions.BaseAction{Log: mgr.GetLogger().WithName("actions").WithName("cleanup")}}) + r.AddAction(&DeployComponentAction{actions.BaseAction{Log: mgr.GetLogger().WithName("actions").WithName("deploy")}}) + + r.AddAction(actions.NewUpdateStatusAction( + actionCtx, + actions.WithUpdateStatusLabel(labels.ComponentName, ComponentName), + )) + + var componentLabelPredicate predicate.Predicate + var componentEventHandler handler.EventHandler + + switch r.Platform { + case cluster.SelfManagedRhods, cluster.ManagedRhods: + componentLabelPredicate = dashboardWatchPredicate(ComponentNameUpstream) + componentEventHandler = watchDashboardResources(ComponentNameUpstream) + default: + componentLabelPredicate = dashboardWatchPredicate(ComponentNameDownstream) + componentEventHandler = watchDashboardResources(ComponentNameDownstream) + } + + err = ctrl.NewControllerManagedBy(mgr). + // API + For(&componentsv1.Dashboard{}, builder.WithPredicates(predicate.Or( + predicate.GenerationChangedPredicate{}, + predicate.LabelChangedPredicate{}))). + // operands + Watches(&corev1.ConfigMap{}, componentEventHandler, builder.WithPredicates(componentLabelPredicate)). + Watches(&corev1.Secret{}, componentEventHandler, builder.WithPredicates(componentLabelPredicate)). + Watches(&rbacv1.ClusterRoleBinding{}, componentEventHandler, builder.WithPredicates(componentLabelPredicate)). + Watches(&rbacv1.ClusterRole{}, componentEventHandler, builder.WithPredicates(componentLabelPredicate)). + Watches(&rbacv1.Role{}, componentEventHandler, builder.WithPredicates(componentLabelPredicate)). + Watches(&rbacv1.RoleBinding{}, componentEventHandler, builder.WithPredicates(componentLabelPredicate)). + Watches(&corev1.ServiceAccount{}, componentEventHandler, builder.WithPredicates(componentLabelPredicate)). + // Include status changes as we need to determine the component + // readiness by observing the status of the deployments + Watches(&appsv1.Deployment{}, componentEventHandler, builder.WithPredicates(componentLabelPredicate)). + // Ignore status changes + Watches(&routev1.Route{}, componentEventHandler, builder.WithPredicates(predicate.And( + componentLabelPredicate, + dependent.New()))). + Complete(r) + + if err != nil { + return fmt.Errorf("could not create the dashboard controller: %w", err) + } + + return nil +} + +func Init(platform cluster.Platform) error { + imageParamMap := map[string]string{ + "odh-dashboard-image": "RELATED_IMAGE_ODH_DASHBOARD_IMAGE", + } + + DefaultPath = map[cluster.Platform]string{ + cluster.SelfManagedRhods: PathDownstream + "/onprem", + cluster.ManagedRhods: PathDownstream + "/addon", + cluster.OpenDataHub: PathUpstream, + cluster.Unknown: PathUpstream, + }[platform] + + if err := deploy.ApplyParams(DefaultPath, imageParamMap); err != nil { + return fmt.Errorf("failed to update images on path %s: %w", DefaultPath, err) + } + + return nil +} + +func GetDashboard(dsc *dscv1.DataScienceCluster) *componentsv1.Dashboard { + dashboardAnnotations := make(map[string]string) + + switch dsc.Spec.Components.Dashboard.ManagementState { + case operatorv1.Managed: + dashboardAnnotations[annotation.ManagementStateAnnotation] = string(operatorv1.Managed) + case operatorv1.Removed: + dashboardAnnotations[annotation.ManagementStateAnnotation] = string(operatorv1.Removed) + case operatorv1.Unmanaged: + dashboardAnnotations[annotation.ManagementStateAnnotation] = string(operatorv1.Unmanaged) + default: + dashboardAnnotations[annotation.ManagementStateAnnotation] = "Unknown" + } + + return &componentsv1.Dashboard{ + TypeMeta: metav1.TypeMeta{ + Kind: "Dashboard", + APIVersion: "components.opendatahub.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: componentsv1.DashboardInstanceName, + Annotations: dashboardAnnotations, + }, + Spec: componentsv1.DashboardSpec{ + DSCDashboard: dsc.Spec.Components.Dashboard, + }, + } +} + +// +kubebuilder:rbac:groups=components.opendatahub.io,resources=dashboards,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=components.opendatahub.io,resources=dashboards/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=components.opendatahub.io,resources=dashboards/finalizers,verbs=update +// +kubebuilder:rbac:groups="opendatahub.io",resources=odhdashboardconfigs,verbs=create;get;patch;watch;update;delete;list +// +kubebuilder:rbac:groups="console.openshift.io",resources=odhquickstarts,verbs=create;get;patch;list;delete +// +kubebuilder:rbac:groups="dashboard.opendatahub.io",resources=odhdocuments,verbs=create;get;patch;list;delete +// +kubebuilder:rbac:groups="dashboard.opendatahub.io",resources=odhapplications,verbs=create;get;patch;list;delete +// +kubebuilder:rbac:groups="dashboard.opendatahub.io",resources=acceleratorprofiles,verbs=create;get;patch;list;delete +// +kubebuilder:rbac:groups="operators.coreos.com",resources=clusterserviceversions,verbs=get;list;watch;delete;update +// +kubebuilder:rbac:groups="operators.coreos.com",resources=customresourcedefinitions,verbs=create;get;patch;delete +// +kubebuilder:rbac:groups="operators.coreos.com",resources=subscriptions,verbs=get;list;watch;delete +// +kubebuilder:rbac:groups="operators.coreos.com",resources=operatorconditions,verbs=get;list;watch +// +kubebuilder:rbac:groups="user.openshift.io",resources=groups,verbs=get;create;list;watch;patch;delete +// +kubebuilder:rbac:groups="console.openshift.io",resources=consolelinks,verbs=create;get;patch;delete +// +kubebuilder:rbac:groups="authorization.openshift.io",resources=roles,verbs=* +// +kubebuilder:rbac:groups="authorization.openshift.io",resources=rolebindings,verbs=* +// +kubebuilder:rbac:groups="authorization.openshift.io",resources=clusterroles,verbs=* +// +kubebuilder:rbac:groups="authorization.openshift.io",resources=clusterrolebindings,verbs=* + +// +kubebuilder:rbac:groups="argoproj.io",resources=workflows,verbs=* + +// +kubebuilder:rbac:groups="apps",resources=statefulsets,verbs=* + +// +kubebuilder:rbac:groups="apps",resources=replicasets,verbs=* + +// +kubebuilder:rbac:groups="apps",resources=deployments/finalizers,verbs=* +// +kubebuilder:rbac:groups="core",resources=deployments,verbs=* +// +kubebuilder:rbac:groups="apps",resources=deployments,verbs=* +// +kubebuilder:rbac:groups="*",resources=deployments,verbs=* +// +kubebuilder:rbac:groups="extensions",resources=deployments,verbs=* + +// +kubebuilder:rbac:groups="apiextensions.k8s.io",resources=customresourcedefinitions,verbs=get;list;watch;create;patch;delete + +// +kubebuilder:rbac:groups="admissionregistration.k8s.io",resources=validatingwebhookconfigurations,verbs=get;list;watch;create;update;delete;patch +// +kubebuilder:rbac:groups="admissionregistration.k8s.io",resources=mutatingwebhookconfigurations,verbs=create;delete;list;update;watch;patch;get + +// +kubebuilder:rbac:groups="*",resources=statefulsets,verbs=create;update;get;list;watch;patch;delete + +// +kubebuilder:rbac:groups="*",resources=replicasets,verbs=* + +//nolint:ireturn +func watchDashboardResources(componentName string) handler.EventHandler { + return handler.EnqueueRequestsFromMapFunc(func(_ context.Context, a client.Object) []reconcile.Request { + switch { + case a.GetLabels()[labels.ODH.Component(componentName)] == "true": + return []reconcile.Request{{NamespacedName: dashboardID}} + case a.GetLabels()[labels.ComponentName] == ComponentName: + return []reconcile.Request{{NamespacedName: dashboardID}} + } + + return nil + }) +} + +func dashboardWatchPredicate(componentName string) predicate.Funcs { + label := labels.ODH.Component(componentName) + return predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + return false + }, + DeleteFunc: func(e event.DeleteEvent) bool { + labelList := e.Object.GetLabels() + + if value, exist := labelList[labels.ComponentName]; exist && value == ComponentName { + return true + } + if value, exist := labelList[label]; exist && value == "true" { + return true + } + + return false + }, + UpdateFunc: func(e event.UpdateEvent) bool { + oldLabels := e.ObjectOld.GetLabels() + + if value, exist := oldLabels[labels.ComponentName]; exist && value == ComponentName { + return true + } + if value, exist := oldLabels[label]; exist && value == "true" { + return true + } + + newLabels := e.ObjectNew.GetLabels() + + if value, exist := newLabels[labels.ComponentName]; exist && value == ComponentName { + return true + } + if value, exist := newLabels[label]; exist && value == "true" { + return true + } + + return false + }, + } +} + +func updateKustomizeVariable(ctx context.Context, cli client.Client, platform cluster.Platform, dscispec *dsciv1.DSCInitializationSpec) (map[string]string, error) { + adminGroups := map[cluster.Platform]string{ + cluster.SelfManagedRhods: "rhods-admins", + cluster.ManagedRhods: "dedicated-admins", + cluster.OpenDataHub: "odh-admins", + cluster.Unknown: "odh-admins", + }[platform] + + sectionTitle := map[cluster.Platform]string{ + cluster.SelfManagedRhods: "OpenShift Self Managed Services", + cluster.ManagedRhods: "OpenShift Managed Services", + cluster.OpenDataHub: "OpenShift Open Data Hub", + cluster.Unknown: "OpenShift Open Data Hub", + }[platform] + + consoleLinkDomain, err := cluster.GetDomain(ctx, cli) + if err != nil { + return nil, fmt.Errorf("error getting console route URL %s : %w", consoleLinkDomain, err) + } + consoleURL := map[cluster.Platform]string{ + cluster.SelfManagedRhods: "https://rhods-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, + cluster.ManagedRhods: "https://rhods-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, + cluster.OpenDataHub: "https://odh-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, + cluster.Unknown: "https://odh-dashboard-" + dscispec.ApplicationsNamespace + "." + consoleLinkDomain, + }[platform] + + return map[string]string{ + "admin_groups": adminGroups, + "dashboard-url": consoleURL, + "section-title": sectionTitle, + }, nil +} + +// Action implementations + +type InitializeAction struct { + actions.BaseAction +} + +func (a *InitializeAction) Execute(ctx context.Context, rr *odhtypes.ReconciliationRequest) error { + // 1. Update manifests + rr.Manifests = map[cluster.Platform]string{ + cluster.SelfManagedRhods: PathDownstream + "/onprem", + cluster.ManagedRhods: PathDownstream + "/addon", + cluster.OpenDataHub: PathUpstream, + cluster.Unknown: PathUpstream, + } + // 2. Append or Update variable for component to consume + extraParamsMap, err := updateKustomizeVariable(ctx, rr.Client, rr.Platform, &rr.DSCI.Spec) + if err != nil { + return errors.New("failed to set variable for extraParamsMap") + } + + // 3. update params.env regardless devFlags is provided of not + // We need this for downstream + if err := deploy.ApplyParams(rr.Manifests[rr.Platform], nil, extraParamsMap); err != nil { + return fmt.Errorf("failed to update params.env from %s : %w", rr.Manifests[rr.Platform], err) + } + + return nil +} + +type SupportDevFlagsAction struct { + actions.BaseAction +} + +func (a *SupportDevFlagsAction) Execute(ctx context.Context, rr *odhtypes.ReconciliationRequest) error { + dashboard, ok := rr.Instance.(*componentsv1.Dashboard) + if !ok { + return fmt.Errorf("resource instance %v is not a componentsv1.Dashboard)", rr.Instance) + } + + if dashboard.Spec.DevFlags == nil { + return nil + } + // Implement devflags support logic + // If dev flags are set, update default manifests path + if len(dashboard.Spec.DevFlags.Manifests) != 0 { + manifestConfig := dashboard.Spec.DevFlags.Manifests[0] + if err := deploy.DownloadManifests(ctx, ComponentNameUpstream, manifestConfig); err != nil { + return err + } + if manifestConfig.SourcePath != "" { + rr.Manifests[rr.Platform] = filepath.Join(deploy.DefaultManifestPath, ComponentNameUpstream, manifestConfig.SourcePath) + } + } + + if rr.DSCI.Spec.DevFlags != nil { + mode := rr.DSCI.Spec.DevFlags.LogMode + a.Log = ctrlogger.NewNamedLogger(logf.FromContext(ctx), ComponentName, mode) + } + + return nil +} + +type CleanupOAuthClientAction struct { + actions.BaseAction +} + +func (a *CleanupOAuthClientAction) Execute(ctx context.Context, rr *odhtypes.ReconciliationRequest) error { + // Remove previous oauth-client secrets + // Check if component is going from state of `Not Installed --> Installed` + // Assumption: Component is currently set to enabled + name := "dashboard-oauth-client" + + // r.Log.Info("Cleanup any left secret") + // Delete client secrets from previous installation + oauthClientSecret := &corev1.Secret{} + err := rr.Client.Get(ctx, client.ObjectKey{ + Namespace: rr.DSCI.Spec.ApplicationsNamespace, + Name: name, + }, oauthClientSecret) + if err != nil { + if !k8serr.IsNotFound(err) { + return fmt.Errorf("error getting secret %s: %w", name, err) + } + } else { + if err := rr.Client.Delete(ctx, oauthClientSecret); err != nil { + return fmt.Errorf("error deleting secret %s: %w", name, err) + } + // r.Log.Info("successfully deleted secret", "secret", name) + } + + return nil +} + +type DeployComponentAction struct { + actions.BaseAction +} + +func (a *DeployComponentAction) Execute(ctx context.Context, rr *odhtypes.ReconciliationRequest) error { + // Implement component deployment logic + // 1. platform specific RBAC + if rr.Platform == cluster.OpenDataHub || rr.Platform == "" { + if err := cluster.UpdatePodSecurityRolebinding(ctx, rr.Client, rr.DSCI.Spec.ApplicationsNamespace, "odh-dashboard"); err != nil { + return err + } + } else { + if err := cluster.UpdatePodSecurityRolebinding(ctx, rr.Client, rr.DSCI.Spec.ApplicationsNamespace, "rhods-dashboard"); err != nil { + return err + } + } + + path := rr.Manifests[rr.Platform] + name := ComponentNameUpstream + + // common: Deploy odh-dashboard manifests + // TODO: check if we can have the same component name odh-dashboard for both, or still keep rhods-dashboard for RHOAI + switch rr.Platform { + case cluster.SelfManagedRhods, cluster.ManagedRhods: + // anaconda + blckownerDel := true + ctrlr := true + err := cluster.CreateSecret( + ctx, + rr.Client, + "anaconda-ce-access", + rr.DSCI.Spec.ApplicationsNamespace, + // set owner reference so it gets deleted when the Dashboard resource get deleted as well + cluster.WithOwnerReference(metav1.OwnerReference{ + APIVersion: rr.Instance.GetObjectKind().GroupVersionKind().GroupVersion().String(), + Kind: rr.Instance.GetObjectKind().GroupVersionKind().Kind, + Name: rr.Instance.GetName(), + UID: rr.Instance.GetUID(), + Controller: &ctrlr, + BlockOwnerDeletion: &blckownerDel, + }), + cluster.WithLabels( + labels.ComponentName, ComponentName, + labels.ODH.Component(name), "true", + labels.K8SCommon.PartOf, name, + ), + ) + + if err != nil { + return fmt.Errorf("failed to create access-secret for anaconda: %w", err) + } + + name = ComponentNameDownstream + default: + } + + err := deploy.DeployManifestsFromPathWithLabels(ctx, rr.Client, rr.Instance, path, rr.DSCI.Spec.ApplicationsNamespace, name, true, map[string]string{ + labels.ComponentName: ComponentName, + }) + + if err != nil { + return fmt.Errorf("failed to apply manifests from %s: %w", name, err) + } + + a.Log.Info("apply manifests done") + + return nil +} diff --git a/controllers/components/datasciencepipelines/datasciencepipelines_controller.go b/controllers/components/datasciencepipelines/datasciencepipelines_controller.go new file mode 100644 index 00000000000..9d551a151f9 --- /dev/null +++ b/controllers/components/datasciencepipelines/datasciencepipelines_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package datasciencepipelines + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" +) + +// DataSciencePipelinesReconciler reconciles a DataSciencePipelines object. +type DataSciencePipelinesReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=datasciencepipelines,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=datasciencepipelines/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=datasciencepipelines/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the DataSciencePipelines object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *DataSciencePipelinesReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *DataSciencePipelinesReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&componentsv1.DataSciencePipelines{}). + Complete(r) +} diff --git a/controllers/components/kserve/kserve_controller.go b/controllers/components/kserve/kserve_controller.go new file mode 100644 index 00000000000..49db9d71de5 --- /dev/null +++ b/controllers/components/kserve/kserve_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kserve + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" +) + +// KserveReconciler reconciles a Kserve object. +type KserveReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=kserves,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=kserves/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=kserves/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the Kserve object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *KserveReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *KserveReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&componentsv1.Kserve{}). + Complete(r) +} diff --git a/controllers/components/kueue/kueue_controller.go b/controllers/components/kueue/kueue_controller.go new file mode 100644 index 00000000000..86eb658fc61 --- /dev/null +++ b/controllers/components/kueue/kueue_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kueue + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" +) + +// KueueReconciler reconciles a Kueue object. +type KueueReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=kueues,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=kueues/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=kueues/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the Kueue object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *KueueReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *KueueReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&componentsv1.Kueue{}). + Complete(r) +} diff --git a/controllers/components/modelmeshserving/modelmeshserving_controller.go b/controllers/components/modelmeshserving/modelmeshserving_controller.go new file mode 100644 index 00000000000..720e50a2b89 --- /dev/null +++ b/controllers/components/modelmeshserving/modelmeshserving_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package modelmeshserving + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" +) + +// ModelMeshServingReconciler reconciles a ModelMeshServing object. +type ModelMeshServingReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=modelmeshservings,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=modelmeshservings/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=modelmeshservings/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ModelMeshServing object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *ModelMeshServingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ModelMeshServingReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&componentsv1.ModelMeshServing{}). + Complete(r) +} diff --git a/controllers/components/modelregistry/modelregistry_controller.go b/controllers/components/modelregistry/modelregistry_controller.go new file mode 100644 index 00000000000..b097dcf2f65 --- /dev/null +++ b/controllers/components/modelregistry/modelregistry_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package modelregistry + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" +) + +// ModelRegistryReconciler reconciles a ModelRegistry object. +type ModelRegistryReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=modelregistries,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=modelregistries/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=modelregistries/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ModelRegistry object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *ModelRegistryReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ModelRegistryReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&componentsv1.ModelRegistry{}). + Complete(r) +} diff --git a/controllers/components/ray/ray_controller.go b/controllers/components/ray/ray_controller.go new file mode 100644 index 00000000000..c147afc9ae8 --- /dev/null +++ b/controllers/components/ray/ray_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ray + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" +) + +// RayReconciler reconciles a Ray object. +type RayReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=rays,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=rays/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=rays/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the Ray object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *RayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *RayReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&componentsv1.Ray{}). + Complete(r) +} diff --git a/controllers/components/suite_test.go b/controllers/components/suite_test.go new file mode 100644 index 00000000000..29231eb7dbe --- /dev/null +++ b/controllers/components/suite_test.go @@ -0,0 +1,80 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package components_test + +//revive:disable:dot-imports +import ( + "path/filepath" + "testing" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Controller Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + ErrorIfCRDPathMissing: true, + } + + var err error + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + err = componentsv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + //+kubebuilder:scaffold:scheme + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(k8sClient).NotTo(BeNil()) + +}, 60) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := testEnv.Stop() + Expect(err).NotTo(HaveOccurred()) +}) diff --git a/controllers/components/trainingoperator/trainingoperator_controller.go b/controllers/components/trainingoperator/trainingoperator_controller.go new file mode 100644 index 00000000000..025d23ee598 --- /dev/null +++ b/controllers/components/trainingoperator/trainingoperator_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trainingoperator + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" +) + +// TrainingOperatorReconciler reconciles a TrainingOperator object. +type TrainingOperatorReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=trainingoperators,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=trainingoperators/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=trainingoperators/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the TrainingOperator object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *TrainingOperatorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *TrainingOperatorReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&componentsv1.TrainingOperator{}). + Complete(r) +} diff --git a/controllers/components/trustyai/trustyai_controller.go b/controllers/components/trustyai/trustyai_controller.go new file mode 100644 index 00000000000..84388069c18 --- /dev/null +++ b/controllers/components/trustyai/trustyai_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trustyai + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" +) + +// TrustyAIReconciler reconciles a TrustyAI object. +type TrustyAIReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=trustyais,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=trustyais/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=trustyais/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the TrustyAI object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *TrustyAIReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *TrustyAIReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&componentsv1.TrustyAI{}). + Complete(r) +} diff --git a/controllers/components/workbenches/workbenches_controller.go b/controllers/components/workbenches/workbenches_controller.go new file mode 100644 index 00000000000..89aca406fa9 --- /dev/null +++ b/controllers/components/workbenches/workbenches_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package workbenches + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" +) + +// WorkbenchesReconciler reconciles a Workbenches object. +type WorkbenchesReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=workbenches,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=workbenches/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=workbenches/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the Workbenches object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *WorkbenchesReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *WorkbenchesReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&componentsv1.Workbenches{}). + Complete(r) +} diff --git a/controllers/datasciencecluster/datasciencecluster_controller.go b/controllers/datasciencecluster/datasciencecluster_controller.go index af00a344e73..9073d8c20ee 100644 --- a/controllers/datasciencecluster/datasciencecluster_controller.go +++ b/controllers/datasciencecluster/datasciencecluster_controller.go @@ -49,14 +49,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" - "github.com/opendatahub-io/opendatahub-operator/v2/components" "github.com/opendatahub-io/opendatahub-operator/v2/components/datasciencepipelines" - "github.com/opendatahub-io/opendatahub-operator/v2/components/modelregistry" + dashboardctrl "github.com/opendatahub-io/opendatahub-operator/v2/controllers/components/dashboard" "github.com/opendatahub-io/opendatahub-operator/v2/controllers/status" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" - ctrlogger "github.com/opendatahub-io/opendatahub-operator/v2/pkg/logger" + odhClient "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/client" annotations "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/annotations" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/labels" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/upgrade" @@ -64,7 +64,7 @@ import ( // DataScienceClusterReconciler reconciles a DataScienceCluster object. type DataScienceClusterReconciler struct { - client.Client + *odhClient.Client Scheme *runtime.Scheme Log logr.Logger // Recorder to generate events @@ -83,7 +83,7 @@ const ( // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. -func (r *DataScienceClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { //nolint:maintidx,gocyclo +func (r *DataScienceClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { //nolint:maintidx log := r.Log log.Info("Reconciling DataScienceCluster resources", "Request.Name", req.Name) @@ -114,10 +114,10 @@ func (r *DataScienceClusterReconciler) Reconcile(ctx context.Context, req ctrl.R instance := &instances.Items[0] - allComponents, err := instance.GetComponents() - if err != nil { - return ctrl.Result{}, err - } + // allComponents, err := instance.GetComponents() + // if err != nil { + // return ctrl.Result{}, err + // } // If DSC CR exist and deletion CM exist // delete DSC CR and let reconcile requeue @@ -137,17 +137,17 @@ func (r *DataScienceClusterReconciler) Reconcile(ctx context.Context, req ctrl.R return reconcile.Result{}, err } } - for _, component := range allComponents { - if err := component.Cleanup(ctx, r.Client, instance, r.DataScienceCluster.DSCISpec); err != nil { - return ctrl.Result{}, err - } - } + // for _, component := range allComponents { + // if err := component.Cleanup(ctx, r.Client, instance, r.DataScienceCluster.DSCISpec); err != nil { + // return ctrl.Result{}, err + // } + // } return reconcile.Result{Requeue: true}, nil } // Verify a valid DSCInitialization instance is created dsciInstances := &dsciv1.DSCInitializationList{} - err = r.Client.List(ctx, dsciInstances) + err := r.Client.List(ctx, dsciInstances) if err != nil { log.Error(err, "Failed to retrieve DSCInitialization resource.", "DSCInitialization Request.Name", req.Name) r.Recorder.Eventf(instance, corev1.EventTypeWarning, "DSCInitializationReconcileError", "Failed to retrieve DSCInitialization instance") @@ -188,11 +188,11 @@ func (r *DataScienceClusterReconciler) Reconcile(ctx context.Context, req ctrl.R } } else { log.Info("Finalization DataScienceCluster start deleting instance", "name", instance.Name, "finalizer", finalizerName) - for _, component := range allComponents { - if err := component.Cleanup(ctx, r.Client, instance, r.DataScienceCluster.DSCISpec); err != nil { - return ctrl.Result{}, err - } - } + // for _, component := range allComponents { + // if err := component.Cleanup(ctx, r.Client, instance, r.DataScienceCluster.DSCISpec); err != nil { + // return ctrl.Result{}, err + // } + // } if controllerutil.ContainsFinalizer(instance, finalizerName) { controllerutil.RemoveFinalizer(instance, finalizerName) if err := r.Update(ctx, instance); err != nil { @@ -241,10 +241,9 @@ func (r *DataScienceClusterReconciler) Reconcile(ctx context.Context, req ctrl.R // Initialize error list, instead of returning errors after every component is deployed var componentErrors *multierror.Error - for _, component := range allComponents { - if instance, err = r.reconcileSubComponent(ctx, instance, platform, component); err != nil { - componentErrors = multierror.Append(componentErrors, err) - } + // Deploy Dashboard + if instance, err = r.reconcileDashboardComponent(ctx, instance); err != nil { + componentErrors = multierror.Append(componentErrors, err) } // Process errors for components @@ -287,53 +286,44 @@ func (r *DataScienceClusterReconciler) Reconcile(ctx context.Context, req ctrl.R return ctrl.Result{}, nil } -func (r *DataScienceClusterReconciler) reconcileSubComponent(ctx context.Context, instance *dscv1.DataScienceCluster, - platform cluster.Platform, component components.ComponentInterface, -) (*dscv1.DataScienceCluster, error) { - log := r.Log - componentName := component.GetComponentName() +// TODO: make it generic for all components. +func (r *DataScienceClusterReconciler) reconcileDashboardComponent(ctx context.Context, instance *dscv1.DataScienceCluster) (*dscv1.DataScienceCluster, error) { + r.Log.Info("Starting reconciliation of Dashboard component") + componentName := dashboardctrl.ComponentName - enabled := component.GetManagementState() == operatorv1.Managed - installedComponentValue, isExistStatus := instance.Status.InstalledComponents[componentName] + enabled := instance.Spec.Components.Dashboard.ManagementState == operatorv1.Managed + _, isExistStatus := instance.Status.InstalledComponents[componentName] - // First set conditions to reflect a component is about to be reconciled - // only set to init condition e.g Unknonw for the very first time when component is not in the list if !isExistStatus { message := "Component is disabled" if enabled { message = "Component is enabled" } - instance, err := status.UpdateWithRetry(ctx, r.Client, instance, func(saved *dscv1.DataScienceCluster) { + var err error + instance, err = status.UpdateWithRetry(ctx, r.Client, instance, func(saved *dscv1.DataScienceCluster) { status.SetComponentCondition(&saved.Status.Conditions, componentName, status.ReconcileInit, message, corev1.ConditionUnknown) }) if err != nil { - _ = r.reportError(err, instance, "failed to update DataScienceCluster conditions before first time reconciling "+componentName) - // try to continue with reconciliation, as further updates can fix the status + return instance, fmt.Errorf("failed to update DataScienceCluster conditions before first time reconciling %s: %w", componentName, err) } } - // Reconcile component - componentLogger := newComponentLogger(log, componentName, r.DataScienceCluster.DSCISpec) - err := component.ReconcileComponent(ctx, r.Client, componentLogger, instance, r.DataScienceCluster.DSCISpec, platform, installedComponentValue) - // TODO: replace this hack with a full refactor of component status in the future + // Create the Dashboard instance + dashboard := dashboardctrl.GetDashboard(instance) + + // Reconcile component + err := r.apply(ctx, instance, dashboard) if err != nil { - // reconciliation failed: log errors, raise event and update status accordingly - instance = r.reportError(err, instance, "failed to reconcile "+componentName+" on DataScienceCluster") + r.Log.Error(err, "Failed to reconcile Dashboard component") + instance = r.reportError(err, instance, fmt.Sprintf("failed to reconcile %s on DataScienceCluster", componentName)) instance, _ = status.UpdateWithRetry(ctx, r.Client, instance, func(saved *dscv1.DataScienceCluster) { - if enabled { - if strings.Contains(err.Error(), datasciencepipelines.ArgoWorkflowCRD+" CRD already exists") { - datasciencepipelines.SetExistingArgoCondition(&saved.Status.Conditions, status.ArgoWorkflowExist, fmt.Sprintf("Component update failed: %v", err)) - } else { - status.SetComponentCondition(&saved.Status.Conditions, componentName, status.ReconcileFailed, fmt.Sprintf("Component reconciliation failed: %v", err), corev1.ConditionFalse) - } - } else { - status.SetComponentCondition(&saved.Status.Conditions, componentName, status.ReconcileFailed, fmt.Sprintf("Component removal failed: %v", err), corev1.ConditionFalse) - } + status.SetComponentCondition(&saved.Status.Conditions, componentName, status.ReconcileFailed, fmt.Sprintf("Component reconciliation failed: %v", err), corev1.ConditionFalse) }) return instance, err } - // reconciliation succeeded: update status accordingly + + r.Log.Info("Dashboard component reconciled successfully") instance, err = status.UpdateWithRetry(ctx, r.Client, instance, func(saved *dscv1.DataScienceCluster) { if saved.Status.InstalledComponents == nil { saved.Status.InstalledComponents = make(map[string]bool) @@ -344,34 +334,14 @@ func (r *DataScienceClusterReconciler) reconcileSubComponent(ctx context.Context } else { status.RemoveComponentCondition(&saved.Status.Conditions, componentName) } - - // TODO: replace this hack with a full refactor of component status in the future - if mr, isMR := component.(*modelregistry.ModelRegistry); isMR { - if enabled { - saved.Status.Components.ModelRegistry = &status.ModelRegistryStatus{RegistriesNamespace: mr.RegistriesNamespace} - } else { - saved.Status.Components.ModelRegistry = nil - } - } }) if err != nil { - instance = r.reportError(err, instance, "failed to update DataScienceCluster status after reconciling "+componentName) - - return instance, err + return instance, fmt.Errorf("failed to update DataScienceCluster status after reconciling %s: %w", componentName, err) } return instance, nil } -// newComponentLogger is a wrapper to add DSC name and extract log mode from DSCISpec. -func newComponentLogger(logger logr.Logger, componentName string, dscispec *dsciv1.DSCInitializationSpec) logr.Logger { - mode := "" - if dscispec.DevFlags != nil { - mode = dscispec.DevFlags.LogMode - } - return ctrlogger.NewNamedLogger(logger, "DSC.Components."+componentName, mode) -} - func (r *DataScienceClusterReconciler) reportError(err error, instance *dscv1.DataScienceCluster, message string) *dscv1.DataScienceCluster { log := r.Log log.Error(err, message, "instance.Name", instance.Name) @@ -395,6 +365,29 @@ var configMapPredicates = predicate.Funcs{ }, } +func (r *DataScienceClusterReconciler) apply(ctx context.Context, dsc *dscv1.DataScienceCluster, obj client.Object) error { + if obj.GetObjectKind().GroupVersionKind().Empty() { + return errors.New("no groupversionkind defined") + } + if err := ctrl.SetControllerReference(dsc, obj, r.Scheme); err != nil { + return err + } + + managementStateAnn, exists := obj.GetAnnotations()[annotations.ManagementStateAnnotation] + if exists && managementStateAnn == string(operatorv1.Removed) { + err := r.Client.Delete(ctx, obj) + if k8serr.IsNotFound(err) { + return nil + } + return err + } + if err := r.Client.Apply(ctx, obj, client.FieldOwner(dsc.Name), client.ForceOwnership); err != nil { + return err + } + + return nil +} + // reduce unnecessary reconcile triggered by odh component's deployment change due to ManagedByODHOperator annotation. var componentDeploymentPredicates = predicate.Funcs{ UpdateFunc: func(e event.UpdateEvent) bool { @@ -514,6 +507,7 @@ func (r *DataScienceClusterReconciler) SetupWithManager(ctx context.Context, mgr &admissionregistrationv1.ValidatingWebhookConfiguration{}, builder.WithPredicates(modelMeshwebhookPredicates), ). + Owns(&componentsv1.Dashboard{}). Owns( &corev1.ServiceAccount{}, builder.WithPredicates(saPredicates), diff --git a/controllers/datasciencecluster/kubebuilder_rbac.go b/controllers/datasciencecluster/kubebuilder_rbac.go index 1733689272a..c57565a6282 100644 --- a/controllers/datasciencecluster/kubebuilder_rbac.go +++ b/controllers/datasciencecluster/kubebuilder_rbac.go @@ -32,6 +32,11 @@ package datasciencecluster //+kubebuilder:rbac:groups="authorization.k8s.io",resources=subjectaccessreviews,verbs=create;get /* This is for dashboard */ + +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=dashboards,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=dashboards/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=components.opendatahub.io,resources=dashboards/finalizers,verbs=update + // +kubebuilder:rbac:groups="opendatahub.io",resources=odhdashboardconfigs,verbs=create;get;patch;watch;update;delete;list // +kubebuilder:rbac:groups="console.openshift.io",resources=odhquickstarts,verbs=create;get;patch;list;delete // +kubebuilder:rbac:groups="dashboard.opendatahub.io",resources=odhdocuments,verbs=create;get;patch;list;delete diff --git a/controllers/dscinitialization/dscinitialization_controller.go b/controllers/dscinitialization/dscinitialization_controller.go index 37991131cb5..437f25ea620 100644 --- a/controllers/dscinitialization/dscinitialization_controller.go +++ b/controllers/dscinitialization/dscinitialization_controller.go @@ -46,6 +46,7 @@ import ( dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" "github.com/opendatahub-io/opendatahub-operator/v2/controllers/status" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" + odhClient "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/client" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/deploy" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/trustedcabundle" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/upgrade" @@ -61,7 +62,7 @@ var managementStateChangeTrustedCA = false // DSCInitializationReconciler reconciles a DSCInitialization object. type DSCInitializationReconciler struct { - client.Client + *odhClient.Client Scheme *runtime.Scheme Log logr.Logger Recorder record.EventRecorder diff --git a/controllers/dscinitialization/suite_test.go b/controllers/dscinitialization/suite_test.go index f3ef428f878..618b9a62e91 100644 --- a/controllers/dscinitialization/suite_test.go +++ b/controllers/dscinitialization/suite_test.go @@ -46,6 +46,7 @@ import ( dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" dscictrl "github.com/opendatahub-io/opendatahub-operator/v2/controllers/dscinitialization" + odhClient "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/client" "github.com/opendatahub-io/opendatahub-operator/v2/tests/envtestutil" . "github.com/onsi/ginkgo/v2" @@ -122,6 +123,10 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) Expect(k8sClient).NotTo(BeNil()) + odhClient, err := odhClient.New(gCtx, cfg, k8sClient) + Expect(err).NotTo(HaveOccurred()) + Expect(odhClient).NotTo(BeNil()) + webhookInstallOptions := &testEnv.WebhookInstallOptions mgr, err := ctrl.NewManager(cfg, ctrl.Options{ Scheme: testScheme, @@ -135,7 +140,7 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) err = (&dscictrl.DSCInitializationReconciler{ - Client: k8sClient, + Client: odhClient, Scheme: testScheme, Log: ctrl.Log.WithName("controllers").WithName("DSCInitialization"), Recorder: mgr.GetEventRecorderFor("dscinitialization-controller"), diff --git a/controllers/secretgenerator/secretgenerator_controller.go b/controllers/secretgenerator/secretgenerator_controller.go index 957e02fe4ae..ac57125050c 100644 --- a/controllers/secretgenerator/secretgenerator_controller.go +++ b/controllers/secretgenerator/secretgenerator_controller.go @@ -40,6 +40,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" + odhClient "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/client" annotation "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/annotations" ) @@ -50,7 +51,7 @@ const ( // SecretGeneratorReconciler holds the controller configuration. type SecretGeneratorReconciler struct { - Client client.Client + *odhClient.Client Scheme *runtime.Scheme Log logr.Logger } diff --git a/controllers/status/status.go b/controllers/status/status.go index 808cfee2f7b..b47c23a037e 100644 --- a/controllers/status/status.go +++ b/controllers/status/status.go @@ -21,6 +21,10 @@ package status import ( conditionsv1 "github.com/openshift/custom-resource-status/conditions/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" ) // These constants represent the overall Phase as used by .Status.Phase. @@ -63,6 +67,8 @@ const ( // ConditionReconcileComplete represents extra Condition Type, used by .Condition.Type. ConditionReconcileComplete conditionsv1.ConditionType = "ReconcileComplete" + + ConditionTypeReady string = "Ready" ) const ( @@ -214,3 +220,8 @@ func RemoveComponentCondition(conditions *[]conditionsv1.Condition, component st type ModelRegistryStatus struct { RegistriesNamespace string `json:"registriesNamespace,omitempty"` } + +func SetStatusCondition(obj components.WithStatus, condition metav1.Condition) bool { + s := obj.GetStatus() + return meta.SetStatusCondition(&s.Conditions, condition) +} diff --git a/controllers/webhook/nowebhook.go b/controllers/webhook/nowebhook.go new file mode 100644 index 00000000000..dc8eefe7533 --- /dev/null +++ b/controllers/webhook/nowebhook.go @@ -0,0 +1,7 @@ +//go:build nowebhook + +package webhook + +import ctrl "sigs.k8s.io/controller-runtime" + +func Init(mgr ctrl.Manager) {} diff --git a/controllers/webhook/webhook.go b/controllers/webhook/webhook.go index 29739e2af00..5a539667b91 100644 --- a/controllers/webhook/webhook.go +++ b/controllers/webhook/webhook.go @@ -1,3 +1,5 @@ +//go:build !nowebhook + /* Copyright 2023. diff --git a/controllers/webhook/webhook_suite_test.go b/controllers/webhook/webhook_suite_test.go index f697c5fecdf..51c6526ce2d 100644 --- a/controllers/webhook/webhook_suite_test.go +++ b/controllers/webhook/webhook_suite_test.go @@ -40,11 +40,12 @@ import ( ctrlwebhook "sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" - "github.com/opendatahub-io/opendatahub-operator/v2/components" + componentsold "github.com/opendatahub-io/opendatahub-operator/v2/components" "github.com/opendatahub-io/opendatahub-operator/v2/components/codeflare" - "github.com/opendatahub-io/opendatahub-operator/v2/components/dashboard" "github.com/opendatahub-io/opendatahub-operator/v2/components/datasciencepipelines" "github.com/opendatahub-io/opendatahub-operator/v2/components/kserve" "github.com/opendatahub-io/opendatahub-operator/v2/components/modelmeshserving" @@ -261,48 +262,48 @@ func newDSC(name string, namespace string) *dscv1.DataScienceCluster { }, Spec: dscv1.DataScienceClusterSpec{ Components: dscv1.Components{ - Dashboard: dashboard.Dashboard{ + Dashboard: componentsv1.DSCDashboard{ Component: components.Component{ ManagementState: operatorv1.Removed, }, }, Workbenches: workbenches.Workbenches{ - Component: components.Component{ + Component: componentsold.Component{ ManagementState: operatorv1.Removed, }, }, ModelMeshServing: modelmeshserving.ModelMeshServing{ - Component: components.Component{ + Component: componentsold.Component{ ManagementState: operatorv1.Removed, }, }, DataSciencePipelines: datasciencepipelines.DataSciencePipelines{ - Component: components.Component{ + Component: componentsold.Component{ ManagementState: operatorv1.Removed, }, }, Kserve: kserve.Kserve{ - Component: components.Component{ + Component: componentsold.Component{ ManagementState: operatorv1.Removed, }, }, CodeFlare: codeflare.CodeFlare{ - Component: components.Component{ + Component: componentsold.Component{ ManagementState: operatorv1.Removed, }, }, Ray: ray.Ray{ - Component: components.Component{ + Component: componentsold.Component{ ManagementState: operatorv1.Removed, }, }, TrustyAI: trustyai.TrustyAI{ - Component: components.Component{ + Component: componentsold.Component{ ManagementState: operatorv1.Removed, }, }, ModelRegistry: modelregistry.ModelRegistry{ - Component: components.Component{ + Component: componentsold.Component{ ManagementState: operatorv1.Removed, }, }, @@ -320,7 +321,7 @@ func newMRDSC1(name string, mrNamespace string, state operatorv1.ManagementState Spec: dscv1.DataScienceClusterSpec{ Components: dscv1.Components{ ModelRegistry: modelregistry.ModelRegistry{ - Component: components.Component{ + Component: componentsold.Component{ ManagementState: state, }, RegistriesNamespace: mrNamespace, @@ -339,7 +340,7 @@ func newMRDSC2(name string) *dscv1.DataScienceCluster { Spec: dscv1.DataScienceClusterSpec{ Components: dscv1.Components{ Workbenches: workbenches.Workbenches{ - Component: components.Component{ + Component: componentsold.Component{ ManagementState: operatorv1.Removed, }, }, diff --git a/docs/api-overview.md b/docs/api-overview.md index 3c963f15088..c797838a5d6 100644 --- a/docs/api-overview.md +++ b/docs/api-overview.md @@ -1,10 +1,895 @@ # API Reference ## Packages +- [components.opendatahub.io/v1](#componentsopendatahubiov1) - [datasciencecluster.opendatahub.io/v1](#datascienceclusteropendatahubiov1) - [dscinitialization.opendatahub.io/v1](#dscinitializationopendatahubiov1) +## components.opendatahub.io/v1 + +Package v1 contains API Schema definitions for the components v1 API group + +### Resource Types +- [CodeFlare](#codeflare) +- [CodeFlareList](#codeflarelist) +- [Dashboard](#dashboard) +- [DashboardList](#dashboardlist) +- [DataSciencePipelines](#datasciencepipelines) +- [DataSciencePipelinesList](#datasciencepipelineslist) +- [Kserve](#kserve) +- [KserveList](#kservelist) +- [Kueue](#kueue) +- [KueueList](#kueuelist) +- [ModelMeshServing](#modelmeshserving) +- [ModelMeshServingList](#modelmeshservinglist) +- [ModelRegistry](#modelregistry) +- [ModelRegistryList](#modelregistrylist) +- [Ray](#ray) +- [RayList](#raylist) +- [TrainingOperator](#trainingoperator) +- [TrainingOperatorList](#trainingoperatorlist) +- [TrustyAI](#trustyai) +- [TrustyAIList](#trustyailist) +- [Workbenches](#workbenches) +- [WorkbenchesList](#workbencheslist) + + + +#### CodeFlare + + + +CodeFlare is the Schema for the codeflares API + + + +_Appears in:_ +- [CodeFlareList](#codeflarelist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `CodeFlare` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[CodeFlareSpec](#codeflarespec)_ | | | | +| `status` _[CodeFlareStatus](#codeflarestatus)_ | | | | + + +#### CodeFlareList + + + +CodeFlareList contains a list of CodeFlare + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `CodeFlareList` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[CodeFlare](#codeflare) array_ | | | | + + +#### CodeFlareSpec + + + +CodeFlareSpec defines the desired state of CodeFlare + + + +_Appears in:_ +- [CodeFlare](#codeflare) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `foo` _string_ | Foo is an example field of CodeFlare. Edit codeflare_types.go to remove/update | | | + + +#### CodeFlareStatus + + + +CodeFlareStatus defines the observed state of CodeFlare + + + +_Appears in:_ +- [CodeFlare](#codeflare) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + +#### DSCDashboard + + + +DSCDashboard contains all the configuration exposed in DSC instance for Dashboard component + + + +_Appears in:_ +- [Components](#components) +- [DashboardSpec](#dashboardspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `Component` _[Component](#component)_ | configuration fields common across components | | | + + +#### Dashboard + + + +Dashboard is the Schema for the dashboards API + + + +_Appears in:_ +- [DashboardList](#dashboardlist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `Dashboard` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[DashboardSpec](#dashboardspec)_ | | | | +| `status` _[DashboardStatus](#dashboardstatus)_ | | | | + + +#### DashboardList + + + +DashboardList contains a list of Dashboard + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `DashboardList` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[Dashboard](#dashboard) array_ | | | | + + +#### DashboardSpec + + + +DashboardSpec defines the desired state of Dashboard + + + +_Appears in:_ +- [Dashboard](#dashboard) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `DSCDashboard` _[DSCDashboard](#dscdashboard)_ | dashboard spec exposed to DSC api | | | + + +#### DashboardStatus + + + +DashboardStatus defines the observed state of Dashboard + + + +_Appears in:_ +- [Dashboard](#dashboard) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + +#### DataSciencePipelines + + + +DataSciencePipelines is the Schema for the datasciencepipelines API + + + +_Appears in:_ +- [DataSciencePipelinesList](#datasciencepipelineslist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `DataSciencePipelines` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[DataSciencePipelinesSpec](#datasciencepipelinesspec)_ | | | | +| `status` _[DataSciencePipelinesStatus](#datasciencepipelinesstatus)_ | | | | + + +#### DataSciencePipelinesList + + + +DataSciencePipelinesList contains a list of DataSciencePipelines + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `DataSciencePipelinesList` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[DataSciencePipelines](#datasciencepipelines) array_ | | | | + + +#### DataSciencePipelinesSpec + + + +DataSciencePipelinesSpec defines the desired state of DataSciencePipelines + + + +_Appears in:_ +- [DataSciencePipelines](#datasciencepipelines) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `foo` _string_ | Foo is an example field of DataSciencePipelines. Edit datasciencepipelines_types.go to remove/update | | | + + +#### DataSciencePipelinesStatus + + + +DataSciencePipelinesStatus defines the observed state of DataSciencePipelines + + + +_Appears in:_ +- [DataSciencePipelines](#datasciencepipelines) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + +#### Kserve + + + +Kserve is the Schema for the kserves API + + + +_Appears in:_ +- [KserveList](#kservelist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `Kserve` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[KserveSpec](#kservespec)_ | | | | +| `status` _[KserveStatus](#kservestatus)_ | | | | + + +#### KserveList + + + +KserveList contains a list of Kserve + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `KserveList` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[Kserve](#kserve) array_ | | | | + + +#### KserveSpec + + + +KserveSpec defines the desired state of Kserve + + + +_Appears in:_ +- [Kserve](#kserve) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `foo` _string_ | Foo is an example field of Kserve. Edit kserve_types.go to remove/update | | | + + +#### KserveStatus + + + +KserveStatus defines the observed state of Kserve + + + +_Appears in:_ +- [Kserve](#kserve) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + +#### Kueue + + + +Kueue is the Schema for the kueues API + + + +_Appears in:_ +- [KueueList](#kueuelist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `Kueue` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[KueueSpec](#kueuespec)_ | | | | +| `status` _[KueueStatus](#kueuestatus)_ | | | | + + +#### KueueList + + + +KueueList contains a list of Kueue + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `KueueList` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[Kueue](#kueue) array_ | | | | + + +#### KueueSpec + + + +KueueSpec defines the desired state of Kueue + + + +_Appears in:_ +- [Kueue](#kueue) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `foo` _string_ | Foo is an example field of Kueue. Edit kueue_types.go to remove/update | | | + + +#### KueueStatus + + + +KueueStatus defines the observed state of Kueue + + + +_Appears in:_ +- [Kueue](#kueue) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + +#### ModelMeshServing + + + +ModelMeshServing is the Schema for the modelmeshservings API + + + +_Appears in:_ +- [ModelMeshServingList](#modelmeshservinglist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `ModelMeshServing` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[ModelMeshServingSpec](#modelmeshservingspec)_ | | | | +| `status` _[ModelMeshServingStatus](#modelmeshservingstatus)_ | | | | + + +#### ModelMeshServingList + + + +ModelMeshServingList contains a list of ModelMeshServing + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `ModelMeshServingList` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[ModelMeshServing](#modelmeshserving) array_ | | | | + + +#### ModelMeshServingSpec + + + +ModelMeshServingSpec defines the desired state of ModelMeshServing + + + +_Appears in:_ +- [ModelMeshServing](#modelmeshserving) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `foo` _string_ | Foo is an example field of ModelMeshServing. Edit modelmeshserving_types.go to remove/update | | | + + +#### ModelMeshServingStatus + + + +ModelMeshServingStatus defines the observed state of ModelMeshServing + + + +_Appears in:_ +- [ModelMeshServing](#modelmeshserving) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + +#### ModelRegistry + + + +ModelRegistry is the Schema for the modelregistries API + + + +_Appears in:_ +- [ModelRegistryList](#modelregistrylist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `ModelRegistry` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[ModelRegistrySpec](#modelregistryspec)_ | | | | +| `status` _[ModelRegistryStatus](#modelregistrystatus)_ | | | | + + +#### ModelRegistryList + + + +ModelRegistryList contains a list of ModelRegistry + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `ModelRegistryList` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[ModelRegistry](#modelregistry) array_ | | | | + + +#### ModelRegistrySpec + + + +ModelRegistrySpec defines the desired state of ModelRegistry + + + +_Appears in:_ +- [ModelRegistry](#modelregistry) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `foo` _string_ | Foo is an example field of ModelRegistry. Edit modelregistry_types.go to remove/update | | | + + +#### ModelRegistryStatus + + + +ModelRegistryStatus defines the observed state of ModelRegistry + + + +_Appears in:_ +- [ModelRegistry](#modelregistry) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + +#### Ray + + + +Ray is the Schema for the rays API + + + +_Appears in:_ +- [RayList](#raylist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `Ray` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[RaySpec](#rayspec)_ | | | | +| `status` _[RayStatus](#raystatus)_ | | | | + + +#### RayList + + + +RayList contains a list of Ray + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `RayList` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[Ray](#ray) array_ | | | | + + +#### RaySpec + + + +RaySpec defines the desired state of Ray + + + +_Appears in:_ +- [Ray](#ray) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `foo` _string_ | Foo is an example field of Ray. Edit ray_types.go to remove/update | | | + + +#### RayStatus + + + +RayStatus defines the observed state of Ray + + + +_Appears in:_ +- [Ray](#ray) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + +#### TrainingOperator + + + +TrainingOperator is the Schema for the trainingoperators API + + + +_Appears in:_ +- [TrainingOperatorList](#trainingoperatorlist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `TrainingOperator` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[TrainingOperatorSpec](#trainingoperatorspec)_ | | | | +| `status` _[TrainingOperatorStatus](#trainingoperatorstatus)_ | | | | + + +#### TrainingOperatorList + + + +TrainingOperatorList contains a list of TrainingOperator + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `TrainingOperatorList` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[TrainingOperator](#trainingoperator) array_ | | | | + + +#### TrainingOperatorSpec + + + +TrainingOperatorSpec defines the desired state of TrainingOperator + + + +_Appears in:_ +- [TrainingOperator](#trainingoperator) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `foo` _string_ | Foo is an example field of TrainingOperator. Edit trainingoperator_types.go to remove/update | | | + + +#### TrainingOperatorStatus + + + +TrainingOperatorStatus defines the observed state of TrainingOperator + + + +_Appears in:_ +- [TrainingOperator](#trainingoperator) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + +#### TrustyAI + + + +TrustyAI is the Schema for the trustyais API + + + +_Appears in:_ +- [TrustyAIList](#trustyailist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `TrustyAI` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[TrustyAISpec](#trustyaispec)_ | | | | +| `status` _[TrustyAIStatus](#trustyaistatus)_ | | | | + + +#### TrustyAIList + + + +TrustyAIList contains a list of TrustyAI + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `TrustyAIList` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[TrustyAI](#trustyai) array_ | | | | + + +#### TrustyAISpec + + + +TrustyAISpec defines the desired state of TrustyAI + + + +_Appears in:_ +- [TrustyAI](#trustyai) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `foo` _string_ | Foo is an example field of TrustyAI. Edit trustyai_types.go to remove/update | | | + + +#### TrustyAIStatus + + + +TrustyAIStatus defines the observed state of TrustyAI + + + +_Appears in:_ +- [TrustyAI](#trustyai) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + +#### Workbenches + + + +Workbenches is the Schema for the workbenches API + + + +_Appears in:_ +- [WorkbenchesList](#workbencheslist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `Workbenches` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[WorkbenchesSpec](#workbenchesspec)_ | | | | +| `status` _[WorkbenchesStatus](#workbenchesstatus)_ | | | | + + +#### WorkbenchesList + + + +WorkbenchesList contains a list of Workbenches + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `components.opendatahub.io/v1` | | | +| `kind` _string_ | `WorkbenchesList` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[Workbenches](#workbenches) array_ | | | | + + +#### WorkbenchesSpec + + + +WorkbenchesSpec defines the desired state of Workbenches + + + +_Appears in:_ +- [Workbenches](#workbenches) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `foo` _string_ | Foo is an example field of Workbenches. Edit workbenches_types.go to remove/update | | | + + +#### WorkbenchesStatus + + + +WorkbenchesStatus defines the observed state of Workbenches + + + +_Appears in:_ +- [Workbenches](#workbenches) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + + ## datasciencecluster.opendatahub.io/codeflare Package codeflare provides utility functions to config CodeFlare as part of the stack @@ -44,7 +929,6 @@ Component struct defines the basis for each OpenDataHub component configuration. _Appears in:_ - [CodeFlare](#codeflare) -- [Dashboard](#dashboard) - [DataSciencePipelines](#datasciencepipelines) - [Kserve](#kserve) - [Kueue](#kueue) @@ -80,46 +964,36 @@ _Appears in:_ | `manifests` _[ManifestsConfig](#manifestsconfig) array_ | List of custom manifests for the given component | | | -#### ManifestsConfig - - - - +#### Status -_Appears in:_ -- [DevFlags](#devflags) - -| Field | Description | Default | Validation | -| --- | --- | --- | --- | -| `uri` _string_ | uri is the URI point to a git repo with tag/branch. e.g. https://github.com/org/repo/tarball/ | | | -| `contextDir` _string_ | contextDir is the relative path to the folder containing manifests in a repository, default value "manifests" | manifests | | -| `sourcePath` _string_ | sourcePath is the subpath within contextDir where kustomize builds start. Examples include any sub-folder or path: `base`, `overlays/dev`, `default`, `odh` etc. | | | - - - -## datasciencecluster.opendatahub.io/dashboard - -Package dashboard provides utility functions to config Open Data Hub Dashboard: A web dashboard that displays -installed Open Data Hub components with easy access to component UIs and documentation -#### Dashboard - - - -Dashboard struct holds the configuration for the Dashboard component. _Appears in:_ -- [Components](#components) +- [CodeFlareStatus](#codeflarestatus) +- [DashboardStatus](#dashboardstatus) +- [DataSciencePipelinesStatus](#datasciencepipelinesstatus) +- [KserveStatus](#kservestatus) +- [KueueStatus](#kueuestatus) +- [ModelMeshServingStatus](#modelmeshservingstatus) +- [ModelRegistryStatus](#modelregistrystatus) +- [RayStatus](#raystatus) +- [TrainingOperatorStatus](#trainingoperatorstatus) +- [TrustyAIStatus](#trustyaistatus) +- [WorkbenchesStatus](#workbenchesstatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `Component` _[Component](#component)_ | | | | +| `phase` _string_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | + + @@ -400,7 +1274,7 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `dashboard` _[Dashboard](#dashboard)_ | Dashboard component configuration. | | | +| `dashboard` _[DSCDashboard](#dscdashboard)_ | Dashboard component configuration. | | | | `workbenches` _[Workbenches](#workbenches)_ | Workbenches component configuration. | | | | `modelmeshserving` _[ModelMeshServing](#modelmeshserving)_ | ModelMeshServing component configuration.
Does not support enabled Kserve at the same time | | | | `datasciencepipelines` _[DataSciencePipelines](#datasciencepipelines)_ | DataServicePipeline component configuration.
Require OpenShift Pipelines Operator to be installed before enable component | | | diff --git a/go.mod b/go.mod index 9b86d8e92c2..cba7ae80440 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/go-logr/logr v1.4.1 github.com/hashicorp/go-multierror v1.1.1 + github.com/onsi/ginkgo v1.16.4 github.com/onsi/ginkgo/v2 v2.14.0 github.com/onsi/gomega v1.30.0 github.com/openshift/addon-operator/apis v0.0.0-20230919043633-820afed15881 @@ -14,6 +15,7 @@ require ( github.com/operator-framework/api v0.18.0 github.com/pkg/errors v0.9.1 github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.68.0 + github.com/rs/xid v1.6.0 github.com/spf13/afero v1.10.0 github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.26.0 @@ -63,6 +65,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nxadm/tail v1.4.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.18.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect @@ -87,6 +90,7 @@ require ( google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/component-base v0.29.2 // indirect k8s.io/klog/v2 v2.110.1 // indirect diff --git a/go.sum b/go.sum index 3b193384846..4605b86184c 100644 --- a/go.sum +++ b/go.sum @@ -261,11 +261,13 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= @@ -332,6 +334,8 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= @@ -798,6 +802,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go index 778a829f5ee..57f8635ca87 100644 --- a/main.go +++ b/main.go @@ -21,7 +21,6 @@ import ( "flag" "os" - "github.com/hashicorp/go-multierror" addonv1alpha1 "github.com/openshift/addon-operator/apis/addons/v1alpha1" ocappsv1 "github.com/openshift/api/apps/v1" //nolint:importas //reason: conflicts with appsv1 "k8s.io/api/apps/v1" buildv1 "github.com/openshift/api/build/v1" @@ -56,16 +55,19 @@ import ( ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/metrics/server" ctrlwebhook "sigs.k8s.io/controller-runtime/pkg/webhook" + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" featurev1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/features/v1" "github.com/opendatahub-io/opendatahub-operator/v2/components/modelregistry" "github.com/opendatahub-io/opendatahub-operator/v2/controllers/certconfigmapgenerator" + dashboardctrl "github.com/opendatahub-io/opendatahub-operator/v2/controllers/components/dashboard" dscctrl "github.com/opendatahub-io/opendatahub-operator/v2/controllers/datasciencecluster" dscictrl "github.com/opendatahub-io/opendatahub-operator/v2/controllers/dscinitialization" "github.com/opendatahub-io/opendatahub-operator/v2/controllers/secretgenerator" "github.com/opendatahub-io/opendatahub-operator/v2/controllers/webhook" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" + odhClient "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/client" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/logger" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/upgrade" ) @@ -78,6 +80,7 @@ var ( ) func init() { //nolint:gochecknoinits + utilruntime.Must(componentsv1.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(dsciv1.AddToScheme(scheme)) @@ -103,20 +106,8 @@ func init() { //nolint:gochecknoinits utilruntime.Must(operatorv1.Install(scheme)) } -func initComponents(ctx context.Context, p cluster.Platform) error { - var errs *multierror.Error - var dummyDSC = &dscv1.DataScienceCluster{} - - components, err := dummyDSC.GetComponents() - if err != nil { - return err - } - - for _, c := range components { - errs = multierror.Append(errs, c.Init(ctx, p)) - } - - return errs.ErrorOrNil() +func initComponents(_ context.Context, p cluster.Platform) error { + return dashboardctrl.Init(p) } func main() { //nolint:funlen,maintidx @@ -176,6 +167,11 @@ func main() { //nolint:funlen,maintidx release := cluster.GetRelease() platform := release.Name + if err := initComponents(ctx, platform); err != nil { + setupLog.Error(err, "unable to init components") + os.Exit(1) + } + secretCache := createSecretCacheConfig(platform) deploymentCache := createDeploymentCacheConfig(platform) cacheOptions := cache.Options{ @@ -236,8 +232,14 @@ func main() { //nolint:funlen,maintidx webhook.Init(mgr) + oc, err := odhClient.NewFromManager(ctx, mgr) + if err != nil { + setupLog.Error(err, "unable to create client") + os.Exit(1) + } + if err = (&dscictrl.DSCInitializationReconciler{ - Client: mgr.GetClient(), + Client: oc, Scheme: mgr.GetScheme(), Log: logger.LogWithLevel(ctrl.Log.WithName(operatorName).WithName("controllers").WithName("DSCInitialization"), logmode), Recorder: mgr.GetEventRecorderFor("dscinitialization-controller"), @@ -248,7 +250,7 @@ func main() { //nolint:funlen,maintidx } if err = (&dscctrl.DataScienceClusterReconciler{ - Client: mgr.GetClient(), + Client: oc, Scheme: mgr.GetScheme(), Log: logger.LogWithLevel(ctrl.Log.WithName(operatorName).WithName("controllers").WithName("DataScienceCluster"), logmode), DataScienceCluster: &dscctrl.DataScienceClusterConfig{ @@ -263,7 +265,7 @@ func main() { //nolint:funlen,maintidx } if err = (&secretgenerator.SecretGeneratorReconciler{ - Client: mgr.GetClient(), + Client: oc, Scheme: mgr.GetScheme(), Log: logger.LogWithLevel(ctrl.Log.WithName(operatorName).WithName("controllers").WithName("SecretGenerator"), logmode), }).SetupWithManager(mgr); err != nil { @@ -272,7 +274,7 @@ func main() { //nolint:funlen,maintidx } if err = (&certconfigmapgenerator.CertConfigmapGeneratorReconciler{ - Client: mgr.GetClient(), + Client: oc, Scheme: mgr.GetScheme(), Log: logger.LogWithLevel(ctrl.Log.WithName(operatorName).WithName("controllers").WithName("CertConfigmapGenerator"), logmode), }).SetupWithManager(mgr); err != nil { @@ -280,6 +282,11 @@ func main() { //nolint:funlen,maintidx os.Exit(1) } + // Initialize component reconcilers + if err = CreateComponentReconcilers(ctx, mgr); err != nil { + os.Exit(1) + } + // get old release version before we create default DSCI CR oldReleaseVersion, _ := upgrade.GetDeployedRelease(ctx, setupClient) @@ -338,10 +345,6 @@ func main() { //nolint:funlen,maintidx setupLog.Error(err, "unable to set up ready check") os.Exit(1) } - if err := initComponents(ctx, platform); err != nil { - setupLog.Error(err, "unable to init components") - os.Exit(1) - } setupLog.Info("starting manager") if err := mgr.Start(ctx); err != nil { @@ -383,3 +386,12 @@ func createDeploymentCacheConfig(platform cluster.Platform) map[string]cache.Con namespaceConfigs[modelregistry.DefaultModelRegistriesNamespace] = cache.Config{} return namespaceConfigs } + +func CreateComponentReconcilers(ctx context.Context, mgr manager.Manager) error { + // TODO: add more here or make it go routine + if err := dashboardctrl.NewDashboardReconciler(ctx, mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "DashboardReconciler") + return err + } + return nil +} diff --git a/pkg/cluster/gvk/gvk.go b/pkg/cluster/gvk/gvk.go index 0415304abe2..5f2e0229bb4 100644 --- a/pkg/cluster/gvk/gvk.go +++ b/pkg/cluster/gvk/gvk.go @@ -67,4 +67,64 @@ var ( Version: "v1alpha", Kind: "OdhDashboardConfig", } + + Dashboard = schema.GroupVersionKind{ + Group: "components.opendatahub.io", + Version: "v1", + Kind: "Dashboard", + } + + Workbenches = schema.GroupVersionKind{ + Group: "components.opendatahub.io", + Version: "v1", + Kind: "Workbenches", + } + + ModelMeshServing = schema.GroupVersionKind{ + Group: "components.opendatahub.io", + Version: "v1", + Kind: "ModelMeshServing", + } + + DataSciencePipelines = schema.GroupVersionKind{ + Group: "components.opendatahub.io", + Version: "v1", + Kind: "DataSciencePipelines", + } + + Kserve = schema.GroupVersionKind{ + Group: "components.opendatahub.io", + Version: "v1", + Kind: "Kserve", + } + + CodeFlare = schema.GroupVersionKind{ + Group: "components.opendatahub.io", + Version: "v1", + Kind: "CodeFlare", + } + + Ray = schema.GroupVersionKind{ + Group: "components.opendatahub.io", + Version: "v1", + Kind: "Ray", + } + + TrustyAI = schema.GroupVersionKind{ + Group: "components.opendatahub.io", + Version: "v1", + Kind: "TrustyAI", + } + + ModelRegistry = schema.GroupVersionKind{ + Group: "components.opendatahub.io", + Version: "v1", + Kind: "ModelRegistry", + } + + TrainingOperator = schema.GroupVersionKind{ + Group: "components.opendatahub.io", + Version: "v1", + Kind: "TrainingOperator", + } ) diff --git a/pkg/controller/actions/action_delete_resources.go b/pkg/controller/actions/action_delete_resources.go new file mode 100644 index 00000000000..aa21da284e9 --- /dev/null +++ b/pkg/controller/actions/action_delete_resources.go @@ -0,0 +1,84 @@ +package actions + +import ( + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/types" +) + +const ( + DeleteResourcesActionName = "delete-resources" +) + +type DeleteResourcesAction struct { + BaseAction + types []client.Object + labels map[string]string +} + +type DeleteResourcesActionOpts func(*DeleteResourcesAction) + +func WithDeleteResourcesTypes(values ...client.Object) DeleteResourcesActionOpts { + return func(action *DeleteResourcesAction) { + action.types = append(action.types, values...) + } +} + +func WithDeleteResourcesLabel(k string, v string) DeleteResourcesActionOpts { + return func(action *DeleteResourcesAction) { + action.labels[k] = v + } +} + +func WithDeleteResourcesLabels(values map[string]string) DeleteResourcesActionOpts { + return func(action *DeleteResourcesAction) { + for k, v := range values { + action.labels[k] = v + } + } +} + +func (r *DeleteResourcesAction) Execute(ctx context.Context, rr *types.ReconciliationRequest) error { + for i := range r.types { + opts := make([]client.DeleteAllOfOption, 0) + + if len(r.labels) > 0 { + opts = append(opts, client.MatchingLabels(r.labels)) + } + + namespaced, err := rr.Client.IsObjectNamespaced(r.types[i]) + if err != nil { + return err + } + + if namespaced { + opts = append(opts, client.InNamespace(rr.DSCI.Spec.ApplicationsNamespace)) + } + + err = rr.Client.DeleteAllOf(ctx, r.types[i], opts...) + if err != nil { + return err + } + } + + return nil +} + +func NewDeleteResourcesAction(ctx context.Context, opts ...DeleteResourcesActionOpts) *DeleteResourcesAction { + action := DeleteResourcesAction{ + BaseAction: BaseAction{ + Log: log.FromContext(ctx).WithName(ActionGroup).WithName(DeleteResourcesActionName), + }, + types: make([]client.Object, 0), + labels: map[string]string{}, + } + + for _, opt := range opts { + opt(&action) + } + + return &action +} diff --git a/pkg/controller/actions/action_delete_resources_test.go b/pkg/controller/actions/action_delete_resources_test.go new file mode 100644 index 00000000000..faff2714802 --- /dev/null +++ b/pkg/controller/actions/action_delete_resources_test.go @@ -0,0 +1,85 @@ +package actions_test + +import ( + "context" + "testing" + + "github.com/onsi/gomega/gstruct" + "github.com/rs/xid" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" + dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster/gvk" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/actions" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/types" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/labels" + + . "github.com/onsi/gomega" +) + +func TestDeleteResourcesAction(t *testing.T) { + g := NewWithT(t) + + ctx := context.Background() + ns := xid.New().String() + + client := NewFakeClient( + &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: gvk.Deployment.GroupVersion().String(), + Kind: gvk.Deployment.Kind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-deployment", + Namespace: ns, + Labels: map[string]string{ + labels.K8SCommon.PartOf: "foo", + }, + }, + }, + &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: gvk.Deployment.GroupVersion().String(), + Kind: gvk.Deployment.Kind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-deployment-2", + Namespace: ns, + Labels: map[string]string{ + labels.K8SCommon.PartOf: "baz", + }, + }, + }, + ) + + action := actions.NewDeleteResourcesAction( + ctx, + actions.WithDeleteResourcesTypes(&appsv1.Deployment{}), + actions.WithDeleteResourcesLabel(labels.K8SCommon.PartOf, "foo")) + + err := action.Execute(ctx, &types.ReconciliationRequest{ + Client: client, + Instance: nil, + DSCI: &dsciv1.DSCInitialization{Spec: dsciv1.DSCInitializationSpec{ApplicationsNamespace: ns}}, + DSC: &dscv1.DataScienceCluster{}, + Platform: cluster.OpenDataHub, + }) + + g.Expect(err).ShouldNot(HaveOccurred()) + + deployments := appsv1.DeploymentList{} + err = client.List(ctx, &deployments) + + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(deployments.Items).Should(HaveLen(1)) + g.Expect(deployments.Items[0]).To( + gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{ + "ObjectMeta": gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{ + "Name": Equal("my-deployment-2"), + }), + }), + ) +} diff --git a/pkg/controller/actions/action_test.go b/pkg/controller/actions/action_test.go new file mode 100644 index 00000000000..b5ec76056c3 --- /dev/null +++ b/pkg/controller/actions/action_test.go @@ -0,0 +1,47 @@ +package actions_test + +import ( + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/types" +) + +func NewFakeClient(objs ...ctrlClient.Object) ctrlClient.WithWatch { //nolint:ireturn + scheme := runtime.NewScheme() + utilruntime.Must(corev1.AddToScheme(scheme)) + utilruntime.Must(appsv1.AddToScheme(scheme)) + + fakeMapper := meta.NewDefaultRESTMapper(scheme.PreferredVersionAllGroups()) + for gvk := range scheme.AllKnownTypes() { + fakeMapper.Add(gvk, meta.RESTScopeNamespace) + // switch { + //// TODO: add cases for cluster scoped + //default: + // fakeMapper.Add(gvk, meta.RESTScopeNamespace) + //} + } + + return fake.NewClientBuilder(). + WithScheme(scheme). + WithRESTMapper(fakeMapper). + WithObjects(objs...). + Build() +} + +func ExtractStatusCondition(conditionType string) func(in types.ResourceObject) metav1.Condition { + return func(in types.ResourceObject) metav1.Condition { + c := meta.FindStatusCondition(in.GetStatus().Conditions, conditionType) + if c == nil { + return metav1.Condition{} + } + + return *c + } +} diff --git a/pkg/controller/actions/action_update_status.go b/pkg/controller/actions/action_update_status.go new file mode 100644 index 00000000000..c6b36621547 --- /dev/null +++ b/pkg/controller/actions/action_update_status.go @@ -0,0 +1,109 @@ +package actions + +import ( + "context" + "fmt" + + appsv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/opendatahub-io/opendatahub-operator/v2/controllers/status" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/types" +) + +const ( + UpdateStatusActionName = "update-status" + DeploymentsNotReadyReason = "DeploymentsNotReady" + ReadyReason = "Ready" +) + +type UpdateStatusAction struct { + BaseAction + labels map[string]string +} + +type UpdateStatusActionOpts func(*UpdateStatusAction) + +func WithUpdateStatusLabel(k string, v string) UpdateStatusActionOpts { + return func(action *UpdateStatusAction) { + action.labels[k] = v + } +} + +func WithUpdateStatusLabels(values map[string]string) UpdateStatusActionOpts { + return func(action *UpdateStatusAction) { + for k, v := range values { + action.labels[k] = v + } + } +} + +func (a *UpdateStatusAction) Execute(ctx context.Context, rr *types.ReconciliationRequest) error { + if len(a.labels) == 0 { + return nil + } + + obj, ok := rr.Instance.(types.ResourceObject) + if !ok { + return fmt.Errorf("resource instance %v is not a ResourceObject", rr.Instance) + } + + deployments := &appsv1.DeploymentList{} + + err := rr.Client.List( + ctx, + deployments, + client.InNamespace(rr.DSCI.Spec.ApplicationsNamespace), + client.MatchingLabels(a.labels), + ) + + if err != nil { + return fmt.Errorf("error fetching list of deployments: %w", err) + } + + ready := 0 + for _, deployment := range deployments.Items { + if deployment.Status.ReadyReplicas == deployment.Status.Replicas { + ready++ + } + } + + s := obj.GetStatus() + s.Phase = "Ready" + + conditionReady := metav1.Condition{ + Type: status.ConditionTypeReady, + Status: metav1.ConditionTrue, + Reason: ReadyReason, + Message: fmt.Sprintf("%d/%d deployments ready", ready, len(deployments.Items)), + } + + if len(deployments.Items) > 0 && ready != len(deployments.Items) { + conditionReady.Status = metav1.ConditionFalse + conditionReady.Reason = DeploymentsNotReadyReason + + s.Phase = "NotReady" + } + + meta.SetStatusCondition(&s.Conditions, conditionReady) + + return nil +} + +func NewUpdateStatusAction(ctx context.Context, opts ...UpdateStatusActionOpts) *UpdateStatusAction { + action := UpdateStatusAction{ + BaseAction: BaseAction{ + Log: log.FromContext(ctx).WithName(ActionGroup).WithName(UpdateStatusActionName), + }, + labels: map[string]string{}, + } + + for _, opt := range opts { + opt(&action) + } + + return &action +} diff --git a/pkg/controller/actions/action_update_status_test.go b/pkg/controller/actions/action_update_status_test.go new file mode 100644 index 00000000000..081cd7d445d --- /dev/null +++ b/pkg/controller/actions/action_update_status_test.go @@ -0,0 +1,165 @@ +//nolint:dupl +package actions_test + +import ( + "context" + "testing" + + "github.com/onsi/gomega/gstruct" + "github.com/rs/xid" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" + dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" + dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" + "github.com/opendatahub-io/opendatahub-operator/v2/controllers/status" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster/gvk" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/actions" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/types" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/labels" + + . "github.com/onsi/gomega" +) + +//nolint:dupl +func TestUpdateStatusActionNotReady(t *testing.T) { + g := NewWithT(t) + + ctx := context.Background() + ns := xid.New().String() + + client := NewFakeClient( + &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: gvk.Deployment.GroupVersion().String(), + Kind: gvk.Deployment.Kind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-deployment", + Namespace: ns, + Labels: map[string]string{ + labels.K8SCommon.PartOf: "foo", + }, + }, + Status: appsv1.DeploymentStatus{ + Replicas: 1, + ReadyReplicas: 0, + }, + }, + &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: gvk.Deployment.GroupVersion().String(), + Kind: gvk.Deployment.Kind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-deployment-2", + Namespace: ns, + Labels: map[string]string{ + labels.K8SCommon.PartOf: "foo", + }, + }, + Status: appsv1.DeploymentStatus{ + Replicas: 1, + ReadyReplicas: 1, + }, + }, + ) + + action := actions.NewUpdateStatusAction( + ctx, + actions.WithUpdateStatusLabel(labels.K8SCommon.PartOf, "foo")) + + rr := types.ReconciliationRequest{ + Client: client, + Instance: &componentsv1.Dashboard{}, + DSCI: &dsciv1.DSCInitialization{Spec: dsciv1.DSCInitializationSpec{ApplicationsNamespace: ns}}, + DSC: &dscv1.DataScienceCluster{}, + Platform: cluster.OpenDataHub, + } + + err := action.Execute(ctx, &rr) + g.Expect(err).ShouldNot(HaveOccurred()) + + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(rr.Instance).Should( + WithTransform( + ExtractStatusCondition(status.ConditionTypeReady), + gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{ + "Status": Equal(metav1.ConditionFalse), + "Reason": Equal(actions.DeploymentsNotReadyReason), + }), + ), + ) +} + +func TestUpdateStatusActionReady(t *testing.T) { + g := NewWithT(t) + + ctx := context.Background() + ns := xid.New().String() + + client := NewFakeClient( + &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: gvk.Deployment.GroupVersion().String(), + Kind: gvk.Deployment.Kind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-deployment", + Namespace: ns, + Labels: map[string]string{ + labels.K8SCommon.PartOf: "foo", + }, + }, + Status: appsv1.DeploymentStatus{ + Replicas: 1, + ReadyReplicas: 1, + }, + }, + &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: gvk.Deployment.GroupVersion().String(), + Kind: gvk.Deployment.Kind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-deployment-2", + Namespace: ns, + Labels: map[string]string{ + labels.K8SCommon.PartOf: "foo", + }, + }, + Status: appsv1.DeploymentStatus{ + Replicas: 1, + ReadyReplicas: 1, + }, + }, + ) + + action := actions.NewUpdateStatusAction( + ctx, + actions.WithUpdateStatusLabel(labels.K8SCommon.PartOf, "foo")) + + rr := types.ReconciliationRequest{ + Client: client, + Instance: &componentsv1.Dashboard{}, + DSCI: &dsciv1.DSCInitialization{Spec: dsciv1.DSCInitializationSpec{ApplicationsNamespace: ns}}, + DSC: &dscv1.DataScienceCluster{}, + Platform: cluster.OpenDataHub, + } + + err := action.Execute(ctx, &rr) + g.Expect(err).ShouldNot(HaveOccurred()) + + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(rr.Instance).Should( + WithTransform( + ExtractStatusCondition(status.ConditionTypeReady), + gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{ + "Status": Equal(metav1.ConditionTrue), + "Reason": Equal(actions.ReadyReason), + }), + ), + ) +} diff --git a/pkg/controller/actions/actions.go b/pkg/controller/actions/actions.go new file mode 100644 index 00000000000..bf1739e9f0b --- /dev/null +++ b/pkg/controller/actions/actions.go @@ -0,0 +1,25 @@ +package actions + +import ( + "context" + + "github.com/go-logr/logr" + + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/types" +) + +// +// Common +// + +const ( + ActionGroup = "action" +) + +type Action interface { + Execute(ctx context.Context, rr *types.ReconciliationRequest) error +} + +type BaseAction struct { + Log logr.Logger +} diff --git a/pkg/controller/client/client.go b/pkg/controller/client/client.go new file mode 100644 index 00000000000..3f356088883 --- /dev/null +++ b/pkg/controller/client/client.go @@ -0,0 +1,56 @@ +package client + +import ( + "context" + "fmt" + + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + ctrlCli "sigs.k8s.io/controller-runtime/pkg/client" +) + +func NewFromManager(ctx context.Context, mgr ctrl.Manager) (*Client, error) { + return New(ctx, mgr.GetConfig(), mgr.GetClient()) +} + +func New(_ context.Context, cfg *rest.Config, client ctrlCli.Client) (*Client, error) { + k8sCli, err := kubernetes.NewForConfig(cfg) + if err != nil { + return nil, fmt.Errorf("unable to construct a playground client: %w", err) + } + + return &Client{ + Client: client, + K: k8sCli, + }, nil +} + +type Client struct { + ctrlCli.Client + K kubernetes.Interface +} + +func (c *Client) Apply(ctx context.Context, obj ctrlCli.Object, opts ...ctrlCli.PatchOption) error { + // remove not required fields + obj.SetManagedFields(nil) + + err := c.Client.Patch(ctx, obj, ctrlCli.Apply, opts...) + if err != nil { + return fmt.Errorf("unable to pactch object %s: %w", obj, err) + } + + return nil +} + +func (c *Client) ApplyStatus(ctx context.Context, obj ctrlCli.Object, opts ...ctrlCli.SubResourcePatchOption) error { + // remove not required fields + obj.SetManagedFields(nil) + + err := c.Client.Status().Patch(ctx, obj, ctrlCli.Apply, opts...) + if err != nil { + return fmt.Errorf("unable to pactch object status %s: %w", obj, err) + } + + return nil +} diff --git a/pkg/controller/predicates/dependent/dependent.go b/pkg/controller/predicates/dependent/dependent.go new file mode 100644 index 00000000000..7151f6acf0c --- /dev/null +++ b/pkg/controller/predicates/dependent/dependent.go @@ -0,0 +1,115 @@ +package dependent + +import ( + "reflect" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/resources" +) + +var _ predicate.Predicate = Predicate{} + +type PredicateOption func(*Predicate) *Predicate + +func WithWatchDeleted(val bool) PredicateOption { + return func(in *Predicate) *Predicate { + in.WatchDelete = val + return in + } +} + +func WithWatchUpdate(val bool) PredicateOption { + return func(in *Predicate) *Predicate { + in.WatchUpdate = val + return in + } +} + +func WithWatchStatus(val bool) PredicateOption { + return func(in *Predicate) *Predicate { + in.WatchStatus = val + return in + } +} + +func New(opts ...PredicateOption) *Predicate { + dp := &Predicate{ + WatchDelete: true, + WatchUpdate: true, + WatchStatus: false, + } + + for i := range opts { + dp = opts[i](dp) + } + + return dp +} + +type Predicate struct { + WatchDelete bool + WatchUpdate bool + WatchStatus bool + + predicate.Funcs +} + +func (p Predicate) Create(event.CreateEvent) bool { + return false +} + +func (p Predicate) Generic(event.GenericEvent) bool { + return false +} + +func (p Predicate) Delete(e event.DeleteEvent) bool { + if !p.WatchDelete { + return false + } + + _, ok := e.Object.(*unstructured.Unstructured) + + return ok +} + +func (p Predicate) Update(e event.UpdateEvent) bool { + if !p.WatchUpdate { + return false + } + + if e.ObjectOld.GetResourceVersion() == e.ObjectNew.GetResourceVersion() { + return false + } + + oldObj, err := resources.ToUnstructured(e.ObjectOld) + if err != nil { + return false + } + + newObj, err := resources.ToUnstructured(e.ObjectNew) + if err != nil { + return false + } + + oldObj = oldObj.DeepCopy() + newObj = newObj.DeepCopy() + + if !p.WatchStatus { + // Update filters out events that change only the dependent resource + // status. It is not typical for the controller of a primary + // resource to write to the status of one its dependent resources. + delete(oldObj.Object, "status") + delete(newObj.Object, "status") + } + + // Reset field not meaningful for comparison + oldObj.SetResourceVersion("") + newObj.SetResourceVersion("") + oldObj.SetManagedFields(nil) + newObj.SetManagedFields(nil) + + return !reflect.DeepEqual(oldObj.Object, newObj.Object) +} diff --git a/pkg/controller/predicates/partial/partial.go b/pkg/controller/predicates/partial/partial.go new file mode 100644 index 00000000000..3832d5da6cf --- /dev/null +++ b/pkg/controller/predicates/partial/partial.go @@ -0,0 +1,77 @@ +package partial + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +var _ predicate.Predicate = Predicate{} + +type PredicateOption func(*Predicate) *Predicate + +func WatchDeleted(val bool) PredicateOption { + return func(in *Predicate) *Predicate { + in.WatchDelete = val + return in + } +} + +func WatchUpdate(val bool) PredicateOption { + return func(in *Predicate) *Predicate { + in.WatchUpdate = val + return in + } +} + +func New(opts ...PredicateOption) *Predicate { + dp := &Predicate{ + WatchDelete: true, + WatchUpdate: true, + } + + for i := range opts { + dp = opts[i](dp) + } + + return dp +} + +type Predicate struct { + WatchDelete bool + WatchUpdate bool + + predicate.Funcs +} + +func (p Predicate) Create(event.CreateEvent) bool { + return false +} + +func (p Predicate) Generic(event.GenericEvent) bool { + return false +} + +func (p Predicate) Delete(e event.DeleteEvent) bool { + if !p.WatchDelete { + return false + } + + _, ok := e.Object.(*metav1.PartialObjectMetadata) + + return ok +} + +func (p Predicate) Update(e event.UpdateEvent) bool { + if !p.WatchUpdate { + return false + } + + if e.ObjectOld.GetResourceVersion() == e.ObjectNew.GetResourceVersion() { + return false + } + + _, ok := e.ObjectNew.(*metav1.PartialObjectMetadata) + + return ok +} diff --git a/pkg/controller/reconciler/component_reconciler.go b/pkg/controller/reconciler/component_reconciler.go new file mode 100644 index 00000000000..202376041d7 --- /dev/null +++ b/pkg/controller/reconciler/component_reconciler.go @@ -0,0 +1,141 @@ +package types + +import ( + "context" + "errors" + "fmt" + "reflect" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/manager" + + dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" + dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/actions" + odhClient "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/client" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/controller/types" +) + +type ComponentReconciler[T types.ResourceObject] struct { + Client *odhClient.Client + Scheme *runtime.Scheme + Actions []actions.Action + Finalizer []actions.Action + Log logr.Logger + Manager manager.Manager + Controller controller.Controller + Recorder record.EventRecorder + Platform cluster.Platform +} + +func NewComponentReconciler[T types.ResourceObject](ctx context.Context, mgr manager.Manager, name string) (*ComponentReconciler[T], error) { + oc, err := odhClient.NewFromManager(ctx, mgr) + if err != nil { + return nil, err + } + + cc := ComponentReconciler[T]{ + Client: oc, + Scheme: mgr.GetScheme(), + Log: ctrl.Log.WithName("controllers").WithName(name), + Manager: mgr, + Recorder: mgr.GetEventRecorderFor(name), + Platform: cluster.GetRelease().Name, + } + + return &cc, nil +} + +func (r *ComponentReconciler[T]) GetLogger() logr.Logger { + return r.Log +} + +func (r *ComponentReconciler[T]) AddAction(action actions.Action) { + r.Actions = append(r.Actions, action) +} + +func (r *ComponentReconciler[T]) AddFinalizer(action actions.Action) { + r.Finalizer = append(r.Finalizer, action) +} + +func (r *ComponentReconciler[T]) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + l := log.FromContext(ctx) + + t := reflect.TypeOf(*new(T)).Elem() + res, ok := reflect.New(t).Interface().(T) + if !ok { + return ctrl.Result{}, fmt.Errorf("unable to construct instance of %v", t) + } + if err := r.Client.Get(ctx, client.ObjectKey{Name: req.Name}, res); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + dscl := dscv1.DataScienceClusterList{} + if err := r.Client.List(ctx, &dscl); err != nil { + return ctrl.Result{}, err + } + + if len(dscl.Items) != 1 { + return ctrl.Result{}, errors.New("unable to find DataScienceCluster") + } + + dscil := dsciv1.DSCInitializationList{} + if err := r.Client.List(ctx, &dscil); err != nil { + return ctrl.Result{}, err + } + + if len(dscil.Items) != 1 { + return ctrl.Result{}, errors.New("unable to find DSCInitialization") + } + + rr := types.ReconciliationRequest{ + Client: r.Client, + Instance: res, + DSC: &dscl.Items[0], + DSCI: &dscil.Items[0], + Platform: r.Platform, + Manifests: make(map[cluster.Platform]string), + } + + // Handle deletion + if !res.GetDeletionTimestamp().IsZero() { + // Execute finalizers + for _, action := range r.Finalizer { + if err := action.Execute(ctx, &rr); err != nil { + l.Error(err, "Failed to execute finalizer", "action", fmt.Sprintf("%T", action)) + return ctrl.Result{}, err + } + } + + return ctrl.Result{}, nil + } + + // Execute actions + for _, action := range r.Actions { + if err := action.Execute(ctx, &rr); err != nil { + l.Error(err, "Failed to execute action", "action", fmt.Sprintf("%T", action)) + return ctrl.Result{}, err + } + } + + // update status + err := r.Client.ApplyStatus( + ctx, + rr.Instance, + client.FieldOwner(rr.Instance.GetName()), + client.ForceOwnership, + ) + + if err != nil { + return ctrl.Result{}, err + } + + return ctrl.Result{}, nil +} diff --git a/pkg/controller/types/types.go b/pkg/controller/types/types.go new file mode 100644 index 00000000000..a519632dce3 --- /dev/null +++ b/pkg/controller/types/types.go @@ -0,0 +1,29 @@ +package types + +import ( + "github.com/go-logr/logr" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" + dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" +) + +type ResourceObject interface { + client.Object + components.WithStatus +} + +type WithLogger interface { + GetLogger() logr.Logger +} + +type ReconciliationRequest struct { + client.Client + Instance client.Object + DSC *dscv1.DataScienceCluster + DSCI *dsciv1.DSCInitialization + Platform cluster.Platform + Manifests map[cluster.Platform]string +} diff --git a/pkg/deploy/deploy.go b/pkg/deploy/deploy.go index fa58f93c16c..e8d7feafa2f 100644 --- a/pkg/deploy/deploy.go +++ b/pkg/deploy/deploy.go @@ -44,7 +44,7 @@ import ( "sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/kyaml/filesys" - "github.com/opendatahub-io/opendatahub-operator/v2/components" + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/conversion" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/annotations" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/labels" @@ -155,6 +155,28 @@ func DeployManifestsFromPath( namespace string, componentName string, componentEnabled bool, +) error { + return DeployManifestsFromPathWithLabels( + ctx, + cli, + owner, + manifestPath, + namespace, + componentName, + componentEnabled, map[string]string{}, + ) +} + +func DeployManifestsFromPathWithLabels( + ctx context.Context, + cli client.Client, + owner metav1.Object, + manifestPath string, + namespace string, + componentName string, + componentEnabled bool, + // TODO: this method must be refactored, left it just to avoid breaking compatibility + additionalLabels map[string]string, ) error { // Render the Kustomize manifests k := krusty.MakeKustomizer(krusty.MakeDefaultOptions()) @@ -180,7 +202,22 @@ func DeployManifestsFromPath( return fmt.Errorf("failed applying namespace plugin when preparing Kustomize resources. %w", err) } - labelsPlugin := plugins.CreateAddLabelsPlugin(componentName) + resourceLabels := map[string]string{ + labels.ODH.Component(componentName): "true", + labels.K8SCommon.PartOf: componentName, + } + + for k, v := range additionalLabels { + _, ok := resourceLabels[k] + if ok { + // don't override default labels + continue + } + + resourceLabels[k] = v + } + + labelsPlugin := plugins.CreateSetLabelsPlugin(resourceLabels) if err := labelsPlugin.Transform(resMap); err != nil { return fmt.Errorf("failed applying labels plugin when preparing Kustomize resources. %w", err) } diff --git a/pkg/metadata/annotations/annotations.go b/pkg/metadata/annotations/annotations.go index e2d4cfde922..897fa723cb7 100644 --- a/pkg/metadata/annotations/annotations.go +++ b/pkg/metadata/annotations/annotations.go @@ -13,3 +13,6 @@ const ( SecretLengthAnnotation = "secret-generator.opendatahub.io/complexity" SecretOauthClientAnnotation = "secret-generator.opendatahub.io/oauth-client-route" ) + +// ManagementStateAnnotation defines what ManagementState value if defined in DSC for the component. +const ManagementStateAnnotation = "component.opendatahub.io/management-state" diff --git a/pkg/metadata/labels/types.go b/pkg/metadata/labels/types.go index 382c2e38db3..f966bb8f884 100644 --- a/pkg/metadata/labels/types.go +++ b/pkg/metadata/labels/types.go @@ -2,6 +2,7 @@ package labels const ( ODHAppPrefix = "app.opendatahub.io" + ComponentName = "components.opendatahub.io/name" InjectTrustCA = "config.openshift.io/inject-trusted-cabundle" SecurityEnforce = "pod-security.kubernetes.io/enforce" ClusterMonitoring = "openshift.io/cluster-monitoring" diff --git a/pkg/plugins/addLabelsplugin.go b/pkg/plugins/addLabelsplugin.go index 13ecada5a93..5c79d2cb613 100644 --- a/pkg/plugins/addLabelsplugin.go +++ b/pkg/plugins/addLabelsplugin.go @@ -16,11 +16,15 @@ import ( // - It adds labels to the "spec/template/metadata/labels" and "spec/selector/matchLabels" paths // for resources of kind "Deployment". func CreateAddLabelsPlugin(componentName string) *builtins.LabelTransformerPlugin { + return CreateSetLabelsPlugin(map[string]string{ + labels.ODH.Component(componentName): "true", + labels.K8SCommon.PartOf: componentName, + }) +} + +func CreateSetLabelsPlugin(labels map[string]string) *builtins.LabelTransformerPlugin { return &builtins.LabelTransformerPlugin{ - Labels: map[string]string{ - labels.ODH.Component(componentName): "true", - labels.K8SCommon.PartOf: componentName, - }, + Labels: labels, FieldSpecs: []types.FieldSpec{ { Gvk: resid.Gvk{Kind: "Deployment"}, diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go new file mode 100644 index 00000000000..f378bd34652 --- /dev/null +++ b/pkg/resources/resources.go @@ -0,0 +1,21 @@ +package resources + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" +) + +func ToUnstructured(obj any) (*unstructured.Unstructured, error) { + data, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + if err != nil { + return nil, fmt.Errorf("unable to convert object %T to unstructured: %w", obj, err) + } + + u := unstructured.Unstructured{ + Object: data, + } + + return &u, nil +} diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go index eedbb45cca3..2389f93e1cf 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -25,13 +25,14 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" featuresv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/features/v1" infrav1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/infrastructure/v1" - "github.com/opendatahub-io/opendatahub-operator/v2/components" + componentsold "github.com/opendatahub-io/opendatahub-operator/v2/components" "github.com/opendatahub-io/opendatahub-operator/v2/components/codeflare" - "github.com/opendatahub-io/opendatahub-operator/v2/components/dashboard" "github.com/opendatahub-io/opendatahub-operator/v2/components/datasciencepipelines" "github.com/opendatahub-io/opendatahub-operator/v2/components/kserve" "github.com/opendatahub-io/opendatahub-operator/v2/components/kueue" @@ -68,38 +69,38 @@ func CreateDefaultDSC(ctx context.Context, cli client.Client) error { }, Spec: dscv1.DataScienceClusterSpec{ Components: dscv1.Components{ - Dashboard: dashboard.Dashboard{ + Dashboard: componentsv1.DSCDashboard{ Component: components.Component{ManagementState: operatorv1.Managed}, }, Workbenches: workbenches.Workbenches{ - Component: components.Component{ManagementState: operatorv1.Managed}, + Component: componentsold.Component{ManagementState: operatorv1.Managed}, }, ModelMeshServing: modelmeshserving.ModelMeshServing{ - Component: components.Component{ManagementState: operatorv1.Managed}, + Component: componentsold.Component{ManagementState: operatorv1.Managed}, }, DataSciencePipelines: datasciencepipelines.DataSciencePipelines{ - Component: components.Component{ManagementState: operatorv1.Managed}, + Component: componentsold.Component{ManagementState: operatorv1.Managed}, }, Kserve: kserve.Kserve{ - Component: components.Component{ManagementState: operatorv1.Managed}, + Component: componentsold.Component{ManagementState: operatorv1.Managed}, }, CodeFlare: codeflare.CodeFlare{ - Component: components.Component{ManagementState: operatorv1.Managed}, + Component: componentsold.Component{ManagementState: operatorv1.Managed}, }, Ray: ray.Ray{ - Component: components.Component{ManagementState: operatorv1.Managed}, + Component: componentsold.Component{ManagementState: operatorv1.Managed}, }, Kueue: kueue.Kueue{ - Component: components.Component{ManagementState: operatorv1.Managed}, + Component: componentsold.Component{ManagementState: operatorv1.Managed}, }, TrustyAI: trustyai.TrustyAI{ - Component: components.Component{ManagementState: operatorv1.Managed}, + Component: componentsold.Component{ManagementState: operatorv1.Managed}, }, ModelRegistry: modelregistry.ModelRegistry{ - Component: components.Component{ManagementState: operatorv1.Managed}, + Component: componentsold.Component{ManagementState: operatorv1.Managed}, }, TrainingOperator: trainingoperator.TrainingOperator{ - Component: components.Component{ManagementState: operatorv1.Managed}, + Component: componentsold.Component{ManagementState: operatorv1.Managed}, }, }, }, diff --git a/tests/e2e/controller_test.go b/tests/e2e/controller_test.go index 59bf3a325ce..c07d5ff2af8 100644 --- a/tests/e2e/controller_test.go +++ b/tests/e2e/controller_test.go @@ -23,6 +23,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" featurev1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/features/v1" @@ -104,6 +105,7 @@ func TestOdhOperator(t *testing.T) { utilruntime.Must(monitoringv1.AddToScheme(scheme)) utilruntime.Must(ofapi.AddToScheme(scheme)) utilruntime.Must(operatorv1.AddToScheme(scheme)) + utilruntime.Must(componentsv1.AddToScheme(scheme)) log.SetLogger(zap.New(zap.UseDevMode(true))) @@ -112,7 +114,9 @@ func TestOdhOperator(t *testing.T) { return } // Run create and delete tests for all the components - t.Run("create Opendatahub components", creationTestSuite) + t.Run("create DSCI and DSC CRs", creationTestSuite) + // Validate deployment of each component in separate test suite + t.Run("validate installation of Dashboard Component", dashboardTestSuite) // Run deletion if skipDeletion is not set if !skipDeletion { diff --git a/tests/e2e/creation_test.go b/tests/e2e/creation_test.go index 2a2abc3cd2b..cdb3d846d8b 100644 --- a/tests/e2e/creation_test.go +++ b/tests/e2e/creation_test.go @@ -1,8 +1,8 @@ +//nolint:unused package e2e_test import ( "context" - "errors" "fmt" "log" "reflect" @@ -11,7 +11,6 @@ import ( operatorv1 "github.com/openshift/api/operator/v1" "github.com/stretchr/testify/require" - autoscalingv1 "k8s.io/api/autoscaling/v1" k8serr "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -19,7 +18,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/client" dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" @@ -36,8 +34,9 @@ func creationTestSuite(t *testing.T) { testCtx, err := NewTestContext() require.NoError(t, err) - err = testCtx.setUp(t) - require.NoError(t, err, "error setting up environment") + // TODO: Uncomment this when we have Kserve api implemented + // err = testCtx.setUp(t) + // require.NoError(t, err, "error setting up environment") t.Run(testCtx.testDsc.Name, func(t *testing.T) { // DSCI @@ -48,10 +47,11 @@ func creationTestSuite(t *testing.T) { t.Run("Creation of more than one of DSCInitialization instance", func(t *testing.T) { testCtx.testDSCIDuplication(t) }) - t.Run("Validate DSCInitialization instance", func(t *testing.T) { - err = testCtx.validateDSCI() - require.NoError(t, err, "error validating DSCInitialization instance") - }) + // Validates Servicemesh fields + // t.Run("Validate DSCInitialization instance", func(t *testing.T) { + // err = testCtx.validateDSCI() + // require.NoError(t, err, "error validating DSCInitialization instance") + // }) t.Run("Check owned namespaces exist", func(t *testing.T) { err = testCtx.testOwnedNamespacesAllExist() require.NoError(t, err, "error owned namespace is missing") @@ -65,55 +65,31 @@ func creationTestSuite(t *testing.T) { t.Run("Creation of more than one of DataScienceCluster instance", func(t *testing.T) { testCtx.testDSCDuplication(t) }) - t.Run("Validate Ownerrefrences exist", func(t *testing.T) { - err = testCtx.testOwnerrefrences() - require.NoError(t, err, "error getting all DataScienceCluster's Ownerrefrences") - }) - t.Run("Validate all deployed components", func(t *testing.T) { - // this will take about 5-6 mins to complete - err = testCtx.testAllComponentCreation(t) - require.NoError(t, err, "error testing deployments for DataScienceCluster: "+testCtx.testDsc.Name) - }) - t.Run("Validate DSC Ready", func(t *testing.T) { - err = testCtx.validateDSCReady() - require.NoError(t, err, "DataScienceCluster instance is not Ready") - }) - - // Kserve - t.Run("Validate Knative resoruce", func(t *testing.T) { - err = testCtx.validateDSC() - require.NoError(t, err, "error getting Knatvie resrouce as part of DataScienceCluster validation") - }) - t.Run("Validate default certs available", func(t *testing.T) { - // move it to be part of check with kserve since it is using serving's secret - err = testCtx.testDefaultCertsAvailable() - require.NoError(t, err, "error getting default cert secrets for Kserve") - }) - - // ModelReg - t.Run("Validate model registry cert config", func(t *testing.T) { - err = testCtx.validateModelRegistryConfig() - require.NoError(t, err, "error validating ModelRegistry config") - }) - t.Run("Validate default model registry cert available", func(t *testing.T) { - err = testCtx.testDefaultModelRegistryCertAvailable() - require.NoError(t, err, "error getting default cert secret for ModelRegistry") - }) - t.Run("Validate model registry servicemeshmember available", func(t *testing.T) { - err = testCtx.testMRServiceMeshMember() - require.NoError(t, err, "error getting servicemeshmember for Model Registry") - }) - // reconcile - t.Run("Validate Controller reconcile", func(t *testing.T) { - // only test Dashboard component for now - err = testCtx.testUpdateComponentReconcile() - require.NoError(t, err, "error testing updates for DSC managed resource") - }) - t.Run("Validate Component Enabled field", func(t *testing.T) { - err = testCtx.testUpdateDSCComponentEnabled() - require.NoError(t, err, "error testing component enabled field") - }) + //// Kserve + // t.Run("Validate Knative resoruce", func(t *testing.T) { + // err = testCtx.validateDSC() + // require.NoError(t, err, "error getting Knatvie resrouce as part of DataScienceCluster validation") + // }) + // t.Run("Validate default certs available", func(t *testing.T) { + // // move it to be part of check with kserve since it is using serving's secret + // err = testCtx.testDefaultCertsAvailable() + // require.NoError(t, err, "error getting default cert secrets for Kserve") + // }) + // + //// ModelReg + // t.Run("Validate model registry cert config", func(t *testing.T) { + // err = testCtx.validateModelRegistryConfig() + // require.NoError(t, err, "error validating ModelRegistry config") + // }) + // t.Run("Validate default model registry cert available", func(t *testing.T) { + // err = testCtx.testDefaultModelRegistryCertAvailable() + // require.NoError(t, err, "error getting default cert secret for ModelRegistry") + // }) + // t.Run("Validate model registry servicemeshmember available", func(t *testing.T) { + // err = testCtx.testMRServiceMeshMember() + // require.NoError(t, err, "error getting servicemeshmember for Model Registry") + // }) }) } @@ -386,25 +362,6 @@ func (tc *testContext) validateDSC() error { return nil } -func (tc *testContext) testOwnerrefrences() error { - // Test any one of the apps - if tc.testDsc.Spec.Components.Dashboard.ManagementState == operatorv1.Managed { - appDeployments, err := tc.kubeClient.AppsV1().Deployments(tc.applicationsNamespace).List(tc.ctx, metav1.ListOptions{ - LabelSelector: labels.ODH.Component(tc.testDsc.Spec.Components.Dashboard.GetComponentName()), - }) - if err != nil { - return fmt.Errorf("error listing component deployments %w", err) - } - // test any one deployment for ownerreference - if len(appDeployments.Items) != 0 && appDeployments.Items[0].OwnerReferences[0].Kind != "DataScienceCluster" { - return fmt.Errorf("expected ownerreference not found. Got ownereferrence: %v", - appDeployments.Items[0].OwnerReferences) - } - } - - return nil -} - func (tc *testContext) testDefaultCertsAvailable() error { // Get expected cert secrets defaultIngressCtrl, err := cluster.FindAvailableIngressController(tc.ctx, tc.customClient) @@ -502,116 +459,6 @@ func (tc *testContext) testMRServiceMeshMember() error { return nil } -func (tc *testContext) testUpdateComponentReconcile() error { - // Test Updating Dashboard Replicas - - appDeployments, err := tc.kubeClient.AppsV1().Deployments(tc.applicationsNamespace).List(tc.ctx, metav1.ListOptions{ - LabelSelector: labels.ODH.Component(tc.testDsc.Spec.Components.Dashboard.GetComponentName()), - }) - if err != nil { - return err - } - - if len(appDeployments.Items) != 1 { - return fmt.Errorf("error getting deployment for component %s", tc.testDsc.Spec.Components.Dashboard.GetComponentName()) - } - - const expectedReplica int32 = 3 - - testDeployment := appDeployments.Items[0] - patchedReplica := &autoscalingv1.Scale{ - ObjectMeta: metav1.ObjectMeta{ - Name: testDeployment.Name, - Namespace: testDeployment.Namespace, - }, - Spec: autoscalingv1.ScaleSpec{ - Replicas: expectedReplica, - }, - Status: autoscalingv1.ScaleStatus{}, - } - updatedDep, err := tc.kubeClient.AppsV1().Deployments(tc.applicationsNamespace).UpdateScale(tc.ctx, testDeployment.Name, patchedReplica, metav1.UpdateOptions{}) - if err != nil { - return fmt.Errorf("error patching component resources : %w", err) - } - if updatedDep.Spec.Replicas != patchedReplica.Spec.Replicas { - return fmt.Errorf("failed to patch replicas : expect to be %v but got %v", patchedReplica.Spec.Replicas, updatedDep.Spec.Replicas) - } - - // Sleep for 40 seconds to allow the operator to reconcile - // we expect it should not revert back to original value because of AllowList - time.Sleep(4 * generalRetryInterval) - reconciledDep, err := tc.kubeClient.AppsV1().Deployments(tc.applicationsNamespace).Get(tc.ctx, testDeployment.Name, metav1.GetOptions{}) - if err != nil { - return fmt.Errorf("error getting component resource after reconcile: %w", err) - } - if *reconciledDep.Spec.Replicas != expectedReplica { - return fmt.Errorf("failed to revert back replicas : expect to be %v but got %v", expectedReplica, *reconciledDep.Spec.Replicas) - } - - return nil -} - -func (tc *testContext) testUpdateDSCComponentEnabled() error { - // Test Updating dashboard to be disabled - var dashboardDeploymentName string - - if tc.testDsc.Spec.Components.Dashboard.ManagementState == operatorv1.Managed { - appDeployments, err := tc.kubeClient.AppsV1().Deployments(tc.applicationsNamespace).List(tc.ctx, metav1.ListOptions{ - LabelSelector: labels.ODH.Component(tc.testDsc.Spec.Components.Dashboard.GetComponentName()), - }) - if err != nil { - return fmt.Errorf("error getting enabled component %v", tc.testDsc.Spec.Components.Dashboard.GetComponentName()) - } - if len(appDeployments.Items) > 0 { - dashboardDeploymentName = appDeployments.Items[0].Name - if appDeployments.Items[0].Status.ReadyReplicas == 0 { - return fmt.Errorf("error getting enabled component: %s its deployment 'ReadyReplicas'", dashboardDeploymentName) - } - } - } else { - return errors.New("dashboard spec should be in 'enabled: true' state in order to perform test") - } - - // Disable component Dashboard - err := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // refresh the instance in case it was updated during the reconcile - err := tc.customClient.Get(tc.ctx, types.NamespacedName{Name: tc.testDsc.Name}, tc.testDsc) - if err != nil { - return fmt.Errorf("error getting resource %w", err) - } - // Disable the Component - tc.testDsc.Spec.Components.Dashboard.ManagementState = operatorv1.Removed - - // Try to update - err = tc.customClient.Update(tc.ctx, tc.testDsc) - // Return err itself here (not wrapped inside another error) - // so that RetryOnConflict can identify it correctly. - if err != nil { - return fmt.Errorf("error updating component from 'enabled: true' to 'enabled: false': %w", err) - } - - return nil - }) - if err != nil { - return fmt.Errorf("error after retry %w", err) - } - - // Sleep for 80 seconds to allow the operator to reconcile - time.Sleep(8 * generalRetryInterval) - _, err = tc.kubeClient.AppsV1().Deployments(tc.applicationsNamespace).Get(tc.ctx, dashboardDeploymentName, metav1.GetOptions{}) - if err != nil { - if k8serr.IsNotFound(err) { - return nil // correct result: should not find deployment after we disable it already - } - - return fmt.Errorf("error getting component resource after reconcile: %w", err) - } - return fmt.Errorf("component %v is disabled, should not get its deployment %v from NS %v any more", - tc.testDsc.Spec.Components.Dashboard.GetComponentName(), - dashboardDeploymentName, - tc.applicationsNamespace) -} - const testNs = "test-model-registries" func (tc *testContext) validateModelRegistryConfig() error { diff --git a/tests/e2e/dashboard_test.go b/tests/e2e/dashboard_test.go new file mode 100644 index 00000000000..f58b24b1f34 --- /dev/null +++ b/tests/e2e/dashboard_test.go @@ -0,0 +1,263 @@ +package e2e_test + +import ( + "context" + "errors" + "fmt" + "reflect" + "testing" + "time" + + operatorv1 "github.com/openshift/api/operator/v1" + "github.com/stretchr/testify/require" + autoscalingv1 "k8s.io/api/autoscaling/v1" + k8serr "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/labels" +) + +type DashboardTestCtx struct { + testCtx *testContext + testDashboardInstance componentsv1.Dashboard +} + +func dashboardTestSuite(t *testing.T) { + dashboardCtx := DashboardTestCtx{} + var err error + dashboardCtx.testCtx, err = NewTestContext() + require.NoError(t, err) + + testCtx := dashboardCtx.testCtx + + t.Run(testCtx.testDsc.Name, func(t *testing.T) { + // DSCI + t.Run("Creation of Dashboard CR", func(t *testing.T) { + err = dashboardCtx.testDashboardCreation() + require.NoError(t, err, "error creating DSCI CR") + }) + + t.Run("Validate Dashboard instance", func(t *testing.T) { + err = dashboardCtx.validateDashboard() + require.NoError(t, err, "error validating Dashboard instance") + }) + + t.Run("Validate Ownerrefrences exist", func(t *testing.T) { + err = dashboardCtx.testOwnerrefrences() + require.NoError(t, err, "error getting all Dashboard's Ownerrefrences") + }) + + t.Run("Validate Dashboard Ready", func(t *testing.T) { + err = dashboardCtx.validateDashboardReady() + require.NoError(t, err, "Dashboard instance is not Ready") + }) + + // reconcile + t.Run("Validate Controller reconcile", func(t *testing.T) { + // only test Dashboard component for now + err = dashboardCtx.testUpdateOnDashboardResources() + require.NoError(t, err, "error testing updates for Dashboard's managed resources") + }) + + t.Run("Validate Disabling Component", func(t *testing.T) { + err = dashboardCtx.testUpdateDashboardComponentDisabled() + require.NoError(t, err, "error testing component enabled field") + }) + }) +} + +func (tc *DashboardTestCtx) testDashboardCreation() error { + existingDashboardList := &componentsv1.DashboardList{} + + if tc.testCtx.testDsc.Spec.Components.Dashboard.ManagementState == operatorv1.Managed { + err := tc.testCtx.customClient.List(tc.testCtx.ctx, existingDashboardList) + if err == nil { + if len(existingDashboardList.Items) == 1 { + tc.testDashboardInstance = existingDashboardList.Items[0] + return nil + } else { + return fmt.Errorf("unexpected Dashboard CR instances. Expected 1 , "+ + "Found %v instance", len(existingDashboardList.Items)) + } + } + } + return nil +} + +func (tc *DashboardTestCtx) validateDashboard() error { + // Dashboard spec should match the spec of Dashboard component in DSC + if !reflect.DeepEqual(tc.testCtx.testDsc.Spec.Components.Dashboard.ManagementState, tc.testDashboardInstance.Spec.ManagementState) { + err := fmt.Errorf("expected smanagement state for Dashboard %v, got %v", + tc.testCtx.testDsc.Spec.Components.Dashboard.ManagementState, tc.testDashboardInstance.Spec.ManagementState) + return err + } + return nil +} + +func (tc *DashboardTestCtx) testOwnerrefrences() error { + // Test Dashboard CR ownerref + if tc.testDashboardInstance.OwnerReferences[0].Kind != "DataScienceCluster" { + return fmt.Errorf("expected ownerreference not found. Got ownereferrence: %v", + tc.testDashboardInstance.OwnerReferences[0].Kind) + } + + // Test Dashboard resources + + appDeployments, err := tc.testCtx.kubeClient.AppsV1().Deployments(tc.testCtx.applicationsNamespace).List(tc.testCtx.ctx, metav1.ListOptions{ + LabelSelector: labels.ODH.Component("dashboard"), + }) + if err != nil { + return fmt.Errorf("error listing component deployments %w", err) + } + // test any one deployment for ownerreference + if len(appDeployments.Items) != 0 && appDeployments.Items[0].OwnerReferences[0].Kind != "Dashboard" { + return fmt.Errorf("expected ownerreference not found. Got ownereferrence: %v", + appDeployments.Items[0].OwnerReferences) + } + + return nil +} + +// Verify Dashboard instance is in Ready phase when dashboard deployments are up and running. +func (tc *DashboardTestCtx) validateDashboardReady() error { + // wait for 2 mins which is on the safe side, normally it should get ready once all components are ready + err := tc.testCtx.wait(func(ctx context.Context) (bool, error) { + key := types.NamespacedName{Name: tc.testDashboardInstance.Name} + dashboard := &componentsv1.Dashboard{} + + err := tc.testCtx.customClient.Get(ctx, key, dashboard) + if err != nil { + return false, err + } + return dashboard.Status.Phase == "Ready", nil + }) + + if err != nil { + return fmt.Errorf("error waiting Ready state for Dashboard %v: %w", tc.testDashboardInstance.Name, err) + } + + return nil +} + +func (tc *DashboardTestCtx) testUpdateOnDashboardResources() error { + // Test Updating Dashboard Replicas + + appDeployments, err := tc.testCtx.kubeClient.AppsV1().Deployments(tc.testCtx.applicationsNamespace).List(tc.testCtx.ctx, metav1.ListOptions{ + LabelSelector: labels.ODH.Component("dashboard"), + }) + if err != nil { + return err + } + + if len(appDeployments.Items) != 1 { + return fmt.Errorf("error getting deployment for component %s", "dashboard") + } + + const expectedReplica int32 = 3 + + testDeployment := appDeployments.Items[0] + patchedReplica := &autoscalingv1.Scale{ + ObjectMeta: metav1.ObjectMeta{ + Name: testDeployment.Name, + Namespace: testDeployment.Namespace, + }, + Spec: autoscalingv1.ScaleSpec{ + Replicas: expectedReplica, + }, + Status: autoscalingv1.ScaleStatus{}, + } + updatedDep, err := tc.testCtx.kubeClient.AppsV1().Deployments(tc.testCtx.applicationsNamespace).UpdateScale(tc.testCtx.ctx, + testDeployment.Name, patchedReplica, metav1.UpdateOptions{}) + if err != nil { + return fmt.Errorf("error patching component resources : %w", err) + } + if updatedDep.Spec.Replicas != patchedReplica.Spec.Replicas { + return fmt.Errorf("failed to patch replicas : expect to be %v but got %v", patchedReplica.Spec.Replicas, updatedDep.Spec.Replicas) + } + + // Sleep for 40 seconds to allow the operator to reconcile + // we expect it should not revert back to original value because of AllowList + time.Sleep(4 * generalRetryInterval) + reconciledDep, err := tc.testCtx.kubeClient.AppsV1().Deployments(tc.testCtx.applicationsNamespace).Get(tc.testCtx.ctx, testDeployment.Name, metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("error getting component resource after reconcile: %w", err) + } + if *reconciledDep.Spec.Replicas != expectedReplica { + return fmt.Errorf("failed to revert back replicas : expect to be %v but got %v", expectedReplica, *reconciledDep.Spec.Replicas) + } + + return nil +} + +func (tc *DashboardTestCtx) testUpdateDashboardComponentDisabled() error { + // Test Updating dashboard to be disabled + var dashboardDeploymentName string + + if tc.testCtx.testDsc.Spec.Components.Dashboard.ManagementState == operatorv1.Managed { + appDeployments, err := tc.testCtx.kubeClient.AppsV1().Deployments(tc.testCtx.applicationsNamespace).List(tc.testCtx.ctx, metav1.ListOptions{ + LabelSelector: labels.ODH.Component("dashboard"), + }) + if err != nil { + return fmt.Errorf("error getting enabled component %v", "dashboard") + } + if len(appDeployments.Items) > 0 { + dashboardDeploymentName = appDeployments.Items[0].Name + if appDeployments.Items[0].Status.ReadyReplicas == 0 { + return fmt.Errorf("error getting enabled component: %s its deployment 'ReadyReplicas'", dashboardDeploymentName) + } + } + } else { + return errors.New("dashboard spec should be in 'enabled: true' state in order to perform test") + } + + // Disable component Dashboard + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // refresh the instance in case it was updated during the reconcile + err := tc.testCtx.customClient.Get(tc.testCtx.ctx, types.NamespacedName{Name: tc.testCtx.testDsc.Name}, tc.testCtx.testDsc) + if err != nil { + return fmt.Errorf("error getting resource %w", err) + } + // Disable the Component + tc.testCtx.testDsc.Spec.Components.Dashboard.ManagementState = operatorv1.Removed + + // Try to update + err = tc.testCtx.customClient.Update(tc.testCtx.ctx, tc.testCtx.testDsc) + // Return err itself here (not wrapped inside another error) + // so that RetryOnConflict can identify it correctly. + if err != nil { + return fmt.Errorf("error updating component from 'enabled: true' to 'enabled: false': %w", err) + } + + return nil + }) + if err != nil { + return fmt.Errorf("error after retry %w", err) + } + + // Verify dashboard CR is deleted + dashboard := &componentsv1.Dashboard{} + err = tc.testCtx.customClient.Get(tc.testCtx.ctx, client.ObjectKey{Name: tc.testDashboardInstance.Name}, dashboard) + if err == nil { + return fmt.Errorf("component %v is disabled, should not get the Dashboard CR %v", "dashboard", tc.testDashboardInstance.Name) + } else if !k8serr.IsNotFound(err) { + return err + } + + // Sleep for 20 seconds to allow the operator to reconcile + time.Sleep(2 * generalRetryInterval) + _, err = tc.testCtx.kubeClient.AppsV1().Deployments(tc.testCtx.applicationsNamespace).Get(tc.testCtx.ctx, dashboardDeploymentName, metav1.GetOptions{}) + if err != nil { + if k8serr.IsNotFound(err) { + return nil // correct result: should not find deployment after we disable it already + } + return fmt.Errorf("error getting component resource after reconcile: %w", err) + } + return fmt.Errorf("component %v is disabled, should not get its deployment %v from NS %v any more", + "dashboard", + dashboardDeploymentName, + tc.testCtx.applicationsNamespace) +} diff --git a/tests/e2e/deletion_test.go b/tests/e2e/deletion_test.go index 654ec01d62a..1d04b6750c6 100644 --- a/tests/e2e/deletion_test.go +++ b/tests/e2e/deletion_test.go @@ -1,43 +1,28 @@ package e2e_test import ( - "context" "fmt" - "log" "testing" "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/wait" "sigs.k8s.io/controller-runtime/pkg/client" dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" - "github.com/opendatahub-io/opendatahub-operator/v2/components" - "github.com/opendatahub-io/opendatahub-operator/v2/pkg/metadata/labels" ) func deletionTestSuite(t *testing.T) { testCtx, err := NewTestContext() require.NoError(t, err) - // pre-check before deletion - t.Run("Ensure all components created", func(t *testing.T) { - err = testCtx.testAllComponentCreation(t) - require.NoError(t, err, "Not all components are created") - }) - t.Run(testCtx.testDsc.Name, func(t *testing.T) { t.Run("Deletion DSC instance", func(t *testing.T) { err = testCtx.testDeletionExistDSC() require.NoError(t, err, "Error to delete DSC instance") }) - t.Run("Check all component resource are deleted", func(t *testing.T) { - err = testCtx.testAllApplicationDeletion(t) - require.NoError(t, err, "Should not found component exist") - }) + t.Run("Deletion DSCI instance", func(t *testing.T) { err = testCtx.testDeletionExistDSCI() require.NoError(t, err, "Error to delete DSCI instance") @@ -66,46 +51,6 @@ func (tc *testContext) testDeletionExistDSC() error { return nil } -func (tc *testContext) testComponentDeletion(component components.ComponentInterface) error { - // Deletion of Deployments - if err := wait.PollUntilContextTimeout(tc.ctx, generalRetryInterval, componentDeletionTimeout, true, func(ctx context.Context) (bool, error) { - appList, err := tc.kubeClient.AppsV1().Deployments(tc.applicationsNamespace).List(ctx, metav1.ListOptions{ - LabelSelector: labels.ODH.Component(component.GetComponentName()), - }) - if err != nil { - log.Printf("error getting component deployments :%v. Trying again...", err) - - return false, err - } - - return len(appList.Items) == 0, nil - }); err != nil { - return fmt.Errorf("error to find component still exist: %v", component.GetComponentName()) - } - - return nil -} - -func (tc *testContext) testAllApplicationDeletion(t *testing.T) error { //nolint:thelper - // Deletion all listed components' deployments - - components, err := tc.testDsc.GetComponents() - if err != nil { - return err - } - - for _, c := range components { - c := c - t.Run("Delete "+c.GetComponentName(), func(t *testing.T) { - t.Parallel() - err = tc.testComponentDeletion(c) - require.NoError(t, err) - }) - } - - return nil -} - // To test if DSCI CR is in the cluster and no problem to delete it // if fail on any of these two conditios, fail test. func (tc *testContext) testDeletionExistDSCI() error { diff --git a/tests/e2e/helper_test.go b/tests/e2e/helper_test.go index 3de13ee0b90..987788c393e 100644 --- a/tests/e2e/helper_test.go +++ b/tests/e2e/helper_test.go @@ -1,3 +1,4 @@ +//nolint:unused package e2e_test import ( @@ -21,12 +22,13 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/opendatahub-io/opendatahub-operator/v2/apis/components" + componentsv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/components/v1" dscv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" infrav1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/infrastructure/v1" - "github.com/opendatahub-io/opendatahub-operator/v2/components" + componentsold "github.com/opendatahub-io/opendatahub-operator/v2/components" "github.com/opendatahub-io/opendatahub-operator/v2/components/codeflare" - "github.com/opendatahub-io/opendatahub-operator/v2/components/dashboard" "github.com/opendatahub-io/opendatahub-operator/v2/components/datasciencepipelines" "github.com/opendatahub-io/opendatahub-operator/v2/components/kserve" "github.com/opendatahub-io/opendatahub-operator/v2/components/kueue" @@ -102,7 +104,7 @@ func setupDSCICR(name string) *dsciv1.DSCInitialization { Name: "data-science-smcp", Namespace: "istio-system", }, - ManagementState: "Managed", + ManagementState: "Removed", }, }, } @@ -117,61 +119,61 @@ func setupDSCInstance(name string) *dscv1.DataScienceCluster { Spec: dscv1.DataScienceClusterSpec{ Components: dscv1.Components{ // keep dashboard as enabled, because other test is rely on this - Dashboard: dashboard.Dashboard{ + Dashboard: componentsv1.DSCDashboard{ Component: components.Component{ ManagementState: operatorv1.Managed, }, }, Workbenches: workbenches.Workbenches{ - Component: components.Component{ - ManagementState: operatorv1.Managed, + Component: componentsold.Component{ + ManagementState: operatorv1.Removed, }, }, ModelMeshServing: modelmeshserving.ModelMeshServing{ - Component: components.Component{ - ManagementState: operatorv1.Managed, + Component: componentsold.Component{ + ManagementState: operatorv1.Removed, }, }, DataSciencePipelines: datasciencepipelines.DataSciencePipelines{ - Component: components.Component{ - ManagementState: operatorv1.Managed, + Component: componentsold.Component{ + ManagementState: operatorv1.Removed, }, }, Kserve: kserve.Kserve{ - Component: components.Component{ - ManagementState: operatorv1.Managed, + Component: componentsold.Component{ + ManagementState: operatorv1.Removed, }, Serving: infrav1.ServingSpec{ - ManagementState: operatorv1.Managed, + ManagementState: operatorv1.Removed, }, }, CodeFlare: codeflare.CodeFlare{ - Component: components.Component{ - ManagementState: operatorv1.Managed, + Component: componentsold.Component{ + ManagementState: operatorv1.Removed, }, }, Ray: ray.Ray{ - Component: components.Component{ - ManagementState: operatorv1.Managed, + Component: componentsold.Component{ + ManagementState: operatorv1.Removed, }, }, Kueue: kueue.Kueue{ - Component: components.Component{ - ManagementState: operatorv1.Managed, + Component: componentsold.Component{ + ManagementState: operatorv1.Removed, }, }, TrustyAI: trustyai.TrustyAI{ - Component: components.Component{ - ManagementState: operatorv1.Managed, + Component: componentsold.Component{ + ManagementState: operatorv1.Removed, }, }, ModelRegistry: modelregistry.ModelRegistry{ - Component: components.Component{ - ManagementState: operatorv1.Managed, + Component: componentsold.Component{ + ManagementState: operatorv1.Removed, }, }, TrainingOperator: trainingoperator.TrainingOperator{ - Component: components.Component{ + Component: componentsold.Component{ ManagementState: operatorv1.Removed, }, }, diff --git a/tests/e2e/odh_manager_test.go b/tests/e2e/odh_manager_test.go index 2c3e8208156..f087dd24df2 100644 --- a/tests/e2e/odh_manager_test.go +++ b/tests/e2e/odh_manager_test.go @@ -37,4 +37,11 @@ func (tc *testContext) validateOwnedCRDs(t *testing.T) { require.NoErrorf(t, tc.validateCRD("featuretrackers.features.opendatahub.io"), "error in validating CRD : featuretrackers.features.opendatahub.io") }) + + // Validate component CRDs + t.Run("Validate Dashboard CRD", func(t *testing.T) { + t.Parallel() + require.NoErrorf(t, tc.validateCRD("dashboards.components.opendatahub.io"), + "error in validating CRD : featuretrackers.features.opendatahub.io") + }) }