Skip to content

Commit ff2d053

Browse files
committed
use system MariaDBAccount for the galera server's root pw
This commit ties together the previous ones to create a new MariaDBAccount when a Galera instance is created, and then to use the password from that account/secret in the mariadb bootstrap/maintenance scripts. Galera gets bootstrapped with this secret, then the mariadbaccount controller, who is waiting for galera to be available to set up this new "root" account, wakes up when galera is running, and changes the root password to itself, establishing the initial job hash for the mariadbaccount. As we now have a mariadbaccount linked to the outermost lifecycle of a galera instance, some hardening of the deletion process has been added to clarify that mariadbaccount will run deletion jobs only if Galera is not marked for deletion. If galera is marked for deletion, then we have to assume the service/pods are gone and no more drops can take place, even if the Galera CR is still present (chainsaw conveniently adds its own finalizer to Galera when running, preventing it from being fully deleted, which exposed this issue).
1 parent a1ccbd6 commit ff2d053

File tree

17 files changed

+346
-63
lines changed

17 files changed

+346
-63
lines changed

api/bases/mariadb.openstack.org_galeras.yaml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,18 @@ spec:
133133
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
134134
type: object
135135
type: object
136+
rootDatabaseAccount:
137+
description: |-
138+
RootDatabaseAccount - name of MariaDBAccount which will be used to
139+
generate root account / password.
140+
this account is generated if not exists, and a name is chosen based
141+
on a naming convention if not present
142+
type: string
136143
secret:
137-
description: Name of the secret to look for password keys
144+
description: |-
145+
Name of the legacy secret to locate the initial galera root
146+
password
147+
this field will be removed once scripts can adjust to using root_auth.sh
138148
type: string
139149
storageClass:
140150
description: Storage class to host the mariadb databases
@@ -173,7 +183,6 @@ spec:
173183
required:
174184
- containerImage
175185
- replicas
176-
- secret
177186
- storageClass
178187
- storageRequest
179188
type: object
@@ -292,6 +301,9 @@ spec:
292301
the opentack-operator in the top-level CR (e.g. the ContainerImage)
293302
format: int64
294303
type: integer
304+
rootDatabaseSecret:
305+
description: name of the Secret that is being used for the root password
306+
type: string
295307
safeToBootstrap:
296308
description: Name of the node that can safely bootstrap a cluster
297309
type: string

