Skip to content

Commit 2f0db6d

Browse files
lmicciniclaude
andcommitted
Drop rabbitmq-cluster-operator dependency and manage RabbitMQ directly
Remove the dependency on the external rabbitmq-cluster-operator and have the infra-operator manage RabbitMQ StatefulSets, Services, ConfigMaps, and Secrets directly. Core controller changes: - Direct StatefulSet management with proper volume mounts, config generation, and TLS support (both client and inter-node) - Service creation for client (AMQP/AMQPS) and headless node discovery - ConfigMap generation for server config, plugins, and config-data - Secret management for default-user credentials and Erlang cookie - PodDisruptionBudget for multi-replica deployments - Fix stale ownerReferences in volumeClaimTemplates from adopted StatefulSets (orphan-delete + recreate with annotation-based storage class preservation) - Set skipPreStopChecks label on pods before StatefulSet deletion (storage wipe and CR deletion) to prevent 7-day termination hangs Version upgrade workflow (3.x to 4.x): - State machine with phases: DeletingResources -> WaitingForCluster - Detects targetVersion changes and triggers storage wipe when crossing major versions (required by RabbitMQ for 3.x -> 4.x upgrades) - Sets wipeReason=VersionUpgrade in status to track upgrade progress - Cleans up StatefulSet PVCs before recreating with new version image - Tracks currentVersion in status after successful upgrade Queue type migration (Mirrored to Quorum): - Supports migrating from classic mirrored (ha-all policy) queues to quorum queues via spec.queueType change - Triggers storage wipe with wipeReason=QueueTypeMigration - Manages ha-all policy lifecycle: applies for Mirrored (replicas > 1), removes when transitioning away from Mirrored - Defaulting webhook forces queueType from Mirrored to Quorum when targetVersion is 4.x+, since mirrored queues are not supported in RabbitMQ 4.x. This enables the openstack-operator to upgrade from 3.x (Mirrored) to 4.x and have the migration handled automatically - Validation webhook rejects Mirrored+4.x as a safety net after defaulting AMQP proxy sidecar: - Python-based TCP proxy injected as a sidecar container when status.proxyRequired is true (after version upgrade or queue migration) - Listens on port 5672 (plain) or 5671 (TLS) depending on TLS config - Forwards connections to RabbitMQ backend on port 5673 - Removed via clients-reconfigured annotation once consumers reconnect - Includes liveness/readiness probes and TLS certificate mounting Migration from rabbitmq-cluster-operator: - Adoption logic reparents existing StatefulSets, Services, and Secrets from old RabbitmqCluster owner to new RabbitMq CR - Cleans up old RabbitmqCluster CR after successful adoption - Fixes stale volumeClaimTemplate ownerReferences that cause new PVCs to be garbage-collected when scaling up adopted StatefulSets Testing: - Comprehensive kuttl tests covering cluster deployment, TLS, scale-up, version upgrade (with and without TLS), queue migration, Mirrored-to- Quorum upgrade with version change, resource management (vhost/user/policy), and migration scenarios - Updated functional tests for the new controller logic including VCT fix, combined version+queue migration, and proxy sidecar Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 863ae03 commit 2f0db6d

125 files changed

Lines changed: 9637 additions & 1684 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Makefile

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,18 @@ tidy: ## Run go mod tidy on every mod file in the repo
121121
PROCS?=$(shell expr $(shell nproc --ignore 2) / 2)
122122
PROC_CMD = --procs ${PROCS}
123123

