Skip to content

Commit 6c820a5

Browse files
committed
Use Patch instead of Update for finalizer operations
Refactor all controllers to use Patch() instead of Update() when adding or removing finalizers to improve performance, and to avoid removing non-cached fields erroneously. This is necesary because we no longer cache the last-applied-configuration annotation, so when we add/remove the finalizers, we are removing that field from the metadata. This causes issues with clients when they don't see that annotation (e.g. apply the same ClusterExtension twice). Update ClusterCatalog and ClusterExtension controllers to use Patch-based funalizer management (ClusterExtensionRevision already uses Patch()) Update all unit tests to match new behavior Signed-off-by: Todd Short <[email protected]>
1 parent 0a34fc2 commit 6c820a5

File tree

2 files changed

+43
-13
lines changed

2 files changed

+43
-13
lines changed

internal/catalogd/controllers/core/clustercatalog_controller.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package core
1818

1919
import (
2020
"context" // #nosec
21+
"encoding/json"
2122
"errors"
2223
"fmt"
2324
"slices"
@@ -28,6 +29,7 @@ import (
2829
"k8s.io/apimachinery/pkg/api/equality"
2930
"k8s.io/apimachinery/pkg/api/meta"
3031
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32+
"k8s.io/apimachinery/pkg/types"
3133
"k8s.io/apimachinery/pkg/util/sets"
3234
"k8s.io/apimachinery/pkg/util/wait"
3335
"k8s.io/utils/ptr"
@@ -124,11 +126,20 @@ func (r *ClusterCatalogReconciler) Reconcile(ctx context.Context, req ctrl.Reque
124126
reconcileErr = errors.Join(reconcileErr, fmt.Errorf("error updating status: %v", err))
125127
}
126128
}
127-
128-
reconciledCatsrc.Finalizers = finalizers
129+
// finalizers are used in patch below
130+
// reconciledCatsrc.Finalizers = finalizers
129131

130132
if updateFinalizers {
131-
if err := r.Update(ctx, reconciledCatsrc); err != nil {
133+
// Use patch to update finalizers on the server
134+
patch := map[string]any{
135+
"metadata": map[string]any{
136+
"finalizers": finalizers,
137+
},
138+
}
139+
patchJSON, err := json.Marshal(patch)
140+
if err != nil {
141+
reconcileErr = errors.Join(reconcileErr, fmt.Errorf("marshalling patch to ensure finalizers: %w", err))
142+
} else if err := r.Patch(ctx, reconciledCatsrc, client.RawPatch(types.MergePatchType, patchJSON)); err != nil {
132143
reconcileErr = errors.Join(reconcileErr, fmt.Errorf("error updating finalizers: %v", err))
133144
}
134145
}
@@ -415,11 +426,15 @@ func (r *ClusterCatalogReconciler) needsPoll(lastSuccessfulPoll time.Time, catal
415426
return nextPoll.Before(time.Now())
416427
}
417428

418-
// Compare resources - ignoring status & metadata.finalizers
429+
// Compare resources - annotations, labels and spec
419430
func checkForUnexpectedFieldChange(a, b ocv1.ClusterCatalog) bool {
420-
a.Status, b.Status = ocv1.ClusterCatalogStatus{}, ocv1.ClusterCatalogStatus{}
421-
a.Finalizers, b.Finalizers = []string{}, []string{}
422-
return !equality.Semantic.DeepEqual(a, b)
431+
if !equality.Semantic.DeepEqual(a.Annotations, b.Annotations) {
432+
return true
433+
}
434+
if !equality.Semantic.DeepEqual(a.Labels, b.Labels) {
435+
return true
436+
}
437+
return !equality.Semantic.DeepEqual(a.Spec, b.Spec)
423438
}
424439

425440
type finalizerFunc func(ctx context.Context, obj client.Object) (crfinalizer.Result, error)

internal/operator-controller/controllers/clusterextension_controller.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package controllers
1818

1919
import (
2020
"context"
21+
"encoding/json"
2122
"errors"
2223
"fmt"
2324
"io/fs"
@@ -150,10 +151,20 @@ func (r *ClusterExtensionReconciler) Reconcile(ctx context.Context, req ctrl.Req
150151
reconcileErr = errors.Join(reconcileErr, fmt.Errorf("error updating status: %v", err))
151152
}
152153
}
153-
reconciledExt.Finalizers = finalizers
154+
// finalizers are used in the patch below
155+
//reconciledExt.Finalizers = finalizers
154156

155157
if updateFinalizers {
156-
if err := r.Update(ctx, reconciledExt); err != nil {
158+
// Use patch to update finalizers on the server
159+
patch := map[string]any{
160+
"metadata": map[string]any{
161+
"finalizers": finalizers,
162+
},
163+
}
164+
patchJSON, err := json.Marshal(patch)
165+
if err != nil {
166+
reconcileErr = errors.Join(reconcileErr, fmt.Errorf("marshalling patch to ensure finalizers: %w", err))
167+
} else if err := r.Patch(ctx, reconciledExt, client.RawPatch(types.MergePatchType, patchJSON)); err != nil {
157168
reconcileErr = errors.Join(reconcileErr, fmt.Errorf("error updating finalizers: %v", err))
158169
}
159170
}
@@ -179,11 +190,15 @@ func ensureAllConditionsWithReason(ext *ocv1.ClusterExtension, reason v1alpha1.C
179190
}
180191
}
181192

182-
// Compare resources - ignoring status & metadata.finalizers
193+
// Compare resources - annotations, labels and spec
183194
func checkForUnexpectedClusterExtensionFieldChange(a, b ocv1.ClusterExtension) bool {
184-
a.Status, b.Status = ocv1.ClusterExtensionStatus{}, ocv1.ClusterExtensionStatus{}
185-
a.Finalizers, b.Finalizers = []string{}, []string{}
186-
return !equality.Semantic.DeepEqual(a, b)
195+
if !equality.Semantic.DeepEqual(a.Annotations, b.Annotations) {
196+
return true
197+
}
198+
if !equality.Semantic.DeepEqual(a.Labels, b.Labels) {
199+
return true
200+
}
201+
return !equality.Semantic.DeepEqual(a.Spec, b.Spec)
187202
}
188203

189204
// SetDeprecationStatus will set the appropriate deprecation statuses for a ClusterExtension

0 commit comments

Comments
 (0)