@@ -27,12 +27,12 @@ import (
2727 helper "github.com/openstack-k8s-operators/lib-common/modules/common/helper"
2828 job "github.com/openstack-k8s-operators/lib-common/modules/common/job"
2929 "github.com/openstack-k8s-operators/lib-common/modules/common/secret"
30+ util "github.com/openstack-k8s-operators/lib-common/modules/common/util"
3031 databasev1beta1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"
3132 mariadb "github.com/openstack-k8s-operators/mariadb-operator/pkg/mariadb"
3233 k8s_errors "k8s.io/apimachinery/pkg/api/errors"
3334 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3435 "k8s.io/apimachinery/pkg/runtime"
35- "k8s.io/apimachinery/pkg/types"
3636 "k8s.io/client-go/kubernetes"
3737 ctrl "sigs.k8s.io/controller-runtime"
3838 "sigs.k8s.io/controller-runtime/pkg/client"
@@ -168,28 +168,10 @@ func (r *MariaDBAccountReconciler) reconcileCreate(
168168
169169 // account create
170170
171- // ensure secret is present before running a job
172- _ , secretResult , err := secret .VerifySecret (
173- ctx ,
174- types.NamespacedName {Name : instance .Spec .Secret , Namespace : instance .Namespace },
175- []string {databasev1beta1 .DatabasePasswordSelector },
176- r .Client ,
177- time .Duration (30 )* time .Second ,
178- )
179- if (err != nil || secretResult != ctrl.Result {}) {
180- // Since the account secret should have been manually created by the user and referenced in the spec,
181- // we treat this as a warning because it means that the service will not be able to start.
182- instance .Status .Conditions .Set (condition .FalseCondition (
183- databasev1beta1 .MariaDBAccountReadyCondition ,
184- secret .ReasonSecretMissing ,
185- condition .SeverityWarning ,
186- databasev1beta1 .MariaDBAccountSecretNotReadyMessage , err ))
187-
188- log .Info (fmt .Sprintf (
189- "MariaDBAccount '%s' didn't find Secret '%s'; requeueing" ,
190- instance .Name , instance .Spec .Secret ))
191-
192- return secretResult , client .IgnoreNotFound (err )
171+ // ensure secret is present, add a finalizer for mariadbaccount
172+ result , err = r .ensureAccountSecret (ctx , log , helper , instance )
173+ if (result != ctrl.Result {} || err != nil ) {
174+ return result , err
193175 }
194176
195177 log .Info (fmt .Sprintf ("Running account create '%s' MariaDBDatabase '%s'" ,
@@ -291,7 +273,11 @@ func (r *MariaDBAccountReconciler) reconcileDelete(
291273 // implemented in the database either, so remove all finalizers and
292274 // exit
293275 if k8s_errors .IsNotFound (err ) {
294- // remove finalizer from the MariaDBDatabase instance
276+ // remove MariaDBAccount finalizer from MariaDBDatabase - this takes the
277+ // form such as openstack.org/mariadbaccount-<accountname> (this naming
278+ // scheme allows multiple MariaDBAccounts to claim the same MariaDBDatabase
279+ // as a dependency) and allows a delete of the MariaDBDatabase to proceed
280+ // assuming no other finalizers
295281 if controllerutil .RemoveFinalizer (mariadbDatabase , fmt .Sprintf ("%s-%s" , helper .GetFinalizer (), instance .Name )) {
296282 err = r .Update (ctx , mariadbDatabase )
297283
@@ -301,10 +287,12 @@ func (r *MariaDBAccountReconciler) reconcileDelete(
301287
302288 }
303289
304- // remove local finalizer
305- controllerutil .RemoveFinalizer (instance , helper .GetFinalizer ())
306-
307- return ctrl.Result {}, nil
290+ // remove finalizer "openstack.org/mariadbaccount" from both the
291+ // MariaDBAccount as well as the Secret which is referenced from the
292+ // MariaDBAccount, allowing both to be deleted assuming no other
293+ // finalizers
294+ err = r .removeAccountAndSecretFinalizer (ctx , helper , instance )
295+ return ctrl.Result {}, err
308296 } else if dbGalera == nil {
309297 return result , err
310298 }
@@ -342,18 +330,24 @@ func (r *MariaDBAccountReconciler) reconcileDelete(
342330 log .Info (fmt .Sprintf ("Job %s hash added - %s" , jobDef .Name , instance .Status .Hash [databasev1beta1 .AccountDeleteHash ]))
343331 }
344332
345- // first, remove finalizer from the MariaDBDatabase instance
333+ // remove MariaDBAccount finalizer from MariaDBDatabase - this takes the
334+ // form such as openstack.org/mariadbaccount-<accountname> (this naming
335+ // scheme allows multiple MariaDBAccounts to claim the same MariaDBDatabase
336+ // as a dependency) and allows a delete of the MariaDBDatabase to proceed
337+ // assuming no other finalizers
346338 if controllerutil .RemoveFinalizer (mariadbDatabase , fmt .Sprintf ("%s-%s" , helper .GetFinalizer (), instance .Name )) {
347339 err = r .Update (ctx , mariadbDatabase )
348340 if err != nil {
349341 return ctrl.Result {}, err
350342 }
351343 }
352344
353- // then remove finalizer from our own instance
354- controllerutil .RemoveFinalizer (instance , helper .GetFinalizer ())
345+ // remove finalizer "openstack.org/mariadbaccount" from
346+ // both the MariaDBAccount as well as the Secret which is referenced
347+ // from the MariaDBAccount, allowing both to be deleted
348+ err = r .removeAccountAndSecretFinalizer (ctx , helper , instance )
355349
356- return ctrl.Result {}, nil
350+ return ctrl.Result {}, err
357351}
358352
359353// getMariaDBDatabaseForCreate - waits for a MariaDBDatabase to be available in preparation
@@ -446,23 +440,35 @@ func (r *MariaDBAccountReconciler) getMariaDBDatabaseForDelete(ctx context.Conte
446440 instance .Name ,
447441 ))
448442
449- controllerutil .RemoveFinalizer (instance , helper .GetFinalizer ())
450- return nil , ctrl.Result {}, nil
443+ // tried to locate the MariaDBDatabase for this MariaDBAccount,
444+ // but the MariaDBAccount does not reference one. Therefore this
445+ // MariaDBAccount doesn't actually exist in any database and is
446+ // safe to be deleted.
447+ // So remove finalizer "openstack.org/mariadbaccount" from
448+ // both the MariaDBAccount as well as the Secret which is referenced
449+ // from the MariaDBAccount, allowing both to be deleted
450+ err := r .removeAccountAndSecretFinalizer (ctx , helper , instance )
451+ return nil , ctrl.Result {}, err
451452 }
452453
453454 // locate the MariaDBDatabase object itself
454455 mariadbDatabase , err := r .getMariaDBDatabaseObject (ctx , instance , mariadbDatabaseName )
455456
456457 if err != nil {
457458 if k8s_errors .IsNotFound (err ) {
458- // not found. this implies MariaDBAccount has no database-level
459- // entry either. Remove MariaDBAccount / secret finalizers and return
460459 log .Info (fmt .Sprintf (
461460 "MariaDBAccount '%s' Didn't find MariaDBDatabase '%s'; no account delete needed" ,
462461 instance .Name , mariadbDatabaseName ))
463462
464- controllerutil .RemoveFinalizer (instance , helper .GetFinalizer ())
465- return nil , ctrl.Result {}, nil
463+ // tried to locate the MariaDBDatabase for this MariaDBAccount,
464+ // but it no longer exists (or never did). Therefore this
465+ // MariaDBAccount doesn't actually exist in any database and is
466+ // safe to be deleted.
467+ // So remove finalizer "openstack.org/mariadbaccount" from
468+ // both the MariaDBAccount as well as the Secret which is referenced
469+ // from the MariaDBAccount, allowing both to be deleted
470+ err = r .removeAccountAndSecretFinalizer (ctx , helper , instance )
471+ return nil , ctrl.Result {}, err
466472 } else {
467473 // unhandled error; exit without change
468474 log .Error (err , "unhandled error retrieving MariaDBDatabase instance" )
@@ -484,6 +490,11 @@ func (r *MariaDBAccountReconciler) getMariaDBDatabaseForDelete(ctx context.Conte
484490 "MariaDBAccount '%s' MariaDBDatabase '%s' not yet complete; no account delete needed" ,
485491 instance .Name , mariadbDatabaseName ))
486492
493+ // remove MariaDBAccount finalizer from MariaDBDatabase - this takes
494+ // the form such as openstack.org/mariadbaccount-<accountname> (this
495+ // naming scheme allows multiple MariaDBAccounts to claim the same
496+ // MariaDBDatabase as a dependency) and allows a delete of the
497+ // MariaDBDatabase to proceed assuming no other finalizers
487498 if controllerutil .RemoveFinalizer (mariadbDatabase , fmt .Sprintf ("%s-%s" , helper .GetFinalizer (), instance .Name )) {
488499 err = r .Update (ctx , mariadbDatabase )
489500
@@ -492,8 +503,15 @@ func (r *MariaDBAccountReconciler) getMariaDBDatabaseForDelete(ctx context.Conte
492503 }
493504 }
494505
495- controllerutil .RemoveFinalizer (instance , helper .GetFinalizer ())
496- return nil , ctrl.Result {}, nil
506+ // tried to locate the MariaDBDatabase for this MariaDBAccount, got the
507+ // MariaDBDatabase CR, and saw that it's not in a ready state.
508+ // Therefore this MariaDBAccount doesn't actually exist in any database
509+ // and is safe to be deleted.
510+ // remove finalizer "openstack.org/mariadbaccount" from
511+ // both the MariaDBAccount as well as the Secret which is referenced
512+ // from the MariaDBAccount
513+ err = r .removeAccountAndSecretFinalizer (ctx , helper , instance )
514+ return nil , ctrl.Result {}, err
497515 }
498516
499517 // return MariaDBDatabase where account delete flow will then continue
@@ -572,3 +590,89 @@ func (r *MariaDBAccountReconciler) getMariaDBDatabaseObject(ctx context.Context,
572590 return mariaDBDatabase , nil
573591
574592}
593+
594+ // ensureAccountSecret - ensures the Secret exists, is valid, adds a finalizer.
595+ // includes requeue for secret does not exist
596+ func (r * MariaDBAccountReconciler ) ensureAccountSecret (
597+ ctx context.Context ,
598+ log logr.Logger ,
599+ h * helper.Helper ,
600+ instance * databasev1beta1.MariaDBAccount ,
601+ ) (ctrl.Result , error ) {
602+
603+ secretName := instance .Spec .Secret
604+ secretNamespace := instance .Namespace
605+ secretObj , _ , err := secret .GetSecret (ctx , h , secretName , secretNamespace )
606+ if err != nil {
607+ // Since the account secret should have been manually created by the user and referenced in the spec,
608+ // we treat this as a warning because it means that the service will not be able to start.
609+ if k8s_errors .IsNotFound (err ) {
610+ instance .Status .Conditions .Set (condition .FalseCondition (
611+ databasev1beta1 .MariaDBAccountReadyCondition ,
612+ secret .ReasonSecretMissing ,
613+ condition .SeverityWarning ,
614+ databasev1beta1 .MariaDBAccountSecretNotReadyMessage , err ))
615+
616+ log .Info (fmt .Sprintf (
617+ "MariaDBAccount '%s' didn't find Secret '%s'; requeueing" ,
618+ instance .Name , instance .Spec .Secret ))
619+
620+ return ctrl.Result {RequeueAfter : time .Duration (30 ) * time .Second }, nil
621+
622+ } else {
623+ return ctrl.Result {}, err
624+ }
625+ }
626+
627+ var expectedFields = []string {databasev1beta1 .DatabasePasswordSelector }
628+
629+ // collect the secret values the caller expects to exist
630+ for _ , field := range expectedFields {
631+ _ , ok := secretObj .Data [field ]
632+ if ! ok {
633+ err := fmt .Errorf ("%w: field %s not found in Secret %s" , util .ErrFieldNotFound , field , secretName )
634+ return ctrl.Result {}, err
635+ }
636+ }
637+
638+ // set finalizer "openstack.org/mariadbaccount" on the Secret that the
639+ // MariaDBAccount references in its "secret" field, preventing the Secret
640+ // from being fully deleted as long as the MariaDBAccount maintains this
641+ // finalizer. As this Secret references the database password that was
642+ // used with this MariaDBAccount, the MariaDBAccount itself must have
643+ // access to this Secret as long as it corresponds to a real database
644+ // account
645+ if controllerutil .AddFinalizer (secretObj , h .GetFinalizer ()) {
646+ err = r .Update (ctx , secretObj )
647+ if err != nil {
648+ return ctrl.Result {}, err
649+ }
650+ }
651+
652+ return ctrl.Result {}, err
653+ }
654+
655+ // removeAccountAndSecretFinalizer - removes finalizer from mariadbaccount as well
656+ // as current primary secret
657+ func (r * MariaDBAccountReconciler ) removeAccountAndSecretFinalizer (ctx context.Context ,
658+ helper * helper.Helper , instance * databasev1beta1.MariaDBAccount ) error {
659+
660+ accountSecret , _ , err := secret .GetSecret (ctx , helper , instance .Spec .Secret , instance .Namespace )
661+
662+ if err == nil {
663+ if controllerutil .RemoveFinalizer (accountSecret , helper .GetFinalizer ()) {
664+ err = r .Update (ctx , accountSecret )
665+ if err != nil {
666+ return err
667+ }
668+ }
669+ } else if ! k8s_errors .IsNotFound (err ) {
670+ return err
671+ }
672+
673+ // will take effect when reconcile ends
674+ controllerutil .RemoveFinalizer (instance , helper .GetFinalizer ())
675+
676+ return nil
677+
678+ }
0 commit comments