124+
# Skip instanceha tests if --focus or --skip is used (focused test run)
125+
ifeq (,$(findstring --focus,$(GINKGO_ARGS))$(findstring --skip,$(GINKGO_ARGS)))
126+
INSTANCEHA_DEP = test-instanceha
127+
else
128+
INSTANCEHA_DEP =
129+
endif
130+
124131
.PHONY: test
125-
test: manifests generate gowork fmt vet envtest ginkgo test-instanceha ## Run tests.
132+
test: manifests generate gowork fmt vet envtest ginkgo $(INSTANCEHA_DEP) ## Run tests.
126133
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) -v debug --bin-dir $(LOCALBIN) use $(ENVTEST_K8S_VERSION) -p path)" \
127134
OPERATOR_TEMPLATES="$(PWD)/templates" \
128-
$(GINKGO) --trace --cover --coverpkg=./pkg/...,./internal/...,./apis/network/v1beta1/...,./apis/rabbitmq/v1beta1/... --coverprofile cover.out --covermode=atomic ${PROC_CMD} $(GINKGO_ARGS) ./test/... ./apis/network/... ./apis/rabbitmq/... ./internal/webhook/...
135+
$(GINKGO) --trace --cover --coverpkg=./pkg/...,./internal/...,./apis/network/v1beta1/...,./apis/rabbitmq/v1beta1/... --coverprofile cover.out --covermode=atomic ${PROC_CMD} $(GINKGO_ARGS) ./test/... ./apis/network/... ./apis/rabbitmq/... ./internal/webhook/... ./internal/controller/...
129136

130137
.PHONY: test-instanceha
131138
test-instanceha: ## Run instanceha tests.

apis/bases/rabbitmq.openstack.org_rabbitmqs.yaml

Lines changed: 181 additions & 165 deletions
Large diffs are not rendered by default.

apis/go.mod

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ go 1.24.4
44

