This is an automated email from the ASF dual-hosted git repository.

astefanutti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 436a34ff835dcc8a1e31d116475f1ff7c0849f9f
Author: Antonin Stefanutti <anto...@stefanutti.fr>
AuthorDate: Mon Jan 17 19:10:26 2022 +0100

    fix(patch): Do not compute positive patch for unstructured object
---
 e2e/support/test_support.go                 |  4 +-
 pkg/client/apply.go                         |  4 +-
 pkg/cmd/builder/builder.go                  |  2 +-
 pkg/cmd/install.go                          |  2 +-
 pkg/controller/build/monitor_routine.go     |  2 +-
 pkg/controller/kameletbinding/initialize.go |  2 +-
 pkg/install/kamelets.go                     |  4 +-
 pkg/install/operator.go                     |  2 +-
 pkg/trait/deployer.go                       |  6 +--
 pkg/util/patch/patch.go                     | 75 +++++++++++++++--------------
 10 files changed, 53 insertions(+), 50 deletions(-)

diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go
index 319ab49..1a69db0 100644
--- a/e2e/support/test_support.go
+++ b/e2e/support/test_support.go
@@ -701,7 +701,7 @@ func PatchIntegration(ns string, name string, mutate 
func(it *v1.Integration)) e
        }
        target := it.DeepCopy()
        mutate(target)
