ref(client): use three-way merge patch strategy

Co-Signed-by: Taylor Thomas <taylor.thomas@microsoft.com>
Signed-off-by: Matthew Fisher <matt.fisher@microsoft.com>
pull/6124/head
Matthew Fisher 5 years ago
parent d360705c83
commit 18ca0dd6c4
No known key found for this signature in database
GPG Key ID: 92AA783CBAAE8E3B

@ -29,7 +29,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
batch "k8s.io/api/batch/v1" batch "k8s.io/api/batch/v1"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@ -281,12 +280,17 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P
return nil, types.StrategicMergePatchType, errors.Wrap(err, "serializing target configuration") return nil, types.StrategicMergePatchType, errors.Wrap(err, "serializing target configuration")
} }
// While different objects need different merge types, the parent function // Fetch the current object for the three way merge
// that calls this does not try to create a patch when the data (first helper := resource.NewHelper(target.Client, target.Mapping)
// returned object) is nil. We can skip calculating the merge type as currentObj, err := helper.Get(target.Namespace, target.Name, target.Export)
// the returned merge type is ignored. if err != nil && !apierrors.IsNotFound(err) {
if apiequality.Semantic.DeepEqual(oldData, newData) { return nil, types.StrategicMergePatchType, errors.Wrapf(err, "unable to get data for current object %s/%s", target.Namespace, target.Name)
return nil, types.StrategicMergePatchType, nil }
// Even if currentObj is nil (because it was not found), it will marshal just fine
currentData, err := json.Marshal(currentObj)
if err != nil {
return nil, types.StrategicMergePatchType, errors.Wrap(err, "serializing live configuration")
} }
// Get a versioned object // Get a versioned object
@ -301,7 +305,13 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P
patch, err := jsonpatch.CreateMergePatch(oldData, newData) patch, err := jsonpatch.CreateMergePatch(oldData, newData)
return patch, types.MergePatchType, err return patch, types.MergePatchType, err
} }
patch, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, versionedObject)
patchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObject)
if err != nil {
return nil, types.StrategicMergePatchType, errors.Wrap(err, "unable to create patch metadata from object")
}
patch, err := strategicpatch.CreateThreeWayMergePatch(oldData, newData, currentData, patchMeta, true)
return patch, types.StrategicMergePatchType, err return patch, types.StrategicMergePatchType, err
} }

@ -119,6 +119,17 @@ func TestUpdate(t *testing.T) {
return newResponse(200, &listA.Items[0]) return newResponse(200, &listA.Items[0])
case p == "/namespaces/default/pods/otter" && m == "GET": case p == "/namespaces/default/pods/otter" && m == "GET":
return newResponse(200, &listA.Items[1]) return newResponse(200, &listA.Items[1])
case p == "/namespaces/default/pods/otter" && m == "PATCH":
data, err := ioutil.ReadAll(req.Body)
if err != nil {
t.Fatalf("could not dump request: %s", err)
}
req.Body.Close()
expected := `{}`
if string(data) != expected {
t.Errorf("expected patch\n%s\ngot\n%s", expected, string(data))
}
return newResponse(200, &listB.Items[0])
case p == "/namespaces/default/pods/dolphin" && m == "GET": case p == "/namespaces/default/pods/dolphin" && m == "GET":
return newResponse(404, notFoundBody()) return newResponse(404, notFoundBody())
case p == "/namespaces/default/pods/starfish" && m == "PATCH": case p == "/namespaces/default/pods/starfish" && m == "PATCH":
@ -165,10 +176,12 @@ func TestUpdate(t *testing.T) {
// t.Fatal(err) // t.Fatal(err)
// } // }
expectedActions := []string{ expectedActions := []string{
"/namespaces/default/pods/starfish:GET",
"/namespaces/default/pods/starfish:GET", "/namespaces/default/pods/starfish:GET",
"/namespaces/default/pods/starfish:PATCH", "/namespaces/default/pods/starfish:PATCH",
"/namespaces/default/pods/otter:GET", "/namespaces/default/pods/otter:GET",
"/namespaces/default/pods/otter:GET", "/namespaces/default/pods/otter:GET",
"/namespaces/default/pods/otter:PATCH",
"/namespaces/default/pods/dolphin:GET", "/namespaces/default/pods/dolphin:GET",
"/namespaces/default/pods:POST", "/namespaces/default/pods:POST",
"/namespaces/default/pods/squid:DELETE", "/namespaces/default/pods/squid:DELETE",

Loading…
Cancel
Save