55
require (
66
github.com/go-logr/logr v1.4.3
7-
github.com/onsi/gomega v1.39.1
8-
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260310070607-b96da8dd520e
9-
github.com/rabbitmq/cluster-operator/v2 v2.16.0
7+
github.com/onsi/gomega v1.39.0
8+
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260205083029-d03e9df035ef
109
k8s.io/api v0.31.14
1110
k8s.io/apiextensions-apiserver v0.33.2
1211
k8s.io/apimachinery v0.31.14
@@ -19,6 +18,7 @@ require (
1918
github.com/cespare/xxhash/v2 v2.3.0 // indirect
2019
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
2120
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
21+
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
2222
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
2323
github.com/fsnotify/fsnotify v1.9.0 // indirect
2424
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
@@ -40,13 +40,13 @@ require (
4040
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
4141
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
4242
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
43+
github.com/onsi/ginkgo/v2 v2.28.1 // indirect
4344
github.com/openshift/api v3.9.0+incompatible // indirect
4445
github.com/pkg/errors v0.9.1 // indirect
4546
github.com/prometheus/client_golang v1.22.0 // indirect
4647
github.com/prometheus/client_model v0.6.2 // indirect
4748
github.com/prometheus/common v0.65.0 // indirect
4849
github.com/prometheus/procfs v0.16.1 // indirect
49-
github.com/rogpeppe/go-internal v1.13.1 // indirect
5050
github.com/spf13/pflag v1.0.7 // indirect
5151
github.com/x448/float16 v0.8.4 // indirect
5252
go.yaml.in/yaml/v2 v2.4.2 // indirect
@@ -90,9 +90,6 @@ replace k8s.io/code-generator => k8s.io/code-generator v0.31.14 //allow-merging
9090

9191
replace k8s.io/component-base => k8s.io/component-base v0.31.14 //allow-merging
9292

93-
// custom RabbitmqClusterSpecCore for OpenStackControlplane (v2.16.0_patches)
94-
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec //allow-merging
95-
9693
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e //allow-merging
9794

9895
replace github.com/cert-manager/cmctl/v2 => github.com/cert-manager/cmctl/v2 v2.1.2-0.20241127223932-88edb96860cf //allow-merging

apis/go.sum

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
21
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
32
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
43
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -77,17 +76,14 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd
7776
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
7877
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
7978
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
80-
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
8179
github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
8280
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
83-
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
84-
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
81+
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
82+
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
8583
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e h1:E1OdwSpqWuDPCedyUt0GEdoAE+r5TXy7YS21yNEo+2U=
8684
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
87-
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260310070607-b96da8dd520e h1:EXpPxBaSHBDyAXhDApotNd9AZOm/DQfvAKdrWO5W4XA=
88-
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260310070607-b96da8dd520e/go.mod h1:+vcGsjqibpMUz3y/g0B5YIXNotlTvQdMB6f92siiwKM=
89-
github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec h1:saovr368HPAKHN0aRPh8h8n9s9dn3d8Frmfua0UYRlc=
90-
github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec/go.mod h1:Nh2NEePLjovUQof2krTAg4JaAoLacqtPTZQXK6izNfg=
85+
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260205083029-d03e9df035ef h1:SgzLekXtZuApbRylC3unCXnMaUClT5FPuqsxzIjt3Go=
86+
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260205083029-d03e9df035ef/go.mod h1:ndqfy1KbVorHH6+zlUFPIrCRhMSxO3ImYJUGaooE0x0=
9187
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
9288
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
9389
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*
2+
Copyright 2025.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1beta1
18+
19+
// DEPRECATED TYPES
20+
// These types are local mirrors of the old rabbitmq-cluster-operator types,
21+
// kept only for backward compatibility with existing CRs during migration.
22+
// They will be removed in a future release once all CRs have been migrated
23+
// to use the new explicit fields in RabbitMqSpecCore.
24+
25+
import (
26+
appsv1 "k8s.io/api/apps/v1"
27+
corev1 "k8s.io/api/core/v1"
28+
"k8s.io/apimachinery/pkg/api/resource"
29+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+
"k8s.io/apimachinery/pkg/runtime"
31+
)
32+
33+
// DeprecatedOverride mirrors the old rabbitmq-cluster-operator OverrideTrimmed type.
34+
// +kubebuilder:pruning:PreserveUnknownFields
35+
type DeprecatedOverride struct {
36+
// Override configuration for the RabbitMQ StatefulSet.
37+
StatefulSet *runtime.RawExtension `json:"statefulSet,omitempty"`
38+
// Override configuration for the Service created to serve traffic to the cluster.
39+
Service *DeprecatedServiceOverride `json:"service,omitempty"`
40+
}
41+
42+
// DeprecatedServiceOverride mirrors the old rabbitmq-cluster-operator Service type.
43+
type DeprecatedServiceOverride struct {
44+
// +optional
45+
*DeprecatedEmbeddedLabelsAnnotations `json:"metadata,omitempty"`
46+
// Spec defines the behavior of a Service.
47+
// +optional
48+
Spec *corev1.ServiceSpec `json:"spec,omitempty"`
49+
}
50+
51+
// DeprecatedEmbeddedLabelsAnnotations mirrors the old rabbitmq-cluster-operator EmbeddedLabelsAnnotations type.
52+
type DeprecatedEmbeddedLabelsAnnotations struct {
53+
// +optional
54+
Labels map[string]string `json:"labels,omitempty"`
55+
// +optional
56+
Annotations map[string]string `json:"annotations,omitempty"`
57+
}
58+
59+
// DeprecatedStatefulSetOverride mirrors the old rabbitmq-cluster-operator StatefulSet type.
60+
// Used for webhook validation of the override.statefulSet JSON field.
61+
type DeprecatedStatefulSetOverride struct {
62+
// +optional
63+
*DeprecatedEmbeddedLabelsAnnotations `json:"metadata,omitempty"`
64+
// +optional
65+
Spec *DeprecatedStatefulSetSpec `json:"spec,omitempty"`
66+
}
67+
68+
// DeprecatedStatefulSetSpec mirrors a subset of the old rabbitmq-cluster-operator StatefulSetSpec type.
69+
type DeprecatedStatefulSetSpec struct {
70+
// +optional
71+
Replicas *int32 `json:"replicas,omitempty"`
72+
// +optional
73+
Selector *metav1.LabelSelector `json:"selector,omitempty"`
74+
// +optional
75+
Template *DeprecatedPodTemplateSpec `json:"template,omitempty"`
76+
// +optional
77+
VolumeClaimTemplates []corev1.PersistentVolumeClaim `json:"volumeClaimTemplates,omitempty"`
78+
// +optional
79+
ServiceName string `json:"serviceName,omitempty"`
80+
// +optional
81+
PodManagementPolicy appsv1.PodManagementPolicyType `json:"podManagementPolicy,omitempty"`
82+
// +optional
83+
UpdateStrategy *appsv1.StatefulSetUpdateStrategy `json:"updateStrategy,omitempty"`
84+
// +optional
85+
MinReadySeconds int32 `json:"minReadySeconds,omitempty"`
86+
// +optional
87+
PersistentVolumeClaimRetentionPolicy *appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy `json:"persistentVolumeClaimRetentionPolicy,omitempty"`
88+
}
89+
90+
// DeprecatedPodTemplateSpec mirrors the old rabbitmq-cluster-operator PodTemplateSpec type.
91+
type DeprecatedPodTemplateSpec struct {
92+
// +optional
93+
*DeprecatedEmbeddedObjectMeta `json:"metadata,omitempty"`
94+
// +optional
95+
Spec *corev1.PodSpec `json:"spec,omitempty"`
96+
}
97+
98+
// DeprecatedEmbeddedObjectMeta mirrors the old rabbitmq-cluster-operator EmbeddedObjectMeta type.
99+
type DeprecatedEmbeddedObjectMeta struct {
100+
// +optional
101+
Name string `json:"name,omitempty"`
102+
// +optional
103+
Namespace string `json:"namespace,omitempty"`
104+
// +optional
105+
Labels map[string]string `json:"labels,omitempty"`
106+
// +optional
107+
Annotations map[string]string `json:"annotations,omitempty"`
108+
}
109+
110+
// DeprecatedPersistenceSpec mirrors the old rabbitmq-cluster-operator RabbitmqClusterPersistenceSpec type.
111+
type DeprecatedPersistenceSpec struct {
112+
// The name of the StorageClass to claim a PersistentVolume from.
113+
StorageClassName *string `json:"storageClassName,omitempty"`
114+
// The requested size of the persistent volume.
115+
// +kubebuilder:default:="10Gi"
116+
Storage *resource.Quantity `json:"storage,omitempty"`
117+
}
118+
119+
// DeprecatedRabbitmqConfigSpec mirrors the old rabbitmq-cluster-operator RabbitmqClusterConfigurationSpec type.
120+
type DeprecatedRabbitmqConfigSpec struct {
121+
// +optional
122+
AdditionalPlugins []string `json:"additionalPlugins,omitempty"`
123+
// +optional
124+
AdditionalConfig string `json:"additionalConfig,omitempty"`
125+
// +optional
126+
AdvancedConfig string `json:"advancedConfig,omitempty"`
127+
// +optional
128+
EnvConfig string `json:"envConfig,omitempty"`
129+
// +optional
130+
ErlangInetConfig string `json:"erlangInetConfig,omitempty"`
131+
}
132+
133+
// DeprecatedSecretBackendSpec mirrors the old rabbitmq-cluster-operator SecretBackend type.
134+
type DeprecatedSecretBackendSpec struct {
135+
// +optional
136+
ExternalSecret *corev1.LocalObjectReference `json:"externalSecret,omitempty"`
137+
// +optional
138+
Vault *DeprecatedVaultSpec `json:"vault,omitempty"`
139+
}
140+
141+
// DeprecatedVaultSpec mirrors the old rabbitmq-cluster-operator VaultSpec type.
142+
type DeprecatedVaultSpec struct {
143+
// +optional
144+
Role string `json:"role,omitempty"`
145+
// +optional
146+
Annotations map[string]string `json:"annotations,omitempty"`
147+
// +optional
148+
DefaultUserPath string `json:"defaultUserPath,omitempty"`
149+
// +optional
150+
DefaultUserUpdaterImage string `json:"defaultUserUpdaterImage,omitempty"`
151+
// +optional
152+
TLS *DeprecatedVaultTLSSpec `json:"tls,omitempty"`
153+
}
154+
155+
// DeprecatedVaultTLSSpec mirrors the old rabbitmq-cluster-operator VaultSpec TLS fields.
156+
type DeprecatedVaultTLSSpec struct {
157+
// +optional
158+
PkiIssuerPath string `json:"pkiIssuerPath,omitempty"`
159+
// +optional
160+
PkiRootPath string `json:"pkiRootPath,omitempty"`
161+
// +optional
162+
AltNames string `json:"altNames,omitempty"`
163+
// +optional
164+
CommonName string `json:"commonName,omitempty"`
165+
// +optional
166+
IpSans string `json:"ipSans,omitempty"`
167+
}

0 commit comments

Comments
 (0)