-       p, err := patch.PositiveMergePatch(it, target)
+       p, err := patch.MergePatch(it, target)
        if err != nil {
                return err
        } else if len(p) == 0 {
@@ -774,7 +774,7 @@ func UpdateKameletBinding(ns string, name string, upd 
func(it *v1alpha1.KameletB
        target := klb.DeepCopy()
        upd(target)
        // For some reasons, full patch fails on some clusters
-       p, err := patch.PositiveMergePatch(klb, target)
+       p, err := patch.MergePatch(klb, target)
        if err != nil {
                return err
        } else if len(p) == 0 {
diff --git a/pkg/client/apply.go b/pkg/client/apply.go
index cfcc2c6..2a63bc2 100644
--- a/pkg/client/apply.go
+++ b/pkg/client/apply.go
@@ -77,7 +77,7 @@ func (a *ServerOrClientSideApplier) Apply(ctx 
context.Context, object ctrl.Objec
 }
 
 func (a *ServerOrClientSideApplier) serverSideApply(ctx context.Context, 
resource runtime.Object) error {
-       target, err := patch.PositiveApplyPatch(resource)
+       target, err := patch.ApplyPatch(resource)
        if err != nil {
                return err
        }
@@ -99,7 +99,7 @@ func (a *ServerOrClientSideApplier) clientSideApply(ctx 
context.Context, resourc
        if err != nil {
                return err
        }
-       p, err := patch.PositiveMergePatch(object, resource)
+       p, err := patch.MergePatch(object, resource)
        if err != nil {
                return err
        } else if len(p) == 0 {
diff --git a/pkg/cmd/builder/builder.go b/pkg/cmd/builder/builder.go
index bd22ddf..390a535 100644
--- a/pkg/cmd/builder/builder.go
+++ b/pkg/cmd/builder/builder.go
@@ -78,7 +78,7 @@ func Run(namespace string, buildName string, taskName string) 
{
        // is made on the build containers.
        target.Status.Phase = v1.BuildPhaseNone
        // Patch the build status with the result
-       p, err := patch.PositiveMergePatch(build, target)
+       p, err := patch.MergePatch(build, target)
        exitOnError(err, "cannot create merge patch")
 
        if len(p) > 0 {
diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index f3869dd..878c15d 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -715,7 +715,7 @@ func createDefaultMavenSettingsConfigMap(ctx 
context.Context, client client.Clie
                        return err
                }
 
-               p, err := patch.PositiveMergePatch(existing, cm)
+               p, err := patch.MergePatch(existing, cm)
                if err != nil {
                        return err
                } else if len(p) != 0 {
diff --git a/pkg/controller/build/monitor_routine.go 
b/pkg/controller/build/monitor_routine.go
index f9d0083..92e55af 100644
--- a/pkg/controller/build/monitor_routine.go
+++ b/pkg/controller/build/monitor_routine.go
@@ -186,7 +186,7 @@ func (action *monitorRoutineAction) updateBuildStatus(ctx 
context.Context, build
        // Copy the failure field from the build to persist recovery state
        target.Status.Failure = build.Status.Failure
        // Patch the build status with the result
-       p, err := patch.PositiveMergePatch(build, target)
+       p, err := patch.MergePatch(build, target)
        if err != nil {
                action.L.Errorf(err, "Cannot patch build status: %s", 
build.Name)
                event.NotifyBuildError(ctx, action.client, action.recorder, 
build, target, err)
diff --git a/pkg/controller/kameletbinding/initialize.go 
b/pkg/controller/kameletbinding/initialize.go
index d65656a..3f85198 100644
--- a/pkg/controller/kameletbinding/initialize.go
+++ b/pkg/controller/kameletbinding/initialize.go
@@ -85,7 +85,7 @@ func (action *initializeAction) propagateIcon(ctx 
context.Context, binding *v1al
        if _, ok := clone.Annotations[v1alpha1.AnnotationIcon]; !ok {
                clone.Annotations[v1alpha1.AnnotationIcon] = icon
        }
-       p, err := patch.PositiveMergePatch(binding, clone)
+       p, err := patch.MergePatch(binding, clone)
        if err != nil {
                action.L.Errorf(err, "cannot compute patch to update icon for 
kamelet binding %q", binding.Name)
                return
diff --git a/pkg/install/kamelets.go b/pkg/install/kamelets.go
index 82a818b..f910436 100644
--- a/pkg/install/kamelets.go
+++ b/pkg/install/kamelets.go
@@ -131,7 +131,7 @@ func KameletCatalog(ctx context.Context, c client.Client, 
namespace string) erro
 }
 
 func serverSideApply(ctx context.Context, c client.Client, resource 
runtime.Object) error {
-       target, err := patch.PositiveApplyPatch(resource)
+       target, err := patch.ApplyPatch(resource)
        if err != nil {
                return err
        }
@@ -153,7 +153,7 @@ func clientSideApply(ctx context.Context, c client.Client, 
resource ctrl.Object)
        if err != nil {
                return err
        }
-       p, err := patch.PositiveMergePatch(object, resource)
+       p, err := patch.MergePatch(object, resource)
        if err != nil {
                return err
        } else if len(p) == 0 {
diff --git a/pkg/install/operator.go b/pkg/install/operator.go
index 33b8371..d602bb5 100644
--- a/pkg/install/operator.go
+++ b/pkg/install/operator.go
@@ -368,7 +368,7 @@ func installClusterRoleBinding(ctx context.Context, c 
client.Client, collection
        // The ClusterRoleBinding.Subjects field does not have a patchStrategy 
key in its field tag,
        // so a strategic merge patch would use the default patch strategy, 
which is replace.
        // Let's compute a simple JSON merge patch from the existing resource, 
and patch it.
-       p, err := patch.PositiveMergePatch(existing, target)
+       p, err := patch.MergePatch(existing, target)
        if err != nil {
                return err
        } else if len(p) == 0 {
diff --git a/pkg/trait/deployer.go b/pkg/trait/deployer.go
index 67cdb79..8bc3b23 100644
--- a/pkg/trait/deployer.go
+++ b/pkg/trait/deployer.go
@@ -62,7 +62,7 @@ func (t *deployerTrait) Apply(e *Environment) error {
        e.PostActions = append(e.PostActions, func(env *Environment) error {
                for _, resource := range env.Resources.Items() {
                        // We assume that server-side apply is enabled by 
default.
-                       // It is currently convoluted to check pro-actively 
whether server-side apply
+                       // It is currently convoluted to check proactively 
whether server-side apply
                        // is enabled. This is possible to fetch the OpenAPI 
endpoint, which returns
                        // the entire server API document, then lookup the 
resource PATCH endpoint, and
                        // check its list of accepted MIME types.
@@ -92,7 +92,7 @@ func (t *deployerTrait) Apply(e *Environment) error {
 }
 
 func (t *deployerTrait) serverSideApply(env *Environment, resource 
ctrl.Object) error {
-       target, err := patch.PositiveApplyPatch(resource)
+       target, err := patch.ApplyPatch(resource)
        if err != nil {
                return err
        }
@@ -119,7 +119,7 @@ func (t *deployerTrait) clientSideApply(env *Environment, 
resource ctrl.Object)
        if err != nil {
                return err
        }
-       p, err := patch.PositiveMergePatch(object, resource)
+       p, err := patch.MergePatch(object, resource)
        if err != nil {
                return err
        } else if len(p) == 0 {
diff --git a/pkg/util/patch/patch.go b/pkg/util/patch/patch.go
index b672459..b7ad290 100644
--- a/pkg/util/patch/patch.go
+++ b/pkg/util/patch/patch.go
@@ -27,60 +27,63 @@ import (
        "k8s.io/apimachinery/pkg/util/json"
 )
 
-func PositiveMergePatch(source interface{}, target interface{}) ([]byte, 
error) {
+func MergePatch(source interface{}, target interface{}) ([]byte, error) {
        sourceJSON, err := json.Marshal(source)
        if err != nil {
                return nil, err
        }
-
        targetJSON, err := json.Marshal(target)
        if err != nil {
                return nil, err
        }
-
        mergePatch, err := jsonpatch.CreateMergePatch(sourceJSON, targetJSON)
        if err != nil {
                return nil, err
        }
 
-       var positivePatch map[string]interface{}
-       err = json.Unmarshal(mergePatch, &positivePatch)
-       if err != nil {
-               return nil, err
-       }
-
-       // The following is a work-around to remove null fields from the JSON 
merge patch,
-       // so that values defaulted by controllers server-side are not deleted.
-       // It's generally acceptable as these values are orthogonal to the 
values managed
-       // by the traits.
-       removeNilValues(reflect.ValueOf(positivePatch), reflect.Value{})
-
-       // Return an empty patch if no keys remain
-       if len(positivePatch) == 0 {
-               return make([]byte, 0), nil
+       switch target.(type) {
+       case *unstructured.Unstructured:
+               // Take the JSON merge patch as is for unstructured objects
+               return mergePatch, nil
+       default:
+               // Otherwise, for typed objects, remove null fields from the 
JSON merge patch,
+               // so that values managed by controllers server-side are not 
deleted.
+               var positivePatch map[string]interface{}
+               err = json.Unmarshal(mergePatch, &positivePatch)
+               if err != nil {
+                       return nil, err
+               }
+               removeNilValues(reflect.ValueOf(positivePatch), reflect.Value{})
+               // Return an empty patch if no keys remain
+               if len(positivePatch) == 0 {
+                       return make([]byte, 0), nil
+               }
+               return json.Marshal(positivePatch)
        }
-
-       return json.Marshal(positivePatch)
 }
 
-func PositiveApplyPatch(source runtime.Object) (*unstructured.Unstructured, 
error) {
-       sourceJSON, err := json.Marshal(source)
-       if err != nil {
-               return nil, err
-       }
+func ApplyPatch(source runtime.Object) (*unstructured.Unstructured, error) {
+       switch s := source.(type) {
+       case *unstructured.Unstructured:
+               // Directly take the unstructured object as apply patch
+               return s, nil
+       default:
+               // Otherwise, for typed objects, remove null fields from the 
apply patch,
+               // so that ownership is not taken for non-managed fields.
+               // See 
https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/2155-clientgo-apply
+               sourceJSON, err := json.Marshal(source)
+               if err != nil {
+                       return nil, err
+               }
+               var positivePatch map[string]interface{}
+               err = json.Unmarshal(sourceJSON, &positivePatch)
+               if err != nil {
+                       return nil, err
+               }
+               removeNilValues(reflect.ValueOf(positivePatch), reflect.Value{})
 
-       var positivePatch map[string]interface{}
-       err = json.Unmarshal(sourceJSON, &positivePatch)
-       if err != nil {
-               return nil, err
+               return &unstructured.Unstructured{Object: positivePatch}, nil
        }
-
-       // The following is a work-around to remove null fields from the apply 
patch,
-       // so that ownership is not taken for non-managed fields.
-       // See 
https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/2155-clientgo-apply
-       removeNilValues(reflect.ValueOf(positivePatch), reflect.Value{})
-
-       return &unstructured.Unstructured{Object: positivePatch}, nil
 }
 
 func removeNilValues(v reflect.Value, parent reflect.Value) {

Reply via email to