Skip to content

Commit 69b9e75

Browse files
committed
Implement top-scope notifications bus interface
Let other services to consume the common notifications bus config from the top scope spec. Make it working for Nova yet, with more services to come by. Signed-off-by: Bohdan Dobrelia <bdobreli@redhat.com>
1 parent 4837ad3 commit 69b9e75

4 files changed

Lines changed: 232 additions & 44 deletions

File tree

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,5 @@ replace github.com/openshift/api => github.com/openshift/api v0.0.0-202408300231
127127

128128
// custom RabbitmqClusterSpecCore for OpenStackControlplane (v2.9.0_patches_tag)
129129
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20241017142550-a3524acedd49 //allow-merging
130+
131+
replace github.com/openstack-k8s-operators/nova-operator/api => github.com/openstack-k8s-operators/nova-operator/api v0.6.1-0.20250522172041-c71791ea3caa

tests/functional/ctlplane/base_test.go

Lines changed: 64 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -44,47 +44,51 @@ import (
4444
)
4545

4646
type Names struct {
47-
Namespace string
48-
OpenStackControlplaneName types.NamespacedName
49-
OpenStackVersionName types.NamespacedName
50-
KeystoneAPIName types.NamespacedName
51-
MemcachedName types.NamespacedName
52-
MemcachedCertName types.NamespacedName
53-
CinderName types.NamespacedName
54-
ManilaName types.NamespacedName
55-
GlanceName types.NamespacedName
56-
NeutronName types.NamespacedName
57-
HorizonName types.NamespacedName
58-
HeatName types.NamespacedName
59-
TelemetryName types.NamespacedName
60-
DBName types.NamespacedName
61-
DBCertName types.NamespacedName
62-
DBCell1Name types.NamespacedName
63-
DBCell1CertName types.NamespacedName
64-
RabbitMQName types.NamespacedName
65-
RabbitMQCertName types.NamespacedName
66-
RabbitMQCell1Name types.NamespacedName
67-
RabbitMQCell1CertName types.NamespacedName
68-
ServiceAccountName types.NamespacedName
69-
RoleName types.NamespacedName
70-
RoleBindingName types.NamespacedName
71-
RootCAPublicName types.NamespacedName
72-
RootCAInternalName types.NamespacedName
73-
RootCAOvnName types.NamespacedName
74-
RootCALibvirtName types.NamespacedName
75-
SelfSignedIssuerName types.NamespacedName
76-
CustomIssuerName types.NamespacedName
77-
CustomServiceCertSecretName types.NamespacedName
78-
CABundleName types.NamespacedName
79-
OpenStackClientName types.NamespacedName
80-
OVNNorthdName types.NamespacedName
81-
OVNNorthdCertName types.NamespacedName
82-
OVNControllerName types.NamespacedName
83-
OVNControllerCertName types.NamespacedName
84-
OVNDbServerNBName types.NamespacedName
85-
OVNDbServerSBName types.NamespacedName
86-
NeutronOVNCertName types.NamespacedName
87-
OpenStackTopology []types.NamespacedName
47+
Namespace string
48+
OpenStackControlplaneName types.NamespacedName
49+
OpenStackVersionName types.NamespacedName
50+
KeystoneAPIName types.NamespacedName
51+
MemcachedName types.NamespacedName
52+
MemcachedCertName types.NamespacedName
53+
CinderName types.NamespacedName
54+
ManilaName types.NamespacedName
55+
GlanceName types.NamespacedName
56+
NeutronName types.NamespacedName
57+
HorizonName types.NamespacedName
58+
HeatName types.NamespacedName
59+
NovaName types.NamespacedName
60+
PlacementName types.NamespacedName
61+
TelemetryName types.NamespacedName
62+
DBName types.NamespacedName
63+
DBCertName types.NamespacedName
64+
DBCell1Name types.NamespacedName
65+
DBCell1CertName types.NamespacedName
66+
RabbitMQName types.NamespacedName
67+
RabbitMQCertName types.NamespacedName
68+
RabbitMQNotificationsCertName types.NamespacedName
69+
RabbitMQCell1Name types.NamespacedName
70+
RabbitMQCell1CertName types.NamespacedName
71+
RabbitMQNotificationsName types.NamespacedName
72+
ServiceAccountName types.NamespacedName
73+
RoleName types.NamespacedName
74+
RoleBindingName types.NamespacedName
75+
RootCAPublicName types.NamespacedName
76+
RootCAInternalName types.NamespacedName
77+
RootCAOvnName types.NamespacedName
78+
RootCALibvirtName types.NamespacedName
79+
SelfSignedIssuerName types.NamespacedName
80+
CustomIssuerName types.NamespacedName
81+
CustomServiceCertSecretName types.NamespacedName
82+
CABundleName types.NamespacedName
83+
OpenStackClientName types.NamespacedName
84+
OVNNorthdName types.NamespacedName
85+
OVNNorthdCertName types.NamespacedName
86+
OVNControllerName types.NamespacedName
87+
OVNControllerCertName types.NamespacedName
88+
OVNDbServerNBName types.NamespacedName
89+
OVNDbServerSBName types.NamespacedName
90+
NeutronOVNCertName types.NamespacedName
91+
OpenStackTopology []types.NamespacedName
8892
}
8993

