Skip to content

Commit 3527102

Browse files
zzzeekclaude
andcommitted
Get MYSQL_PWD using an on-demand cluster query
In order to facilitate an in-place change to the name of the Secret that is referenced by a Galera instance for the mysql root password, rework the approach used by pods and shell scripts to no longer require the root secret name and/or password be passed by environment variable, instead using a pod-level cluster query to retrieve the current root password. The logic to retrieve this password is encapsulated into a single shell script that is present as a volume mount on running containers. This allows Job objects to be created with hashes that do not link to a specific Secret name, as well as to create StatefulSet objects that don't refer to this name. When the Secret name changes on a Galera instance for an in-place root password change, the hashes / CRs for these objects will remain unchanged. A subsequent change to the mariadb operator will add the ability to change the mysql root password of a Galera cluster using a dual-reference architecture where the "current" root secret will be part of <CR>/Status, while the secret referenced in <CR>/Spec will be the "new" root secret. When these two names differ, that will indicate an in-place password change should take place, as well as allowing the pre-existing root password to be available at the same time as the new one in order to do a root password change. The same architecture will be applied to a new class of "system" MariaDBAccount objects that are for use only by the Galera instance itself and do not have a link to any MariaDBDatabase CR. The Galera CR itself will no longer use osp-secret for the mysql root password nor will the secret be directly referenced from the Galera CR, instead referenced by a "system" MariaDBAccount CR which the Galera operator itself will create. 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 5cb294a commit 3527102

File tree

29 files changed

+352
-168
lines changed

29 files changed

+352
-168
lines changed

