Skip to content

Commit 3d3857d

Browse files
lmicciniopenshift-merge-bot[bot]
authored andcommitted
Use quorum queues if enabled
With openstack-k8s-operators/infra-operator#429 we added the ability to configure RabbitMQ to use quorum queues. This commit adds a check to verify if "quorumqueues" has been added to the TransportURL secret. If its value is true, the services will be configured to use quorum queues. Jira: https://issues.redhat.com/browse/OSPRH-19160 Assisted-by: claude-4-sonnet
1 parent a8a1a81 commit 3d3857d

17 files changed

Lines changed: 301 additions & 27 deletions

api/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.21
44

55
require (
66
github.com/google/go-cmp v0.7.0
7-
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250813063935-fdc20530dcf1
7+
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250909143828-e33d35ffd64f
88
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250730071847-837b07f8d72f
99
github.com/robfig/cron/v3 v3.0.1
1010
k8s.io/api v0.29.15

api/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo
7373
github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
7474
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
7575
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
76-
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250813063935-fdc20530dcf1 h1:77TRnwfSxNI5cn/RxMS9I+kqefMm7XRQsNknIhEE4tg=
77-
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250813063935-fdc20530dcf1/go.mod h1:Dv8qpmBIQy3Jv/EyQnOyc0w61X8vyfxpjcIQONP5CwY=
76+
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250909143828-e33d35ffd64f h1:chuu4iBT5sXHYw8aPeP/pWC+S3yGo6hdy39foP7c5vs=
77+
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250909143828-e33d35ffd64f/go.mod h1:Dv8qpmBIQy3Jv/EyQnOyc0w61X8vyfxpjcIQONP5CwY=
7878
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250730071847-837b07f8d72f h1:DW8aNjEtDFrWiZ6vWuOXwdRB4eBD0n+bA9foQkOEx6U=
7979
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250730071847-837b07f8d72f/go.mod h1:P+7F1wiwZUxOy4myYXFyc/uBtGATDFpk3yAllXe1Vzk=
8080
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

controllers/common.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@ const (
100100
// top level notification message bus transport URL
101101
NotificationTransportURLSelector = "notification_transport_url"
102102

103+
// QuorumQueuesSelector is the name of key in the TransportURL Secret for
104+
// the message bus quorum queues
105+
QuorumQueuesSelector = "quorumqueues"
106+
107+
// QuorumQueuesTemplateKey is the name of key in template parameters for
108+
// the message bus quorum queues configuration
109+
QuorumQueuesTemplateKey = "quorum_queues"
110+
103111
// fields to index to reconcile when change
104112
passwordSecretField = ".spec.secret"
105113
caBundleSecretNameField = ".spec.tls.caBundleSecretName" // #nosec G101
@@ -747,3 +755,11 @@ func SortNovaCellListByName(cellList *novav1.NovaCellList) {
747755
return cellList.Items[i].Name < cellList.Items[j].Name
748756
})
749757
}
758+
759+
// parseQuorumQueues parses the quorum queues value from secret data
760+
func parseQuorumQueues(data []byte) bool {
761+
if data == nil {
762+
return false
763+
}
764+
return string(data) == "true"
765+
}

