@@ -32,6 +32,7 @@ import (
3232 mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"
3333 "github.com/openstack-k8s-operators/nova-operator/internal/placement"
3434 corev1 "k8s.io/api/core/v1"
35+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3536 "k8s.io/apimachinery/pkg/types"
3637)
3738
@@ -1526,4 +1527,259 @@ var _ = Describe("PlacementAPI reconfiguration", func() {
15261527 })
15271528 })
15281529
1530+ When ("ApplicationCredential consumer finalizer is managed" , func () {
1531+ var acSecretName string
1532+
1533+ BeforeEach (func () {
1534+ acSecretName = "ac-placement-a1b2c-secret" //nolint:gosec // G101
1535+ secret := & corev1.Secret {
1536+ ObjectMeta : metav1.ObjectMeta {
1537+ Namespace : names .Namespace ,
1538+ Name : acSecretName ,
1539+ },
1540+ Data : map [string ][]byte {
1541+ keystonev1 .ACIDSecretKey : []byte ("a1b2ctest-ac-id" ),
1542+ keystonev1 .ACSecretSecretKey : []byte ("test-ac-secret" ),
1543+ },
1544+ }
1545+ DeferCleanup (k8sClient .Delete , ctx , secret )
1546+ Expect (k8sClient .Create (ctx , secret )).To (Succeed ())
1547+
1548+ spec := GetDefaultPlacementAPISpec ()
1549+ spec ["auth" ] = map [string ]any {
1550+ "applicationCredentialSecret" : acSecretName ,
1551+ }
1552+
1553+ DeferCleanup (th .DeleteInstance , CreatePlacementAPI (names .PlacementAPIName , spec ))
1554+ DeferCleanup (
1555+ k8sClient .Delete , ctx , CreatePlacementAPISecret (names .Namespace , SecretName ))
1556+ keystoneAPIName := keystone .CreateKeystoneAPI (names .Namespace )
1557+ DeferCleanup (keystone .DeleteKeystoneAPI , keystoneAPIName )
1558+ DeferCleanup (
1559+ mariadb .DeleteDBService ,
1560+ mariadb .CreateDBService (
1561+ names .Namespace ,
1562+ GetDefaultPlacementAPISpec ()["databaseInstance" ].(string ),
1563+ corev1.ServiceSpec {
1564+ Ports : []corev1.ServicePort {{Port : 3306 }},
1565+ },
1566+ ),
1567+ )
1568+ mariadb .SimulateMariaDBDatabaseCompleted (names .MariaDBDatabaseName )
1569+ mariadb .SimulateMariaDBAccountCompleted (names .MariaDBAccount )
1570+ })
1571+
1572+ It ("should add the consumer finalizer to the AC secret" , func () {
1573+ Eventually (func (g Gomega ) {
1574+ secret := th .GetSecret (types.NamespacedName {
1575+ Namespace : names .Namespace ,
1576+ Name : acSecretName ,
1577+ })
1578+ g .Expect (secret .Finalizers ).To (
1579+ ContainElement (placement .ACConsumerFinalizer ))
1580+ }, timeout , interval ).Should (Succeed ())
1581+ })
1582+
1583+ It ("should track the consumed AC secret in status" , func () {
1584+ Eventually (func (g Gomega ) {
1585+ p := GetPlacementAPI (names .PlacementAPIName )
1586+ g .Expect (p .Status .ApplicationCredentialSecret ).To (Equal (acSecretName ))
1587+ }, timeout , interval ).Should (Succeed ())
1588+ })
1589+
1590+ It ("should move the finalizer from the old to the new secret on rotation" , func () {
1591+ Eventually (func (g Gomega ) {
1592+ secret := th .GetSecret (types.NamespacedName {
1593+ Namespace : names .Namespace ,
1594+ Name : acSecretName ,
1595+ })
1596+ g .Expect (secret .Finalizers ).To (
1597+ ContainElement (placement .ACConsumerFinalizer ))
1598+ }, timeout , interval ).Should (Succeed ())
1599+
1600+ newACSecretName := "ac-placement-x9y8z-secret" //nolint:gosec // G101
1601+ newSecret := & corev1.Secret {
1602+ ObjectMeta : metav1.ObjectMeta {
1603+ Namespace : names .Namespace ,
1604+ Name : newACSecretName ,
1605+ },
1606+ Data : map [string ][]byte {
1607+ keystonev1 .ACIDSecretKey : []byte ("x9y8zrotated-ac-id" ),
1608+ keystonev1 .ACSecretSecretKey : []byte ("rotated-ac-secret" ),
1609+ },
1610+ }
1611+ DeferCleanup (k8sClient .Delete , ctx , newSecret )
1612+ Expect (k8sClient .Create (ctx , newSecret )).To (Succeed ())
1613+
1614+ Eventually (func (g Gomega ) {
1615+ p := GetPlacementAPI (names .PlacementAPIName )
1616+ p .Spec .Auth .ApplicationCredentialSecret = newACSecretName
1617+ g .Expect (k8sClient .Update (ctx , p )).Should (Succeed ())
1618+ }, timeout , interval ).Should (Succeed ())
1619+
1620+ Eventually (func (g Gomega ) {
1621+ secret := th .GetSecret (types.NamespacedName {
1622+ Namespace : names .Namespace ,
1623+ Name : newACSecretName ,
1624+ })
1625+ g .Expect (secret .Finalizers ).To (
1626+ ContainElement (placement .ACConsumerFinalizer ))
1627+ }, timeout , interval ).Should (Succeed ())
1628+
1629+ Eventually (func (g Gomega ) {
1630+ secret := th .GetSecret (types.NamespacedName {
1631+ Namespace : names .Namespace ,
1632+ Name : acSecretName ,
1633+ })
1634+ g .Expect (secret .Finalizers ).NotTo (
1635+ ContainElement (placement .ACConsumerFinalizer ))
1636+ }, timeout , interval ).Should (Succeed ())
1637+
1638+ Eventually (func (g Gomega ) {
1639+ p := GetPlacementAPI (names .PlacementAPIName )
1640+ g .Expect (p .Status .ApplicationCredentialSecret ).To (Equal (newACSecretName ))
1641+ }, timeout , interval ).Should (Succeed ())
1642+ })
1643+
1644+ It ("should remove the consumer finalizer from AC secret on CR deletion" , func () {
1645+ Eventually (func (g Gomega ) {
1646+ secret := th .GetSecret (types.NamespacedName {
1647+ Namespace : names .Namespace ,
1648+ Name : acSecretName ,
1649+ })
1650+ g .Expect (secret .Finalizers ).To (
1651+ ContainElement (placement .ACConsumerFinalizer ))
1652+ }, timeout , interval ).Should (Succeed ())
1653+
1654+ th .DeleteInstance (GetPlacementAPI (names .PlacementAPIName ))
1655+
1656+ secret := th .GetSecret (types.NamespacedName {
1657+ Namespace : names .Namespace ,
1658+ Name : acSecretName ,
1659+ })
1660+ Expect (secret .Finalizers ).NotTo (
1661+ ContainElement (placement .ACConsumerFinalizer ))
1662+ })
1663+
1664+ It ("should remove the consumer finalizer when AC auth is cleared from spec" , func () {
1665+ Eventually (func (g Gomega ) {
1666+ secret := th .GetSecret (types.NamespacedName {
1667+ Namespace : names .Namespace ,
1668+ Name : acSecretName ,
1669+ })
1670+ g .Expect (secret .Finalizers ).To (
1671+ ContainElement (placement .ACConsumerFinalizer ))
1672+ }, timeout , interval ).Should (Succeed ())
1673+
1674+ Eventually (func (g Gomega ) {
1675+ p := GetPlacementAPI (names .PlacementAPIName )
1676+ p .Spec .Auth .ApplicationCredentialSecret = ""
1677+ g .Expect (k8sClient .Update (ctx , p )).Should (Succeed ())
1678+ }, timeout , interval ).Should (Succeed ())
1679+
1680+ Eventually (func (g Gomega ) {
1681+ secret := th .GetSecret (types.NamespacedName {
1682+ Namespace : names .Namespace ,
1683+ Name : acSecretName ,
1684+ })
1685+ g .Expect (secret .Finalizers ).NotTo (
1686+ ContainElement (placement .ACConsumerFinalizer ))
1687+ }, timeout , interval ).Should (Succeed ())
1688+
1689+ Eventually (func (g Gomega ) {
1690+ p := GetPlacementAPI (names .PlacementAPIName )
1691+ g .Expect (p .Status .ApplicationCredentialSecret ).To (BeEmpty ())
1692+ }, timeout , interval ).Should (Succeed ())
1693+ })
1694+ })
1695+
1696+ When ("ApplicationCredential secret is not found" , func () {
1697+ BeforeEach (func () {
1698+ DeferCleanup (
1699+ k8sClient .Delete , ctx , CreatePlacementAPISecret (names .Namespace , SecretName ))
1700+ keystoneAPIName := keystone .CreateKeystoneAPI (names .Namespace )
1701+ DeferCleanup (keystone .DeleteKeystoneAPI , keystoneAPIName )
1702+
1703+ spec := GetDefaultPlacementAPISpec ()
1704+ spec ["auth" ] = map [string ]any {
1705+ "applicationCredentialSecret" : "nonexistent-ac-secret" ,
1706+ }
1707+
1708+ DeferCleanup (th .DeleteInstance , CreatePlacementAPI (names .PlacementAPIName , spec ))
1709+
1710+ DeferCleanup (
1711+ mariadb .DeleteDBService ,
1712+ mariadb .CreateDBService (
1713+ names .Namespace ,
1714+ GetDefaultPlacementAPISpec ()["databaseInstance" ].(string ),
1715+ corev1.ServiceSpec {
1716+ Ports : []corev1.ServicePort {{Port : 3306 }},
1717+ },
1718+ ),
1719+ )
1720+ mariadb .SimulateMariaDBDatabaseCompleted (names .MariaDBDatabaseName )
1721+ mariadb .SimulateMariaDBAccountCompleted (names .MariaDBAccount )
1722+ })
1723+
1724+ It ("should set ServiceConfigReady to False" , func () {
1725+ th .ExpectCondition (
1726+ names .PlacementAPIName ,
1727+ ConditionGetterFunc (PlacementConditionGetter ),
1728+ condition .ServiceConfigReadyCondition ,
1729+ corev1 .ConditionFalse ,
1730+ )
1731+ })
1732+ })
1733+
1734+ When ("ApplicationCredential secret is missing required keys" , func () {
1735+ BeforeEach (func () {
1736+ DeferCleanup (
1737+ k8sClient .Delete , ctx , CreatePlacementAPISecret (names .Namespace , SecretName ))
1738+ keystoneAPIName := keystone .CreateKeystoneAPI (names .Namespace )
1739+ DeferCleanup (keystone .DeleteKeystoneAPI , keystoneAPIName )
1740+
1741+ badACSecretName := "ac-placement-bad-secret" //nolint:gosec // G101
1742+ badSecret := & corev1.Secret {
1743+ ObjectMeta : metav1.ObjectMeta {
1744+ Namespace : names .Namespace ,
1745+ Name : badACSecretName ,
1746+ },
1747+ Data : map [string ][]byte {
1748+ "WRONG_KEY" : []byte ("some-value" ),
1749+ },
1750+ }
1751+ DeferCleanup (k8sClient .Delete , ctx , badSecret )
1752+ Expect (k8sClient .Create (ctx , badSecret )).To (Succeed ())
1753+
1754+ spec := GetDefaultPlacementAPISpec ()
1755+ spec ["auth" ] = map [string ]any {
1756+ "applicationCredentialSecret" : badACSecretName ,
1757+ }
1758+
1759+ DeferCleanup (th .DeleteInstance , CreatePlacementAPI (names .PlacementAPIName , spec ))
1760+
1761+ DeferCleanup (
1762+ mariadb .DeleteDBService ,
1763+ mariadb .CreateDBService (
1764+ names .Namespace ,
1765+ GetDefaultPlacementAPISpec ()["databaseInstance" ].(string ),
1766+ corev1.ServiceSpec {
1767+ Ports : []corev1.ServicePort {{Port : 3306 }},
1768+ },
1769+ ),
1770+ )
1771+ mariadb .SimulateMariaDBDatabaseCompleted (names .MariaDBDatabaseName )
1772+ mariadb .SimulateMariaDBAccountCompleted (names .MariaDBAccount )
1773+ })
1774+
1775+ It ("should set ServiceConfigReady to False" , func () {
1776+ th .ExpectCondition (
1777+ names .PlacementAPIName ,
1778+ ConditionGetterFunc (PlacementConditionGetter ),
1779+ condition .ServiceConfigReadyCondition ,
1780+ corev1 .ConditionFalse ,
1781+ )
1782+ })
1783+ })
1784+
15291785})
0 commit comments