controllers/galera_controller.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,16 @@ func (r *GaleraReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res
495495
Resources: []string{"services"},
496496
Verbs: []string{"get", "list", "update", "patch"},
497497
},
498+
{
499+
APIGroups: []string{"mariadb.openstack.org"},
500+
Resources: []string{"galeras"},
501+
Verbs: []string{"get", "list"},
502+
},
503+
{
504+
APIGroups: []string{""},
505+
Resources: []string{"secrets"},
506+
Verbs: []string{"get"},
507+
},
498508
}
499509
rbacResult, err := common_rbac.ReconcileRbac(ctx, helper, instance, rbacRules)
500510
if err != nil {
@@ -948,19 +958,21 @@ func (r *GaleraReconciler) generateConfigMaps(
948958
) error {
949959
log := GetLog(ctx, "galera")
950960
templateParameters := map[string]any{
951-
"logToDisk": instance.Spec.LogToDisk,
961+
"logToDisk": instance.Spec.LogToDisk,
962+
"galeraInstanceName": instance.Name,
952963
}
953964
customData := make(map[string]string)
954965
customData[mariadbv1.CustomServiceConfigFile] = instance.Spec.CustomServiceConfig
955966

956967
cms := []util.Template{
957968
// ScriptsConfigMap
958969
{
959-
Name: configMapNameForScripts(instance),
960-
Namespace: instance.Namespace,
961-
Type: util.TemplateTypeScripts,
962-
InstanceType: instance.Kind,
963-
Labels: map[string]string{},
970+
Name: configMapNameForScripts(instance),
971+
Namespace: instance.Namespace,
972+
Type: util.TemplateTypeScripts,
973+
InstanceType: instance.Kind,
974+
Labels: map[string]string{},
975+
ConfigOptions: templateParameters,
964976
},
965977
// ConfigMap
966978
{

controllers/mariadbaccount_controller.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,14 +243,13 @@ func (r *MariaDBAccountReconciler) reconcileCreate(
243243
return ctrl.Result{}, err
244244
}
245245

246-
var dbAdminSecret, dbContainerImage, serviceAccountName string
246+
var dbContainerImage, serviceAccountName string
247247

248248
if !dbGalera.Status.Bootstrapped {
249249
log.Info("DB bootstrap not complete. Requeue...")
250250
return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil
251251
}
252252

253-
dbAdminSecret = dbGalera.Spec.Secret
254253
dbContainerImage = dbGalera.Spec.ContainerImage
255254
serviceAccountName = dbGalera.RbacResourceName()
256255

@@ -289,7 +288,7 @@ func (r *MariaDBAccountReconciler) reconcileCreate(
289288

290289
log.Info(fmt.Sprintf("Running account create '%s' MariaDBDatabase '%s'", instance.Name, mariadbDatabaseName))
291290

292-
jobDef, err := mariadb.CreateDbAccountJob(instance, mariadbDatabase.Spec.Name, dbHostname, dbAdminSecret, dbContainerImage, serviceAccountName, dbGalera.Spec.NodeSelector)
291+
jobDef, err := mariadb.CreateDbAccountJob(dbGalera, instance, mariadbDatabase.Spec.Name, dbHostname, dbContainerImage, serviceAccountName, dbGalera.Spec.NodeSelector)
293292
if err != nil {
294293
return ctrl.Result{}, err
295294
}
@@ -480,7 +479,7 @@ func (r *MariaDBAccountReconciler) reconcileDelete(
480479
}
481480
}
482481

483-
var dbAdminSecret, dbContainerImage, serviceAccountName string
482+
var dbContainerImage, serviceAccountName string
484483

485484
if !dbGalera.Status.Bootstrapped {
486485
log.Info("DB bootstrap not complete. Requeue...")
@@ -495,7 +494,6 @@ func (r *MariaDBAccountReconciler) reconcileDelete(
495494
return ctrl.Result{RequeueAfter: time.Second * 10}, nil
496495
}
497496

498-
dbAdminSecret = dbGalera.Spec.Secret
499497
dbContainerImage = dbGalera.Spec.ContainerImage
500498
serviceAccountName = dbGalera.RbacResourceName()
501499

@@ -514,7 +512,7 @@ func (r *MariaDBAccountReconciler) reconcileDelete(
514512

515513
log.Info(fmt.Sprintf("Running account delete '%s' MariaDBDatabase '%s'", instance.Name, mariadbDatabaseName))
516514

517-
jobDef, err := mariadb.DeleteDbAccountJob(instance, mariadbDatabase.Spec.Name, dbHostname, dbAdminSecret, dbContainerImage, serviceAccountName, dbGalera.Spec.NodeSelector)
515+
jobDef, err := mariadb.DeleteDbAccountJob(dbGalera, instance, mariadbDatabase.Spec.Name, dbHostname, dbContainerImage, serviceAccountName, dbGalera.Spec.NodeSelector)
518516
if err != nil {
519517
return ctrl.Result{}, err
520518
}

controllers/mariadbdatabase_controller.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ func (r *MariaDBDatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Requ
165165
//
166166
// Non-deletion (normal) flow follows
167167
//
168-
var dbSecret, dbContainerImage, serviceAccount string
168+
var dbContainerImage, serviceAccount string
169169
// NOTE(dciabrin) When configured to only allow TLS connections, all clients
170170
// accessing this DB must support client connection via TLS.
171171
useTLS := dbGalera.Spec.TLS.Enabled() && dbGalera.Spec.DisableNonTLSListeners
@@ -183,7 +183,6 @@ func (r *MariaDBDatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Requ
183183
return ctrl.Result{RequeueAfter: time.Second * 10}, nil
184184
}
185185

186-
dbSecret = dbGalera.Spec.Secret
187186
dbContainerImage = dbGalera.Spec.ContainerImage
188187
serviceAccount = dbGalera.RbacResourceName()
189188

@@ -199,7 +198,7 @@ func (r *MariaDBDatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Requ
199198
)
200199

201200
// Define a new Job object (hostname, password, containerImage)
202-
jobDef, err := mariadb.DbDatabaseJob(instance, dbHostname, dbSecret, dbContainerImage, serviceAccount, useTLS, dbGalera.Spec.NodeSelector)
201+
jobDef, err := mariadb.DbDatabaseJob(dbGalera, instance, dbHostname, dbContainerImage, serviceAccount, useTLS, dbGalera.Spec.NodeSelector)
203202
if err != nil {
204203
return ctrl.Result{}, err
205204
}

pkg/mariadb/account.go

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"strings"
66

77
util "github.com/openstack-k8s-operators/lib-common/modules/common/util"
8-
databasev1beta1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"
8+
mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"
99
batchv1 "k8s.io/api/batch/v1"
1010
corev1 "k8s.io/api/core/v1"
1111
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -20,7 +20,7 @@ type accountCreateOrDeleteOptions struct {
2020
}
2121

2222
// CreateDbAccountJob creates a Kubernetes job for creating a MariaDB database account
23-
func CreateDbAccountJob(account *databasev1beta1.MariaDBAccount, databaseName string, databaseHostName string, databaseSecret string, containerImage string, serviceAccountName string, nodeSelector *map[string]string) (*batchv1.Job, error) {
23+
func CreateDbAccountJob(galera *mariadbv1.Galera, account *mariadbv1.MariaDBAccount, databaseName string, databaseHostName string, containerImage string, serviceAccountName string, nodeSelector *map[string]string) (*batchv1.Job, error) {
2424
var tlsStatement string
2525
if account.Spec.RequireTLS {
2626
tlsStatement = " REQUIRE SSL"
@@ -62,31 +62,22 @@ func CreateDbAccountJob(account *databasev1beta1.MariaDBAccount, databaseName st
6262
Image: containerImage,
6363
Command: []string{"/bin/sh", "-c", dbCmd},
6464
Env: []corev1.EnvVar{
65-
{
66-
Name: "MYSQL_PWD",
67-
ValueFrom: &corev1.EnvVarSource{
68-
SecretKeyRef: &corev1.SecretKeySelector{
69-
LocalObjectReference: corev1.LocalObjectReference{
70-
Name: databaseSecret,
71-
},
72-
Key: databasev1beta1.DbRootPasswordSelector,
73-
},
74-
},
75-
},
7665
{
7766
Name: "DatabasePassword",
7867
ValueFrom: &corev1.EnvVarSource{
7968
SecretKeyRef: &corev1.SecretKeySelector{
8069
LocalObjectReference: corev1.LocalObjectReference{
8170
Name: account.Spec.Secret,
8271
},
83-
Key: databasev1beta1.DatabasePasswordSelector,
72+
Key: mariadbv1.DatabasePasswordSelector,
8473
},
8574
},
8675
},
8776
},
77+
VolumeMounts: getGaleraRootOnlyVolumeMounts(),
8878
},
8979
},
80+
Volumes: getGaleraRootOnlyVolumes(galera),
9081
},
9182
},
9283
},
@@ -100,7 +91,7 @@ func CreateDbAccountJob(account *databasev1beta1.MariaDBAccount, databaseName st
10091
}
10192

10293
// DeleteDbAccountJob creates a Kubernetes job for deleting a MariaDB database account
103-
func DeleteDbAccountJob(account *databasev1beta1.MariaDBAccount, databaseName string, databaseHostName string, databaseSecret string, containerImage string, serviceAccountName string, nodeSelector *map[string]string) (*batchv1.Job, error) {
94+
func DeleteDbAccountJob(galera *mariadbv1.Galera, account *mariadbv1.MariaDBAccount, databaseName string, databaseHostName string, containerImage string, serviceAccountName string, nodeSelector *map[string]string) (*batchv1.Job, error) {
10495

10596
opts := accountCreateOrDeleteOptions{account.Spec.UserName, databaseName, databaseHostName, "root", ""}
10697

@@ -124,24 +115,13 @@ func DeleteDbAccountJob(account *databasev1beta1.MariaDBAccount, databaseName st
124115
ServiceAccountName: serviceAccountName,
125116
Containers: []corev1.Container{
126117
{
127-
Name: "mariadb-account-delete",
128-
Image: containerImage,
129-
Command: []string{"/bin/sh", "-c", delCmd},
130-
Env: []corev1.EnvVar{
131-
{
132-
Name: "MYSQL_PWD",
133-
ValueFrom: &corev1.EnvVarSource{
134-
SecretKeyRef: &corev1.SecretKeySelector{
135-
LocalObjectReference: corev1.LocalObjectReference{
136-
Name: databaseSecret,
137-
},
138-
Key: databasev1beta1.DbRootPasswordSelector,
139-
},
140-
},
141-
},
142-
},
118+
Name: "mariadb-account-delete",
119+
Image: containerImage,
120+
Command: []string{"/bin/sh", "-c", delCmd},
121+
VolumeMounts: getGaleraRootOnlyVolumeMounts(),
143122
},
144123
},
124+
Volumes: getGaleraRootOnlyVolumes(galera),
145125
},
146126
},
147127
},

pkg/mariadb/database.go

Lines changed: 18 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"strings"
55

66
util "github.com/openstack-k8s-operators/lib-common/modules/common/util"
7-
databasev1beta1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"
7+
mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"
88
batchv1 "k8s.io/api/batch/v1"
99
corev1 "k8s.io/api/core/v1"
1010
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -20,7 +20,7 @@ type dbCreateOptions struct {
2020
}
2121

2222
// DbDatabaseJob -
23-
func DbDatabaseJob(database *databasev1beta1.MariaDBDatabase, databaseHostName string, databaseSecret string, containerImage string, serviceAccountName string, useTLS bool, nodeSelector *map[string]string) (*batchv1.Job, error) {
23+
func DbDatabaseJob(galera *mariadbv1.Galera, database *mariadbv1.MariaDBDatabase, databaseHostName string, containerImage string, serviceAccountName string, useTLS bool, nodeSelector *map[string]string) (*batchv1.Job, error) {
2424
var tlsStatement string
2525
if useTLS {
2626
tlsStatement = " REQUIRE SSL"
@@ -48,17 +48,6 @@ func DbDatabaseJob(database *databasev1beta1.MariaDBDatabase, databaseHostName s
4848

4949
if database.Spec.Secret != nil {
5050
scriptEnv = []corev1.EnvVar{
51-
{
52-
Name: "MYSQL_PWD",
53-
ValueFrom: &corev1.EnvVarSource{
54-
SecretKeyRef: &corev1.SecretKeySelector{
55-
LocalObjectReference: corev1.LocalObjectReference{
56-
Name: databaseSecret,
57-
},
58-
Key: "DbRootPassword",
59-
},
60-
},
61-
},
6251
// send deprecated Secret field but only if non-nil
6352
{
6453
Name: "DatabasePassword",
@@ -73,19 +62,7 @@ func DbDatabaseJob(database *databasev1beta1.MariaDBDatabase, databaseHostName s
7362
},
7463
}
7564
} else {
76-
scriptEnv = []corev1.EnvVar{
77-
{
78-
Name: "MYSQL_PWD",
79-
ValueFrom: &corev1.EnvVarSource{
80-
SecretKeyRef: &corev1.SecretKeySelector{
81-
LocalObjectReference: corev1.LocalObjectReference{
82-
Name: databaseSecret,
83-
},
84-
Key: "DbRootPassword",
85-
},
86-
},
87-
},
88-
}
65+
scriptEnv = []corev1.EnvVar{}
8966
}
9067

9168
job := &batchv1.Job{
@@ -104,12 +81,14 @@ func DbDatabaseJob(database *databasev1beta1.MariaDBDatabase, databaseHostName s
10481
ServiceAccountName: serviceAccountName,
10582
Containers: []corev1.Container{
10683
{
107-
Name: "mariadb-database-create",
108-
Image: containerImage,
109-
Command: []string{"/bin/sh", "-c", dbCmd},
110-
Env: scriptEnv,
84+
Name: "mariadb-database-create",
85+
Image: containerImage,
86+
Command: []string{"/bin/sh", "-c", dbCmd},
87+
Env: scriptEnv,
88+
VolumeMounts: getGaleraRootOnlyVolumeMounts(),
11189
},
11290
},
91+
Volumes: getGaleraRootOnlyVolumes(galera),
11392
},
11493
},
11594
},
@@ -123,7 +102,7 @@ func DbDatabaseJob(database *databasev1beta1.MariaDBDatabase, databaseHostName s
123102
}
124103

125104
// DeleteDbDatabaseJob -
126-
func DeleteDbDatabaseJob(database *databasev1beta1.MariaDBDatabase, databaseHostName string, databaseSecret string, containerImage string, serviceAccountName string, nodeSelector *map[string]string) (*batchv1.Job, error) {
105+
func DeleteDbDatabaseJob(galera *mariadbv1.Galera, database *mariadbv1.MariaDBDatabase, databaseHostName string, containerImage string, serviceAccountName string, nodeSelector *map[string]string) (*batchv1.Job, error) {
127106

128107
opts := dbCreateOptions{
129108
database.Spec.Name,
@@ -145,17 +124,6 @@ func DeleteDbDatabaseJob(database *databasev1beta1.MariaDBDatabase, databaseHost
145124

146125
if database.Spec.Secret != nil {
147126
scriptEnv = []corev1.EnvVar{
148-
{
149-
Name: "MYSQL_PWD",
150-
ValueFrom: &corev1.EnvVarSource{
151-
SecretKeyRef: &corev1.SecretKeySelector{
152-
LocalObjectReference: corev1.LocalObjectReference{
153-
Name: databaseSecret,
154-
},
155-
Key: databasev1beta1.DbRootPasswordSelector,
156-
},
157-
},
158-
},
159127
// send deprecated Secret field but only if non-nil. otherwise
160128
// the script should not try to drop usernames from mysql.user
161129
{
@@ -165,25 +133,13 @@ func DeleteDbDatabaseJob(database *databasev1beta1.MariaDBDatabase, databaseHost
165133
LocalObjectReference: corev1.LocalObjectReference{
166134
Name: *database.Spec.Secret,
167135
},
168-
Key: databasev1beta1.DatabasePasswordSelector,
136+
Key: mariadbv1.DatabasePasswordSelector,
169137
},
170138
},
171139
},
172140
}
173141
} else {
174-
scriptEnv = []corev1.EnvVar{
175-
{
176-
Name: "MYSQL_PWD",
177-
ValueFrom: &corev1.EnvVarSource{
178-
SecretKeyRef: &corev1.SecretKeySelector{
179-
LocalObjectReference: corev1.LocalObjectReference{
180-
Name: databaseSecret,
181-
},
182-
Key: databasev1beta1.DbRootPasswordSelector,
183-
},
184-
},
185-
},
186-
}
142+
scriptEnv = []corev1.EnvVar{}
187143
}
188144

189145
job := &batchv1.Job{
@@ -199,12 +155,14 @@ func DeleteDbDatabaseJob(database *databasev1beta1.MariaDBDatabase, databaseHost
199155
ServiceAccountName: serviceAccountName,
200156
Containers: []corev1.Container{
201157
{
202-
Name: "mariadb-database-create",
203-
Image: containerImage,
204-
Command: []string{"/bin/sh", "-c", delCmd},
205-
Env: scriptEnv,
158+
Name: "mariadb-database-create",
159+
Image: containerImage,
160+
Command: []string{"/bin/sh", "-c", delCmd},
161+
Env: scriptEnv,
162+
VolumeMounts: getGaleraRootOnlyVolumeMounts(),
206163
},
207164
},
165+
Volumes: getGaleraRootOnlyVolumes(galera),
208166
},
209167
},
210168
},

pkg/mariadb/statefulset.go

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -104,16 +104,6 @@ func getGaleraInitContainers(g *mariadbv1.Galera) []corev1.Container {
104104
}, {
105105
Name: "KOLLA_CONFIG_STRATEGY",
106106
Value: "COPY_ALWAYS",
107-
}, {
108-
Name: "DB_ROOT_PASSWORD",
109-
ValueFrom: &corev1.EnvVarSource{
110-
SecretKeyRef: &corev1.SecretKeySelector{
111-
LocalObjectReference: corev1.LocalObjectReference{
112-
Name: g.Spec.Secret,
113-
},
114-
Key: "DbRootPassword",
115-
},
116-
},
117107
}},
118108
Resources: g.Spec.Resources,
119109
VolumeMounts: getGaleraInitVolumeMounts(g),
@@ -132,16 +122,6 @@ func getGaleraContainers(g *mariadbv1.Galera, configHash string) []corev1.Contai
132122
}, {
133123
Name: "KOLLA_CONFIG_STRATEGY",
134124
Value: "COPY_ALWAYS",
135-
}, {
136-
Name: "DB_ROOT_PASSWORD",
137-
ValueFrom: &corev1.EnvVarSource{
138-
SecretKeyRef: &corev1.SecretKeySelector{
139-
LocalObjectReference: corev1.LocalObjectReference{
140-
Name: g.Spec.Secret,
141-
},
142-
Key: "DbRootPassword",
143-
},
144-
},
145125
}},
146126
Ports: []corev1.ContainerPort{{
147127
ContainerPort: 3306,

0 commit comments

Comments
 (0)