@@ -37,6 +37,7 @@ import (
3737 "github.com/openstack-k8s-operators/lib-common/modules/common/util"
3838 novav1 "github.com/openstack-k8s-operators/nova-operator/api/nova/v1beta1"
3939 controllers "github.com/openstack-k8s-operators/nova-operator/internal/controller/nova"
40+ nova "github.com/openstack-k8s-operators/nova-operator/internal/nova"
4041
4142 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4243
@@ -2157,4 +2158,164 @@ var _ = Describe("application credentials", func() {
21572158 }, timeout , interval ).Should (Succeed ())
21582159 })
21592160 })
2161+
2162+ When ("ApplicationCredential consumer finalizer is managed" , func () {
2163+ var acSecretName string
2164+
2165+ BeforeEach (func () {
2166+ acSecretName = "ac-nova-a1b2c-secret" //nolint:gosec // G101
2167+ ac := & corev1.Secret {
2168+ ObjectMeta : metav1.ObjectMeta {
2169+ Namespace : novaNames .NovaName .Namespace ,
2170+ Name : acSecretName ,
2171+ },
2172+ Data : map [string ][]byte {
2173+ keystonev1 .ACIDSecretKey : []byte ("a1b2ctest-ac-id" ),
2174+ keystonev1 .ACSecretSecretKey : []byte ("test-ac-secret" ),
2175+ },
2176+ }
2177+ DeferCleanup (k8sClient .Delete , ctx , ac )
2178+ Expect (k8sClient .Create (ctx , ac )).To (Succeed ())
2179+
2180+ DeferCleanup (k8sClient .Delete , ctx , CreateNovaSecret (novaNames .NovaName .Namespace , SecretName ))
2181+ DeferCleanup (k8sClient .Delete , ctx , CreateNovaMessageBusSecret (cell0 ))
2182+ DeferCleanup (
2183+ mariadb .DeleteDBService ,
2184+ mariadb .CreateDBService (
2185+ novaNames .NovaName .Namespace ,
2186+ "openstack" ,
2187+ corev1.ServiceSpec {
2188+ Ports : []corev1.ServicePort {{Port : 3306 }},
2189+ },
2190+ ),
2191+ )
2192+ memcachedSpec := infra .GetDefaultMemcachedSpec ()
2193+ DeferCleanup (infra .DeleteMemcached , infra .CreateMemcached (novaNames .NovaName .Namespace , MemcachedInstance , memcachedSpec ))
2194+ infra .SimulateMemcachedReady (novaNames .MemcachedNamespace )
2195+
2196+ DeferCleanup (keystone .DeleteKeystoneAPI , keystone .CreateKeystoneAPI (novaNames .NovaName .Namespace ))
2197+
2198+ rawNova := map [string ]any {
2199+ "apiVersion" : "nova.openstack.org/v1beta1" ,
2200+ "kind" : "Nova" ,
2201+ "metadata" : map [string ]any {
2202+ "name" : novaNames .NovaName .Name ,
2203+ "namespace" : novaNames .NovaName .Namespace ,
2204+ },
2205+ "spec" : map [string ]any {
2206+ "secret" : SecretName ,
2207+ "apiDatabaseAccount" : novaNames .APIMariaDBDatabaseAccount .Name ,
2208+ "cellTemplates" : map [string ]any {
2209+ "cell0" : map [string ]any {
2210+ "cellDatabaseAccount" : cell0 .MariaDBAccountName .Name ,
2211+ "apiDatabaseAccount" : novaNames .APIMariaDBDatabaseAccount .Name ,
2212+ "hasAPIAccess" : true ,
2213+ "dbPurge" : map [string ]any {
2214+ "schedule" : "1 0 * * *" ,
2215+ },
2216+ },
2217+ },
2218+ "messagingBus" : map [string ]any {
2219+ "cluster" : cell0 .TransportURLName .Name ,
2220+ },
2221+ "auth" : map [string ]any {
2222+ "applicationCredentialSecret" : acSecretName ,
2223+ },
2224+ },
2225+ }
2226+ DeferCleanup (th .DeleteInstance , th .CreateUnstructured (rawNova ))
2227+ })
2228+
2229+ It ("should add the consumer finalizer to the AC secret" , func () {
2230+ Eventually (func (g Gomega ) {
2231+ secret := th .GetSecret (types.NamespacedName {
2232+ Namespace : novaNames .NovaName .Namespace ,
2233+ Name : acSecretName ,
2234+ })
2235+ g .Expect (secret .Finalizers ).To (
2236+ ContainElement (nova .ACConsumerFinalizer ))
2237+ }, timeout , interval ).Should (Succeed ())
2238+ })
2239+
2240+ It ("should track the consumed AC secret in status" , func () {
2241+ Eventually (func (g Gomega ) {
2242+ n := GetNova (novaNames .NovaName )
2243+ g .Expect (n .Status .ApplicationCredentialSecret ).To (Equal (acSecretName ))
2244+ }, timeout , interval ).Should (Succeed ())
2245+ })
2246+
2247+ It ("should move the finalizer from the old to the new secret on rotation" , func () {
2248+ Eventually (func (g Gomega ) {
2249+ secret := th .GetSecret (types.NamespacedName {
2250+ Namespace : novaNames .NovaName .Namespace ,
2251+ Name : acSecretName ,
2252+ })
2253+ g .Expect (secret .Finalizers ).To (
2254+ ContainElement (nova .ACConsumerFinalizer ))
2255+ }, timeout , interval ).Should (Succeed ())
2256+
2257+ newACSecretName := "ac-nova-x9y8z-secret" //nolint:gosec // G101
2258+ newSecret := & corev1.Secret {
2259+ ObjectMeta : metav1.ObjectMeta {
2260+ Namespace : novaNames .NovaName .Namespace ,
2261+ Name : newACSecretName ,
2262+ },
2263+ Data : map [string ][]byte {
2264+ keystonev1 .ACIDSecretKey : []byte ("x9y8zrotated-ac-id" ),
2265+ keystonev1 .ACSecretSecretKey : []byte ("rotated-ac-secret" ),
2266+ },
2267+ }
2268+ DeferCleanup (k8sClient .Delete , ctx , newSecret )
2269+ Expect (k8sClient .Create (ctx , newSecret )).To (Succeed ())
2270+
2271+ Eventually (func (g Gomega ) {
2272+ n := GetNova (novaNames .NovaName )
2273+ n .Spec .Auth .ApplicationCredentialSecret = newACSecretName
2274+ g .Expect (k8sClient .Update (ctx , n )).Should (Succeed ())
2275+ }, timeout , interval ).Should (Succeed ())
2276+
2277+ Eventually (func (g Gomega ) {
2278+ secret := th .GetSecret (types.NamespacedName {
2279+ Namespace : novaNames .NovaName .Namespace ,
2280+ Name : newACSecretName ,
2281+ })
2282+ g .Expect (secret .Finalizers ).To (
2283+ ContainElement (nova .ACConsumerFinalizer ))
2284+ }, timeout , interval ).Should (Succeed ())
2285+
2286+ Eventually (func (g Gomega ) {
2287+ secret := th .GetSecret (types.NamespacedName {
2288+ Namespace : novaNames .NovaName .Namespace ,
2289+ Name : acSecretName ,
2290+ })
2291+ g .Expect (secret .Finalizers ).NotTo (
2292+ ContainElement (nova .ACConsumerFinalizer ))
2293+ }, timeout , interval ).Should (Succeed ())
2294+
2295+ Eventually (func (g Gomega ) {
2296+ n := GetNova (novaNames .NovaName )
2297+ g .Expect (n .Status .ApplicationCredentialSecret ).To (Equal (newACSecretName ))
2298+ }, timeout , interval ).Should (Succeed ())
2299+ })
2300+
2301+ It ("should remove the consumer finalizer from AC secret on CR deletion" , func () {
2302+ Eventually (func (g Gomega ) {
2303+ secret := th .GetSecret (types.NamespacedName {
2304+ Namespace : novaNames .NovaName .Namespace ,
2305+ Name : acSecretName ,
2306+ })
2307+ g .Expect (secret .Finalizers ).To (
2308+ ContainElement (nova .ACConsumerFinalizer ))
2309+ }, timeout , interval ).Should (Succeed ())
2310+
2311+ th .DeleteInstance (GetNova (novaNames .NovaName ))
2312+
2313+ secret := th .GetSecret (types.NamespacedName {
2314+ Namespace : novaNames .NovaName .Namespace ,
2315+ Name : acSecretName ,
2316+ })
2317+ Expect (secret .Finalizers ).NotTo (
2318+ ContainElement (nova .ACConsumerFinalizer ))
2319+ })
2320+ })
21602321})
0 commit comments