Skip to content

Commit a782229

Browse files
committed
feat: Remove ownerReference from Keycloak resources (#71)
Setting ownerReference with controller:true for Keycloak resources has disadvantages: - `controller: true` should be set for resources created by a controller. For example, we create a Deployment, and the controller creates a ReplicaSet with an `ownerReference` to the Deployment. In our case, we create resources separately, and the Keycloak controller isn't responsible for their creation. - ArgoCD doesn't remove resources with `controller: true`. It considers another controller responsible for them. If we remove the ArgoCD environment that contains KeycloakClient, this CR won't be removed by either ArgoCD or the Keycloak operator. This change breaks the automatic deletion of CRs if related Keycloak/KeycloakRealm is removed. Now, it isn't the responsibility of the keycloak operator.
1 parent a4331c6 commit a782229

16 files changed

+8
-352
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ To prevent the operator from deleting resources from Keycloak, add the `edp.epam
125125
kind: Keycloak
126126
```
127127

128+
#### Resources deletion
129+
130+
To avoid resources getting stuck during deletion, it is important to delete them in the correct order:
131+
132+
1. **First**, remove realm resources `KeycloakClient`, `KeycloakRealmUser`, etc.
133+
2. **Then**, remove `KeycloakRealm`/`ClusterKeycloakRealm`.
134+
3. **Finally**, remove `Keycloak`/`ClusterKeycloak`.
135+
128136
## Local Development
129137

130138
To develop the operator, first set up a local environment, and refer to the [Local Development](https://epam.github.io/edp-install/developer-guide/local-development/) page.

controllers/clusterkeycloakrealm/clusterkeycloakrealm_controller.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ type Helper interface {
2323
SetFailureCount(fc helper.FailureCountable) time.Duration
2424
TryToDelete(ctx context.Context, obj client.Object, terminator helper.Terminator, finalizer string) (isDeleted bool, resultErr error)
2525
CreateKeycloakClientFromClusterRealm(ctx context.Context, realm *keycloakAlpha.ClusterKeycloakRealm) (keycloak.Client, error)
26-
SetKeycloakOwnerRef(ctx context.Context, object helper.ObjectWithKeycloakRef) error
2726
InvalidateKeycloakClientTokenSecret(ctx context.Context, namespace, rootKeycloakName string) error
2827
}
2928

@@ -61,10 +60,6 @@ func (r *ClusterKeycloakRealmReconciler) Reconcile(ctx context.Context, req ctrl
6160
return ctrl.Result{}, fmt.Errorf("unable to get cluster realm: %w", err)
6261
}
6362

64-
if err := r.helper.SetKeycloakOwnerRef(ctx, clusterRealm); err != nil {
65-
return ctrl.Result{}, fmt.Errorf("unable to set keycloak owner ref: %w", err)
66-
}
67-
6863
kClient, err := r.helper.CreateKeycloakClientFromClusterRealm(ctx, clusterRealm)
6964
if err != nil {
7065
if errors.Is(err, helper.ErrKeycloakIsNotAvailable) {

controllers/helper/controller_helper.go

Lines changed: 0 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"github.com/go-logr/logr"
1111
"github.com/go-resty/resty/v2"
1212
"github.com/pkg/errors"
13-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1413
"k8s.io/apimachinery/pkg/runtime"
1514
"k8s.io/apimachinery/pkg/types"
1615
ctrl "sigs.k8s.io/controller-runtime"
@@ -61,8 +60,6 @@ type adapterBuilder func(
6160
//
6261
//go:generate mockery --name ControllerHelper --filename helper_mock.go
6362
type ControllerHelper interface {
64-
SetKeycloakOwnerRef(ctx context.Context, object ObjectWithKeycloakRef) error
65-
SetRealmOwnerRef(ctx context.Context, object ObjectWithRealmRef) error
6663
SetFailureCount(fc FailureCountable) time.Duration
6764
TryToDelete(ctx context.Context, obj client.Object, terminator Terminator, finalizer string) (isDeleted bool, resultErr error)
6865
GetKeycloakRealmFromRef(ctx context.Context, object ObjectWithRealmRef, kcClient keycloak.Client) (*gocloak.RealmRepresentation, error)
@@ -115,114 +112,6 @@ func MakeHelper(client client.Client, scheme *runtime.Scheme, operatorNamespace
115112
}
116113
}
117114

118-
// SetKeycloakOwnerRef sets owner reference for object.
119-
//
120-
//nolint:dupl,cyclop
121-
func (h *Helper) SetKeycloakOwnerRef(ctx context.Context, object ObjectWithKeycloakRef) error {
122-
if metav1.GetControllerOf(object) != nil {
123-
return nil
124-
}
125-
126-
kind := object.GetKeycloakRef().Kind
127-
name := object.GetKeycloakRef().Name
128-
129-
switch kind {
130-
case keycloakApi.KeycloakKind:
131-
kc := &keycloakApi.Keycloak{}
132-
if err := h.client.Get(ctx, types.NamespacedName{
133-
Namespace: object.GetNamespace(),
134-
Name: name,
135-
}, kc); err != nil {
136-
return fmt.Errorf("failed to get Keycloak: %w", err)
137-
}
138-
139-
if err := controllerutil.SetControllerReference(kc, object, h.scheme); err != nil {
140-
return fmt.Errorf("failed to set controller reference for %s: %w", object.GetName(), err)
141-
}
142-
143-
if err := h.client.Update(ctx, object); err != nil {
144-
return fmt.Errorf("failed to update keycloak owner reference %s: %w", kc.GetName(), err)
145-
}
146-
147-
return nil
148-
149-
case keycloakAlpha.ClusterKeycloakKind:
150-
clusterKc := &keycloakAlpha.ClusterKeycloak{}
151-
if err := h.client.Get(ctx, types.NamespacedName{
152-
Name: name,
153-
}, clusterKc); err != nil {
154-
return fmt.Errorf("failed to get ClusterKeycloak: %w", err)
155-
}
156-
157-
if err := controllerutil.SetControllerReference(clusterKc, object, h.scheme); err != nil {
158-
return fmt.Errorf("failed to set controller reference for %s: %w", object.GetName(), err)
159-
}
160-
161-
if err := h.client.Update(ctx, object); err != nil {
162-
return fmt.Errorf("failed to update keycloak owner reference %s: %w", clusterKc.GetName(), err)
163-
}
164-
165-
return nil
166-
167-
default:
168-
return fmt.Errorf("unknown keycloak kind: %s", kind)
169-
}
170-
}
171-
172-
// SetRealmOwnerRef sets owner reference for object.
173-
//
174-
//nolint:dupl,cyclop
175-
func (h *Helper) SetRealmOwnerRef(ctx context.Context, object ObjectWithRealmRef) error {
176-
if metav1.GetControllerOf(object) != nil {
177-
return nil
178-
}
179-
180-
kind := object.GetRealmRef().Kind
181-
name := object.GetRealmRef().Name
182-
183-
switch kind {
184-
case keycloakApi.KeycloakRealmKind:
185-
realm := &keycloakApi.KeycloakRealm{}
186-
if err := h.client.Get(ctx, types.NamespacedName{
187-
Namespace: object.GetNamespace(),
188-
Name: name,
189-
}, realm); err != nil {
190-
return fmt.Errorf("failed to get KeycloakRealm: %w", err)
191-
}
192-
193-
if err := controllerutil.SetControllerReference(realm, object, h.scheme); err != nil {
194-
return fmt.Errorf("failed to set controller reference for %s: %w", object.GetName(), err)
195-
}
196-
197-
if err := h.client.Update(ctx, object); err != nil {
198-
return fmt.Errorf("failed to update realm owner reference %s: %w", realm.GetName(), err)
199-
}
200-
201-
return nil
202-
203-
case keycloakAlpha.ClusterKeycloakRealmKind:
204-
clusterRealm := &keycloakAlpha.ClusterKeycloakRealm{}
205-
if err := h.client.Get(ctx, types.NamespacedName{
206-
Name: name,
207-
}, clusterRealm); err != nil {
208-
return fmt.Errorf("failed to get ClusterKeycloakRealm: %w", err)
209-
}
210-
211-
if err := controllerutil.SetControllerReference(clusterRealm, object, h.scheme); err != nil {
212-
return fmt.Errorf("unable to set controller reference for %s: %w", object.GetName(), err)
213-
}
214-
215-
if err := h.client.Update(ctx, object); err != nil {
216-
return fmt.Errorf("failed to update realm owner reference %s: %w", clusterRealm.GetName(), err)
217-
}
218-
219-
return nil
220-
221-
default:
222-
return fmt.Errorf("unknown realm kind: %s", kind)
223-
}
224-
}
225-
226115
func (h *Helper) TryToDelete(ctx context.Context, obj client.Object, terminator Terminator, finalizer string) (isDeleted bool, resultErr error) {
227116
logger := ctrl.LoggerFrom(ctx)
228117

controllers/helper/controller_helper_test.go

Lines changed: 0 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -8,139 +8,17 @@ import (
88
"github.com/go-logr/logr"
99
"github.com/go-resty/resty/v2"
1010
"github.com/pkg/errors"
11-
"github.com/stretchr/testify/assert"
12-
testifymock "github.com/stretchr/testify/mock"
1311
"github.com/stretchr/testify/require"
1412
corev1 "k8s.io/api/core/v1"
1513
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16-
"k8s.io/apimachinery/pkg/runtime"
17-
"k8s.io/apimachinery/pkg/types"
18-
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
1914
"sigs.k8s.io/controller-runtime/pkg/client/fake"
2015

21-
"github.com/epam/edp-keycloak-operator/api/common"
2216
keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
2317
"github.com/epam/edp-keycloak-operator/pkg/client/keycloak/adapter"
2418
"github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mock"
2519
"github.com/epam/edp-keycloak-operator/pkg/fakehttp"
2620
)
2721

28-
func TestHelper_GetOrCreateRealmOwnerRef(t *testing.T) {
29-
mc := K8SClientMock{}
30-
31-
sch := runtime.NewScheme()
32-
utilruntime.Must(keycloakApi.AddToScheme(sch))
33-
34-
helper := MakeHelper(&mc, sch, "default")
35-
36-
kcGroup := keycloakApi.KeycloakRealmGroup{
37-
ObjectMeta: metav1.ObjectMeta{
38-
Namespace: "test",
39-
},
40-
Spec: keycloakApi.KeycloakRealmGroupSpec{
41-
RealmRef: common.RealmRef{
42-
Kind: keycloakApi.KeycloakRealmKind,
43-
Name: "realm",
44-
},
45-
},
46-
}
47-
48-
mc.On("Get", types.NamespacedName{
49-
Namespace: "test",
50-
Name: "realm",
51-
}, &keycloakApi.KeycloakRealm{}).Return(nil)
52-
mc.On("Update", testifymock.Anything, testifymock.Anything).Return(nil)
53-
54-
err := helper.SetRealmOwnerRef(context.Background(), &kcGroup)
55-
require.NoError(t, err)
56-
57-
kcGroup = keycloakApi.KeycloakRealmGroup{
58-
ObjectMeta: metav1.ObjectMeta{
59-
Namespace: "test",
60-
},
61-
Spec: keycloakApi.KeycloakRealmGroupSpec{
62-
Realm: "foo13",
63-
RealmRef: common.RealmRef{
64-
Kind: keycloakApi.KeycloakRealmKind,
65-
Name: "realm",
66-
},
67-
},
68-
}
69-
70-
mc.On("Get", types.NamespacedName{
71-
Namespace: "test",
72-
Name: "foo13",
73-
}, &keycloakApi.KeycloakRealm{}).Return(nil)
74-
75-
err = helper.SetRealmOwnerRef(context.Background(), &kcGroup)
76-
require.NoError(t, err)
77-
}
78-
79-
func TestHelper_GetOrCreateRealmOwnerRef_Failure(t *testing.T) {
80-
mc := K8SClientMock{}
81-
82-
sch := runtime.NewScheme()
83-
utilruntime.Must(keycloakApi.AddToScheme(sch))
84-
85-
helper := MakeHelper(&mc, sch, "default")
86-
87-
kcGroup := keycloakApi.KeycloakRealmGroup{
88-
ObjectMeta: metav1.ObjectMeta{
89-
Namespace: "test",
90-
OwnerReferences: []metav1.OwnerReference{
91-
{
92-
Name: "foo",
93-
Kind: "KeycloakRealm",
94-
},
95-
},
96-
},
97-
Spec: keycloakApi.KeycloakRealmGroupSpec{
98-
RealmRef: common.RealmRef{
99-
Kind: keycloakApi.KeycloakRealmKind,
100-
Name: "realm",
101-
},
102-
},
103-
}
104-
105-
mockErr := errors.New("mock error")
106-
107-
mc.On("Get", types.NamespacedName{
108-
Namespace: "test",
109-
Name: kcGroup.Spec.RealmRef.Name,
110-
}, &keycloakApi.KeycloakRealm{}).Return(mockErr)
111-
112-
err := helper.SetRealmOwnerRef(context.Background(), &kcGroup)
113-
if err == nil {
114-
t.Fatal("no error on k8s client get fatal")
115-
}
116-
117-
assert.ErrorIs(t, err, mockErr)
118-
119-
kcGroup = keycloakApi.KeycloakRealmGroup{
120-
ObjectMeta: metav1.ObjectMeta{
121-
Namespace: "test",
122-
},
123-
Spec: keycloakApi.KeycloakRealmGroupSpec{
124-
RealmRef: common.RealmRef{
125-
Kind: keycloakApi.KeycloakRealmKind,
126-
Name: "realm",
127-
},
128-
},
129-
}
130-
131-
mc.On("Get", types.NamespacedName{
132-
Namespace: "test",
133-
Name: kcGroup.Spec.RealmRef.Name,
134-
}, &keycloakApi.KeycloakRealm{}).Return(mockErr)
135-
136-
err = helper.SetRealmOwnerRef(context.Background(), &kcGroup)
137-
if err == nil {
138-
t.Fatal("no error on k8s client get fatal")
139-
}
140-
141-
assert.ErrorIs(t, err, mockErr)
142-
}
143-
14422
func TestMakeHelper(t *testing.T) {
14523
rCl := resty.New()
14624

controllers/keycloakauthflow/keycloakauthflow_controller.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ type Helper interface {
3030
SetFailureCount(fc helper.FailureCountable) time.Duration
3131
TryToDelete(ctx context.Context, obj client.Object, terminator helper.Terminator, finalizer string) (isDeleted bool, resultErr error)
3232
CreateKeycloakClientFromRealmRef(ctx context.Context, object helper.ObjectWithRealmRef) (keycloak.Client, error)
33-
SetRealmOwnerRef(ctx context.Context, object helper.ObjectWithRealmRef) error
3433
GetKeycloakRealmFromRef(ctx context.Context, object helper.ObjectWithRealmRef, kcClient keycloak.Client) (*gocloak.RealmRepresentation, error)
3534
}
3635

@@ -127,10 +126,6 @@ func (r *Reconcile) Reconcile(ctx context.Context, request reconcile.Request) (r
127126
}
128127

129128
func (r *Reconcile) tryReconcile(ctx context.Context, instance *keycloakApi.KeycloakAuthFlow) error {
130-
if err := r.helper.SetRealmOwnerRef(ctx, instance); err != nil {
131-
return fmt.Errorf("unable to set realm owner ref: %w", err)
132-
}
133-
134129
kClient, err := r.helper.CreateKeycloakClientFromRealmRef(ctx, instance)
135130
if err != nil {
136131
return fmt.Errorf("unable to create keycloak client from realm ref: %w", err)

controllers/keycloakclient/keycloakclient_controller.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626
type Helper interface {
2727
SetFailureCount(fc helper.FailureCountable) time.Duration
2828
TryToDelete(ctx context.Context, obj client.Object, terminator helper.Terminator, finalizer string) (isDeleted bool, resultErr error)
29-
SetRealmOwnerRef(ctx context.Context, object helper.ObjectWithRealmRef) error
3029
CreateKeycloakClientFromRealmRef(ctx context.Context, object helper.ObjectWithRealmRef) (keycloak.Client, error)
3130
GetKeycloakRealmFromRef(ctx context.Context, object helper.ObjectWithRealmRef, kcClient keycloak.Client) (*gocloak.RealmRepresentation, error)
3231
}
@@ -118,11 +117,6 @@ func (r *ReconcileKeycloakClient) Reconcile(ctx context.Context, request reconci
118117
}
119118

120119
func (r *ReconcileKeycloakClient) tryReconcile(ctx context.Context, keycloakClient *keycloakApi.KeycloakClient) error {
121-
err := r.helper.SetRealmOwnerRef(ctx, keycloakClient)
122-
if err != nil {
123-
return fmt.Errorf("unable to set realm owner ref: %w", err)
124-
}
125-
126120
kClient, err := r.helper.CreateKeycloakClientFromRealmRef(ctx, keycloakClient)
127121
if err != nil {
128122
return fmt.Errorf("unable to create keycloak client from realm ref: %w", err)

controllers/keycloakclientscope/keycloakclientscope_controller.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ const finalizerName = "keycloak.clientscope.operator.finalizer.name"
3030
type Helper interface {
3131
SetFailureCount(fc helper.FailureCountable) time.Duration
3232
TryToDelete(ctx context.Context, obj client.Object, terminator helper.Terminator, finalizer string) (isDeleted bool, resultErr error)
33-
SetRealmOwnerRef(ctx context.Context, object helper.ObjectWithRealmRef) error
3433
GetKeycloakRealmFromRef(ctx context.Context, object helper.ObjectWithRealmRef, kcClient keycloak.Client) (*gocloak.RealmRepresentation, error)
3534
CreateKeycloakClientFromRealmRef(ctx context.Context, object helper.ObjectWithRealmRef) (keycloak.Client, error)
3635
}
@@ -131,11 +130,6 @@ func (r *Reconcile) Reconcile(ctx context.Context, request reconcile.Request) (r
131130
}
132131

133132
func (r *Reconcile) tryReconcile(ctx context.Context, instance *keycloakApi.KeycloakClientScope) (string, error) {
134-
err := r.helper.SetRealmOwnerRef(ctx, instance)
135-
if err != nil {
136-
return "", fmt.Errorf("unable to set realm owner ref: %w", err)
137-
}
138-
139133
cl, err := r.helper.CreateKeycloakClientFromRealmRef(ctx, instance)
140134
if err != nil {
141135
return "", fmt.Errorf("unable to create keycloak client from realm ref: %w", err)

controllers/keycloakrealm/keycloakrealm_controller.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ type Helper interface {
2929
SetFailureCount(fc helper.FailureCountable) time.Duration
3030
TryToDelete(ctx context.Context, obj client.Object, terminator helper.Terminator, finalizer string) (isDeleted bool, resultErr error)
3131
CreateKeycloakClientFromRealm(ctx context.Context, realm *keycloakApi.KeycloakRealm) (keycloak.Client, error)
32-
SetKeycloakOwnerRef(ctx context.Context, object helper.ObjectWithKeycloakRef) error
3332
InvalidateKeycloakClientTokenSecret(ctx context.Context, namespace, rootKeycloakName string) error
3433
}
3534

@@ -123,10 +122,6 @@ func (r *ReconcileKeycloakRealm) Reconcile(ctx context.Context, request reconcil
123122
}
124123

125124
func (r *ReconcileKeycloakRealm) tryReconcile(ctx context.Context, realm *keycloakApi.KeycloakRealm) error {
126-
if err := r.helper.SetKeycloakOwnerRef(ctx, realm); err != nil {
127-
return fmt.Errorf("failed to set keycloak owner reference: %w", err)
128-
}
129-
130125
kClient, err := r.helper.CreateKeycloakClientFromRealm(ctx, realm)
131126
if err != nil {
132127
return fmt.Errorf("failed to create keycloak client for realm: %w", err)

0 commit comments

Comments
 (0)