Skip to content

Commit c33f33b

Browse files
Merge pull request #429 from opendatahub-io/feature-rearchitecture
Feature rearchitecture
2 parents 049e39c + 874b18b commit c33f33b

File tree

16 files changed

+210
-74
lines changed

16 files changed

+210
-74
lines changed

README.md

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,37 @@ This operator is the primary operator for Open Data Hub. It is responsible for e
33
Jupyter Notebooks, Modelmesh serving, Datascience pipelines etc. The operator makes use of `DataScienceCluster` CRD to deploy
44
and configure these applications.
55

6-
## Dev Preview
7-
8-
Developer Preview of the new Open Data Hub operator codebase is now avaible.
9-
Refer [Dev-Preview.md](./docs/Dev-Preview.md) for testing preview features.
10-
116
## Usage
127

138
### Installation
149

15-
The latest version of operator can be installed from the community-operators catalog on OperatorHub. It can also be build
10+
The latest version of operator can be installed from the `community-operators` catalog on `OperatorHub`. It can also be build
1611
and installed from source manually, see the Developer guide for further instructions.
1712

13+
1. Subscribe to operator by creating following subscription
14+
```console
15+
cat <<EOF | oc create -f -
16+
apiVersion: operators.coreos.com/v1alpha1
17+
kind: Subscription
18+
metadata:
19+
name: opendatahub-operator
20+
namespace: openshift-operators
21+
spec:
22+
channel: fast
23+
name: opendatahub-operator
24+
source: community-operators
25+
sourceNamespace: openshift-marketplace
26+
EOF
27+
```
28+
29+
2. Create [DataScienceCluster](#example-datasciencecluster) CR to enable components
30+
31+
## Dev Preview
32+
33+
Developer Preview of the new Open Data Hub operator codebase is now avaible.
34+
Refer [Dev-Preview.md](./docs/Dev-Preview.md) for testing preview features.
35+
36+
1837
### Developer Guide
1938

2039
#### Pre-requisites

apis/datasciencecluster/v1alpha1/datasciencecluster_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import (
3333
// Defines the desired state of DataScienceCluster
3434
type DataScienceClusterSpec struct {
3535
// Override and fine tune specific component configurations.
36-
// +operator-sdk:csv:customresourcedefinitions:type=spec
36+
// +operator-sdk:csv:customresourcedefinitions:type=spec,order=1
3737
Components Components `json:"components,omitempty"`
3838
}
3939

apis/dscinitialization/v1alpha1/dscinitialization_types.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,18 @@ import (
2323
)
2424

2525
// DSCInitializationSpec defines the desired state of DSCInitialization
26+
// +operator-sdk:csv:customresourcedefinitions:order=1
2627
type DSCInitializationSpec struct {
2728
// +kubebuilder:default:=opendatahub
2829
// Namespace for applications to be installed, non-configurable, default to "opendatahub"
29-
// +operator-sdk:csv:customresourcedefinitions:type=spec
30+
// +operator-sdk:csv:customresourcedefinitions:type=spec,order=1
3031
ApplicationsNamespace string `json:"applicationsNamespace"`
3132
// Enable monitoring on specified namespace
32-
// +operator-sdk:csv:customresourcedefinitions:type=spec
33+
// +operator-sdk:csv:customresourcedefinitions:type=spec,order=2
3334
// +optional
3435
Monitoring Monitoring `json:"monitoring,omitempty"`
3536
// Internal development useful field
36-
// +operator-sdk:csv:customresourcedefinitions:type=spec
37+
// +operator-sdk:csv:customresourcedefinitions:type=spec,order=3
3738
// +optional
3839
ManifestsUri string `json:"manifestsUri,omitempty"`
3940
}

bundle/manifests/dashboard.opendatahub.io_odhapplications.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ spec:
118118
type: string
119119
isEnabled:
120120
type: boolean
121+
kfdefApplications:
122+
description: (Deprecated) Apps do not rely on other deployments, they
123+
are deployed by those components.
124+
items:
125+
type: string
126+
type: array
121127
link:
122128
type: string
123129
provider:

bundle/manifests/opendatahub-operator.clusterserviceversion.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,12 @@ spec:
194194
default to "opendatahub"
195195
displayName: Applications Namespace
196196
path: applicationsNamespace
197-
- description: Internal development useful field
198-
displayName: Manifests Uri
199-
path: manifestsUri
200197
- description: Enable monitoring on specified namespace
201198
displayName: Monitoring
202199
path: monitoring
200+
- description: Internal development useful field
201+
displayName: Manifests Uri
202+
path: manifestsUri
203203
statusDescriptors:
204204
- description: Conditions describes the state of the DSCInitializationStatus
205205
resource.

components/dashboard/dashboard.go

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"github.com/opendatahub-io/opendatahub-operator/v2/pkg/common"
99
"github.com/opendatahub-io/opendatahub-operator/v2/pkg/deploy"
1010
routev1 "github.com/openshift/api/route/v1"
11-
apierrs "k8s.io/apimachinery/pkg/api/errors"
1211
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1312
"k8s.io/apimachinery/pkg/runtime"
1413
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -25,6 +24,9 @@ const (
2524
PathOVMS = deploy.DefaultManifestPath + "/" + ComponentName + "/modelserving"
2625
PathODHDashboardConfig = deploy.DefaultManifestPath + "/" + ComponentName + "/odhdashboardconfig"
2726
PathConsoleLink = deploy.DefaultManifestPath + "/" + ComponentName + "/consolelink"
27+
NameConsoleLink = "console"
28+
NamespaceConsoleLink = "openshift-console"
29+
PathAnaconda = deploy.DefaultManifestPath + "/partners/anaconda/base/"
2830
)
2931

3032
var imageParamMap = map[string]string{
@@ -102,6 +104,19 @@ func (d *Dashboard) ReconcileComponent(owner metav1.Object, cli client.Client, s
102104
if err != nil {
103105
return fmt.Errorf("failed to set dashboard OVMS from %s: %v", PathOVMS, err)
104106
}
107+
108+
// Apply anaconda config
109+
err = common.CreateSecret(cli, "anaconda-ce-access", namespace)
110+
if err != nil {
111+
return fmt.Errorf("failed to create access-secret for anaconda: %v", err)
112+
}
113+
err = deploy.DeployManifestsFromPath(owner, cli, ComponentNameSupported,
114+
PathAnaconda,
115+
namespace,
116+
scheme, enabled)
117+
if err != nil {
118+
return fmt.Errorf("failed to deploy anaconda resources from %s: %v", PathAnaconda, err)
119+
}
105120
}
106121

107122
// Update image parameters
@@ -139,6 +154,27 @@ func (d *Dashboard) ReconcileComponent(owner metav1.Object, cli client.Client, s
139154
if err != nil {
140155
return fmt.Errorf("failed to set dashboard ISV from %s: %v", PathISVSM, err)
141156
}
157+
// ConsoleLink handling
158+
consoleRoute := &routev1.Route{}
159+
err = cli.Get(context.TODO(), client.ObjectKey{Name: NameConsoleLink, Namespace: NamespaceConsoleLink}, consoleRoute)
160+
if err != nil {
161+
return fmt.Errorf("error getting console route URL : %v", err)
162+
}
163+
domainIndex := strings.Index(consoleRoute.Spec.Host, ".")
164+
consolelinkDomain := consoleRoute.Spec.Host[domainIndex+1:]
165+
err = common.ReplaceStringsInFile(PathConsoleLink, map[string]string{
166+
"<rhods-dashboard-url>": "https://rhods-dashboard-" + namespace + "." + consolelinkDomain,
167+
})
168+
if err != nil {
169+
return fmt.Errorf("error replacing with correct dashboard url for ConsoleLink: %v", err)
170+
}
171+
err = deploy.DeployManifestsFromPath(owner, cli, ComponentNameSupported,
172+
PathConsoleLink,
173+
namespace,
174+
scheme, enabled)
175+
if err != nil {
176+
return fmt.Errorf("failed to set dashboard consolelink from %s", PathConsoleLink)
177+
}
142178
return err
143179
case deploy.ManagedRhods:
144180
err = deploy.DeployManifestsFromPath(owner, cli, ComponentNameSupported,
@@ -150,14 +186,14 @@ func (d *Dashboard) ReconcileComponent(owner metav1.Object, cli client.Client, s
150186
}
151187
// ConsoleLink handling
152188
consoleRoute := &routev1.Route{}
153-
err = cli.Get(context.TODO(), client.ObjectKey{Name: "console", Namespace: "openshift-console"}, consoleRoute)
154-
if err != nil && !apierrs.IsNotFound(err) {
155-
return fmt.Errorf("Error getting console route URL : %v", err)
189+
err = cli.Get(context.TODO(), client.ObjectKey{Name: NameConsoleLink, Namespace: NamespaceConsoleLink}, consoleRoute)
190+
if err != nil {
191+
return fmt.Errorf("error getting console route URL : %v", err)
156192
}
157193
domainIndex := strings.Index(consoleRoute.Spec.Host, ".")
158194
consolelinkDomain := consoleRoute.Spec.Host[domainIndex+1:]
159195
err = common.ReplaceStringsInFile(PathConsoleLink, map[string]string{
160-
"<rhods-dashboard-url>": "https://rhods-dashboard-" + namespace + consolelinkDomain,
196+
"<rhods-dashboard-url>": "https://rhods-dashboard-" + namespace + "." + consolelinkDomain,
161197
})
162198
if err != nil {
163199
return fmt.Errorf("Error replacing with correct dashboard url for ConsoleLink: %v", err)
@@ -169,13 +205,6 @@ func (d *Dashboard) ReconcileComponent(owner metav1.Object, cli client.Client, s
169205
if err != nil {
170206
return fmt.Errorf("failed to set dashboard consolelink from %s", PathConsoleLink)
171207
}
172-
err = deploy.DeployManifestsFromPath(owner, cli, ComponentNameSupported,
173-
PathConsoleLink,
174-
namespace,
175-
scheme, enabled)
176-
if err != nil {
177-
return fmt.Errorf("failed to set dashboard consolelink from %s", PathConsoleLink)
178-
}
179208
return err
180209
default:
181210
return nil

config/crd/bases/odhapplications.dashboard.opendatahub.io_odhapplications.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ spec:
117117
type: string
118118
isEnabled:
119119
type: boolean
120+
kfdefApplications:
121+
description: "(Deprecated) Apps do not rely on other deployments, they are deployed by those components."
122+
items:
123+
type: string
124+
type: array
120125
link:
121126
type: string
122127
provider:
@@ -161,4 +166,4 @@ status:
161166
kind: ""
162167
plural: ""
163168
conditions: []
164-
storedVersions: []
169+
storedVersions: []

config/manifests/bases/opendatahub-operator.clusterserviceversion.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ spec:
3434
default to "opendatahub"
3535
displayName: Applications Namespace
3636
path: applicationsNamespace
37-
- description: Internal development useful field
38-
displayName: Manifests Uri
39-
path: manifestsUri
4037
- description: Enable monitoring on specified namespace
4138
displayName: Monitoring
4239
path: monitoring
40+
- description: Internal development useful field
41+
displayName: Manifests Uri
42+
path: manifestsUri
4343
statusDescriptors:
4444
- description: Conditions describes the state of the DSCInitializationStatus
4545
resource.

controllers/datasciencecluster/datasciencecluster_controller.go

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/opendatahub-io/opendatahub-operator/v2/components/datasciencepipelines"
3232
"github.com/opendatahub-io/opendatahub-operator/v2/components/kserve"
3333
"github.com/opendatahub-io/opendatahub-operator/v2/components/modelmeshserving"
34+
"github.com/opendatahub-io/opendatahub-operator/v2/components/ray"
3435
"github.com/opendatahub-io/opendatahub-operator/v2/components/workbenches"
3536
appsv1 "k8s.io/api/apps/v1"
3637
netv1 "k8s.io/api/networking/v1"
@@ -114,56 +115,62 @@ func (r *DataScienceClusterReconciler) Reconcile(ctx context.Context, req ctrl.R
114115
}
115116
}
116117

117-
// // Ensure all omitted components show up as explicitly disabled
118-
// instance, err = r.updateComponents(instance)
119-
// if err != nil {
120-
// _ = r.reportError(err, instance, "error updating list of components in the CR")
121-
// return ctrl.Result{}, err
122-
// }
118+
// Ensure all omitted components show up as explicitly disabled
119+
instance, err = r.updateComponents(instance)
120+
if err != nil {
121+
_ = r.reportError(err, instance, "error updating list of components in the CR")
122+
return ctrl.Result{}, err
123+
}
123124

124125
// Initialize error list, instead of returning errors after every component is deployed
125126
componentErrorList := make(map[string]error)
126127

127128
// reconcile dashboard component
128129
if instance, err = r.reconcileSubComponent(instance, dashboard.ComponentName, instance.Spec.Components.Dashboard.Enabled,
129-
&(instance.Spec.Components.Dashboard), ctx); err != nil {
130+
&(instance.Spec.Components.Dashboard)); err != nil {
130131
// no need to log any errors as this is done in the reconcileSubComponent method
131132
componentErrorList[dashboard.ComponentName] = err
132133
}
133134

134135
// reconcile DataSciencePipelines component
135136
if instance, err = r.reconcileSubComponent(instance, datasciencepipelines.ComponentName, instance.Spec.Components.DataSciencePipelines.Enabled,
136-
&(instance.Spec.Components.DataSciencePipelines), ctx); err != nil {
137+
&(instance.Spec.Components.DataSciencePipelines)); err != nil {
137138
// no need to log any errors as this is done in the reconcileSubComponent method
138139
componentErrorList[datasciencepipelines.ComponentName] = err
139140
}
140141

141142
// reconcile Workbench component
142143
if instance, err = r.reconcileSubComponent(instance, workbenches.ComponentName, instance.Spec.Components.Workbenches.Enabled,
143-
&(instance.Spec.Components.Workbenches), ctx); err != nil {
144+
&(instance.Spec.Components.Workbenches)); err != nil {
144145
// no need to log any errors as this is done in the reconcileSubComponent method
145146
componentErrorList[workbenches.ComponentName] = err
146147
}
147148

148149
// reconcile Kserve component
149-
if instance, err = r.reconcileSubComponent(instance, kserve.ComponentName, instance.Spec.Components.Kserve.Enabled, &(instance.Spec.Components.Kserve), ctx); err != nil {
150+
if instance, err = r.reconcileSubComponent(instance, kserve.ComponentName, instance.Spec.Components.Kserve.Enabled, &(instance.Spec.Components.Kserve)); err != nil {
150151
// no need to log any errors as this is done in the reconcileSubComponent method
151152
componentErrorList[kserve.ComponentName] = err
152153
}
153154

154155
// reconcile ModelMesh component
155156
if instance, err = r.reconcileSubComponent(instance, modelmeshserving.ComponentName, instance.Spec.Components.ModelMeshServing.Enabled,
156-
&(instance.Spec.Components.ModelMeshServing), ctx); err != nil {
157+
&(instance.Spec.Components.ModelMeshServing)); err != nil {
157158
// no need to log any errors as this is done in the reconcileSubComponent method
158159
componentErrorList[modelmeshserving.ComponentName] = err
159160
}
160161

161162
// reconcile CodeFlare component
162-
if instance, err = r.reconcileSubComponent(instance, codeflare.ComponentName, instance.Spec.Components.CodeFlare.Enabled, &(instance.Spec.Components.CodeFlare), ctx); err != nil {
163+
if instance, err = r.reconcileSubComponent(instance, codeflare.ComponentName, instance.Spec.Components.CodeFlare.Enabled, &(instance.Spec.Components.CodeFlare)); err != nil {
163164
// no need to log any errors as this is done in the reconcileSubComponent method
164165
componentErrorList[codeflare.ComponentName] = err
165166
}
166167

168+
// reconcile Ray component
169+
if instance, err = r.reconcileSubComponent(instance, ray.ComponentName, instance.Spec.Components.Ray.Enabled, &(instance.Spec.Components.Ray)); err != nil {
170+
// no need to log any errors as this is done in the reconcileSubComponent method
171+
componentErrorList[ray.ComponentName] = err
172+
}
173+
167174
// Process errors for components
168175
if componentErrorList != nil && len(componentErrorList) != 0 {
169176
r.Log.Info("DataScienceCluster Deployment Incomplete.")
@@ -177,12 +184,6 @@ func (r *DataScienceClusterReconciler) Reconcile(ctx context.Context, req ctrl.R
177184
return ctrl.Result{RequeueAfter: time.Second * 10}, fmt.Errorf(fmt.Sprint(componentErrorList))
178185
}
179186

180-
// reconcile Ray component
181-
// if instance, val, err = r.reconcileSubComponent(instance, ray.ComponentName, instance.Spec.Components.Ray.Enabled, &(instance.Spec.Components.Ray), ctx); err != nil {
182-
// // no need to log any errors as this is done in the reconcileSubComponent method
183-
// return val, err
184-
// }
185-
186187
// finalize reconciliation
187188
instance, err = r.updateStatus(instance, func(saved *dsc.DataScienceCluster) {
188189
status.SetCompleteCondition(&saved.Status.Conditions, status.ReconcileCompleted, "DataScienceCluster resource reconciled successfully")
@@ -201,7 +202,7 @@ func (r *DataScienceClusterReconciler) Reconcile(ctx context.Context, req ctrl.R
201202
}
202203

203204
func (r *DataScienceClusterReconciler) reconcileSubComponent(instance *dsc.DataScienceCluster, componentName string, enabled bool,
204-
component components.ComponentInterface, ctx context.Context) (*dsc.DataScienceCluster, error) {
205+
component components.ComponentInterface) (*dsc.DataScienceCluster, error) {
205206

206207
// First set contidions to reflect a component is about to be reconciled
207208
instance, err := r.updateStatus(instance, func(saved *dsc.DataScienceCluster) {
@@ -306,20 +307,20 @@ func (r *DataScienceClusterReconciler) updateStatus(original *dsc.DataScienceClu
306307
return saved, err
307308
}
308309

309-
// func (r *DataScienceClusterReconciler) updateComponents(original *dsc.DataScienceCluster) (*dsc.DataScienceCluster, error) {
310-
// saved := &dsc.DataScienceCluster{}
311-
// err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
312-
313-
// err := r.Client.Get(context.TODO(), client.ObjectKeyFromObject(original), saved)
314-
// if err != nil {
315-
// return err
316-
// }
317-
318-
// // Try to update
319-
// err = r.Client.Update(context.TODO(), saved)
320-
// // Return err itself here (not wrapped inside another error)
321-
// // so that RetryOnConflict can identify it correctly.
322-
// return err
323-
// })
324-
// return saved, err
325-
// }
310+
func (r *DataScienceClusterReconciler) updateComponents(original *dsc.DataScienceCluster) (*dsc.DataScienceCluster, error) {
311+
saved := &dsc.DataScienceCluster{}
312+
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
313+
314+
err := r.Client.Get(context.TODO(), client.ObjectKeyFromObject(original), saved)
315+
if err != nil {
316+
return err
317+
}
318+
319+
// Try to update
320+
err = r.Client.Update(context.TODO(), saved)
321+
// Return err itself here (not wrapped inside another error)
322+
// so that RetryOnConflict can identify it correctly.
323+
return err
324+
})
325+
return saved, err
326+
}

controllers/dscinitialization/dscinitialization_controller.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package dscinitialization
1919
import (
2020
"context"
2121
"errors"
22+
"github.com/opendatahub-io/opendatahub-operator/v2/pkg/common"
2223
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2324

2425
logr "github.com/go-logr/logr"
@@ -163,7 +164,7 @@ func (r *DSCInitializationReconciler) Reconcile(ctx context.Context, req ctrl.Re
163164

164165
// Apply common rhods-specific config
165166
// Create rhods-notebooks namespace
166-
err = r.createOdhNamespace(instance, "rhods-notebooks", ctx)
167+
err = common.CreateNamespace(r.Client, "rhods-notebooks")
167168
if err != nil {
168169
// no need to log error as it was already logged in createOdhNamespace
169170
return reconcile.Result{}, err

0 commit comments

Comments
 (0)