Skip to content

Commit 12f90e2

Browse files
Andrea SerrecchiaSergK
authored andcommitted
feat: Allow finalizer cleanup when realm is already deleted (#173)
1 parent f5f5e66 commit 12f90e2

File tree

11 files changed

+147
-4
lines changed

11 files changed

+147
-4
lines changed

cmd/main.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,6 @@ func enableOwnerRef() bool {
323323
b, err := strconv.ParseBool(val)
324324
if err != nil {
325325
setupLog.Error(err, "unable to parse ENABLE_OWNER_REF. Using default value false")
326-
327326
return false
328327
}
329328

internal/controller/helper/controller_helper.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ type ControllerHelper interface {
6565
SetRealmOwnerRef(ctx context.Context, object ObjectWithRealmRef) error
6666
SetFailureCount(fc FailureCountable) time.Duration
6767
TryToDelete(ctx context.Context, obj client.Object, terminator Terminator, finalizer string) (isDeleted bool, resultErr error)
68+
TryRemoveFinalizer(ctx context.Context, obj client.Object, finalizer string) error
6869
GetKeycloakRealmFromRef(ctx context.Context, object ObjectWithRealmRef, kcClient keycloak.Client) (*gocloak.RealmRepresentation, error)
6970
CreateKeycloakClientFromRealmRef(ctx context.Context, object ObjectWithRealmRef) (keycloak.Client, error)
7071
CreateKeycloakClientFromRealm(ctx context.Context, realm *keycloakApi.KeycloakRealm) (keycloak.Client, error)
@@ -248,6 +249,18 @@ func (h *Helper) SetRealmOwnerRef(ctx context.Context, object ObjectWithRealmRef
248249
}
249250
}
250251

252+
func (h *Helper) TryRemoveFinalizer(ctx context.Context, obj client.Object, finalizer string) error {
253+
if !obj.GetDeletionTimestamp().IsZero() {
254+
if controllerutil.RemoveFinalizer(obj, finalizer) {
255+
if err := h.client.Update(ctx, obj); err != nil {
256+
return errors.Wrap(err, "unable to update instance")
257+
}
258+
}
259+
}
260+
261+
return nil
262+
}
263+
251264
func (h *Helper) TryToDelete(ctx context.Context, obj client.Object, terminator Terminator, finalizer string) (isDeleted bool, resultErr error) {
252265
logger := ctrl.LoggerFrom(ctx)
253266

internal/controller/helper/controller_helper_auth.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const (
2525
)
2626

2727
var ErrKeycloakIsNotAvailable = errors.New("keycloak is not available")
28+
var ErrKeycloakRealmNotFound = errors.New("keycloak realm is not available")
2829

2930
// KeycloakAuthData contains data for keycloak authentication.
3031
type KeycloakAuthData struct {
@@ -220,13 +221,21 @@ func (h *Helper) getKeycloakAuthDataFromRealmRef(ctx context.Context, object Obj
220221
case keycloakApi.KeycloakRealmKind:
221222
realm := &keycloakApi.KeycloakRealm{}
222223
if err := h.client.Get(ctx, types.NamespacedName{Name: name, Namespace: object.GetNamespace()}, realm); err != nil {
224+
if k8sErrors.IsNotFound(err) && object.GetDeletionTimestamp() != nil {
225+
return nil, ErrKeycloakRealmNotFound
226+
}
227+
223228
return nil, fmt.Errorf("unable to get realm: %w", err)
224229
}
225230

226231
return h.getKeycloakAuthDataFromRealm(ctx, realm)
227232
case keycloakAlpha.ClusterKeycloakRealmKind:
228233
clusterRealm := &keycloakAlpha.ClusterKeycloakRealm{}
229234
if err := h.client.Get(ctx, types.NamespacedName{Name: name}, clusterRealm); err != nil {
235+
if k8sErrors.IsNotFound(err) && object.GetDeletionTimestamp() != nil {
236+
return nil, ErrKeycloakRealmNotFound
237+
}
238+
230239
return nil, fmt.Errorf("unable to get cluster realm: %w", err)
231240
}
232241

internal/controller/keycloakauthflow/keycloakauthflow_controller.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const finalizerName = "keycloak.authflow.operator.finalizer.name"
2727

2828
type Helper interface {
2929
SetFailureCount(fc helper.FailureCountable) time.Duration
30+
TryRemoveFinalizer(ctx context.Context, obj client.Object, finalizer string) error
3031
TryToDelete(ctx context.Context, obj client.Object, terminator helper.Terminator, finalizer string) (isDeleted bool, resultErr error)
3132
CreateKeycloakClientFromRealmRef(ctx context.Context, object helper.ObjectWithRealmRef) (keycloak.Client, error)
3233
SetRealmOwnerRef(ctx context.Context, object helper.ObjectWithRealmRef) error
@@ -126,6 +127,15 @@ func (r *Reconcile) tryReconcile(ctx context.Context, instance *keycloakApi.Keyc
126127

127128
kClient, err := r.helper.CreateKeycloakClientFromRealmRef(ctx, instance)
128129
if err != nil {
130+
// if the realm is already deleted try to delete finalizer
131+
if errors.Is(err, helper.ErrKeycloakRealmNotFound) {
132+
if removeErr := r.helper.TryRemoveFinalizer(ctx, instance, finalizerName); removeErr != nil {
133+
return fmt.Errorf("unable to remove finalizer: %w", removeErr)
134+
}
135+
136+
return nil
137+
}
138+
129139
return fmt.Errorf("unable to create keycloak client from realm ref: %w", err)
130140
}
131141

internal/controller/keycloakclient/keycloakclient_controller.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
type Helper interface {
2626
SetFailureCount(fc helper.FailureCountable) time.Duration
27+
TryRemoveFinalizer(ctx context.Context, obj client.Object, finalizer string) error
2728
TryToDelete(ctx context.Context, obj client.Object, terminator helper.Terminator, finalizer string) (isDeleted bool, resultErr error)
2829
SetRealmOwnerRef(ctx context.Context, object helper.ObjectWithRealmRef) error
2930
CreateKeycloakClientFromRealmRef(ctx context.Context, object helper.ObjectWithRealmRef) (keycloak.Client, error)
@@ -125,6 +126,15 @@ func (r *ReconcileKeycloakClient) tryReconcile(ctx context.Context, keycloakClie
125126

126127
kClient, err := r.helper.CreateKeycloakClientFromRealmRef(ctx, keycloakClient)
127128
if err != nil {
129+
// if the realm is already deleted try to delete finalizer
130+
if errors.Is(err, helper.ErrKeycloakRealmNotFound) {
131+
if removeErr := r.helper.TryRemoveFinalizer(ctx, keycloakClient, keyCloakClientOperatorFinalizerName); removeErr != nil {
132+
return fmt.Errorf("unable to remove finalizer: %w", removeErr)
133+
}
134+
135+
return nil
136+
}
137+
128138
return fmt.Errorf("unable to create keycloak client from realm ref: %w", err)
129139
}
130140

internal/controller/keycloakclient/keycloakclient_controller_integration_test.go

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1313
"k8s.io/apimachinery/pkg/types"
14+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
1415

1516
"github.com/epam/edp-keycloak-operator/api/common"
1617
keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
@@ -65,7 +66,7 @@ var _ = Describe("KeycloakClient controller", Ordered, func() {
6566
Browser: "browser",
6667
DirectGrant: "direct grant",
6768
},
68-
AdminFineGrainedPermissionsEnabled: true,
69+
//AdminFineGrainedPermissionsEnabled: true,
6970
},
7071
}
7172

@@ -397,4 +398,55 @@ var _ = Describe("KeycloakClient controller", Ordered, func() {
397398
createdKeycloakClient.Status.ClientID != ""
398399
}, timeout, interval).Should(BeTrue(), "KeycloakClient should be updated successfully")
399400
})
401+
402+
It("Should successfully delete KeycloakClient if ErrKeycloakRealmNotFound occurs", func() {
403+
By("By creating a KeycloakRealm")
404+
testRealm := &keycloakApi.KeycloakRealm{
405+
ObjectMeta: metav1.ObjectMeta{
406+
Name: "test-realm",
407+
Namespace: ns,
408+
},
409+
Spec: keycloakApi.KeycloakRealmSpec{
410+
RealmName: "test-realm",
411+
KeycloakRef: common.KeycloakRef{
412+
Kind: keycloakApi.KeycloakKind,
413+
Name: KeycloakCR,
414+
},
415+
},
416+
}
417+
Expect(k8sClient.Create(ctx, testRealm)).Should(Succeed())
418+
419+
By("Creating a KeycloakClient")
420+
keycloakClient := &keycloakApi.KeycloakClient{
421+
ObjectMeta: metav1.ObjectMeta{
422+
Name: "test-keycloak-client",
423+
Namespace: ns,
424+
},
425+
Spec: keycloakApi.KeycloakClientSpec{
426+
RealmRef: common.RealmRef{Name: "test-realm"},
427+
ClientId: "test-client-id",
428+
},
429+
}
430+
Expect(k8sClient.Create(ctx, keycloakClient)).Should(Succeed())
431+
432+
By("Waiting for KeycloakClient to be ready")
433+
Eventually(func() bool {
434+
var c keycloakApi.KeycloakClient
435+
err := k8sClient.Get(ctx, types.NamespacedName{Name: keycloakClient.Name, Namespace: ns}, &c)
436+
return err == nil && controllerutil.ContainsFinalizer(&c, keyCloakClientOperatorFinalizerName)
437+
}, timeout, interval).Should(BeTrue())
438+
439+
By("Deleting KeycloakRealm")
440+
Expect(k8sClient.Delete(ctx, testRealm)).Should(Succeed())
441+
442+
By("Deleting KeycloakClient")
443+
Expect(k8sClient.Delete(ctx, keycloakClient)).Should(Succeed())
444+
445+
By("Waiting for KeycloakClient to be deleted")
446+
Eventually(func() bool {
447+
var c keycloakApi.KeycloakClient
448+
err := k8sClient.Get(ctx, types.NamespacedName{Name: keycloakClient.Name, Namespace: ns}, &c)
449+
return k8sErrors.IsNotFound(err)
450+
}, timeout, interval).Should(BeTrue())
451+
})
400452
})

internal/controller/keycloakclientscope/keycloakclientscope_controller.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const finalizerName = "keycloak.clientscope.operator.finalizer.name"
2828

2929
type Helper interface {
3030
SetFailureCount(fc helper.FailureCountable) time.Duration
31+
TryRemoveFinalizer(ctx context.Context, obj client.Object, finalizer string) error
3132
TryToDelete(ctx context.Context, obj client.Object, terminator helper.Terminator, finalizer string) (isDeleted bool, resultErr error)
3233
SetRealmOwnerRef(ctx context.Context, object helper.ObjectWithRealmRef) error
3334
GetKeycloakRealmFromRef(ctx context.Context, object helper.ObjectWithRealmRef, kcClient keycloak.Client) (*gocloak.RealmRepresentation, error)
@@ -131,6 +132,15 @@ func (r *Reconcile) tryReconcile(ctx context.Context, instance *keycloakApi.Keyc
131132

132133
cl, err := r.helper.CreateKeycloakClientFromRealmRef(ctx, instance)
133134
if err != nil {
135+
// if the realm is already deleted try to delete finalizer
136+
if errors.Is(err, helper.ErrKeycloakRealmNotFound) {
137+
if removeErr := r.helper.TryRemoveFinalizer(ctx, instance, finalizerName); removeErr != nil {
138+
return "", fmt.Errorf("unable to remove finalizer: %w", removeErr)
139+
}
140+
141+
return "", nil
142+
}
143+
134144
return "", fmt.Errorf("unable to create keycloak client from realm ref: %w", err)
135145
}
136146

internal/controller/keycloakrealmgroup/keycloakrealmgroup_controller.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const keyCloakRealmGroupOperatorFinalizerName = "keycloak.realmgroup.operator.fi
2424

2525
type Helper interface {
2626
SetFailureCount(fc helper.FailureCountable) time.Duration
27+
TryRemoveFinalizer(ctx context.Context, obj client.Object, finalizer string) error
2728
TryToDelete(ctx context.Context, obj client.Object, terminator helper.Terminator, finalizer string) (isDeleted bool, resultErr error)
2829
SetRealmOwnerRef(ctx context.Context, object helper.ObjectWithRealmRef) error
2930
GetKeycloakRealmFromRef(ctx context.Context, object helper.ObjectWithRealmRef, kcClient keycloak.Client) (*gocloak.RealmRepresentation, error)
@@ -115,6 +116,15 @@ func (r *ReconcileKeycloakRealmGroup) tryReconcile(ctx context.Context, keycloak
115116

116117
kClient, err := r.helper.CreateKeycloakClientFromRealmRef(ctx, keycloakRealmGroup)
117118
if err != nil {
119+
// if the realm is already deleted try to delete finalizer
120+
if errors.Is(err, helper.ErrKeycloakRealmNotFound) {
121+
if removeErr := r.helper.TryRemoveFinalizer(ctx, keycloakRealmGroup, keyCloakRealmGroupOperatorFinalizerName); removeErr != nil {
122+
return fmt.Errorf("unable to remove finalizer: %w", removeErr)
123+
}
124+
125+
return nil
126+
}
127+
118128
return fmt.Errorf("unable to create keycloak client from realm ref: %w", err)
119129
}
120130

internal/controller/keycloakrealmidentityprovider/keycloakrealmidentityprovider_controller.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const finalizerName = "keycloak.realmidp.operator.finalizer.name"
2828

2929
type Helper interface {
3030
SetFailureCount(fc helper.FailureCountable) time.Duration
31+
TryRemoveFinalizer(ctx context.Context, obj client.Object, finalizer string) error
3132
TryToDelete(ctx context.Context, obj client.Object, terminator helper.Terminator, finalizer string) (isDeleted bool, resultErr error)
3233
SetRealmOwnerRef(ctx context.Context, object helper.ObjectWithRealmRef) error
3334
GetKeycloakRealmFromRef(ctx context.Context, object helper.ObjectWithRealmRef, kcClient keycloak.Client) (*gocloak.RealmRepresentation, error)
@@ -139,6 +140,15 @@ func (r *Reconcile) tryReconcile(ctx context.Context, keycloakRealmIDP *keycloak
139140

140141
kClient, err := r.helper.CreateKeycloakClientFromRealmRef(ctx, keycloakRealmIDP)
141142
if err != nil {
143+
// if the realm is already deleted try to delete finalizer
144+
if errors.Is(err, helper.ErrKeycloakRealmNotFound) {
145+
if removeErr := r.helper.TryRemoveFinalizer(ctx, keycloakRealmIDP, finalizerName); removeErr != nil {
146+
return fmt.Errorf("unable to remove finalizer: %w", removeErr)
147+
}
148+
149+
return nil
150+
}
151+
142152
return fmt.Errorf("unable to create keycloak client from realm ref: %w", err)
143153
}
144154

internal/controller/keycloakrealmrole/keycloakrealmrole_controller.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const keyCloakRealmRoleOperatorFinalizerName = "keycloak.realmrole.operator.fina
2727

2828
type Helper interface {
2929
SetFailureCount(fc helper.FailureCountable) time.Duration
30+
TryRemoveFinalizer(ctx context.Context, obj client.Object, finalizer string) error
3031
TryToDelete(ctx context.Context, obj client.Object, terminator helper.Terminator, finalizer string) (isDeleted bool, resultErr error)
3132
SetRealmOwnerRef(ctx context.Context, object helper.ObjectWithRealmRef) error
3233
GetKeycloakRealmFromRef(ctx context.Context, object helper.ObjectWithRealmRef, kcClient keycloak.Client) (*gocloak.RealmRepresentation, error)
@@ -138,6 +139,15 @@ func (r *ReconcileKeycloakRealmRole) tryReconcile(ctx context.Context, keycloakR
138139

139140
kClient, err := r.helper.CreateKeycloakClientFromRealmRef(ctx, keycloakRealmRole)
140141
if err != nil {
142+
// if the realm is already deleted try to delete finalizer
143+
if errors.Is(err, helper.ErrKeycloakRealmNotFound) {
144+
if removeErr := r.helper.TryRemoveFinalizer(ctx, keycloakRealmRole, keyCloakRealmRoleOperatorFinalizerName); removeErr != nil {
145+
return "", fmt.Errorf("unable to remove finalizer: %w", removeErr)
146+
}
147+
148+
return "", nil
149+
}
150+
141151
return "", fmt.Errorf("unable to create keycloak client from realm ref: %w", err)
142152
}
143153

0 commit comments

Comments
 (0)