From d08abdb187c84591210bdc1593dd7bb6dedf36bf Mon Sep 17 00:00:00 2001 From: Wojciech Tyczynski Date: Fri, 30 Dec 2016 11:19:22 +0100 Subject: [PATCH] Allow for returning map[string]interface{} from patch. --- pkg/client/record/events_cache.go | 2 +- .../statusupdater/node_status_updater.go | 4 +- pkg/genericapiserver/api/handlers/rest.go | 6 +-- .../api/handlers/rest_test.go | 2 +- pkg/kubectl/cmd/patch.go | 2 +- pkg/util/strategicpatch/patch.go | 52 ++++++++++++------- 6 files changed, 41 insertions(+), 27 deletions(-) diff --git a/pkg/client/record/events_cache.go b/pkg/client/record/events_cache.go index ae2dbf609b1..09ea3dcbec5 100644 --- a/pkg/client/record/events_cache.go +++ b/pkg/client/record/events_cache.go @@ -244,7 +244,7 @@ func (e *eventLogger) eventObserve(newEvent *v1.Event) (*v1.Event, []byte, error newData, _ := json.Marshal(event) oldData, _ := json.Marshal(eventCopy2) - patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event) + patch, err = strategicpatch.CreateTwoWayMergePatch(oldData, newData, event) } // record our new observation diff --git a/pkg/controller/volume/attachdetach/statusupdater/node_status_updater.go b/pkg/controller/volume/attachdetach/statusupdater/node_status_updater.go index dec35a3082b..48de957ba8f 100644 --- a/pkg/controller/volume/attachdetach/statusupdater/node_status_updater.go +++ b/pkg/controller/volume/attachdetach/statusupdater/node_status_updater.go @@ -111,10 +111,10 @@ func (nsu *nodeStatusUpdater) UpdateNodeStatuses() error { } patchBytes, err := - strategicpatch.CreateStrategicMergePatch(oldData, newData, node) + strategicpatch.CreateTwoWayMergePatch(oldData, newData, node) if err != nil { return fmt.Errorf( - "failed to CreateStrategicMergePatch for node %q. %v", + "failed to CreateTwoWayMergePatch for node %q. %v", nodeName, err) } diff --git a/pkg/genericapiserver/api/handlers/rest.go b/pkg/genericapiserver/api/handlers/rest.go index 1b31278a4ca..e621d340b9b 100644 --- a/pkg/genericapiserver/api/handlers/rest.go +++ b/pkg/genericapiserver/api/handlers/rest.go @@ -607,11 +607,11 @@ func patchResource( if err != nil { return nil, err } - currentPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, currentObjectJS, versionedObj) + currentPatch, err := strategicpatch.CreateTwoWayMergePatch(originalObjJS, currentObjectJS, versionedObj) if err != nil { return nil, err } - originalPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, originalPatchedObjJS, versionedObj) + originalPatch, err := strategicpatch.CreateTwoWayMergePatch(originalObjJS, originalPatchedObjJS, versionedObj) if err != nil { return nil, err } @@ -1090,7 +1090,7 @@ func getPatchedJS(patchType types.PatchType, originalJS, patchJS []byte, obj run case types.MergePatchType: return jsonpatch.MergePatch(originalJS, patchJS) case types.StrategicMergePatchType: - return strategicpatch.StrategicMergePatchData(originalJS, patchJS, obj) + return strategicpatch.StrategicMergePatch(originalJS, patchJS, obj) default: // only here as a safety net - go-restful filters content-type return nil, fmt.Errorf("unknown Content-Type header for patch: %v", patchType) diff --git a/pkg/genericapiserver/api/handlers/rest_test.go b/pkg/genericapiserver/api/handlers/rest_test.go index 22c0fe4876a..12e5fa617c1 100644 --- a/pkg/genericapiserver/api/handlers/rest_test.go +++ b/pkg/genericapiserver/api/handlers/rest_test.go @@ -215,7 +215,7 @@ func (tc *patchTestCase) Run(t *testing.T) { continue case types.StrategicMergePatchType: - patch, err = strategicpatch.CreateStrategicMergePatch(originalObjJS, changedJS, versionedObj) + patch, err = strategicpatch.CreateTwoWayMergePatch(originalObjJS, changedJS, versionedObj) if err != nil { t.Errorf("%s: unexpected error: %v", tc.name, err) return diff --git a/pkg/kubectl/cmd/patch.go b/pkg/kubectl/cmd/patch.go index bc8a9c74b3e..2e8b06dc0e3 100644 --- a/pkg/kubectl/cmd/patch.go +++ b/pkg/kubectl/cmd/patch.go @@ -261,7 +261,7 @@ func getPatchedJSON(patchType types.PatchType, originalJS, patchJS []byte, obj r return jsonpatch.MergePatch(originalJS, patchJS) case types.StrategicMergePatchType: - return strategicpatch.StrategicMergePatchData(originalJS, patchJS, obj) + return strategicpatch.StrategicMergePatch(originalJS, patchJS, obj) default: // only here as a safety net - go-restful filters content-type diff --git a/pkg/util/strategicpatch/patch.go b/pkg/util/strategicpatch/patch.go index a81207ce9ec..fe8f2c33818 100644 --- a/pkg/util/strategicpatch/patch.go +++ b/pkg/util/strategicpatch/patch.go @@ -48,6 +48,13 @@ const ( deleteFromPrimitiveListDirectivePrefix = "$deleteFromPrimitiveList" ) +// JSONMap is a representations of JSON object encoded as map[string]interface{} +// where the children can be either map[string]interface{}, []interface{} or +// primitive type). +// Operating on JSONMap representation is much faster as it doesn't require any +// json marshaling and/or unmarshaling operations. +type JSONMap map[string]interface{} + // IsPreconditionFailed returns true if the provided error indicates // a precondition failed. func IsPreconditionFailed(err error) bool { @@ -136,11 +143,6 @@ func RequireMetadataKeyUnchanged(key string) PreconditionFunc { } } -// Deprecated: Use the synonym CreateTwoWayMergePatch, instead. -func CreateStrategicMergePatch(original, modified []byte, dataStruct interface{}) ([]byte, error) { - return CreateTwoWayMergePatch(original, modified, dataStruct) -} - // CreateTwoWayMergePatch creates a patch that can be passed to StrategicMergePatch from an original // document and a modified document, which are passed to the method as json encoded content. It will // return a patch that yields the modified document when applied to the original document, or an error @@ -160,12 +162,24 @@ func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, f } } + patchMap, err := CreateTwoWayMergeMapPatch(originalMap, modifiedMap, dataStruct, fns...) + if err != nil { + return nil, err + } + + return json.Marshal(patchMap) +} + +// CreateTwoWayMergeMapPatch creates a patch from an original and modified JSON objects, +// encoded JSONMap. +// The serialized version of the map can then be passed to StrategicMergeMapPatch. +func CreateTwoWayMergeMapPatch(original, modified JSONMap, dataStruct interface{}, fns ...PreconditionFunc) (JSONMap, error) { t, err := getTagStructType(dataStruct) if err != nil { return nil, err } - patchMap, err := diffMaps(originalMap, modifiedMap, t, false, false) + patchMap, err := diffMaps(original, modified, t, false, false) if err != nil { return nil, err } @@ -177,7 +191,7 @@ func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, f } } - return json.Marshal(patchMap) + return patchMap, nil } // Returns a (recursive) strategic merge patch that yields modified when applied to original. @@ -494,12 +508,6 @@ loopB: return patch, nil } -// Deprecated: StrategicMergePatchData is deprecated. Use the synonym StrategicMergePatch, -// instead, which follows the naming convention of evanphx/json-patch. -func StrategicMergePatchData(original, patch []byte, dataStruct interface{}) ([]byte, error) { - return StrategicMergePatch(original, patch, dataStruct) -} - // StrategicMergePatch applies a strategic merge patch. The patch and the original document // must be json encoded content. A patch can be created from an original and a modified document // by calling CreateStrategicMergePatch. @@ -524,12 +532,7 @@ func StrategicMergePatch(original, patch []byte, dataStruct interface{}) ([]byte return nil, errBadJSONDoc } - t, err := getTagStructType(dataStruct) - if err != nil { - return nil, err - } - - result, err := mergeMap(originalMap, patchMap, t, true) + result, err := StrategicMergeMapPatch(originalMap, patchMap, dataStruct) if err != nil { return nil, err } @@ -537,6 +540,17 @@ func StrategicMergePatch(original, patch []byte, dataStruct interface{}) ([]byte return json.Marshal(result) } +// StrategicMergePatch applies a strategic merge patch. The original and patch documents +// must be JSONMap. A patch can be created from an original and modified document by +// calling CreateTwoWayMergeMapPatch. +func StrategicMergeMapPatch(original, patch JSONMap, dataStruct interface{}) (JSONMap, error) { + t, err := getTagStructType(dataStruct) + if err != nil { + return nil, err + } + return mergeMap(original, patch, t, true) +} + func getTagStructType(dataStruct interface{}) (reflect.Type, error) { if dataStruct == nil { return nil, fmt.Errorf(errBadArgTypeFmt, "struct", "nil")