9094
func CreateNames(openstackControlplaneName types.NamespacedName) Names {
@@ -168,6 +172,14 @@ func CreateNames(openstackControlplaneName types.NamespacedName) Names {
168172
Namespace: openstackControlplaneName.Namespace,
169173
Name: "telemetry",
170174
},
175+
NovaName: types.NamespacedName{
176+
Namespace: openstackControlplaneName.Namespace,
177+
Name: "nova",
178+
},
179+
PlacementName: types.NamespacedName{
180+
Namespace: openstackControlplaneName.Namespace,
181+
Name: "placement",
182+
},
171183
DBName: types.NamespacedName{
172184
Namespace: openstackControlplaneName.Namespace,
173185
Name: "openstack",
@@ -192,10 +204,18 @@ func CreateNames(openstackControlplaneName types.NamespacedName) Names {
192204
Namespace: openstackControlplaneName.Namespace,
193205
Name: "cert-rabbitmq-svc",
194206
},
207+
RabbitMQNotificationsCertName: types.NamespacedName{
208+
Namespace: openstackControlplaneName.Namespace,
209+
Name: "cert-rabbitmq-notifications-svc",
210+
},
195211
RabbitMQCell1Name: types.NamespacedName{
196212
Namespace: openstackControlplaneName.Namespace,
197213
Name: "rabbitmq-cell1",
198214
},
215+
RabbitMQNotificationsName: types.NamespacedName{
216+
Namespace: openstackControlplaneName.Namespace,
217+
Name: "rabbitmq-notifications",
218+
},
199219
RabbitMQCell1CertName: types.NamespacedName{
200220
Namespace: openstackControlplaneName.Namespace,
201221
Name: "cert-rabbitmq-cell1-svc",
@@ -484,6 +504,9 @@ func GetDefaultOpenStackControlPlaneSpec() map[string]interface{} {
484504
names.RabbitMQCell1Name.Name: map[string]interface{}{
485505
"replicas": 1,
486506
},
507+
names.RabbitMQNotificationsName.Name: map[string]interface{}{
508+
"replicas": 1,
509+
},
487510
}
488511
galeraTemplate := map[string]interface{}{
489512
names.DBName.Name: map[string]interface{}{

tests/functional/ctlplane/openstackoperator_controller_test.go

Lines changed: 165 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030

3131
k8s_corev1 "k8s.io/api/core/v1"
3232
k8s_errors "k8s.io/apimachinery/pkg/api/errors"
33+
3334
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3435
"k8s.io/apimachinery/pkg/types"
3536
"k8s.io/utils/ptr"
@@ -40,11 +41,13 @@ import (
4041
cinderv1 "github.com/openstack-k8s-operators/cinder-operator/api/v1beta1"
4142
rabbitmqv1 "github.com/openstack-k8s-operators/infra-operator/apis/rabbitmq/v1beta1"
4243
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
44+
4345
"github.com/openstack-k8s-operators/lib-common/modules/certmanager"
4446
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
4547
"github.com/openstack-k8s-operators/lib-common/modules/common/service"
4648
"github.com/openstack-k8s-operators/lib-common/modules/common/tls"
4749
manilav1 "github.com/openstack-k8s-operators/manila-operator/api/v1beta1"
50+
novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1"
4851
clientv1 "github.com/openstack-k8s-operators/openstack-operator/apis/client/v1beta1"
4952
corev1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1"
5053
ovnv1 "github.com/openstack-k8s-operators/ovn-operator/api/v1beta1"
@@ -828,6 +831,7 @@ var _ = Describe("OpenStackOperator controller", func() {
828831
BeforeEach(func() {
829832
// create cert secrets for rabbitmq instances
830833
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCertName))
834+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQNotificationsCertName))
831835
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCell1CertName))
832836
// create cert secrets for memcached instance
833837
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.MemcachedCertName))
@@ -1141,6 +1145,7 @@ var _ = Describe("OpenStackOperator controller", func() {
11411145
BeforeEach(func() {
11421146
// create cert secrets for rabbitmq instances
11431147
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCertName))
1148+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQNotificationsCertName))
11441149
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCell1CertName))
11451150
// create cert secrets for memcached instance
11461151
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.MemcachedCertName))
@@ -1268,6 +1273,7 @@ var _ = Describe("OpenStackOperator controller", func() {
12681273
BeforeEach(func() {
12691274
// create cert secrets for rabbitmq instances
12701275
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCertName))
1276+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQNotificationsCertName))
12711277
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCell1CertName))
12721278
// create cert secrets for memcached instance
12731279
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.MemcachedCertName))
@@ -1791,6 +1797,160 @@ var _ = Describe("OpenStackOperator controller", func() {
17911797
})
17921798
})
17931799

