From 869fcb58f312c009eef43404c29d2729c1dd0847 Mon Sep 17 00:00:00 2001 From: Tarek Sharafi Date: Thu, 1 Feb 2024 16:42:00 +0200 Subject: [PATCH] feat: custom equalities in CreateOrUpdate --- .../controllerutil/controllerutil.go | 8 +++++- .../controllerutil/controllerutil_test.go | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/pkg/controller/controllerutil/controllerutil.go b/pkg/controller/controllerutil/controllerutil.go index 05153f74ce..5b7d9413a1 100644 --- a/pkg/controller/controllerutil/controllerutil.go +++ b/pkg/controller/controllerutil/controllerutil.go @@ -25,6 +25,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/utils/ptr" @@ -274,6 +275,11 @@ const ( // They should complete the sentence "Deployment default/foo has been .. // Note: changes made by MutateFn to any sub-resource (status...), will be // discarded. func CreateOrUpdate(ctx context.Context, c client.Client, obj client.Object, f MutateFn) (OperationResult, error) { + return CreateOrUpdateWithEqualities(ctx, c, obj, equality.Semantic, f) +} + +// CreateOrUpdateWithEqualities is like CreateOrUpdate but allows customizing the equality check. +func CreateOrUpdateWithEqualities(ctx context.Context, c client.Client, obj client.Object, eq conversion.Equalities, f MutateFn) (OperationResult, error) { key := client.ObjectKeyFromObject(obj) if err := c.Get(ctx, key, obj); err != nil { if !apierrors.IsNotFound(err) { @@ -293,7 +299,7 @@ func CreateOrUpdate(ctx context.Context, c client.Client, obj client.Object, f M return OperationResultNone, err } - if equality.Semantic.DeepEqual(existing, obj) { + if eq.DeepEqual(existing, obj) { return OperationResultNone, nil } diff --git a/pkg/controller/controllerutil/controllerutil_test.go b/pkg/controller/controllerutil/controllerutil_test.go index a72dd01e09..2e5c7042da 100644 --- a/pkg/controller/controllerutil/controllerutil_test.go +++ b/pkg/controller/controllerutil/controllerutil_test.go @@ -26,6 +26,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + "k8s.io/apimachinery/pkg/api/equality" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -507,6 +508,30 @@ var _ = Describe("Controllerutil", func() { Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone)) }) + It("uses custom equality check as-is", func() { + op, err := controllerutil.CreateOrUpdate(context.TODO(), c, deploy, specr) + + Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated)) + Expect(err).NotTo(HaveOccurred()) + + eq := equality.Semantic.Copy() + eq.AddFunc(func(a, b appsv1.DeploymentStrategy) bool { + // intentionallity ignore and return true + return true + }) + op, err = controllerutil.CreateOrUpdateWithEqualities(context.TODO(), c, deploy, eq, func() error { + deploy.Spec.Strategy = appsv1.DeploymentStrategy{ + Type: appsv1.RecreateDeploymentStrategyType, // just any change + } + return nil + }) + By("returning no error") + Expect(err).NotTo(HaveOccurred()) + + By("returning OperationResultNone") + Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone)) + }) + It("errors when MutateFn changes object name on creation", func() { op, err := controllerutil.CreateOrUpdate(context.TODO(), c, deploy, func() error { Expect(specr()).To(Succeed())