From 8fcfaa104a82cf5d5fea300ed9257146bc93ff30 Mon Sep 17 00:00:00 2001 From: fabriziopandini Date: Fri, 20 Feb 2026 13:29:41 +0100 Subject: [PATCH] Improve patch helper for no-op cases --- util/patch/patch.go | 52 +++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/util/patch/patch.go b/util/patch/patch.go index 64378f457e68..21310d1cf95d 100644 --- a/util/patch/patch.go +++ b/util/patch/patch.go @@ -19,6 +19,7 @@ package patch import ( "context" "encoding/json" + "reflect" "time" "github.com/pkg/errors" @@ -70,26 +71,9 @@ func NewHelper(obj client.Object, crClient client.Client) (*Helper, error) { return nil, errors.New("failed to create patch helper: object is nil") } - // Get the GroupVersionKind of the object, - // used to validate against later on. - gvk, err := apiutil.GVKForObject(obj, crClient.Scheme()) - if err != nil { - return nil, errors.Wrapf(err, "failed to create patch helper for object %s", klog.KObj(obj)) - } - - // Identify location of the condition fields according to the canonical place defined by the proposal for - // improving status in Cluster API conditions. - metav1ConditionsFieldPath, clusterv1ConditionsFieldPath, err := identifyConditionsFieldsPath(obj) - if err != nil { - return nil, errors.Wrapf(err, "failed to identify condition fields for object %s", klog.KObj(obj)) - } - return &Helper{ - client: crClient, - gvk: gvk, - beforeObject: obj.DeepCopyObject().(client.Object), - metav1ConditionsFieldPath: metav1ConditionsFieldPath, - clusterv1ConditionsFieldPath: clusterv1ConditionsFieldPath, + client: crClient, + beforeObject: obj.DeepCopyObject().(client.Object), }, nil } @@ -100,13 +84,31 @@ func (h *Helper) Patch(ctx context.Context, obj client.Object, opts ...Option) e return errors.Errorf("failed to patch %s %s: modified object is nil", h.gvk.Kind, klog.KObj(h.beforeObject)) } + if reflect.DeepEqual(obj, h.beforeObject) { + return nil + } + + // Get the GroupVersionKind of the object, + // used to validate against later on. + beforeGvk, err := apiutil.GVKForObject(h.beforeObject, h.client.Scheme()) + if err != nil { + return errors.Wrapf(err, "failed to create patch helper for object %s", klog.KObj(obj)) + } + // Get the GroupVersionKind of the object that we want to patch. - gvk, err := apiutil.GVKForObject(obj, h.client.Scheme()) + h.gvk, err = apiutil.GVKForObject(obj, h.client.Scheme()) if err != nil { return errors.Wrapf(err, "failed to patch %s %s", h.gvk.Kind, klog.KObj(h.beforeObject)) } - if gvk != h.gvk { - return errors.Errorf("failed to patch %s %s: unmatched GroupVersionKind, expected %q got %q", h.gvk.Kind, klog.KObj(h.beforeObject), h.gvk, gvk) + if h.gvk != beforeGvk { + return errors.Errorf("failed to patch %s %s: unmatched GroupVersionKind, expected %q got %q", h.gvk.Kind, klog.KObj(h.beforeObject), h.gvk, beforeGvk) + } + + // Identify location of the condition fields according to the canonical place defined by the proposal for + // improving status in Cluster API conditions. + h.metav1ConditionsFieldPath, h.clusterv1ConditionsFieldPath, err = identifyConditionsFieldsPath(obj) + if err != nil { + return errors.Wrapf(err, "failed to identify condition fields for object %s", klog.KObj(obj)) } // Calculate the options. @@ -132,15 +134,15 @@ func (h *Helper) Patch(ctx context.Context, obj client.Object, opts ...Option) e } // Convert the before object to unstructured. - h.before, err = toUnstructured(h.beforeObject, gvk) + h.before, err = toUnstructured(h.beforeObject, h.gvk) if err != nil { return errors.Wrapf(err, "failed to patch %s %s: failed to convert before object to Unstructured", h.gvk.Kind, klog.KObj(h.beforeObject)) } // Convert the after object to unstructured. - h.after, err = toUnstructured(obj, gvk) + h.after, err = toUnstructured(obj, h.gvk) if err != nil { - return errors.Wrapf(err, "failed to patch %s %s: failed to convert after object to Unstructured", h.gvk.Kind, klog.KObj(h.beforeObject)) + return errors.Wrapf(err, "failed to patch %s %s: failed to convert after object to Unstructured", h.gvk.Kind, klog.KObj(obj)) } // Include .status.observedGeneration if IncludeStatusObservedGeneration is set.