Skip to content

Commit 97bb482

Browse files
lmicciniclaude
andcommitted
Implement RabbitMQ user finalizer management for EDPM nodes
Add dataplane-specific logic to track and manage RabbitMQ user finalizers for OpenStackDataPlaneNodeSet services, enabling safe credential rotation across multi-cluster deployments. Key features: - Per-nodeset finalizers on shared RabbitMQ users - Incremental deployment support with proper finalizer timing - Nova-operator rabbitmq_user_name field integration for simplified tracking - Automatic cleanup of temporary cleanup-blocked finalizers - Comprehensive test coverage for rotation and multi-cluster scenarios Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent f46ba0f commit 97bb482

16 files changed

+4381
-3
lines changed

api/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,6 +1973,14 @@ spec:
19731973
items:
19741974
type: string
19751975
type: array
1976+
finalizerHash:
1977+
description: |-
1978+
FinalizerHash is a short, deterministic hash derived from the nodeset name.
1979+
Used to create unique, collision-free finalizer names for RabbitMQ users.
1980+
Format: first 8 characters of SHA256(nodeset.metadata.name)
1981+
Example: "a3f2b5c8"
1982+
This allows easy lookup of which nodeset owns a specific finalizer.
1983+
type: string
19761984
inventorySecretName:
19771985
description: InventorySecretName Name of a secret containing the ansible
19781986
inventory

api/dataplane/v1beta1/openstackdataplanenodeset_types.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,13 @@ type OpenStackDataPlaneNodeSetStatus struct {
160160

161161
//DeployedBmhHash - Hash of BMHs deployed
162162
DeployedBmhHash string `json:"deployedBmhHash,omitempty"`
163+
164+
// FinalizerHash is a short, deterministic hash derived from the nodeset name.
165+
// Used to create unique, collision-free finalizer names for RabbitMQ users.
166+
// Format: first 8 characters of SHA256(nodeset.metadata.name)
167+
// Example: "a3f2b5c8"
168+
// This allows easy lookup of which nodeset owns a specific finalizer.
169+
FinalizerHash string `json:"finalizerHash,omitempty"`
163170
}
164171

165172
// +kubebuilder:object:root=true

api/dataplane/v1beta1/openstackdataplanenodeset_webhook.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
apierrors "k8s.io/apimachinery/pkg/api/errors"
2929
"k8s.io/apimachinery/pkg/runtime"
3030
"k8s.io/apimachinery/pkg/runtime/schema"
31+
"k8s.io/apimachinery/pkg/types"
3132
apimachineryvalidation "k8s.io/apimachinery/pkg/util/validation"
3233
"k8s.io/apimachinery/pkg/util/validation/field"
3334
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -170,6 +171,27 @@ func (r *OpenStackDataPlaneNodeSet) ValidateUpdate(ctx context.Context, old runt
170171
for deployName, deployConditions := range oldNodeSet.Status.DeploymentStatuses {
171172
deployCondition := deployConditions.Get(NodeSetDeploymentReadyCondition)
172173
if !deployConditions.IsTrue(NodeSetDeploymentReadyCondition) && !condition.IsError(deployCondition) {
174+
// Check if the deployment is being deleted - if so, allow the NodeSet update
175+
deployment := &OpenStackDataPlaneDeployment{}
176+
err := c.Get(ctx, types.NamespacedName{Name: deployName, Namespace: r.Namespace}, deployment)
177+
if err != nil {
178+
if apierrors.IsNotFound(err) {
179+
// Deployment no longer exists, allow the update
180+
continue
181+
}
182+
// If we can't check the deployment, log but don't block
183+
openstackdataplanenodesetlog.Info("could not check deployment status during validation",
184+
"deployment", deployName, "error", err)
185+
continue
186+
}
187+
188+
// If deployment is being deleted, allow the NodeSet update
189+
if deployment.DeletionTimestamp != nil {
190+
openstackdataplanenodesetlog.Info("allowing NodeSet update because deployment is being deleted",
191+
"deployment", deployName)
192+
continue
193+
}
194+
173195
return nil, apierrors.NewConflict(
174196
schema.GroupResource{Group: "dataplane.openstack.org", Resource: "OpenStackDataPlaneNodeSet"},
175197
r.Name,

bindata/crds/crds.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20543,6 +20543,14 @@ spec:
2054320543
items:
2054420544
type: string
2054520545
type: array
20546+
finalizerHash:
20547+
description: |-
20548+
FinalizerHash is a short, deterministic hash derived from the nodeset name.
20549+
Used to create unique, collision-free finalizer names for RabbitMQ users.
20550+
Format: first 8 characters of SHA256(nodeset.metadata.name)
20551+
Example: "a3f2b5c8"
20552+
This allows easy lookup of which nodeset owns a specific finalizer.
20553+
type: string
2054620554
inventorySecretName:
2054720555
description: InventorySecretName Name of a secret containing the ansible
2054820556
inventory

bindata/rbac/rbac.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,23 @@ rules:
655655
- patch
656656
- update
657657
- watch
658+
- apiGroups:
659+
- rabbitmq.openstack.org
660+
resources:
661+
- rabbitmqusers
662+
verbs:
663+
- get
664+
- list
665+
- patch
666+
- update
667+
- watch
668+
- apiGroups:
669+
- rabbitmq.openstack.org
670+
resources:
671+
- rabbitmqusers/finalizers
672+
verbs:
673+
- patch
674+
- update
658675
- apiGroups:
659676
- rbac.authorization.k8s.io
660677
resources:

config/crd/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,6 +1973,14 @@ spec:
19731973
items:
19741974
type: string
19751975
type: array
1976+
finalizerHash:
1977+
description: |-
1978+
FinalizerHash is a short, deterministic hash derived from the nodeset name.
1979+
Used to create unique, collision-free finalizer names for RabbitMQ users.
1980+
Format: first 8 characters of SHA256(nodeset.metadata.name)
1981+
Example: "a3f2b5c8"
1982+
This allows easy lookup of which nodeset owns a specific finalizer.
1983+
type: string
19761984
inventorySecretName:
19771985
description: InventorySecretName Name of a secret containing the ansible
19781986
inventory

config/rbac/role.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,23 @@ rules:
606606
- patch
607607
- update
608608
- watch
609+
- apiGroups:
610+
- rabbitmq.openstack.org
611+
resources:
612+
- rabbitmqusers
613+
verbs:
614+
- get
615+
- list
616+
- patch
617+
- update
618+
- watch
619+
- apiGroups:
620+
- rabbitmq.openstack.org
621+
resources:
622+
- rabbitmqusers/finalizers
623+
verbs:
624+
- patch
625+
- update
609626
- apiGroups:
610627
- rbac.authorization.k8s.io
611628
resources:

0 commit comments

Comments
 (0)