Skip to content

Commit 19657d0

Browse files
Merge pull request #723 from Deydra71/appcred-finalizer-split
Split appcred finalizer management
2 parents ded1309 + bcf30e9 commit 19657d0

3 files changed

Lines changed: 71 additions & 8 deletions

File tree

internal/controller/ironic_controller.go

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -508,11 +508,12 @@ func (r *IronicReconciler) reconcileNormal(ctx context.Context, instance *ironic
508508
}
509509
// Create ConfigMaps and Secrets - end
510510

511-
// Manage consumer finalizer for ironic AC secret
512-
if instance.Spec.Auth.ApplicationCredentialSecret != "" || instance.Status.ApplicationCredentialSecret != "" {
511+
// Add consumer finalizer to the new ironic AC secret (early phase of the
512+
// split pattern -- old secret finalizer removal is deferred to end of reconcile).
513+
if instance.Spec.Auth.ApplicationCredentialSecret != "" {
513514
if err := keystonev1.ManageACSecretFinalizer(ctx, helper, instance.Namespace,
514515
instance.Spec.Auth.ApplicationCredentialSecret,
515-
instance.Status.ApplicationCredentialSecret,
516+
"",
516517
ironic.ACConsumerFinalizer); err != nil {
517518
instance.Status.Conditions.Set(condition.FalseCondition(
518519
condition.ServiceConfigReadyCondition,
@@ -523,13 +524,12 @@ func (r *IronicReconciler) reconcileNormal(ctx context.Context, instance *ironic
523524
return ctrl.Result{}, err
524525
}
525526
}
526-
instance.Status.ApplicationCredentialSecret = instance.Spec.Auth.ApplicationCredentialSecret
527527

528-
// Manage consumer finalizer for ironic-inspector AC secret
529-
if instance.Spec.IronicInspector.Auth.ApplicationCredentialSecret != "" || instance.Status.InspectorApplicationCredentialSecret != "" {
528+
// Add consumer finalizer to the new ironic-inspector AC secret.
529+
if instance.Spec.IronicInspector.Auth.ApplicationCredentialSecret != "" {
530530
if err := keystonev1.ManageACSecretFinalizer(ctx, helper, instance.Namespace,
531531
instance.Spec.IronicInspector.Auth.ApplicationCredentialSecret,
532-
instance.Status.InspectorApplicationCredentialSecret,
532+
"",
533533
ironic.InspectorACConsumerFinalizer); err != nil {
534534
instance.Status.Conditions.Set(condition.FalseCondition(
535535
condition.ServiceConfigReadyCondition,
@@ -540,7 +540,6 @@ func (r *IronicReconciler) reconcileNormal(ctx context.Context, instance *ironic
540540
return ctrl.Result{}, err
541541
}
542542
}
543-
instance.Status.InspectorApplicationCredentialSecret = instance.Spec.IronicInspector.Auth.ApplicationCredentialSecret
544543

545544
instance.Status.Conditions.MarkTrue(condition.ServiceConfigReadyCondition, condition.ServiceConfigReadyMessage)
546545

@@ -793,6 +792,37 @@ func (r *IronicReconciler) reconcileNormal(ctx context.Context, instance *ironic
793792
return ctrl.Result{}, err
794793
}
795794

795+
// Late phase of the AC split pattern: remove the old AC secret's finalizer
796+
// and update status only after all sub-services are ready with the new
797+
// credentials. This prevents premature revocation during rapid rotations.
798+
isIronicRotation := instance.Status.ApplicationCredentialSecret != "" &&
799+
instance.Status.ApplicationCredentialSecret != instance.Spec.Auth.ApplicationCredentialSecret
800+
if isIronicRotation {
801+
if instance.Status.Conditions.AllSubConditionIsTrue() {
802+
if err := keystonev1.RemoveACSecretConsumerFinalizer(ctx, helper, instance.Namespace,
803+
instance.Status.ApplicationCredentialSecret, ironic.ACConsumerFinalizer); err != nil {
804+
return ctrl.Result{}, err
805+
}
806+
instance.Status.ApplicationCredentialSecret = instance.Spec.Auth.ApplicationCredentialSecret
807+
}
808+
} else {
809+
instance.Status.ApplicationCredentialSecret = instance.Spec.Auth.ApplicationCredentialSecret
810+
}
811+
812+
isInspectorRotation := instance.Status.InspectorApplicationCredentialSecret != "" &&
813+
instance.Status.InspectorApplicationCredentialSecret != instance.Spec.IronicInspector.Auth.ApplicationCredentialSecret
814+
if isInspectorRotation {
815+
if instance.Status.Conditions.AllSubConditionIsTrue() {
816+
if err := keystonev1.RemoveACSecretConsumerFinalizer(ctx, helper, instance.Namespace,
817+
instance.Status.InspectorApplicationCredentialSecret, ironic.InspectorACConsumerFinalizer); err != nil {
818+
return ctrl.Result{}, err
819+
}
820+
instance.Status.InspectorApplicationCredentialSecret = instance.Spec.IronicInspector.Auth.ApplicationCredentialSecret
821+
}
822+
} else {
823+
instance.Status.InspectorApplicationCredentialSecret = instance.Spec.IronicInspector.Auth.ApplicationCredentialSecret
824+
}
825+
796826
// We reached the end of the Reconcile, update the Ready condition based on
797827
// the sub conditions
798828
if instance.Status.Conditions.AllSubConditionIsTrue() {

test/functional/base_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,28 @@ func GetSampleTopologySpec(label string) (map[string]any, []corev1.TopologySprea
734734
return topologySpec, topologySpecObj
735735
}
736736

737+
func simulateIronicSubServicesReady(names IronicNames) {
738+
th.SimulateJobSuccess(names.IronicDBSyncJobName)
739+
keystone.SimulateKeystoneServiceReady(names.IronicName)
740+
keystone.SimulateKeystoneEndpointReady(names.IronicName)
741+
infra.GetTransportURL(names.InspectorTransportURLName)
742+
infra.SimulateTransportURLReady(names.InspectorTransportURLName)
743+
mariadb.GetMariaDBDatabase(names.InspectorDatabaseName)
744+
mariadb.SimulateMariaDBAccountCompleted(names.InspectorDatabaseAccount)
745+
mariadb.SimulateMariaDBDatabaseCompleted(names.InspectorDatabaseName)
746+
th.SimulateJobSuccess(names.InspectorDBSyncJobName)
747+
keystone.SimulateKeystoneServiceReady(names.InspectorName)
748+
keystone.SimulateKeystoneEndpointReady(names.InspectorName)
749+
nestedINATransportURLName := names.INATransportURLName
750+
nestedINATransportURLName.Name = names.IronicName.Name + "-" + nestedINATransportURLName.Name
751+
infra.GetTransportURL(nestedINATransportURLName)
752+
infra.SimulateTransportURLReady(nestedINATransportURLName)
753+
th.SimulateDeploymentReplicaReady(names.IronicName)
754+
th.SimulateStatefulSetReplicaReady(names.ConductorName)
755+
th.SimulateStatefulSetReplicaReady(names.InspectorName)
756+
th.SimulateDeploymentReplicaReady(names.INAName)
757+
}
758+
737759
// CreateIronicInvalidSecret creates a secret with an invalid password for testing
738760
func CreateIronicInvalidSecret(namespace string, name string) *corev1.Secret {
739761
return th.CreateSecret(

test/functional/ironic_controller_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,7 @@ var _ = Describe("Ironic controller", func() {
17361736
})
17371737

17381738
It("should track the consumed AC secrets in status", func() {
1739+
th.SimulateJobSuccess(ironicNames.IronicDBSyncJobName)
17391740
Eventually(func(g Gomega) {
17401741
i := GetIronic(ironicNames.IronicName)
17411742
g.Expect(i.Status.ApplicationCredentialSecret).To(Equal(acIronicSecretName))
@@ -1753,6 +1754,12 @@ var _ = Describe("Ironic controller", func() {
17531754
ContainElement(ironic.ACConsumerFinalizer))
17541755
}, timeout, interval).Should(Succeed())
17551756

1757+
simulateIronicSubServicesReady(ironicNames)
1758+
Eventually(func(g Gomega) {
1759+
i := GetIronic(ironicNames.IronicName)
1760+
g.Expect(i.Status.Conditions.IsTrue(condition.ReadyCondition)).To(BeTrue())
1761+
}, timeout, interval).Should(Succeed())
1762+
17561763
newACSecretName := "ac-ironic-rotated-x9y8z7-secret" //nolint:gosec // G101
17571764
newSecret := &corev1.Secret{
17581765
ObjectMeta: metav1.ObjectMeta{
@@ -1783,6 +1790,10 @@ var _ = Describe("Ironic controller", func() {
17831790
}, timeout, interval).Should(Succeed())
17841791

17851792
Eventually(func(g Gomega) {
1793+
th.SimulateDeploymentReplicaReady(ironicNames.IronicName)
1794+
th.SimulateStatefulSetReplicaReady(ironicNames.ConductorName)
1795+
th.SimulateStatefulSetReplicaReady(ironicNames.InspectorName)
1796+
th.SimulateDeploymentReplicaReady(ironicNames.INAName)
17861797
secret := th.GetSecret(types.NamespacedName{
17871798
Namespace: ironicNames.Namespace,
17881799
Name: acIronicSecretName,

0 commit comments

Comments
 (0)