controllers/nova_controller.go

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
366366
// Create TransportURLs to access the message buses of each cell. Cell0
367367
// message bus is always the same as the top level API message bus so
368368
// we create API MQ separately first
369-
apiTransportURL, apiMQStatus, apiMQError := r.ensureMQ(
369+
apiTransportURL, apiQuorumQueues, apiMQStatus, apiMQError := r.ensureMQ(
370370
ctx, h, instance, instance.Name+"-api-transport", instance.Spec.APIMessageBusInstance)
371371
switch apiMQStatus {
372372
case nova.MQFailed:
@@ -403,7 +403,7 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
403403

404404
notificationTransportURLName := instance.Name + "-notification-transport"
405405
if notificationBusName != "" {
406-
notificationTransportURL, notificationMQStatus, notificationMQError = r.ensureMQ(
406+
notificationTransportURL, _, notificationMQStatus, notificationMQError = r.ensureMQ(
407407
ctx, h, instance, notificationTransportURLName, notificationBusName)
408408

409409
switch notificationMQStatus {
@@ -459,14 +459,16 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
459459
var status nova.MessageBusStatus
460460
var err error
461461
cellTemplate := instance.Spec.CellTemplates[cellName]
462+
var cellQuorumQueues bool
462463
// cell0 does not need its own cell message bus it uses the
463464
// API message bus instead
464465
if cellName == novav1.Cell0Name {
465466
cellTransportURL = apiTransportURL
467+
cellQuorumQueues = apiQuorumQueues
466468
status = apiMQStatus
467469
err = apiMQError
468470
} else {
469-
cellTransportURL, status, err = r.ensureMQ(
471+
cellTransportURL, cellQuorumQueues, status, err = r.ensureMQ(
470472
ctx, h, instance, instance.Name+"-"+cellName+"-transport", cellTemplate.CellMessageBusInstance)
471473
}
472474
switch status {
@@ -478,7 +480,7 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
478480
default:
479481
return ctrl.Result{}, fmt.Errorf("%w from ensureMQ: %d for cell %s", util.ErrInvalidStatus, status, cellName)
480482
}
481-
cellMQs[cellName] = &nova.MessageBus{TransportURL: cellTransportURL, Status: status}
483+
cellMQs[cellName] = &nova.MessageBus{TransportURL: cellTransportURL, QuorumQueues: cellQuorumQueues, Status: status}
482484
}
483485
if len(failedMQs) > 0 {
484486
instance.Status.Conditions.Set(condition.FalseCondition(
@@ -541,7 +543,7 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
541543
}
542544
cell, status, err := r.ensureCell(
543545
ctx, h, instance, cellName, cellTemplate,
544-
cellDB.Database, apiDB, cellMQ.TransportURL, notificationTransportURL,
546+
cellDB.Database, apiDB, cellMQ.TransportURL, cellMQ.QuorumQueues, notificationTransportURL,
545547
keystoneInternalAuthURL, secret,
546548
)
547549
cells[cellName] = cell
@@ -608,7 +610,7 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
608610

609611
topLevelSecretName, err := r.ensureTopLevelSecret(
610612
ctx, h, instance,
611-
apiTransportURL,
613+
apiTransportURL, apiQuorumQueues,
612614
notificationTransportURL,
613615
secret)
614616
if err != nil {
@@ -1196,6 +1198,7 @@ func (r *NovaReconciler) ensureCell(
11961198
cellDB *mariadbv1.Database,
11971199
apiDB *mariadbv1.Database,
11981200
cellTransportURL string,
1201+
cellQuorumQueues bool,
11991202
notificationTransportURL string,
12001203
keystoneAuthURL string,
12011204
secret corev1.Secret,
@@ -1204,7 +1207,7 @@ func (r *NovaReconciler) ensureCell(
12041207

12051208
cellSecretName, err := r.ensureCellSecret(
12061209
ctx, h, instance, cellName, cellTemplate,
1207-
cellTransportURL, notificationTransportURL,
1210+
cellTransportURL, cellQuorumQueues, notificationTransportURL,
12081211
secret)
12091212
if err != nil {
12101213
return nil, nova.CellDeploying, err
@@ -1708,7 +1711,7 @@ func (r *NovaReconciler) ensureMQ(
17081711
instance *novav1.Nova,
17091712
transportName string,
17101713
messageBusInstanceName string,
1711-
) (string, nova.MessageBusStatus, error) {
1714+
) (string, bool, nova.MessageBusStatus, error) {
17121715
Log := r.GetLogger(ctx)
17131716
transportURL := &rabbitmqv1.TransportURL{
17141717
ObjectMeta: metav1.ObjectMeta{
@@ -1725,7 +1728,7 @@ func (r *NovaReconciler) ensureMQ(
17251728
})
17261729

17271730
if err != nil && !k8s_errors.IsNotFound(err) {
1728-
return "", nova.MQFailed, util.WrapErrorForObject(
1731+
return "", false, nova.MQFailed, util.WrapErrorForObject(
17291732
fmt.Sprintf("Error create or update TransportURL object %s", transportName),
17301733
transportURL,
17311734
err,
@@ -1734,20 +1737,20 @@ func (r *NovaReconciler) ensureMQ(
17341737

17351738
if op != controllerutil.OperationResultNone {
17361739
Log.Info(fmt.Sprintf("TransportURL object %s created or patched", transportName))
1737-
return "", nova.MQCreating, nil
1740+
return "", false, nova.MQCreating, nil
17381741
}
17391742

17401743
err = r.Client.Get(ctx, types.NamespacedName{Namespace: instance.Namespace, Name: transportName}, transportURL)
17411744
if err != nil && !k8s_errors.IsNotFound(err) {
1742-
return "", nova.MQFailed, util.WrapErrorForObject(
1745+
return "", false, nova.MQFailed, util.WrapErrorForObject(
17431746
fmt.Sprintf("Error reading TransportURL object %s", transportName),
17441747
transportURL,
17451748
err,
17461749
)
17471750
}
17481751

17491752
if k8s_errors.IsNotFound(err) || !transportURL.IsReady() || transportURL.Status.SecretName == "" {
1750-
return "", nova.MQCreating, nil
1753+
return "", false, nova.MQCreating, nil
17511754
}
17521755

17531756
secretName := types.NamespacedName{Namespace: instance.Namespace, Name: transportURL.Status.SecretName}
@@ -1756,17 +1759,24 @@ func (r *NovaReconciler) ensureMQ(
17561759
err = h.GetClient().Get(ctx, secretName, secret)
17571760
if err != nil {
17581761
if k8s_errors.IsNotFound(err) {
1759-
return "", nova.MQCreating, nil
1762+
return "", false, nova.MQCreating, nil
17601763
}
1761-
return "", nova.MQFailed, err
1764+
return "", false, nova.MQFailed, err
17621765
}
17631766

17641767
url, ok := secret.Data[TransportURLSelector]
17651768
if !ok {
1766-
return "", nova.MQFailed, fmt.Errorf(
1769+
return "", false, nova.MQFailed, fmt.Errorf(
17671770
"%w: the TransportURL secret %s does not have 'transport_url' field", util.ErrFieldNotFound, transportURL.Status.SecretName)
17681771
}
1769-
return string(url), nova.MQCompleted, nil
1772+
1773+
// Check if quorum queues are enabled
1774+
quorumQueues := false
1775+
if val, ok := secret.Data[QuorumQueuesSelector]; ok {
1776+
quorumQueues = string(val) == "true"
1777+
}
1778+
1779+
return string(url), quorumQueues, nova.MQCompleted, nil
17701780
}
17711781

17721782
func (r *NovaReconciler) ensureMQDeleted(
@@ -1993,15 +2003,22 @@ func (r *NovaReconciler) ensureCellSecret(
19932003
cellName string,
19942004
cellTemplate novav1.NovaCellTemplate,
19952005
cellTransportURL string,
2006+
cellQuorumQueues bool,
19962007
notificationTransportURL string,
19972008
externalSecret corev1.Secret,
19982009
) (string, error) {
19992010
// NOTE(gibi): We can move other sensitive data to the internal Secret from
20002011
// the NovaCellSpec fields, possibly hostnames or usernames.
2012+
quorumQueuesValue := "false"
2013+
if cellQuorumQueues {
2014+
quorumQueuesValue = "true"
2015+
}
2016+
20012017
data := map[string]string{
20022018
ServicePasswordSelector: string(externalSecret.Data[instance.Spec.PasswordSelectors.Service]),
20032019
TransportURLSelector: cellTransportURL,
20042020
NotificationTransportURLSelector: notificationTransportURL,
2021+
QuorumQueuesTemplateKey: quorumQueuesValue,
20052022
}
20062023

20072024
// If metadata is enabled in the cell then the cell secret needs the
@@ -2045,16 +2062,23 @@ func (r *NovaReconciler) ensureTopLevelSecret(
20452062
h *helper.Helper,
20462063
instance *novav1.Nova,
20472064
apiTransportURL string,
2065+
apiQuorumQueues bool,
20482066
notificationTransportURL string,
20492067
externalSecret corev1.Secret,
20502068
) (string, error) {
20512069
// NOTE(gibi): We can move other sensitive data to the internal Secret from
20522070
// the subCR fields, possibly hostnames or usernames.
2071+
quorumQueuesValue := "false"
2072+
if apiQuorumQueues {
2073+
quorumQueuesValue = "true"
2074+
}
2075+
20532076
data := map[string]string{
20542077
ServicePasswordSelector: string(externalSecret.Data[instance.Spec.PasswordSelectors.Service]),
20552078
MetadataSecretSelector: string(externalSecret.Data[instance.Spec.PasswordSelectors.MetadataSecret]),
20562079
TransportURLSelector: apiTransportURL,
20572080
NotificationTransportURLSelector: notificationTransportURL,
2081+
QuorumQueuesTemplateKey: quorumQueuesValue,
20582082
}
20592083

20602084
// NOTE(gibi): When we switch to immutable secrets then we need to include

controllers/novaapi_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ func (r *NovaAPIReconciler) generateConfigs(
515515
"MemcachedServers": memcachedInstance.GetMemcachedServerListString(),
516516
"MemcachedServersWithInet": memcachedInstance.GetMemcachedServerListWithInetString(),
517517
"MemcachedTLS": memcachedInstance.GetMemcachedTLSSupport(),
518+
QuorumQueuesTemplateKey: parseQuorumQueues(secret.Data[QuorumQueuesTemplateKey]),
518519
}
519520
// create httpd vhost template parameters
520521
httpdVhostConfig := map[string]interface{}{}

controllers/novacell_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,7 @@ func (r *NovaCellReconciler) generateComputeConfigs(
780780
"compute_driver": "libvirt.LibvirtDriver",
781781
"transport_url": string(secret.Data[TransportURLSelector]),
782782
"notification_transport_url": string(secret.Data[NotificationTransportURLSelector]),
783+
QuorumQueuesTemplateKey: parseQuorumQueues(secret.Data[QuorumQueuesTemplateKey]),
783784
}
784785
// vnc is optional so we only need to configure it for the compute
785786
// if the proxy service is deployed in the cell

controllers/novacompute_controller.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,8 @@ func (r *NovaComputeReconciler) generateConfigs(
369369
"notification_transport_url": string(secret.Data[NotificationTransportURLSelector]),
370370
"compute_driver": instance.Spec.ComputeDriver,
371371
// Neither the ironic driver nor the fake driver support VNC
372-
"vnc_enabled": false,
372+
"vnc_enabled": false,
373+
QuorumQueuesTemplateKey: parseQuorumQueues(secret.Data[QuorumQueuesTemplateKey]),
373374
}
374375

375376
extraData := map[string]string{}

controllers/novaconductor_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ func (r *NovaConductorReconciler) generateConfigs(
468468
"MemcachedServers": memcachedInstance.GetMemcachedServerListString(),
469469
"MemcachedServersWithInet": memcachedInstance.GetMemcachedServerListWithInetString(),
470470
"MemcachedTLS": memcachedInstance.GetMemcachedTLSSupport(),
471+
QuorumQueuesTemplateKey: parseQuorumQueues(secret.Data[QuorumQueuesTemplateKey]),
471472
}
472473
if len(instance.Spec.APIDatabaseHostname) > 0 {
473474
apiDatabaseAccount, apiDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, instance.Spec.APIDatabaseAccount, instance.Namespace)

controllers/novametadata_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ func (r *NovaMetadataReconciler) generateConfigs(
507507
"MemcachedServers": memcachedInstance.GetMemcachedServerListString(),
508508
"MemcachedServersWithInet": memcachedInstance.GetMemcachedServerListWithInetString(),
509509
"MemcachedTLS": memcachedInstance.GetMemcachedTLSSupport(),
510+
QuorumQueuesTemplateKey: parseQuorumQueues(secret.Data[QuorumQueuesTemplateKey]),
510511
"TimeOut": instance.Spec.APITimeout,
511512
}
512513

controllers/novanovncproxy_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ func (r *NovaNoVNCProxyReconciler) generateConfigs(
483483
"MemcachedServers": memcachedInstance.GetMemcachedServerListString(),
484484
"MemcachedServersWithInet": memcachedInstance.GetMemcachedServerListWithInetString(),
485485
"MemcachedTLS": memcachedInstance.GetMemcachedTLSSupport(),
486+
QuorumQueuesTemplateKey: parseQuorumQueues(secret.Data[QuorumQueuesTemplateKey]),
486487
}
487488
if instance.Spec.TLS.Service.Enabled() {
488489
templateParameters["SSLCertificateFile"] = fmt.Sprintf("/etc/pki/tls/certs/%s.crt", novncproxy.ServiceName)

0 commit comments

Comments
 (0)