Skip to content

Commit e311b40

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 6bb0ca8 commit e311b40

File tree

19 files changed

+353
-65
lines changed

19 files changed

+353
-65
lines changed

api/bases/mariadb.openstack.org_galeras.yaml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,18 @@ spec:
137137
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
138138
type: object
139139
type: object
140+
rootDatabaseAccount:
141+
description: |-
142+
RootDatabaseAccount - name of MariaDBAccount which will be used to
143+
generate root account / password.
144+
this account is generated if not exists, and a name is chosen based
145+
on a naming convention if not present
146+
type: string
140147
secret:
141-
description: Name of the secret to look for password keys
148+
description: |-
149+
Name of the legacy secret to locate the initial galera root
150+
password
151+
this field will be removed once scripts can adjust to using root_auth.sh
142152
type: string
143153
storageClass:
144154
description: Storage class to host the mariadb databases
@@ -177,7 +187,6 @@ spec:
177187
required:
178188
- containerImage
179189
- replicas
180-
- secret
181190
- storageClass
182191
- storageRequest
183192
type: object
@@ -296,6 +305,9 @@ spec:
296305
the opentack-operator in the top-level CR (e.g. the ContainerImage)
297306
format: int64
298307
type: integer
308+
rootDatabaseSecret:
309+
description: name of the Secret that is being used for the root password
310+
type: string
299311
safeToBootstrap:
300312
description: Name of the node that can safely bootstrap a cluster
301313
type: string

api/v1beta1/conditions.go

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

57+
// ReasonDBResourceDeleted - the galera resource has been marked for deletion
58+
ReasonDBResourceDeleted condition.Reason = "DatabaseResourceDeleted"
59+
5760
// ReasonDBSync - Database sync in progress
5861
ReasonDBSync condition.Reason = "DBSync"
5962
)
@@ -92,8 +95,12 @@ const (
9295

9396
MariaDBServerNotBootstrappedMessage = "MariaDB / Galera server not bootstrapped"
9497

98+
MariaDBServerDeletedMessage = "MariaDB / Galera server has been marked for deletion"
99+
95100
MariaDBAccountReadyInitMessage = "MariaDBAccount create / drop not started"
96101

102+
MariaDBSystemAccountReadyMessage = "MariaDBAccount System account '%s' creation complete"
103+
97104
MariaDBAccountReadyMessage = "MariaDBAccount creation complete"
98105

99106
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
@@ -137,8 +137,18 @@ spec:
137137
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
138138
type: object
139139
type: object
140+
rootDatabaseAccount:
141+
description: |-
142+
RootDatabaseAccount - name of MariaDBAccount which will be used to
143+
generate root account / password.
144+
this account is generated if not exists, and a name is chosen based
145+
on a naming convention if not present
146+
type: string
140147
secret:
141-
description: Name of the secret to look for password keys
148+
description: |-
149+
Name of the legacy secret to locate the initial galera root
150+
password
151+
this field will be removed once scripts can adjust to using root_auth.sh
142152
type: string
143153
storageClass:
144154
description: Storage class to host the mariadb databases
@@ -177,7 +187,6 @@ spec:
177187
required:
178188
- containerImage
179189
- replicas
180-
- secret
181190
- storageClass
182191
- storageRequest
183192
type: object
@@ -296,6 +305,9 @@ spec:
296305
the opentack-operator in the top-level CR (e.g. the ContainerImage)
297306
format: int64
298307
type: integer
308+
rootDatabaseSecret:
309+
description: name of the Secret that is being used for the root password
310+
type: string
299311
safeToBootstrap:
300312
description: Name of the node that can safely bootstrap a cluster
301313
type: string

0 commit comments

Comments
 (0)