@@ -26,6 +26,7 @@ import (
2626 "fmt"
2727
2828 "github.com/google/go-cmp/cmp"
29+ rabbitmqv1 "github.com/openstack-k8s-operators/infra-operator/apis/rabbitmq/v1beta1"
2930 service "github.com/openstack-k8s-operators/lib-common/modules/common/service"
3031 "github.com/robfig/cron/v3"
3132
@@ -88,6 +89,24 @@ func (spec *NovaSpecCore) Default() {
8889 spec .APITimeout = novaDefaults .APITimeout
8990 }
9091
92+ // Default MessagingBus.Cluster from APIMessageBusInstance if not already set
93+ if spec .MessagingBus .Cluster == "" {
94+ spec .MessagingBus .Cluster = spec .APIMessageBusInstance
95+ }
96+
97+ // Default NotificationsBus if NotificationsBusInstance is specified
98+ if spec .NotificationsBusInstance != nil && * spec .NotificationsBusInstance != "" {
99+ if spec .NotificationsBus == nil {
100+ // Initialize empty NotificationsBus - credentials will be created dynamically
101+ // to ensure separation from MessagingBus (RPC and notifications should never share credentials)
102+ spec .NotificationsBus = & rabbitmqv1.RabbitMqConfig {}
103+ }
104+ // Default cluster name if not already set
105+ if spec .NotificationsBus .Cluster == "" {
106+ spec .NotificationsBus .Cluster = * spec .NotificationsBusInstance
107+ }
108+ }
109+
91110 for cellName , cellTemplate := range spec .CellTemplates {
92111
93112 if cellTemplate .MetadataServiceTemplate .Enabled == nil {
@@ -106,6 +125,11 @@ func (spec *NovaSpecCore) Default() {
106125 }
107126 }
108127
128+ // Default MessagingBus.Cluster from CellMessageBusInstance if not already set
129+ if cellTemplate .MessagingBus .Cluster == "" {
130+ cellTemplate .MessagingBus .Cluster = cellTemplate .CellMessageBusInstance
131+ }
132+
109133 // "cellTemplate" is a by-value copy, so we need to re-inject the updated version of it into the map
110134 spec .CellTemplates [cellName ] = cellTemplate
111135 }
@@ -138,18 +162,34 @@ func (spec *NovaSpecCore) ValidateCellTemplates(basePath *field.Path, namespace
138162 cell .TopologyRef , * basePath .Child ("topologyRef" ), namespace )... )
139163
140164 if name != Cell0Name {
141- if dupName , ok := cellMessageBusNames [cell .CellMessageBusInstance ]; ok {
165+ // Determine which rabbit cluster this cell is using
166+ // Prefer the new MessagingBus.Cluster field, fall back to deprecated CellMessageBusInstance
167+ var cellCluster string
168+ if cell .MessagingBus .Cluster != "" {
169+ cellCluster = cell .MessagingBus .Cluster
170+ } else {
171+ cellCluster = cell .CellMessageBusInstance
172+ }
173+
174+ // Check if this rabbit cluster is already used by another cell
175+ if dupName , ok := cellMessageBusNames [cellCluster ]; ok {
176+ // Determine which field to report the error on
177+ fieldPath := cellPath .Child ("messagingBus" ).Child ("cluster" )
178+ if cell .MessagingBus .Cluster == "" {
179+ fieldPath = cellPath .Child ("cellMessageBusInstance" )
180+ }
181+
142182 errors = append (errors , field .Invalid (
143- cellPath . Child ( "cellMessageBusInstance" ) ,
144- cell . CellMessageBusInstance ,
183+ fieldPath ,
184+ cellCluster ,
145185 fmt .Sprintf (
146186 "RabbitMqCluster CR need to be uniq per cell. It's duplicated with cell: %s" ,
147187 dupName ),
148188 ),
149189 )
150190 }
151191
152- cellMessageBusNames [cell . CellMessageBusInstance ] = name
192+ cellMessageBusNames [cellCluster ] = name
153193 }
154194 if * cell .MetadataServiceTemplate .Enabled && * spec .MetadataServiceTemplate .Enabled {
155195 errors = append (
@@ -315,7 +355,78 @@ func (spec *NovaSpec) ValidateUpdate(old NovaSpec, basePath *field.Path, namespa
315355// expected to be called by the validation webhook in the higher level meta
316356// operator
317357func (spec * NovaSpecCore ) ValidateUpdate (old NovaSpecCore , basePath * field.Path , namespace string ) field.ErrorList {
318- errors := spec .ValidateCellTemplates (basePath , namespace )
358+ var errors field.ErrorList
359+
360+ // Validate deprecated fields and their new equivalents
361+ // Don't allow setting both old and new fields with different values
362+ // Users can either set both to the same value, or null out the old field and set the new one
363+ if spec .APIMessageBusInstance != "" && spec .MessagingBus .Cluster != "" &&
364+ spec .APIMessageBusInstance != spec .MessagingBus .Cluster {
365+ errors = append (errors , field .Invalid (
366+ basePath .Child ("messagingBus" ).Child ("cluster" ),
367+ spec .MessagingBus .Cluster ,
368+ fmt .Sprintf ("messagingBus.cluster cannot differ from deprecated apiMessageBusInstance (%s). " +
369+ "Either use the new messagingBus.cluster field or the deprecated apiMessageBusInstance, but not both with different values" ,
370+ spec .APIMessageBusInstance )))
371+ }
372+
373+ // Reject changes to deprecated field unless nulling it out
374+ if spec .APIMessageBusInstance != old .APIMessageBusInstance && spec .APIMessageBusInstance != "" {
375+ errors = append (errors , field .Forbidden (
376+ basePath .Child ("apiMessageBusInstance" ),
377+ "apiMessageBusInstance is deprecated and cannot be changed. Please use messagingBus.cluster instead" ))
378+ }
379+
380+ // Similar validation for NotificationsBusInstance
381+ // Don't allow setting both old and new fields with different values
382+ if spec .NotificationsBusInstance != nil && * spec .NotificationsBusInstance != "" &&
383+ spec .NotificationsBus != nil && spec .NotificationsBus .Cluster != "" &&
384+ * spec .NotificationsBusInstance != spec .NotificationsBus .Cluster {
385+ errors = append (errors , field .Invalid (
386+ basePath .Child ("notificationsBus" ).Child ("cluster" ),
387+ spec .NotificationsBus .Cluster ,
388+ fmt .Sprintf ("notificationsBus.cluster cannot differ from deprecated notificationsBusInstance (%s). " +
389+ "Either use the new notificationsBus.cluster field or the deprecated notificationsBusInstance, but not both with different values" ,
390+ * spec .NotificationsBusInstance )))
391+ }
392+
393+ // Reject changes to deprecated field unless nulling it out
394+ if spec .NotificationsBusInstance != nil && old .NotificationsBusInstance != nil &&
395+ * spec .NotificationsBusInstance != * old .NotificationsBusInstance &&
396+ * spec .NotificationsBusInstance != "" {
397+ errors = append (errors , field .Forbidden (
398+ basePath .Child ("notificationsBusInstance" ),
399+ "notificationsBusInstance is deprecated and cannot be changed. Please use notificationsBus.cluster instead" ))
400+ }
401+
402+ // Check cell template changes
403+ for cellName , cellTemplate := range spec .CellTemplates {
404+ if oldCell , exists := old .CellTemplates [cellName ]; exists {
405+ cellPath := basePath .Child ("cellTemplates" ).Key (cellName )
406+
407+ // Don't allow setting both old and new fields with different values
408+ // Users can either set both to the same value, or null out the old field and set the new one
409+ if cellTemplate .CellMessageBusInstance != "" && cellTemplate .MessagingBus .Cluster != "" &&
410+ cellTemplate .CellMessageBusInstance != cellTemplate .MessagingBus .Cluster {
411+ errors = append (errors , field .Invalid (
412+ cellPath .Child ("messagingBus" ).Child ("cluster" ),
413+ cellTemplate .MessagingBus .Cluster ,
414+ fmt .Sprintf ("messagingBus.cluster cannot differ from deprecated cellMessageBusInstance (%s). " +
415+ "Either use the new messagingBus.cluster field or the deprecated cellMessageBusInstance, but not both with different values" ,
416+ cellTemplate .CellMessageBusInstance )))
417+ }
418+
419+ // Reject changes to deprecated field unless nulling it out
420+ if cellTemplate .CellMessageBusInstance != oldCell .CellMessageBusInstance &&
421+ cellTemplate .CellMessageBusInstance != "" {
422+ errors = append (errors , field .Forbidden (
423+ cellPath .Child ("cellMessageBusInstance" ),
424+ "cellMessageBusInstance is deprecated and cannot be changed. Please use messagingBus.cluster instead" ))
425+ }
426+ }
427+ }
428+
429+ errors = append (errors , spec .ValidateCellTemplates (basePath , namespace )... )
319430 // Validate top-level TopologyRef
320431 errors = append (errors , topologyv1 .ValidateTopologyRef (
321432 spec .TopologyRef , * basePath .Child ("topologyRef" ), namespace )... )
0 commit comments