api/v1beta1/conditions.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ const (
4848
// ReasonDBServiceNameError - error getting the DB service hostname
4949
ReasonDBServiceNameError condition.Reason = "DatabaseServiceNameError"
5050

51+
// ReasonDBResourceDeleted - the galera resource has been marked for deletion
52+
ReasonDBResourceDeleted condition.Reason = "DatabaseResourceDeleted"
53+
5154
// ReasonDBSync - Database sync in progress
5255
ReasonDBSync condition.Reason = "DBSync"
5356
)
@@ -82,8 +85,12 @@ const (
8285

8386
MariaDBServerNotBootstrappedMessage = "MariaDB / Galera server not bootstrapped"
8487

88+
MariaDBServerDeletedMessage = "MariaDB / Galera server has been marked for deletion"
89+
8590
MariaDBAccountReadyInitMessage = "MariaDBAccount create / drop not started"
8691

92+
MariaDBSystemAccountReadyMessage = "MariaDBAccount System account '%s' creation complete"
93+
8794
MariaDBAccountReadyMessage = "MariaDBAccount creation complete"
8895

8996
MariaDBAccountNotReadyMessage = "MariaDBAccount is not present: %s"

api/v1beta1/galera_types.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,19 @@ type GaleraSpec struct {
5151

5252
// GaleraSpec defines the desired state of Galera
5353
type GaleraSpecCore struct {
54-
// Name of the secret to look for password keys
55-
// +kubebuilder:validation:Required
54+
// Name of the legacy secret to locate the initial galera root
55+
// password
56+
// this field will be removed once scripts can adjust to using root_auth.sh
57+
// +kubebuilder:validation:Optional
5658
Secret string `json:"secret"`
59+
60+
// RootDatabaseAccount - name of MariaDBAccount which will be used to
61+
// generate root account / password.
62+
// this account is generated if not exists, and a name is chosen based
63+
// on a naming convention if not present
64+
// +kubebuilder:validation:Optional
65+
RootDatabaseAccount string `json:"rootDatabaseAccount"`
66+
5767
// Storage class to host the mariadb databases
5868
// +kubebuilder:validation:Required
5969
StorageClass string `json:"storageClass"`
@@ -113,6 +123,9 @@ type GaleraAttributes struct {
113123
type GaleraStatus struct {
114124
// A map of database node attributes for each pod
115125
Attributes map[string]GaleraAttributes `json:"attributes,omitempty"`
126+
// name of the Secret that is being used for the root password
127+
// +kubebuilder:validation:Optional
128+
RootDatabaseSecret string `json:"rootDatabaseSecret"`
116129
// Name of the node that can safely bootstrap a cluster
117130
SafeToBootstrap string `json:"safeToBootstrap,omitempty"`
118131
// Is the galera cluster currently running

api/v1beta1/mariadbaccount_types.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ const (
2828
// AccountDeleteHash hash
2929
AccountDeleteHash = "accountdelete"
3030

31-
// DbRootPassword selector for galera root account
32-
DbRootPasswordSelector = "DbRootPassword"
33-
3431
// DatabasePassword selector for MariaDBAccount->Secret
3532
DatabasePasswordSelector = "DatabasePassword"
3633
)

api/v1beta1/mariadbdatabase_funcs.go

Lines changed: 99 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,50 @@ func DeleteDatabaseAndAccountFinalizers(
541541
namespace string,
542542
) error {
543543

544+
err := DeleteAccountFinalizers(
545+
ctx,
546+
h,
547+
accountName,
548+
namespace,
549+
)
550+
if err != nil {
551+
return err
552+
}
553+
554+
// also do a delete for "unused" MariaDBAccounts, associated with
555+
// this MariaDBDatabase.
556+
err = DeleteUnusedMariaDBAccountFinalizers(
557+
ctx, h, name, accountName, namespace,
558+
)
559+
if err != nil && !k8s_errors.IsNotFound(err) {
560+
return err
561+
}
562+
563+
mariaDBDatabase, err := GetDatabase(ctx, h, name, namespace)
564+
if err != nil && !k8s_errors.IsNotFound(err) {
565+
return err
566+
} else if err == nil && controllerutil.RemoveFinalizer(mariaDBDatabase, h.GetFinalizer()) {
567+
err := h.GetClient().Update(ctx, mariaDBDatabase)
568+
if err != nil && !k8s_errors.IsNotFound(err) {
569+
return err
570+
}
571+
util.LogForObject(h, fmt.Sprintf("Removed finalizer %s from MariaDBDatabase %s", h.GetFinalizer(), mariaDBDatabase.Spec.Name), mariaDBDatabase)
572+
}
573+
574+
return nil
575+
}
576+
577+
// DeleteAccountFinalizers performs just the primary account + secret finalizer
578+
// removal part of DeleteDatabaseAndAccountFinalizers
579+
func DeleteAccountFinalizers(
580+
ctx context.Context,
581+
h *helper.Helper,
582+
accountName string,
583+
namespace string,
584+
) error {
585+
if accountName == "" {
586+
return fmt.Errorf("Account name is blank")
587+
}
544588
databaseAccount, err := GetAccount(ctx, h, accountName, namespace)
545589
if err != nil && !k8s_errors.IsNotFound(err) {
546590
return err
@@ -572,26 +616,6 @@ func DeleteDatabaseAndAccountFinalizers(
572616
}
573617
}
574618

575-
// also do a delete for "unused" MariaDBAccounts, associated with
576-
// this MariaDBDatabase.
577-
err = DeleteUnusedMariaDBAccountFinalizers(
578-
ctx, h, name, accountName, namespace,
579-
)
580-
if err != nil && !k8s_errors.IsNotFound(err) {
581-
return err
582-
}
583-
584-
mariaDBDatabase, err := GetDatabase(ctx, h, name, namespace)
585-
if err != nil && !k8s_errors.IsNotFound(err) {
586-
return err
587-
} else if err == nil && controllerutil.RemoveFinalizer(mariaDBDatabase, h.GetFinalizer()) {
588-
err := h.GetClient().Update(ctx, mariaDBDatabase)
589-
if err != nil && !k8s_errors.IsNotFound(err) {
590-
return err
591-
}
592-
util.LogForObject(h, fmt.Sprintf("Removed finalizer %s from MariaDBDatabase %s", h.GetFinalizer(), mariaDBDatabase.Spec.Name), mariaDBDatabase)
593-
}
594-
595619
return nil
596620
}
597621

@@ -811,6 +835,32 @@ func EnsureMariaDBAccount(ctx context.Context,
811835
userNamePrefix string,
812836
) (*MariaDBAccount, *corev1.Secret, error) {
813837

838+
return ensureMariaDBAccount(
839+
ctx, helper, accountName, namespace, requireTLS,
840+
userNamePrefix, "", "", map[string]string{})
841+
842+
}
843+
844+
// EnsureMariaDBSystemAccount ensures a MariaDBAccount has been created for a given
845+
// operator calling the function, and returns the MariaDBAccount and its
846+
// Secret for use in consumption into a configuration.
847+
// Unlike EnsureMariaDBAccount, the function accepts an exact username that
848+
// expected to remain constant, supporting in-place password changes for the
849+
// account.
850+
func EnsureMariaDBSystemAccount(ctx context.Context,
851+
helper *helper.Helper,
852+
accountName string, galeraInstanceName string, namespace string, requireTLS bool,
853+
exactUserName string, exactPassword string) (*MariaDBAccount, *corev1.Secret, error) {
854+
return ensureMariaDBAccount(
855+
ctx, helper, accountName, namespace, requireTLS,
856+
"", exactUserName, exactPassword, map[string]string{"dbName": galeraInstanceName})
857+
}
858+
859+
func ensureMariaDBAccount(ctx context.Context,
860+
helper *helper.Helper,
861+
accountName string, namespace string, requireTLS bool,
862+
userNamePrefix string, exactUserName string, exactPassword string, labels map[string]string,
863+
) (*MariaDBAccount, *corev1.Secret, error) {
814864
if accountName == "" {
815865
return nil, nil, fmt.Errorf("accountName is empty")
816866
}
@@ -822,9 +872,20 @@ func EnsureMariaDBAccount(ctx context.Context,
822872
return nil, nil, err
823873
}
824874

825-
username, err := generateUniqueUsername(userNamePrefix)
826-
if err != nil {
827-
return nil, nil, err
875+
var username string
876+
var accountType AccountType
877+
878+
if exactUserName == "" {
879+
accountType = "User"
880+
username, err = generateUniqueUsername(userNamePrefix)
881+
if err != nil {
882+
return nil, nil, err
883+
}
884+
} else if userNamePrefix != "" {
885+
return nil, nil, fmt.Errorf("userNamePrefix and exactUserName are mutually exclusive")
886+
} else {
887+
accountType = "System"
888+
username = exactUserName
828889
}
829890

830891
account = &MariaDBAccount{
@@ -837,9 +898,10 @@ func EnsureMariaDBAccount(ctx context.Context,
837898
// MariaDBAccount once this is filled in
838899
},
839900
Spec: MariaDBAccountSpec{
840-
UserName: username,
841-
Secret: fmt.Sprintf("%s-db-secret", accountName),
842-
RequireTLS: requireTLS,
901+
UserName: username,
902+
Secret: fmt.Sprintf("%s-db-secret", accountName),
903+
RequireTLS: requireTLS,
904+
AccountType: accountType,
843905
},
844906
}
845907

@@ -849,6 +911,7 @@ func EnsureMariaDBAccount(ctx context.Context,
849911
if account.Spec.Secret == "" {
850912
account.Spec.Secret = fmt.Sprintf("%s-db-secret", accountName)
851913
}
914+
852915
}
853916

854917
dbSecret, _, err := secret.GetSecret(ctx, helper, account.Spec.Secret, namespace)
@@ -858,9 +921,14 @@ func EnsureMariaDBAccount(ctx context.Context,
858921
return nil, nil, err
859922
}
860923

861-
dbPassword, err := generateDBPassword()
862-
if err != nil {
863-
return nil, nil, err
924+
var dbPassword string
925+
if exactPassword == "" {
926+
dbPassword, err = generateDBPassword()
927+
if err != nil {
928+
return nil, nil, err
929+
}
930+
} else {
931+
dbPassword = exactPassword
864932
}
865933

866934
dbSecret = &corev1.Secret{
@@ -874,7 +942,7 @@ func EnsureMariaDBAccount(ctx context.Context,
874942
}
875943
}
876944

877-
_, err = createOrPatchAccountAndSecret(ctx, helper, account, dbSecret, map[string]string{})
945+
_, err = createOrPatchAccountAndSecret(ctx, helper, account, dbSecret, labels)
878946
if err != nil {
879947
return nil, nil, err
880948
}
@@ -890,6 +958,7 @@ func EnsureMariaDBAccount(ctx context.Context,
890958
)
891959

892960
return account, dbSecret, nil
961+
893962
}
894963

895964
// generateUniqueUsername creates a MySQL-compliant database username based on

config/crd/bases/mariadb.openstack.org_galeras.yaml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,18 @@ spec:
133133
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
134134
type: object
135135
type: object
136+
rootDatabaseAccount:
137+
description: |-
138+
RootDatabaseAccount - name of MariaDBAccount which will be used to
139+
generate root account / password.
140+
this account is generated if not exists, and a name is chosen based
141+
on a naming convention if not present
142+
type: string
136143
secret:
137-
description: Name of the secret to look for password keys
144+
description: |-
145+
Name of the legacy secret to locate the initial galera root
146+
password
147+
this field will be removed once scripts can adjust to using root_auth.sh
138148
type: string
139149
storageClass:
140150
description: Storage class to host the mariadb databases
@@ -173,7 +183,6 @@ spec:
173183
required:
174184
- containerImage
175185
- replicas
176-
- secret
177186
- storageClass
178187
- storageRequest
179188
type: object
@@ -292,6 +301,9 @@ spec:
292301
the opentack-operator in the top-level CR (e.g. the ContainerImage)
293302
format: int64
294303
type: integer
304+
rootDatabaseSecret:
305+
description: name of the Secret that is being used for the root password
306+
type: string
295307
safeToBootstrap:
296308
description: Name of the node that can safely bootstrap a cluster
297309
type: string

0 commit comments

Comments
 (0)