Skip to content

Commit 6bf7113

Browse files
Merge pull request opendatahub-io#133 from gmfrasca/storage-readiness-conditions
Add Database and ObjectStorage Health Checks
2 parents 45e499b + 0c406ff commit 6bf7113

14 files changed

+373
-70
lines changed

api/v1alpha1/dspipeline_types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ type MlPipelineUI struct {
122122
type Database struct {
123123
*MariaDB `json:"mariaDB,omitempty"`
124124
*ExternalDB `json:"externalDB,omitempty"`
125+
// +kubebuilder:default:=false
126+
// +kubebuilder:validation:Optional
127+
DisableHealthCheck bool `json:"disableHealthCheck"`
125128
}
126129

127130
type MariaDB struct {
@@ -151,6 +154,9 @@ type ExternalDB struct {
151154
type ObjectStorage struct {
152155
*Minio `json:"minio,omitempty"`
153156
*ExternalStorage `json:"externalStorage,omitempty"`
157+
// +kubebuilder:default:=false
158+
// +kubebuilder:validation:Optional
159+
DisableHealthCheck bool `json:"disableHealthCheck"`
154160
}
155161

156162
type Minio struct {

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/datasciencepipelinesapplications.opendatahub.io_datasciencepipelinesapplications.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ spec:
138138
mariaDB:
139139
deploy: true
140140
properties:
141+
disableHealthCheck:
142+
default: false
143+
type: boolean
141144
externalDB:
142145
properties:
143146
host:
@@ -431,6 +434,9 @@ spec:
431434
type: object
432435
objectStorage:
433436
properties:
437+
disableHealthCheck:
438+
default: false
439+
type: boolean
434440
externalStorage:
435441
properties:
436442
bucket:

config/samples/dspa_all_fields.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ spec:
7474
# otherwise operator will not deploy DSPA
7575
configMap: ds-pipeline-ui-configmap
7676
database:
77+
disableHealthCheck: false
7778
mariaDB: # mutually exclusive with externalDB
7879
deploy: true
7980
image: registry.redhat.io/rhel8/mariadb-103:1-188
@@ -101,6 +102,7 @@ spec:
101102
# name: somesecret
102103
# key: somekey
103104
objectStorage:
105+
disableHealthCheck: false
104106
minio: # mutually exclusive with externalStorage
105107
deploy: true
106108
image: quay.io/opendatahub/minio:RELEASE.2019-08-14T20-37-41Z-license-compliance

config/samples/dspa_local_dev.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# A simple DSPA with the Database and ObjectStore Health Checks Disabled
2+
#
3+
# Since the default database and storage options leverage internal Services,
4+
# a locally-run DSPO that manages an external cluster (common development practice)
5+
# would not be able to run the pre-deploy health checks on these prerequisite components
6+
# and therefore the DSPA will never fully deploy without disabling them, as this DSPA sample does
7+
apiVersion: datasciencepipelinesapplications.opendatahub.io/v1alpha1
8+
kind: DataSciencePipelinesApplication
9+
metadata:
10+
name: sample
11+
spec:
12+
database:
13+
disableHealthCheck: true
14+
objectStorage:
15+
disableHealthCheck: true
16+
minio:
17+
image: 'quay.io/opendatahub/minio:RELEASE.2019-08-14T20-37-41Z-license-compliance'
18+
mlpipelineUI:
19+
image: 'quay.io/opendatahub/odh-ml-pipelines-frontend-container:beta-ui'

controllers/config/defaults.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ const (
6969

7070
// DSPA Status Condition Types
7171
const (
72+
DatabaseAvailable = "DatabaseAvailable"
73+
ObjectStoreAvailable = "ObjectStoreAvailable"
7274
APIServerReady = "APIServerReady"
7375
PersistenceAgentReady = "PersistenceAgentReady"
7476
ScheduledWorkflowReady = "ScheduledWorkflowReady"
@@ -81,9 +83,10 @@ const (
8183
// kubectl get output, and in summarizing
8284
// occurrences of causes
8385
const (
84-
MinimumReplicasAvailable = "MinimumReplicasAvailable"
85-
FailingToDeploy = "FailingToDeploy"
86-
Deploying = "Deploying"
86+
MinimumReplicasAvailable = "MinimumReplicasAvailable"
87+
FailingToDeploy = "FailingToDeploy"
88+
Deploying = "Deploying"
89+
ComponentDeploymentNotFound = "ComponentDeploymentNotFound"
8790
)
8891

8992
// Any required Configmap paths can be added here,

controllers/database.go

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ package controllers
1717

1818
import (
1919
"context"
20+
"database/sql"
21+
b64 "encoding/base64"
22+
"fmt"
23+
24+
_ "github.com/go-sql-driver/mysql"
2025

2126
dspav1alpha1 "github.com/opendatahub-io/data-science-pipelines-operator/api/v1alpha1"
2227
)
@@ -31,6 +36,52 @@ var dbTemplates = []string{
3136
dbSecret,
3237
}
3338

39+
// extract to var for mocking in testing
40+
var ConnectAndQueryDatabase = func(host, port, username, password, dbname string) bool {
41+
connectionString := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", username, password, host, port, dbname)
42+
db, err := sql.Open("mysql", connectionString)
43+
if err != nil {
44+
return false
45+
}
46+
defer db.Close()
47+
48+
testStatement := "SELECT 1;"
49+
_, err = db.Exec(testStatement)
50+
return err == nil
51+
}
52+
53+
func (r *DSPAReconciler) isDatabaseAccessible(ctx context.Context, dsp *dspav1alpha1.DataSciencePipelinesApplication,
54+
params *DSPAParams) bool {
55+
log := r.Log.WithValues("namespace", dsp.Namespace).WithValues("dspa_name", dsp.Name)
56+
57+
if params.DatabaseHealthCheckDisabled(dsp) {
58+
log.V(1).Info("Database health check disabled, assuming database is available and ready.")
59+
return true
60+
}
61+
62+
log.Info("Performing Database Health Check")
63+
databaseSpecified := dsp.Spec.Database != nil
64+
usingExternalDB := params.UsingExternalDB(dsp)
65+
usingMariaDB := !databaseSpecified || dsp.Spec.Database.MariaDB != nil
66+
if !usingMariaDB && !usingExternalDB {
67+
log.Info("Could not connect to Database: Unsupported Type")
68+
return false
69+
}
70+
71+
decodePass, _ := b64.StdEncoding.DecodeString(params.DBConnection.Password)
72+
dbHealthCheckPassed := ConnectAndQueryDatabase(params.DBConnection.Host,
73+
params.DBConnection.Port,
74+
params.DBConnection.Username,
75+
string(decodePass),
76+
params.DBConnection.DBName)
77+
if dbHealthCheckPassed {
78+
log.Info("Database Health Check Successful")
79+
} else {
80+
log.Info("Unable to connect to Database")
81+
}
82+
return dbHealthCheckPassed
83+
}
84+
3485
func (r *DSPAReconciler) ReconcileDatabase(ctx context.Context, dsp *dspav1alpha1.DataSciencePipelinesApplication,
3586
params *DSPAParams) error {
3687

@@ -40,8 +91,12 @@ func (r *DSPAReconciler) ReconcileDatabase(ctx context.Context, dsp *dspav1alpha
4091
// DB field can be specified as an empty obj, confirm that subfields are also specified
4192
// By default if Database is empty, we deploy mariadb
4293
externalDBSpecified := params.UsingExternalDB(dsp)
43-
mariaDBSpecified := !databaseSpecified || dsp.Spec.Database.MariaDB != nil
44-
deployMariaDB := !databaseSpecified || (mariaDBSpecified && dsp.Spec.Database.MariaDB.Deploy)
94+
mariaDBSpecified := dsp.Spec.Database.MariaDB != nil
95+
defaultDBRequired := !databaseSpecified || (!externalDBSpecified && !mariaDBSpecified)
96+
97+
deployMariaDB := mariaDBSpecified && dsp.Spec.Database.MariaDB.Deploy
98+
// Default DB is currently MariaDB as well, but storing these bools seperately in case that changes
99+
deployDefaultDB := !databaseSpecified || defaultDBRequired
45100

46101
// If external db is specified, it takes precedence
47102
if externalDBSpecified {
@@ -52,7 +107,7 @@ func (r *DSPAReconciler) ReconcileDatabase(ctx context.Context, dsp *dspav1alpha
52107
if err != nil {
53108
return err
54109
}
55-
} else if deployMariaDB {
110+
} else if deployMariaDB || deployDefaultDB {
56111
log.Info("Applying mariaDB resources.")
57112
for _, template := range dbTemplates {
58113
err := r.Apply(dsp, params, template)
@@ -65,6 +120,8 @@ func (r *DSPAReconciler) ReconcileDatabase(ctx context.Context, dsp *dspav1alpha
65120
// desired state.
66121
if !databaseSpecified {
67122
dsp.Spec.Database = &dspav1alpha1.Database{}
123+
}
124+
if !databaseSpecified || defaultDBRequired {
68125
dsp.Spec.Database.MariaDB = params.MariaDB.DeepCopy()
69126
dsp.Spec.Database.MariaDB.Deploy = true
70127
if err := r.Update(ctx, dsp); err != nil {

0 commit comments

Comments
 (0)