@@ -26,6 +26,7 @@ import (
2626 "k8s.io/apimachinery/pkg/types"
2727
2828 corev1 "k8s.io/api/core/v1"
29+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2930
3031 keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
3132 "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
@@ -503,4 +504,185 @@ var _ = Describe("OctaviaAPI controller", func() {
503504 }, timeout , interval ).Should (Succeed ())
504505 })
505506 })
507+
508+ When ("ApplicationCredential consumer finalizer is managed" , func () {
509+ var (
510+ acSecretName string
511+ servicePasswordSecret * corev1.Secret
512+ )
513+
514+ BeforeEach (func () {
515+ keystoneAPIName := keystone .CreateKeystoneAPI (namespace )
516+ DeferCleanup (keystone .DeleteKeystoneAPI , keystoneAPIName )
517+ keystoneInternalEndpoint := fmt .Sprintf ("http://keystone-for-%s-internal" , octaviaAPIName .Name )
518+ keystonePublicEndpoint := fmt .Sprintf ("http://keystone-for-%s-public" , octaviaAPIName .Name )
519+ SimulateKeystoneReady (keystoneAPIName , keystonePublicEndpoint , keystoneInternalEndpoint )
520+
521+ servicePasswordSecret = CreateOctaviaSecret (namespace )
522+ DeferCleanup (k8sClient .Delete , ctx , servicePasswordSecret )
523+ DeferCleanup (k8sClient .Delete , ctx , CreateTransportURLSecret (transportURLSecretName ))
524+
525+ acSecretName = "ac-octavia-a1b2c-secret" //nolint:gosec // G101
526+ secret := & corev1.Secret {
527+ ObjectMeta : metav1.ObjectMeta {
528+ Namespace : namespace ,
529+ Name : acSecretName ,
530+ },
531+ Data : map [string ][]byte {
532+ keystonev1 .ACIDSecretKey : []byte ("a1b2ctest-ac-id" ),
533+ keystonev1 .ACSecretSecretKey : []byte ("test-ac-secret" ),
534+ },
535+ }
536+ DeferCleanup (k8sClient .Delete , ctx , secret )
537+ Expect (k8sClient .Create (ctx , secret )).To (Succeed ())
538+
539+ spec ["auth" ] = map [string ]any {
540+ "applicationCredentialSecret" : acSecretName ,
541+ }
542+ DeferCleanup (th .DeleteInstance , CreateOctaviaAPI (octaviaAPIName , spec ))
543+
544+ mariaDBDatabaseName := mariadb .CreateMariaDBDatabase (namespace , octavia .DatabaseCRName , mariadbv1.MariaDBDatabaseSpec {})
545+ mariaDBDatabase := mariadb .GetMariaDBDatabase (mariaDBDatabaseName )
546+ DeferCleanup (k8sClient .Delete , ctx , mariaDBDatabase )
547+
548+ octaviaAPI := GetOctaviaAPI (octaviaAPIName )
549+ apiMariaDBAccount , apiMariaDBSecret := mariadb .CreateMariaDBAccountAndSecret (
550+ types.NamespacedName {
551+ Namespace : namespace ,
552+ Name : octaviaAPI .Spec .DatabaseAccount ,
553+ }, mariadbv1.MariaDBAccountSpec {})
554+ DeferCleanup (k8sClient .Delete , ctx , apiMariaDBAccount )
555+ DeferCleanup (k8sClient .Delete , ctx , apiMariaDBSecret )
556+
557+ mariaDBDatabaseName = mariadb .CreateMariaDBDatabase (namespace , octavia .PersistenceDatabaseCRName , mariadbv1.MariaDBDatabaseSpec {})
558+ mariaDBDatabase = mariadb .GetMariaDBDatabase (mariaDBDatabaseName )
559+ DeferCleanup (k8sClient .Delete , ctx , mariaDBDatabase )
560+
561+ apiMariaDBAccount , apiMariaDBSecret = mariadb .CreateMariaDBAccountAndSecret (
562+ types.NamespacedName {
563+ Namespace : namespace ,
564+ Name : octaviaAPI .Spec .PersistenceDatabaseAccount ,
565+ }, mariadbv1.MariaDBAccountSpec {})
566+ DeferCleanup (k8sClient .Delete , ctx , apiMariaDBAccount )
567+ DeferCleanup (k8sClient .Delete , ctx , apiMariaDBSecret )
568+
569+ ovndbCluster := ovn .CreateOVNDBCluster (nil , namespace ,
570+ ovnv1.OVNDBClusterSpec {
571+ OVNDBClusterSpecCore : ovnv1.OVNDBClusterSpecCore {
572+ DBType : ovnv1 .NBDBType ,
573+ }})
574+ ovndb := ovn .GetOVNDBCluster (ovndbCluster )
575+ DeferCleanup (k8sClient .Delete , ctx , ovndb )
576+ Eventually (func (g Gomega ) {
577+ ovndb .Status .InternalDBAddress = OVNNBDBEndpoint
578+ g .Expect (k8sClient .Status ().Update (ctx , ovndb )).To (Succeed ())
579+ }).Should (Succeed ())
580+ ovn .SimulateOVNDBClusterReady (ovndbCluster )
581+
582+ ovndbCluster = ovn .CreateOVNDBCluster (nil , namespace ,
583+ ovnv1.OVNDBClusterSpec {
584+ OVNDBClusterSpecCore : ovnv1.OVNDBClusterSpecCore {
585+ DBType : ovnv1 .SBDBType ,
586+ }})
587+ ovndb = ovn .GetOVNDBCluster (ovndbCluster )
588+ DeferCleanup (k8sClient .Delete , ctx , ovndb )
589+ Eventually (func (g Gomega ) {
590+ ovndb .Status .InternalDBAddress = OVNSBDBEndpoint
591+ g .Expect (k8sClient .Status ().Update (ctx , ovndb )).To (Succeed ())
592+ }).Should (Succeed ())
593+ ovn .SimulateOVNDBClusterReady (ovndbCluster )
594+ })
595+
596+ It ("should add the consumer finalizer to the AC secret" , func () {
597+ Eventually (func (g Gomega ) {
598+ secret := th .GetSecret (types.NamespacedName {
599+ Namespace : namespace ,
600+ Name : acSecretName ,
601+ })
602+ g .Expect (secret .Finalizers ).To (
603+ ContainElement (octavia .ACConsumerFinalizer ))
604+ }, timeout , interval ).Should (Succeed ())
605+ })
606+
607+ It ("should track the consumed AC secret in status" , func () {
608+ Eventually (func (g Gomega ) {
609+ o := GetOctaviaAPI (octaviaAPIName )
610+ g .Expect (o .Status .ApplicationCredentialSecret ).To (Equal (acSecretName ))
611+ }, timeout , interval ).Should (Succeed ())
612+ })
613+
614+ It ("should move the finalizer from the old to the new secret on rotation" , func () {
615+ Eventually (func (g Gomega ) {
616+ secret := th .GetSecret (types.NamespacedName {
617+ Namespace : namespace ,
618+ Name : acSecretName ,
619+ })
620+ g .Expect (secret .Finalizers ).To (
621+ ContainElement (octavia .ACConsumerFinalizer ))
622+ }, timeout , interval ).Should (Succeed ())
623+
624+ newACSecretName := "ac-octavia-x9y8z-secret" //nolint:gosec // G101
625+ newSecret := & corev1.Secret {
626+ ObjectMeta : metav1.ObjectMeta {
627+ Namespace : namespace ,
628+ Name : newACSecretName ,
629+ },
630+ Data : map [string ][]byte {
631+ keystonev1 .ACIDSecretKey : []byte ("x9y8zrotated-ac-id" ),
632+ keystonev1 .ACSecretSecretKey : []byte ("rotated-ac-secret" ),
633+ },
634+ }
635+ DeferCleanup (k8sClient .Delete , ctx , newSecret )
636+ Expect (k8sClient .Create (ctx , newSecret )).To (Succeed ())
637+
638+ Eventually (func (g Gomega ) {
639+ o := GetOctaviaAPI (octaviaAPIName )
640+ o .Spec .Auth .ApplicationCredentialSecret = newACSecretName
641+ g .Expect (k8sClient .Update (ctx , o )).Should (Succeed ())
642+ }, timeout , interval ).Should (Succeed ())
643+
644+ Eventually (func (g Gomega ) {
645+ secret := th .GetSecret (types.NamespacedName {
646+ Namespace : namespace ,
647+ Name : newACSecretName ,
648+ })
649+ g .Expect (secret .Finalizers ).To (
650+ ContainElement (octavia .ACConsumerFinalizer ))
651+ }, timeout , interval ).Should (Succeed ())
652+
653+ Eventually (func (g Gomega ) {
654+ secret := th .GetSecret (types.NamespacedName {
655+ Namespace : namespace ,
656+ Name : acSecretName ,
657+ })
658+ g .Expect (secret .Finalizers ).NotTo (
659+ ContainElement (octavia .ACConsumerFinalizer ))
660+ }, timeout , interval ).Should (Succeed ())
661+
662+ Eventually (func (g Gomega ) {
663+ o := GetOctaviaAPI (octaviaAPIName )
664+ g .Expect (o .Status .ApplicationCredentialSecret ).To (Equal (newACSecretName ))
665+ }, timeout , interval ).Should (Succeed ())
666+ })
667+
668+ It ("should remove the consumer finalizer from AC secret on CR deletion" , func () {
669+ Eventually (func (g Gomega ) {
670+ secret := th .GetSecret (types.NamespacedName {
671+ Namespace : namespace ,
672+ Name : acSecretName ,
673+ })
674+ g .Expect (secret .Finalizers ).To (
675+ ContainElement (octavia .ACConsumerFinalizer ))
676+ }, timeout , interval ).Should (Succeed ())
677+
678+ th .DeleteInstance (GetOctaviaAPI (octaviaAPIName ))
679+
680+ secret := th .GetSecret (types.NamespacedName {
681+ Namespace : namespace ,
682+ Name : acSecretName ,
683+ })
684+ Expect (secret .Finalizers ).NotTo (
685+ ContainElement (octavia .ACConsumerFinalizer ))
686+ })
687+ })
506688})
0 commit comments