1800+
When("A OpenStackControlplane instance is created with top-scope notifications config pushed down", func() {
1801+
BeforeEach(func() {
1802+
// NOTE(bogdando): DBs certs need to be created here as well, but those are already existing somehow
1803+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCertName))
1804+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQNotificationsCertName))
1805+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCell1CertName))
1806+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.MemcachedCertName))
1807+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNNorthdCertName))
1808+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNControllerCertName))
1809+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.NeutronOVNCertName))
1810+
1811+
DeferCleanup(k8sClient.Delete, ctx,
1812+
th.CreateSecret(types.NamespacedName{Name: "openstack-config-secret", Namespace: namespace}, map[string][]byte{"secure.yaml": []byte("foo")}))
1813+
DeferCleanup(k8sClient.Delete, ctx,
1814+
th.CreateConfigMap(types.NamespacedName{Name: "openstack-config", Namespace: namespace}, map[string]interface{}{"clouds.yaml": string("foo"), "OS_CLOUD": "default"}))
1815+
1816+
spec := GetDefaultOpenStackControlPlaneSpec()
1817+
spec["notificationsBus"] = "rabbitmq-notifications"
1818+
// enable dependencies
1819+
spec["nova"] = map[string]interface{}{
1820+
"enabled": true,
1821+
"template": map[string]interface{}{
1822+
"apiTimeout": 60,
1823+
"cellTemplates": map[string]interface{}{
1824+
"cell0": map[string]interface{}{},
1825+
},
1826+
},
1827+
}
1828+
spec["galera"] = map[string]interface{}{
1829+
"enabled": true,
1830+
}
1831+
spec["memcached"] = map[string]interface{}{
1832+
"enabled": true,
1833+
"templates": map[string]interface{}{
1834+
"memcached": map[string]interface{}{
1835+
"replicas": 1,
1836+
},
1837+
},
1838+
}
1839+
spec["rabbitmq"] = map[string]interface{}{
1840+
"enabled": true,
1841+
"templates": map[string]interface{}{
1842+
"rabbitmq": map[string]interface{}{
1843+
"replicas": 1,
1844+
},
1845+
},
1846+
}
1847+
spec["keystone"] = map[string]interface{}{
1848+
"enabled": true,
1849+
}
1850+
spec["glance"] = map[string]interface{}{
1851+
"enabled": true,
1852+
}
1853+
spec["neutron"] = map[string]interface{}{
1854+
"enabled": true,
1855+
}
1856+
spec["placement"] = map[string]interface{}{
1857+
"enabled": true,
1858+
"template": map[string]interface{}{
1859+
"apiTimeout": 60,
1860+
},
1861+
}
1862+
// turn off unrelated to this test case services
1863+
spec["horizon"] = map[string]interface{}{
1864+
"enabled": false,
1865+
}
1866+
spec["cinder"] = map[string]interface{}{
1867+
"enabled": false,
1868+
}
1869+
spec["swift"] = map[string]interface{}{
1870+
"enabled": false,
1871+
}
1872+
spec["redis"] = map[string]interface{}{
1873+
"enabled": false,
1874+
}
1875+
spec["ironic"] = map[string]interface{}{
1876+
"enabled": false,
1877+
}
1878+
spec["designate"] = map[string]interface{}{
1879+
"enabled": false,
1880+
}
1881+
spec["barbican"] = map[string]interface{}{
1882+
"enabled": false,
1883+
}
1884+
spec["manila"] = map[string]interface{}{
1885+
"enabled": false,
1886+
}
1887+
spec["heat"] = map[string]interface{}{
1888+
"enabled": false,
1889+
}
1890+
spec["telemetry"] = map[string]interface{}{
1891+
"enabled": false,
1892+
}
1893+
1894+
Eventually(func(g Gomega) {
1895+
g.Expect(CreateOpenStackControlPlane(names.OpenStackControlplaneName, spec)).Should(Not(BeNil()))
1896+
keystoneAPI := keystone.GetKeystoneAPI(names.KeystoneAPIName)
1897+
g.Expect(keystoneAPI).Should(Not(BeNil()))
1898+
SimulateControlplaneReady()
1899+
}, timeout, interval).Should(Succeed())
1900+
1901+
DeferCleanup(
1902+
th.DeleteInstance,
1903+
GetOpenStackControlPlane(names.OpenStackControlplaneName),
1904+
)
1905+
1906+
Eventually(func(g Gomega) {
1907+
OSCtlplane := GetOpenStackControlPlane(names.OpenStackControlplaneName)
1908+
OSCtlplane.Status.ObservedGeneration = OSCtlplane.Generation
1909+
OSCtlplane.Status.Conditions.MarkTrue(corev1.OpenStackControlPlaneMemcachedReadyCondition, "Ready")
1910+
OSCtlplane.Status.Conditions.MarkTrue(corev1.OpenStackControlPlaneRabbitMQReadyCondition, "Ready")
1911+
OSCtlplane.Status.Conditions.MarkTrue(corev1.OpenStackControlPlaneNeutronReadyCondition, "Ready")
1912+
OSCtlplane.Status.Conditions.MarkTrue(corev1.OpenStackControlPlaneGlanceReadyCondition, "Ready")
1913+
OSCtlplane.Status.Conditions.MarkTrue(corev1.OpenStackControlPlanePlacementAPIReadyCondition, "Ready")
1914+
g.Expect(k8sClient.Update(ctx, OSCtlplane)).Should(Succeed())
1915+
th.Logger.Info("Simulated nova dependencies ready", "on", names.OpenStackControlplaneName)
1916+
}, timeout, interval).Should(Succeed())
1917+
1918+
// nova to become ready
1919+
Eventually(func(g Gomega) {
1920+
conditions := OpenStackControlPlaneConditionGetter(names.OpenStackControlplaneName)
1921+
g.Expect(conditions.Has(corev1.OpenStackControlPlaneNovaReadyCondition)).To(BeTrue())
1922+
}, timeout, interval).Should(Succeed())
1923+
})
1924+
1925+
It("should have configured nova notifications bus instance from top-scope", func() {
1926+
nova := &novav1.Nova{}
1927+
notificationBusName := "rabbitmq-notifications"
1928+
Eventually(func(g Gomega) {
1929+
g.Expect(k8sClient.Get(ctx, names.NovaName, nova)).Should(Succeed())
1930+
g.Expect(nova).ShouldNot(BeNil())
1931+
g.Expect(nova.Spec.NotificationsBusInstance).Should(Equal(&notificationBusName))
1932+
}, timeout, interval).Should(Succeed())
1933+
})
1934+
1935+
It("should have configured nova notifications bus instance from the service template", func() {
1936+
OSCtlplane := GetOpenStackControlPlane(names.OpenStackControlplaneName)
1937+
overrideBusName := "rabbitmq-custom"
1938+
Eventually(func(g Gomega) {
1939+
// force-update the notifications bus instance, unless it is overriden in templates
1940+
OSCtlplane.Spec.NotificationsBus = ""
1941+
OSCtlplane.Spec.Nova.Template.NotificationsBusInstance = &overrideBusName
1942+
g.Expect(k8sClient.Update(ctx, OSCtlplane)).Should(Succeed())
1943+
}, timeout, interval).Should(Succeed())
1944+
1945+
nova := &novav1.Nova{}
1946+
Eventually(func(g Gomega) {
1947+
g.Expect(k8sClient.Get(ctx, names.NovaName, nova)).Should(Succeed())
1948+
g.Expect(nova).ShouldNot(BeNil())
1949+
g.Expect(nova.Spec.NotificationsBusInstance).Should(Equal(&overrideBusName))
1950+
}, timeout, interval).Should(Succeed())
1951+
})
1952+
})
1953+
17941954
When("OpenStackControlplane instance is deleted", func() {
17951955
BeforeEach(func() {
17961956
DeferCleanup(
@@ -2073,6 +2233,7 @@ var _ = Describe("OpenStackOperator controller", func() {
20732233

20742234
// create cert secrets for rabbitmq instances
20752235
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCertName))
2236+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQNotificationsCertName))
20762237
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCell1CertName))
20772238
// create cert secrets for memcached instance
20782239
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.MemcachedCertName))
@@ -2913,6 +3074,7 @@ var _ = Describe("OpenStackOperator controller galera and rabbitmq", func() {
29133074

29143075
// create cert secrets for rabbitmq instances
29153076
th.CreateCertSecret(names.RabbitMQCertName)
3077+
th.CreateCertSecret(names.RabbitMQNotificationsCertName)
29163078
th.CreateCertSecret(names.RabbitMQCell1CertName)
29173079

29183080
extGalera := CreateGaleraConfig(namespace, GetDefaultGaleraSpec())
@@ -3048,17 +3210,17 @@ var _ = Describe("OpenStackOperator controller galera and rabbitmq", func() {
30483210
Eventually(func(g Gomega) {
30493211
OSCtlplane := GetOpenStackControlPlane(names.OpenStackControlplaneName)
30503212
rabbitTemplates := *(OSCtlplane.Spec.Rabbitmq.Templates)
3051-
g.Expect(rabbitTemplates).Should(HaveLen(2))
3213+
g.Expect(rabbitTemplates).Should(HaveLen(3))
30523214
delete(rabbitTemplates, names.RabbitMQCell1Name.Name)
30533215
OSCtlplane.Spec.Rabbitmq.Templates = &rabbitTemplates
30543216
g.Expect(k8sClient.Update(ctx, OSCtlplane)).Should(Succeed())
30553217
}, timeout, interval).Should(Succeed())
30563218

3057-
// Only 1 cell in rabbitmq template
3219+
// Only 1 cell and notifications bus in rabbitmq template
30583220
Eventually(func(g Gomega) {
30593221
OSCtlplane := GetOpenStackControlPlane(names.OpenStackControlplaneName)
30603222
rabbitTemplates := *(OSCtlplane.Spec.Rabbitmq.Templates)
3061-
g.Expect(rabbitTemplates).Should(HaveLen(1))
3223+
g.Expect(rabbitTemplates).Should(HaveLen(2))
30623224
}, timeout, interval).Should(Succeed())
30633225

30643226
// cell1.rabbitmq should not exists in db

tests/functional/ctlplane/openstackversion_controller_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ var _ = Describe("OpenStackOperator controller", func() {
275275

276276
// create cert secrets for rabbitmq instances
277277
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCertName))
278+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQNotificationsCertName))
278279
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.RabbitMQCell1CertName))
279280

280281
// (mschuppert) create root CA secrets as there is no certmanager running.

0 commit comments

Comments
 (0)