github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/util/strategicpatch/patch.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package strategicpatch
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"sort"
    23  	"strings"
    24  
    25  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/apis/meta/v1/unstructured"
    26  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/json"
    27  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/mergepatch"
    28  )
    29  
    30  // An alternate implementation of JSON Merge Patch
    31  // (https://tools.ietf.org/html/rfc7386) which supports the ability to annotate
    32  // certain fields with metadata that indicates whether the elements of JSON
    33  // lists should be merged or replaced.
    34  //
    35  // For more information, see the PATCH section of docs/devel/api-conventions.md.
    36  //
    37  // Some of the content of this package was borrowed with minor adaptations from
    38  // evanphx/json-patch and openshift/origin.
    39  
    40  const (
    41  	directiveMarker  = "$patch"
    42  	deleteDirective  = "delete"
    43  	replaceDirective = "replace"
    44  	mergeDirective   = "merge"
    45  
    46  	retainKeysStrategy = "retainKeys"
    47  
    48  	deleteFromPrimitiveListDirectivePrefix = "$deleteFromPrimitiveList"
    49  	retainKeysDirective                    = "$" + retainKeysStrategy
    50  	setElementOrderDirectivePrefix         = "$setElementOrder"
    51  )
    52  
    53  // JSONMap is a representations of JSON object encoded as map[string]interface{}
    54  // where the children can be either map[string]interface{}, []interface{} or
    55  // primitive type).
    56  // Operating on JSONMap representation is much faster as it doesn't require any
    57  // json marshaling and/or unmarshaling operations.
    58  type JSONMap map[string]interface{}
    59  
    60  type DiffOptions struct {
    61  	// SetElementOrder determines whether we generate the $setElementOrder parallel list.
    62  	SetElementOrder bool
    63  	// IgnoreChangesAndAdditions indicates if we keep the changes and additions in the patch.
    64  	IgnoreChangesAndAdditions bool
    65  	// IgnoreDeletions indicates if we keep the deletions in the patch.
    66  	IgnoreDeletions bool
    67  	// We introduce a new value retainKeys for patchStrategy.
    68  	// It indicates that all fields needing to be preserved must be
    69  	// present in the `retainKeys` list.
    70  	// And the fields that are present will be merged with live object.
    71  	// All the missing fields will be cleared when patching.
    72  	BuildRetainKeysDirective bool
    73  }
    74  
    75  type MergeOptions struct {
    76  	// MergeParallelList indicates if we are merging the parallel list.
    77  	// We don't merge parallel list when calling mergeMap() in CreateThreeWayMergePatch()
    78  	// which is called client-side.
    79  	// We merge parallel list iff when calling mergeMap() in StrategicMergeMapPatch()
    80  	// which is called server-side
    81  	MergeParallelList bool
    82  	// IgnoreUnmatchedNulls indicates if we should process the unmatched nulls.
    83  	IgnoreUnmatchedNulls bool
    84  }
    85  
    86  // The following code is adapted from github.com/openshift/origin/pkg/util/jsonmerge.
    87  // Instead of defining a Delta that holds an original, a patch and a set of preconditions,
    88  // the reconcile method accepts a set of preconditions as an argument.
    89  
    90  // CreateTwoWayMergePatch creates a patch that can be passed to StrategicMergePatch from an original
    91  // document and a modified document, which are passed to the method as json encoded content. It will
    92  // return a patch that yields the modified document when applied to the original document, or an error
    93  // if either of the two documents is invalid.
    94  func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, fns ...mergepatch.PreconditionFunc) ([]byte, error) {
    95  	schema, err := NewPatchMetaFromStruct(dataStruct)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	return CreateTwoWayMergePatchUsingLookupPatchMeta(original, modified, schema, fns...)
   101  }
   102  
   103  func CreateTwoWayMergePatchUsingLookupPatchMeta(
   104  	original, modified []byte, schema LookupPatchMeta, fns ...mergepatch.PreconditionFunc) ([]byte, error) {
   105  	originalMap := map[string]interface{}{}
   106  	if len(original) > 0 {
   107  		if err := json.Unmarshal(original, &originalMap); err != nil {
   108  			return nil, mergepatch.ErrBadJSONDoc
   109  		}
   110  	}
   111  
   112  	modifiedMap := map[string]interface{}{}
   113  	if len(modified) > 0 {
   114  		if err := json.Unmarshal(modified, &modifiedMap); err != nil {
   115  			return nil, mergepatch.ErrBadJSONDoc
   116  		}
   117  	}
   118  
   119  	patchMap, err := CreateTwoWayMergeMapPatchUsingLookupPatchMeta(originalMap, modifiedMap, schema, fns...)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  
   124  	return json.Marshal(patchMap)
   125  }
   126  
   127  // CreateTwoWayMergeMapPatch creates a patch from an original and modified JSON objects,
   128  // encoded JSONMap.
   129  // The serialized version of the map can then be passed to StrategicMergeMapPatch.
   130  func CreateTwoWayMergeMapPatch(original, modified JSONMap, dataStruct interface{}, fns ...mergepatch.PreconditionFunc) (JSONMap, error) {
   131  	schema, err := NewPatchMetaFromStruct(dataStruct)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  
   136  	return CreateTwoWayMergeMapPatchUsingLookupPatchMeta(original, modified, schema, fns...)
   137  }
   138  
   139  func CreateTwoWayMergeMapPatchUsingLookupPatchMeta(original, modified JSONMap, schema LookupPatchMeta, fns ...mergepatch.PreconditionFunc) (JSONMap, error) {
   140  	diffOptions := DiffOptions{
   141  		SetElementOrder: true,
   142  	}
   143  	patchMap, err := diffMaps(original, modified, schema, diffOptions)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	// Apply the preconditions to the patch, and return an error if any of them fail.
   149  	for _, fn := range fns {
   150  		if !fn(patchMap) {
   151  			return nil, mergepatch.NewErrPreconditionFailed(patchMap)
   152  		}
   153  	}
   154  
   155  	return patchMap, nil
   156  }
   157  
   158  // Returns a (recursive) strategic merge patch that yields modified when applied to original.
   159  // Including:
   160  // - Adding fields to the patch present in modified, missing from original
   161  // - Setting fields to the patch present in modified and original with different values
   162  // - Delete fields present in original, missing from modified through
   163  // - IFF map field - set to nil in patch
   164  // - IFF list of maps && merge strategy - use deleteDirective for the elements
   165  // - IFF list of primitives && merge strategy - use parallel deletion list
   166  // - IFF list of maps or primitives with replace strategy (default) - set patch value to the value in modified
   167  // - Build $retainKeys directive for fields with retainKeys patch strategy
   168  func diffMaps(original, modified map[string]interface{}, schema LookupPatchMeta, diffOptions DiffOptions) (map[string]interface{}, error) {
   169  	patch := map[string]interface{}{}
   170  
   171  	// This will be used to build the $retainKeys directive sent in the patch
   172  	retainKeysList := make([]interface{}, 0, len(modified))
   173  
   174  	// Compare each value in the modified map against the value in the original map
   175  	for key, modifiedValue := range modified {
   176  		// Get the underlying type for pointers
   177  		if diffOptions.BuildRetainKeysDirective && modifiedValue != nil {
   178  			retainKeysList = append(retainKeysList, key)
   179  		}
   180  
   181  		originalValue, ok := original[key]
   182  		if !ok {
   183  			// Key was added, so add to patch
   184  			if !diffOptions.IgnoreChangesAndAdditions {
   185  				patch[key] = modifiedValue
   186  			}
   187  			continue
   188  		}
   189  
   190  		// The patch may have a patch directive
   191  		// TODO: figure out if we need this. This shouldn't be needed by apply. When would the original map have patch directives in it?
   192  		foundDirectiveMarker, err := handleDirectiveMarker(key, originalValue, modifiedValue, patch)
   193  		if err != nil {
   194  			return nil, err
   195  		}
   196  		if foundDirectiveMarker {
   197  			continue
   198  		}
   199  
   200  		if reflect.TypeOf(originalValue) != reflect.TypeOf(modifiedValue) {
   201  			// Types have changed, so add to patch
   202  			if !diffOptions.IgnoreChangesAndAdditions {
   203  				patch[key] = modifiedValue
   204  			}
   205  			continue
   206  		}
   207  
   208  		// Types are the same, so compare values
   209  		switch originalValueTyped := originalValue.(type) {
   210  		case map[string]interface{}:
   211  			modifiedValueTyped := modifiedValue.(map[string]interface{})
   212  			err = handleMapDiff(key, originalValueTyped, modifiedValueTyped, patch, schema, diffOptions)
   213  		case []interface{}:
   214  			modifiedValueTyped := modifiedValue.([]interface{})
   215  			err = handleSliceDiff(key, originalValueTyped, modifiedValueTyped, patch, schema, diffOptions)
   216  		default:
   217  			replacePatchFieldIfNotEqual(key, originalValue, modifiedValue, patch, diffOptions)
   218  		}
   219  		if err != nil {
   220  			return nil, err
   221  		}
   222  	}
   223  
   224  	updatePatchIfMissing(original, modified, patch, diffOptions)
   225  	// Insert the retainKeysList iff there are values present in the retainKeysList and
   226  	// either of the following is true:
   227  	// - the patch is not empty
   228  	// - there are additional field in original that need to be cleared
   229  	if len(retainKeysList) > 0 &&
   230  		(len(patch) > 0 || hasAdditionalNewField(original, modified)) {
   231  		patch[retainKeysDirective] = sortScalars(retainKeysList)
   232  	}
   233  	return patch, nil
   234  }
   235  
   236  // handleDirectiveMarker handles how to diff directive marker between 2 objects
   237  func handleDirectiveMarker(key string, originalValue, modifiedValue interface{}, patch map[string]interface{}) (bool, error) {
   238  	if key == directiveMarker {
   239  		originalString, ok := originalValue.(string)
   240  		if !ok {
   241  			return false, fmt.Errorf("invalid value for special key: %s", directiveMarker)
   242  		}
   243  		modifiedString, ok := modifiedValue.(string)
   244  		if !ok {
   245  			return false, fmt.Errorf("invalid value for special key: %s", directiveMarker)
   246  		}
   247  		if modifiedString != originalString {
   248  			patch[directiveMarker] = modifiedValue
   249  		}
   250  		return true, nil
   251  	}
   252  	return false, nil
   253  }
   254  
   255  // handleMapDiff diff between 2 maps `originalValueTyped` and `modifiedValue`,
   256  // puts the diff in the `patch` associated with `key`
   257  // key is the key associated with originalValue and modifiedValue.
   258  // originalValue, modifiedValue are the old and new value respectively.They are both maps
   259  // patch is the patch map that contains key and the updated value, and it is the parent of originalValue, modifiedValue
   260  // diffOptions contains multiple options to control how we do the diff.
   261  func handleMapDiff(key string, originalValue, modifiedValue, patch map[string]interface{},
   262  	schema LookupPatchMeta, diffOptions DiffOptions) error {
   263  	subschema, patchMeta, err := schema.LookupPatchMetadataForStruct(key)
   264  
   265  	if err != nil {
   266  		// We couldn't look up metadata for the field
   267  		// If the values are identical, this doesn't matter, no patch is needed
   268  		if reflect.DeepEqual(originalValue, modifiedValue) {
   269  			return nil
   270  		}
   271  		// Otherwise, return the error
   272  		return err
   273  	}
   274  	retainKeys, patchStrategy, err := extractRetainKeysPatchStrategy(patchMeta.GetPatchStrategies())
   275  	if err != nil {
   276  		return err
   277  	}
   278  	diffOptions.BuildRetainKeysDirective = retainKeys
   279  	switch patchStrategy {
   280  	// The patch strategic from metadata tells us to replace the entire object instead of diffing it
   281  	case replaceDirective:
   282  		if !diffOptions.IgnoreChangesAndAdditions {
   283  			patch[key] = modifiedValue
   284  		}
   285  	default:
   286  		patchValue, err := diffMaps(originalValue, modifiedValue, subschema, diffOptions)
   287  		if err != nil {
   288  			return err
   289  		}
   290  		// Maps were not identical, use provided patch value
   291  		if len(patchValue) > 0 {
   292  			patch[key] = patchValue
   293  		}
   294  	}
   295  	return nil
   296  }
   297  
   298  // handleSliceDiff diff between 2 slices `originalValueTyped` and `modifiedValue`,
   299  // puts the diff in the `patch` associated with `key`
   300  // key is the key associated with originalValue and modifiedValue.
   301  // originalValue, modifiedValue are the old and new value respectively.They are both slices
   302  // patch is the patch map that contains key and the updated value, and it is the parent of originalValue, modifiedValue
   303  // diffOptions contains multiple options to control how we do the diff.
   304  func handleSliceDiff(key string, originalValue, modifiedValue []interface{}, patch map[string]interface{},
   305  	schema LookupPatchMeta, diffOptions DiffOptions) error {
   306  	subschema, patchMeta, err := schema.LookupPatchMetadataForSlice(key)
   307  	if err != nil {
   308  		// We couldn't look up metadata for the field
   309  		// If the values are identical, this doesn't matter, no patch is needed
   310  		if reflect.DeepEqual(originalValue, modifiedValue) {
   311  			return nil
   312  		}
   313  		// Otherwise, return the error
   314  		return err
   315  	}
   316  	retainKeys, patchStrategy, err := extractRetainKeysPatchStrategy(patchMeta.GetPatchStrategies())
   317  	if err != nil {
   318  		return err
   319  	}
   320  	switch patchStrategy {
   321  	// Merge the 2 slices using mergePatchKey
   322  	case mergeDirective:
   323  		diffOptions.BuildRetainKeysDirective = retainKeys
   324  		addList, deletionList, setOrderList, err := diffLists(originalValue, modifiedValue, subschema, patchMeta.GetPatchMergeKey(), diffOptions)
   325  		if err != nil {
   326  			return err
   327  		}
   328  		if len(addList) > 0 {
   329  			patch[key] = addList
   330  		}
   331  		// generate a parallel list for deletion
   332  		if len(deletionList) > 0 {
   333  			parallelDeletionListKey := fmt.Sprintf("%s/%s", deleteFromPrimitiveListDirectivePrefix, key)
   334  			patch[parallelDeletionListKey] = deletionList
   335  		}
   336  		if len(setOrderList) > 0 {
   337  			parallelSetOrderListKey := fmt.Sprintf("%s/%s", setElementOrderDirectivePrefix, key)
   338  			patch[parallelSetOrderListKey] = setOrderList
   339  		}
   340  	default:
   341  		replacePatchFieldIfNotEqual(key, originalValue, modifiedValue, patch, diffOptions)
   342  	}
   343  	return nil
   344  }
   345  
   346  // replacePatchFieldIfNotEqual updates the patch if original and modified are not deep equal
   347  // if diffOptions.IgnoreChangesAndAdditions is false.
   348  // original is the old value, maybe either the live cluster object or the last applied configuration
   349  // modified is the new value, is always the users new config
   350  func replacePatchFieldIfNotEqual(key string, original, modified interface{},
   351  	patch map[string]interface{}, diffOptions DiffOptions) {
   352  	if diffOptions.IgnoreChangesAndAdditions {
   353  		// Ignoring changes - do nothing
   354  		return
   355  	}
   356  	if reflect.DeepEqual(original, modified) {
   357  		// Contents are identical - do nothing
   358  		return
   359  	}
   360  	// Create a patch to replace the old value with the new one
   361  	patch[key] = modified
   362  }
   363  
   364  // updatePatchIfMissing iterates over `original` when ignoreDeletions is false.
   365  // Clear the field whose key is not present in `modified`.
   366  // original is the old value, maybe either the live cluster object or the last applied configuration
   367  // modified is the new value, is always the users new config
   368  func updatePatchIfMissing(original, modified, patch map[string]interface{}, diffOptions DiffOptions) {
   369  	if diffOptions.IgnoreDeletions {
   370  		// Ignoring deletion - do nothing
   371  		return
   372  	}
   373  	// Add nils for deleted values
   374  	for key := range original {
   375  		if _, found := modified[key]; !found {
   376  			patch[key] = nil
   377  		}
   378  	}
   379  }
   380  
   381  // validateMergeKeyInLists checks if each map in the list has the mentryerge key.
   382  func validateMergeKeyInLists(mergeKey string, lists ...[]interface{}) error {
   383  	for _, list := range lists {
   384  		for _, item := range list {
   385  			m, ok := item.(map[string]interface{})
   386  			if !ok {
   387  				return mergepatch.ErrBadArgType(m, item)
   388  			}
   389  			if _, ok = m[mergeKey]; !ok {
   390  				return mergepatch.ErrNoMergeKey(m, mergeKey)
   391  			}
   392  		}
   393  	}
   394  	return nil
   395  }
   396  
   397  // normalizeElementOrder sort `patch` list by `patchOrder` and sort `serverOnly` list by `serverOrder`.
   398  // Then it merges the 2 sorted lists.
   399  // It guarantee the relative order in the patch list and in the serverOnly list is kept.
   400  // `patch` is a list of items in the patch, and `serverOnly` is a list of items in the live object.
   401  // `patchOrder` is the order we want `patch` list to have and
   402  // `serverOrder` is the order we want `serverOnly` list to have.
   403  // kind is the kind of each item in the lists `patch` and `serverOnly`.
   404  func normalizeElementOrder(patch, serverOnly, patchOrder, serverOrder []interface{}, mergeKey string, kind reflect.Kind) ([]interface{}, error) {
   405  	patch, err := normalizeSliceOrder(patch, patchOrder, mergeKey, kind)
   406  	if err != nil {
   407  		return nil, err
   408  	}
   409  	serverOnly, err = normalizeSliceOrder(serverOnly, serverOrder, mergeKey, kind)
   410  	if err != nil {
   411  		return nil, err
   412  	}
   413  	all := mergeSortedSlice(serverOnly, patch, serverOrder, mergeKey, kind)
   414  
   415  	return all, nil
   416  }
   417  
   418  // mergeSortedSlice merges the 2 sorted lists by serverOrder with best effort.
   419  // It will insert each item in `left` list to `right` list. In most cases, the 2 lists will be interleaved.
   420  // The relative order of left and right are guaranteed to be kept.
   421  // They have higher precedence than the order in the live list.
   422  // The place for a item in `left` is found by:
   423  // scan from the place of last insertion in `right` to the end of `right`,
   424  // the place is before the first item that is greater than the item we want to insert.
   425  // example usage: using server-only items as left and patch items as right. We insert server-only items
   426  // to patch list. We use the order of live object as record for comparison.
   427  func mergeSortedSlice(left, right, serverOrder []interface{}, mergeKey string, kind reflect.Kind) []interface{} {
   428  	// Returns if l is less than r, and if both have been found.
   429  	// If l and r both present and l is in front of r, l is less than r.
   430  	less := func(l, r interface{}) (bool, bool) {
   431  		li := index(serverOrder, l, mergeKey, kind)
   432  		ri := index(serverOrder, r, mergeKey, kind)
   433  		if li >= 0 && ri >= 0 {
   434  			return li < ri, true
   435  		} else {
   436  			return false, false
   437  		}
   438  	}
   439  
   440  	// left and right should be non-overlapping.
   441  	size := len(left) + len(right)
   442  	i, j := 0, 0
   443  	s := make([]interface{}, size, size)
   444  
   445  	for k := 0; k < size; k++ {
   446  		if i >= len(left) && j < len(right) {
   447  			// have items left in `right` list
   448  			s[k] = right[j]
   449  			j++
   450  		} else if j >= len(right) && i < len(left) {
   451  			// have items left in `left` list
   452  			s[k] = left[i]
   453  			i++
   454  		} else {
   455  			// compare them if i and j are both in bound
   456  			less, foundBoth := less(left[i], right[j])
   457  			if foundBoth && less {
   458  				s[k] = left[i]
   459  				i++
   460  			} else {
   461  				s[k] = right[j]
   462  				j++
   463  			}
   464  		}
   465  	}
   466  	return s
   467  }
   468  
   469  // index returns the index of the item in the given items, or -1 if it doesn't exist
   470  // l must NOT be a slice of slices, this should be checked before calling.
   471  func index(l []interface{}, valToLookUp interface{}, mergeKey string, kind reflect.Kind) int {
   472  	var getValFn func(interface{}) interface{}
   473  	// Get the correct `getValFn` based on item `kind`.
   474  	// It should return the value of merge key for maps and
   475  	// return the item for other kinds.
   476  	switch kind {
   477  	case reflect.Map:
   478  		getValFn = func(item interface{}) interface{} {
   479  			typedItem, ok := item.(map[string]interface{})
   480  			if !ok {
   481  				return nil
   482  			}
   483  			val := typedItem[mergeKey]
   484  			return val
   485  		}
   486  	default:
   487  		getValFn = func(item interface{}) interface{} {
   488  			return item
   489  		}
   490  	}
   491  
   492  	for i, v := range l {
   493  		if getValFn(valToLookUp) == getValFn(v) {
   494  			return i
   495  		}
   496  	}
   497  	return -1
   498  }
   499  
   500  // extractToDeleteItems takes a list and
   501  // returns 2 lists: one contains items that should be kept and the other contains items to be deleted.
   502  func extractToDeleteItems(l []interface{}) ([]interface{}, []interface{}, error) {
   503  	var nonDelete, toDelete []interface{}
   504  	for _, v := range l {
   505  		m, ok := v.(map[string]interface{})
   506  		if !ok {
   507  			return nil, nil, mergepatch.ErrBadArgType(m, v)
   508  		}
   509  
   510  		directive, foundDirective := m[directiveMarker]
   511  		if foundDirective && directive == deleteDirective {
   512  			toDelete = append(toDelete, v)
   513  		} else {
   514  			nonDelete = append(nonDelete, v)
   515  		}
   516  	}
   517  	return nonDelete, toDelete, nil
   518  }
   519  
   520  // normalizeSliceOrder sort `toSort` list by `order`
   521  func normalizeSliceOrder(toSort, order []interface{}, mergeKey string, kind reflect.Kind) ([]interface{}, error) {
   522  	var toDelete []interface{}
   523  	if kind == reflect.Map {
   524  		// make sure each item in toSort, order has merge key
   525  		err := validateMergeKeyInLists(mergeKey, toSort, order)
   526  		if err != nil {
   527  			return nil, err
   528  		}
   529  		toSort, toDelete, err = extractToDeleteItems(toSort)
   530  		if err != nil {
   531  			return nil, err
   532  		}
   533  	}
   534  
   535  	sort.SliceStable(toSort, func(i, j int) bool {
   536  		if ii := index(order, toSort[i], mergeKey, kind); ii >= 0 {
   537  			if ij := index(order, toSort[j], mergeKey, kind); ij >= 0 {
   538  				return ii < ij
   539  			}
   540  		}
   541  		return true
   542  	})
   543  	toSort = append(toSort, toDelete...)
   544  	return toSort, nil
   545  }
   546  
   547  // Returns a (recursive) strategic merge patch, a parallel deletion list if necessary and
   548  // another list to set the order of the list
   549  // Only list of primitives with merge strategy will generate a parallel deletion list.
   550  // These two lists should yield modified when applied to original, for lists with merge semantics.
   551  func diffLists(original, modified []interface{}, schema LookupPatchMeta, mergeKey string, diffOptions DiffOptions) ([]interface{}, []interface{}, []interface{}, error) {
   552  	if len(original) == 0 {
   553  		// Both slices are empty - do nothing
   554  		if len(modified) == 0 || diffOptions.IgnoreChangesAndAdditions {
   555  			return nil, nil, nil, nil
   556  		}
   557  
   558  		// Old slice was empty - add all elements from the new slice
   559  		return modified, nil, nil, nil
   560  	}
   561  
   562  	elementType, err := sliceElementType(original, modified)
   563  	if err != nil {
   564  		return nil, nil, nil, err
   565  	}
   566  
   567  	var patchList, deleteList, setOrderList []interface{}
   568  	kind := elementType.Kind()
   569  	switch kind {
   570  	case reflect.Map:
   571  		patchList, deleteList, err = diffListsOfMaps(original, modified, schema, mergeKey, diffOptions)
   572  		if err != nil {
   573  			return nil, nil, nil, err
   574  		}
   575  		patchList, err = normalizeSliceOrder(patchList, modified, mergeKey, kind)
   576  		if err != nil {
   577  			return nil, nil, nil, err
   578  		}
   579  		orderSame, err := isOrderSame(original, modified, mergeKey)
   580  		if err != nil {
   581  			return nil, nil, nil, err
   582  		}
   583  		// append the deletions to the end of the patch list.
   584  		patchList = append(patchList, deleteList...)
   585  		deleteList = nil
   586  		// generate the setElementOrder list when there are content changes or order changes
   587  		if diffOptions.SetElementOrder &&
   588  			((!diffOptions.IgnoreChangesAndAdditions && (len(patchList) > 0 || !orderSame)) ||
   589  				(!diffOptions.IgnoreDeletions && len(patchList) > 0)) {
   590  			// Generate a list of maps that each item contains only the merge key.
   591  			setOrderList = make([]interface{}, len(modified))
   592  			for i, v := range modified {
   593  				typedV := v.(map[string]interface{})
   594  				setOrderList[i] = map[string]interface{}{
   595  					mergeKey: typedV[mergeKey],
   596  				}
   597  			}
   598  		}
   599  	case reflect.Slice:
   600  		// Lists of Lists are not permitted by the api
   601  		return nil, nil, nil, mergepatch.ErrNoListOfLists
   602  	default:
   603  		patchList, deleteList, err = diffListsOfScalars(original, modified, diffOptions)
   604  		if err != nil {
   605  			return nil, nil, nil, err
   606  		}
   607  		patchList, err = normalizeSliceOrder(patchList, modified, mergeKey, kind)
   608  		// generate the setElementOrder list when there are content changes or order changes
   609  		if diffOptions.SetElementOrder && ((!diffOptions.IgnoreDeletions && len(deleteList) > 0) ||
   610  			(!diffOptions.IgnoreChangesAndAdditions && !reflect.DeepEqual(original, modified))) {
   611  			setOrderList = modified
   612  		}
   613  	}
   614  	return patchList, deleteList, setOrderList, err
   615  }
   616  
   617  // isOrderSame checks if the order in a list has changed
   618  func isOrderSame(original, modified []interface{}, mergeKey string) (bool, error) {
   619  	if len(original) != len(modified) {
   620  		return false, nil
   621  	}
   622  	for i, modifiedItem := range modified {
   623  		equal, err := mergeKeyValueEqual(original[i], modifiedItem, mergeKey)
   624  		if err != nil || !equal {
   625  			return equal, err
   626  		}
   627  	}
   628  	return true, nil
   629  }
   630  
   631  // diffListsOfScalars returns 2 lists, the first one is addList and the second one is deletionList.
   632  // Argument diffOptions.IgnoreChangesAndAdditions controls if calculate addList. true means not calculate.
   633  // Argument diffOptions.IgnoreDeletions controls if calculate deletionList. true means not calculate.
   634  // original may be changed, but modified is guaranteed to not be changed
   635  func diffListsOfScalars(original, modified []interface{}, diffOptions DiffOptions) ([]interface{}, []interface{}, error) {
   636  	modifiedCopy := make([]interface{}, len(modified))
   637  	copy(modifiedCopy, modified)
   638  	// Sort the scalars for easier calculating the diff
   639  	originalScalars := sortScalars(original)
   640  	modifiedScalars := sortScalars(modifiedCopy)
   641  
   642  	originalIndex, modifiedIndex := 0, 0
   643  	addList := []interface{}{}
   644  	deletionList := []interface{}{}
   645  
   646  	for {
   647  		originalInBounds := originalIndex < len(originalScalars)
   648  		modifiedInBounds := modifiedIndex < len(modifiedScalars)
   649  		if !originalInBounds && !modifiedInBounds {
   650  			break
   651  		}
   652  		// we need to compare the string representation of the scalar,
   653  		// because the scalar is an interface which doesn't support either < or >
   654  		// And that's how func sortScalars compare scalars.
   655  		var originalString, modifiedString string
   656  		var originalValue, modifiedValue interface{}
   657  		if originalInBounds {
   658  			originalValue = originalScalars[originalIndex]
   659  			originalString = fmt.Sprintf("%v", originalValue)
   660  		}
   661  		if modifiedInBounds {
   662  			modifiedValue = modifiedScalars[modifiedIndex]
   663  			modifiedString = fmt.Sprintf("%v", modifiedValue)
   664  		}
   665  
   666  		originalV, modifiedV := compareListValuesAtIndex(originalInBounds, modifiedInBounds, originalString, modifiedString)
   667  		switch {
   668  		case originalV == nil && modifiedV == nil:
   669  			originalIndex++
   670  			modifiedIndex++
   671  		case originalV != nil && modifiedV == nil:
   672  			if !diffOptions.IgnoreDeletions {
   673  				deletionList = append(deletionList, originalValue)
   674  			}
   675  			originalIndex++
   676  		case originalV == nil && modifiedV != nil:
   677  			if !diffOptions.IgnoreChangesAndAdditions {
   678  				addList = append(addList, modifiedValue)
   679  			}
   680  			modifiedIndex++
   681  		default:
   682  			return nil, nil, fmt.Errorf("Unexpected returned value from compareListValuesAtIndex: %v and %v", originalV, modifiedV)
   683  		}
   684  	}
   685  
   686  	return addList, deduplicateScalars(deletionList), nil
   687  }
   688  
   689  // If first return value is non-nil, list1 contains an element not present in list2
   690  // If second return value is non-nil, list2 contains an element not present in list1
   691  func compareListValuesAtIndex(list1Inbounds, list2Inbounds bool, list1Value, list2Value string) (interface{}, interface{}) {
   692  	bothInBounds := list1Inbounds && list2Inbounds
   693  	switch {
   694  	// scalars are identical
   695  	case bothInBounds && list1Value == list2Value:
   696  		return nil, nil
   697  	// only list2 is in bound
   698  	case !list1Inbounds:
   699  		fallthrough
   700  	// list2 has additional scalar
   701  	case bothInBounds && list1Value > list2Value:
   702  		return nil, list2Value
   703  	// only original is in bound
   704  	case !list2Inbounds:
   705  		fallthrough
   706  	// original has additional scalar
   707  	case bothInBounds && list1Value < list2Value:
   708  		return list1Value, nil
   709  	default:
   710  		return nil, nil
   711  	}
   712  }
   713  
   714  // diffListsOfMaps takes a pair of lists and
   715  // returns a (recursive) strategic merge patch list contains additions and changes and
   716  // a deletion list contains deletions
   717  func diffListsOfMaps(original, modified []interface{}, schema LookupPatchMeta, mergeKey string, diffOptions DiffOptions) ([]interface{}, []interface{}, error) {
   718  	patch := make([]interface{}, 0, len(modified))
   719  	deletionList := make([]interface{}, 0, len(original))
   720  
   721  	originalSorted, err := sortMergeListsByNameArray(original, schema, mergeKey, false)
   722  	if err != nil {
   723  		return nil, nil, err
   724  	}
   725  	modifiedSorted, err := sortMergeListsByNameArray(modified, schema, mergeKey, false)
   726  	if err != nil {
   727  		return nil, nil, err
   728  	}
   729  
   730  	originalIndex, modifiedIndex := 0, 0
   731  	for {
   732  		originalInBounds := originalIndex < len(originalSorted)
   733  		modifiedInBounds := modifiedIndex < len(modifiedSorted)
   734  		bothInBounds := originalInBounds && modifiedInBounds
   735  		if !originalInBounds && !modifiedInBounds {
   736  			break
   737  		}
   738  
   739  		var originalElementMergeKeyValueString, modifiedElementMergeKeyValueString string
   740  		var originalElementMergeKeyValue, modifiedElementMergeKeyValue interface{}
   741  		var originalElement, modifiedElement map[string]interface{}
   742  		if originalInBounds {
   743  			originalElement, originalElementMergeKeyValue, err = getMapAndMergeKeyValueByIndex(originalIndex, mergeKey, originalSorted)
   744  			if err != nil {
   745  				return nil, nil, err
   746  			}
   747  			originalElementMergeKeyValueString = fmt.Sprintf("%v", originalElementMergeKeyValue)
   748  		}
   749  		if modifiedInBounds {
   750  			modifiedElement, modifiedElementMergeKeyValue, err = getMapAndMergeKeyValueByIndex(modifiedIndex, mergeKey, modifiedSorted)
   751  			if err != nil {
   752  				return nil, nil, err
   753  			}
   754  			modifiedElementMergeKeyValueString = fmt.Sprintf("%v", modifiedElementMergeKeyValue)
   755  		}
   756  
   757  		switch {
   758  		case bothInBounds && ItemMatchesOriginalAndModifiedSlice(originalElementMergeKeyValueString, modifiedElementMergeKeyValueString):
   759  			// Merge key values are equal, so recurse
   760  			patchValue, err := diffMaps(originalElement, modifiedElement, schema, diffOptions)
   761  			if err != nil {
   762  				return nil, nil, err
   763  			}
   764  			if len(patchValue) > 0 {
   765  				patchValue[mergeKey] = modifiedElementMergeKeyValue
   766  				patch = append(patch, patchValue)
   767  			}
   768  			originalIndex++
   769  			modifiedIndex++
   770  		// only modified is in bound
   771  		case !originalInBounds:
   772  			fallthrough
   773  		// modified has additional map
   774  		case bothInBounds && ItemAddedToModifiedSlice(originalElementMergeKeyValueString, modifiedElementMergeKeyValueString):
   775  			if !diffOptions.IgnoreChangesAndAdditions {
   776  				patch = append(patch, modifiedElement)
   777  			}
   778  			modifiedIndex++
   779  		// only original is in bound
   780  		case !modifiedInBounds:
   781  			fallthrough
   782  		// original has additional map
   783  		case bothInBounds && ItemRemovedFromModifiedSlice(originalElementMergeKeyValueString, modifiedElementMergeKeyValueString):
   784  			if !diffOptions.IgnoreDeletions {
   785  				// Item was deleted, so add delete directive
   786  				deletionList = append(deletionList, CreateDeleteDirective(mergeKey, originalElementMergeKeyValue))
   787  			}
   788  			originalIndex++
   789  		}
   790  	}
   791  
   792  	return patch, deletionList, nil
   793  }
   794  
   795  // getMapAndMergeKeyValueByIndex return a map in the list and its merge key value given the index of the map.
   796  func getMapAndMergeKeyValueByIndex(index int, mergeKey string, listOfMaps []interface{}) (map[string]interface{}, interface{}, error) {
   797  	m, ok := listOfMaps[index].(map[string]interface{})
   798  	if !ok {
   799  		return nil, nil, mergepatch.ErrBadArgType(m, listOfMaps[index])
   800  	}
   801  
   802  	val, ok := m[mergeKey]
   803  	if !ok {
   804  		return nil, nil, mergepatch.ErrNoMergeKey(m, mergeKey)
   805  	}
   806  	return m, val, nil
   807  }
   808  
   809  // StrategicMergePatch applies a strategic merge patch. The patch and the original document
   810  // must be json encoded content. A patch can be created from an original and a modified document
   811  // by calling CreateStrategicMergePatch.
   812  func StrategicMergePatch(original, patch []byte, dataStruct interface{}) ([]byte, error) {
   813  	schema, err := NewPatchMetaFromStruct(dataStruct)
   814  	if err != nil {
   815  		return nil, err
   816  	}
   817  
   818  	return StrategicMergePatchUsingLookupPatchMeta(original, patch, schema)
   819  }
   820  
   821  func StrategicMergePatchUsingLookupPatchMeta(original, patch []byte, schema LookupPatchMeta) ([]byte, error) {
   822  	originalMap, err := handleUnmarshal(original)
   823  	if err != nil {
   824  		return nil, err
   825  	}
   826  	patchMap, err := handleUnmarshal(patch)
   827  	if err != nil {
   828  		return nil, err
   829  	}
   830  
   831  	result, err := StrategicMergeMapPatchUsingLookupPatchMeta(originalMap, patchMap, schema)
   832  	if err != nil {
   833  		return nil, err
   834  	}
   835  
   836  	return json.Marshal(result)
   837  }
   838  
   839  func handleUnmarshal(j []byte) (map[string]interface{}, error) {
   840  	if j == nil {
   841  		j = []byte("{}")
   842  	}
   843  
   844  	m := map[string]interface{}{}
   845  	err := json.Unmarshal(j, &m)
   846  	if err != nil {
   847  		return nil, mergepatch.ErrBadJSONDoc
   848  	}
   849  	return m, nil
   850  }
   851  
   852  // StrategicMergeMapPatch applies a strategic merge patch. The original and patch documents
   853  // must be JSONMap. A patch can be created from an original and modified document by
   854  // calling CreateTwoWayMergeMapPatch.
   855  // Warning: the original and patch JSONMap objects are mutated by this function and should not be reused.
   856  func StrategicMergeMapPatch(original, patch JSONMap, dataStruct interface{}) (JSONMap, error) {
   857  	schema, err := NewPatchMetaFromStruct(dataStruct)
   858  	if err != nil {
   859  		return nil, err
   860  	}
   861  
   862  	// We need the go struct tags `patchMergeKey` and `patchStrategy` for fields that support a strategic merge patch.
   863  	// For native resources, we can easily figure out these tags since we know the fields.
   864  
   865  	// Because custom resources are decoded as Unstructured and because we're missing the metadata about how to handle
   866  	// each field in a strategic merge patch, we can't find the go struct tags. Hence, we can't easily  do a strategic merge
   867  	// for custom resources. So we should fail fast and return an error.
   868  	if _, ok := dataStruct.(*unstructured.Unstructured); ok {
   869  		return nil, mergepatch.ErrUnsupportedStrategicMergePatchFormat
   870  	}
   871  
   872  	return StrategicMergeMapPatchUsingLookupPatchMeta(original, patch, schema)
   873  }
   874  
   875  func StrategicMergeMapPatchUsingLookupPatchMeta(original, patch JSONMap, schema LookupPatchMeta) (JSONMap, error) {
   876  	mergeOptions := MergeOptions{
   877  		MergeParallelList:    true,
   878  		IgnoreUnmatchedNulls: true,
   879  	}
   880  	return mergeMap(original, patch, schema, mergeOptions)
   881  }
   882  
   883  // MergeStrategicMergeMapPatchUsingLookupPatchMeta merges strategic merge
   884  // patches retaining `null` fields and parallel lists. If 2 patches change the
   885  // same fields and the latter one will override the former one. If you don't
   886  // want that happen, you need to run func MergingMapsHaveConflicts before
   887  // merging these patches. Applying the resulting merged merge patch to a JSONMap
   888  // yields the same as merging each strategic merge patch to the JSONMap in
   889  // succession.
   890  func MergeStrategicMergeMapPatchUsingLookupPatchMeta(schema LookupPatchMeta, patches ...JSONMap) (JSONMap, error) {
   891  	mergeOptions := MergeOptions{
   892  		MergeParallelList:    false,
   893  		IgnoreUnmatchedNulls: false,
   894  	}
   895  	merged := JSONMap{}
   896  	var err error
   897  	for _, patch := range patches {
   898  		merged, err = mergeMap(merged, patch, schema, mergeOptions)
   899  		if err != nil {
   900  			return nil, err
   901  		}
   902  	}
   903  	return merged, nil
   904  }
   905  
   906  // handleDirectiveInMergeMap handles the patch directive when merging 2 maps.
   907  func handleDirectiveInMergeMap(directive interface{}, patch map[string]interface{}) (map[string]interface{}, error) {
   908  	if directive == replaceDirective {
   909  		// If the patch contains "$patch: replace", don't merge it, just use the
   910  		// patch directly. Later on, we can add a single level replace that only
   911  		// affects the map that the $patch is in.
   912  		delete(patch, directiveMarker)
   913  		return patch, nil
   914  	}
   915  
   916  	if directive == deleteDirective {
   917  		// If the patch contains "$patch: delete", don't merge it, just return
   918  		//  an empty map.
   919  		return map[string]interface{}{}, nil
   920  	}
   921  
   922  	return nil, mergepatch.ErrBadPatchType(directive, patch)
   923  }
   924  
   925  func containsDirectiveMarker(item interface{}) bool {
   926  	m, ok := item.(map[string]interface{})
   927  	if ok {
   928  		if _, foundDirectiveMarker := m[directiveMarker]; foundDirectiveMarker {
   929  			return true
   930  		}
   931  	}
   932  	return false
   933  }
   934  
   935  func mergeKeyValueEqual(left, right interface{}, mergeKey string) (bool, error) {
   936  	if len(mergeKey) == 0 {
   937  		return left == right, nil
   938  	}
   939  	typedLeft, ok := left.(map[string]interface{})
   940  	if !ok {
   941  		return false, mergepatch.ErrBadArgType(typedLeft, left)
   942  	}
   943  	typedRight, ok := right.(map[string]interface{})
   944  	if !ok {
   945  		return false, mergepatch.ErrBadArgType(typedRight, right)
   946  	}
   947  	mergeKeyLeft, ok := typedLeft[mergeKey]
   948  	if !ok {
   949  		return false, mergepatch.ErrNoMergeKey(typedLeft, mergeKey)
   950  	}
   951  	mergeKeyRight, ok := typedRight[mergeKey]
   952  	if !ok {
   953  		return false, mergepatch.ErrNoMergeKey(typedRight, mergeKey)
   954  	}
   955  	return mergeKeyLeft == mergeKeyRight, nil
   956  }
   957  
   958  // extractKey trims the prefix and return the original key
   959  func extractKey(s, prefix string) (string, error) {
   960  	substrings := strings.SplitN(s, "/", 2)
   961  	if len(substrings) <= 1 || substrings[0] != prefix {
   962  		switch prefix {
   963  		case deleteFromPrimitiveListDirectivePrefix:
   964  			return "", mergepatch.ErrBadPatchFormatForPrimitiveList
   965  		case setElementOrderDirectivePrefix:
   966  			return "", mergepatch.ErrBadPatchFormatForSetElementOrderList
   967  		default:
   968  			return "", fmt.Errorf("fail to find unknown prefix %q in %s\n", prefix, s)
   969  		}
   970  	}
   971  	return substrings[1], nil
   972  }
   973  
   974  // validatePatchUsingSetOrderList verifies:
   975  // the relative order of any two items in the setOrderList list matches that in the patch list.
   976  // the items in the patch list must be a subset or the same as the $setElementOrder list (deletions are ignored).
   977  func validatePatchWithSetOrderList(patchList, setOrderList interface{}, mergeKey string) error {
   978  	typedSetOrderList, ok := setOrderList.([]interface{})
   979  	if !ok {
   980  		return mergepatch.ErrBadPatchFormatForSetElementOrderList
   981  	}
   982  	typedPatchList, ok := patchList.([]interface{})
   983  	if !ok {
   984  		return mergepatch.ErrBadPatchFormatForSetElementOrderList
   985  	}
   986  	if len(typedSetOrderList) == 0 || len(typedPatchList) == 0 {
   987  		return nil
   988  	}
   989  
   990  	var nonDeleteList []interface{}
   991  	var err error
   992  	if len(mergeKey) > 0 {
   993  		nonDeleteList, _, err = extractToDeleteItems(typedPatchList)
   994  		if err != nil {
   995  			return err
   996  		}
   997  	} else {
   998  		nonDeleteList = typedPatchList
   999  	}
  1000  
  1001  	patchIndex, setOrderIndex := 0, 0
  1002  	for patchIndex < len(nonDeleteList) && setOrderIndex < len(typedSetOrderList) {
  1003  		if containsDirectiveMarker(nonDeleteList[patchIndex]) {
  1004  			patchIndex++
  1005  			continue
  1006  		}
  1007  		mergeKeyEqual, err := mergeKeyValueEqual(nonDeleteList[patchIndex], typedSetOrderList[setOrderIndex], mergeKey)
  1008  		if err != nil {
  1009  			return err
  1010  		}
  1011  		if mergeKeyEqual {
  1012  			patchIndex++
  1013  		}
  1014  		setOrderIndex++
  1015  	}
  1016  	// If patchIndex is inbound but setOrderIndex if out of bound mean there are items mismatching between the patch list and setElementOrder list.
  1017  	// the second check is a sanity check, and should always be true if the first is true.
  1018  	if patchIndex < len(nonDeleteList) && setOrderIndex >= len(typedSetOrderList) {
  1019  		return fmt.Errorf("The order in patch list:\n%v\n doesn't match %s list:\n%v\n", typedPatchList, setElementOrderDirectivePrefix, setOrderList)
  1020  	}
  1021  	return nil
  1022  }
  1023  
  1024  // preprocessDeletionListForMerging preprocesses the deletion list.
  1025  // it returns shouldContinue, isDeletionList, noPrefixKey
  1026  func preprocessDeletionListForMerging(key string, original map[string]interface{},
  1027  	patchVal interface{}, mergeDeletionList bool) (bool, bool, string, error) {
  1028  	// If found a parallel list for deletion and we are going to merge the list,
  1029  	// overwrite the key to the original key and set flag isDeleteList
  1030  	foundParallelListPrefix := strings.HasPrefix(key, deleteFromPrimitiveListDirectivePrefix)
  1031  	if foundParallelListPrefix {
  1032  		if !mergeDeletionList {
  1033  			original[key] = patchVal
  1034  			return true, false, "", nil
  1035  		}
  1036  		originalKey, err := extractKey(key, deleteFromPrimitiveListDirectivePrefix)
  1037  		return false, true, originalKey, err
  1038  	}
  1039  	return false, false, "", nil
  1040  }
  1041  
  1042  // applyRetainKeysDirective looks for a retainKeys directive and applies to original
  1043  // - if no directive exists do nothing
  1044  // - if directive is found, clear keys in original missing from the directive list
  1045  // - validate that all keys present in the patch are present in the retainKeys directive
  1046  // note: original may be another patch request, e.g. applying the add+modified patch to the deletions patch. In this case it may have directives
  1047  func applyRetainKeysDirective(original, patch map[string]interface{}, options MergeOptions) error {
  1048  	retainKeysInPatch, foundInPatch := patch[retainKeysDirective]
  1049  	if !foundInPatch {
  1050  		return nil
  1051  	}
  1052  	// cleanup the directive
  1053  	delete(patch, retainKeysDirective)
  1054  
  1055  	if !options.MergeParallelList {
  1056  		// If original is actually a patch, make sure the retainKeys directives are the same in both patches if present in both.
  1057  		// If not present in the original patch, copy from the modified patch.
  1058  		retainKeysInOriginal, foundInOriginal := original[retainKeysDirective]
  1059  		if foundInOriginal {
  1060  			if !reflect.DeepEqual(retainKeysInOriginal, retainKeysInPatch) {
  1061  				// This error actually should never happen.
  1062  				return fmt.Errorf("%v and %v are not deep equal: this may happen when calculating the 3-way diff patch", retainKeysInOriginal, retainKeysInPatch)
  1063  			}
  1064  		} else {
  1065  			original[retainKeysDirective] = retainKeysInPatch
  1066  		}
  1067  		return nil
  1068  	}
  1069  
  1070  	retainKeysList, ok := retainKeysInPatch.([]interface{})
  1071  	if !ok {
  1072  		return mergepatch.ErrBadPatchFormatForRetainKeys
  1073  	}
  1074  
  1075  	// validate patch to make sure all fields in the patch are present in the retainKeysList.
  1076  	// The map is used only as a set, the value is never referenced
  1077  	m := map[interface{}]struct{}{}
  1078  	for _, v := range retainKeysList {
  1079  		m[v] = struct{}{}
  1080  	}
  1081  	for k, v := range patch {
  1082  		if v == nil || strings.HasPrefix(k, deleteFromPrimitiveListDirectivePrefix) ||
  1083  			strings.HasPrefix(k, setElementOrderDirectivePrefix) {
  1084  			continue
  1085  		}
  1086  		// If there is an item present in the patch but not in the retainKeys list,
  1087  		// the patch is invalid.
  1088  		if _, found := m[k]; !found {
  1089  			return mergepatch.ErrBadPatchFormatForRetainKeys
  1090  		}
  1091  	}
  1092  
  1093  	// clear not present fields
  1094  	for k := range original {
  1095  		if _, found := m[k]; !found {
  1096  			delete(original, k)
  1097  		}
  1098  	}
  1099  	return nil
  1100  }
  1101  
  1102  // mergePatchIntoOriginal processes $setElementOrder list.
  1103  // When not merging the directive, it will make sure $setElementOrder list exist only in original.
  1104  // When merging the directive, it will try to find the $setElementOrder list and
  1105  // its corresponding patch list, validate it and merge it.
  1106  // Then, sort them by the relative order in setElementOrder, patch list and live list.
  1107  // The precedence is $setElementOrder > order in patch list > order in live list.
  1108  // This function will delete the item after merging it to prevent process it again in the future.
  1109  // Ref: https://git.k8s.io/community/contributors/design-proposals/cli/preserve-order-in-strategic-merge-patch.md
  1110  func mergePatchIntoOriginal(original, patch map[string]interface{}, schema LookupPatchMeta, mergeOptions MergeOptions) error {
  1111  	for key, patchV := range patch {
  1112  		// Do nothing if there is no ordering directive
  1113  		if !strings.HasPrefix(key, setElementOrderDirectivePrefix) {
  1114  			continue
  1115  		}
  1116  
  1117  		setElementOrderInPatch := patchV
  1118  		// Copies directive from the second patch (`patch`) to the first patch (`original`)
  1119  		// and checks they are equal and delete the directive in the second patch
  1120  		if !mergeOptions.MergeParallelList {
  1121  			setElementOrderListInOriginal, ok := original[key]
  1122  			if ok {
  1123  				// check if the setElementOrder list in original and the one in patch matches
  1124  				if !reflect.DeepEqual(setElementOrderListInOriginal, setElementOrderInPatch) {
  1125  					return mergepatch.ErrBadPatchFormatForSetElementOrderList
  1126  				}
  1127  			} else {
  1128  				// move the setElementOrder list from patch to original
  1129  				original[key] = setElementOrderInPatch
  1130  			}
  1131  		}
  1132  		delete(patch, key)
  1133  
  1134  		var (
  1135  			ok                                          bool
  1136  			originalFieldValue, patchFieldValue, merged []interface{}
  1137  			patchStrategy                               string
  1138  			patchMeta                                   PatchMeta
  1139  			subschema                                   LookupPatchMeta
  1140  		)
  1141  		typedSetElementOrderList, ok := setElementOrderInPatch.([]interface{})
  1142  		if !ok {
  1143  			return mergepatch.ErrBadArgType(typedSetElementOrderList, setElementOrderInPatch)
  1144  		}
  1145  		// Trim the setElementOrderDirectivePrefix to get the key of the list field in original.
  1146  		originalKey, err := extractKey(key, setElementOrderDirectivePrefix)
  1147  		if err != nil {
  1148  			return err
  1149  		}
  1150  		// try to find the list with `originalKey` in `original` and `modified` and merge them.
  1151  		originalList, foundOriginal := original[originalKey]
  1152  		patchList, foundPatch := patch[originalKey]
  1153  		if foundOriginal {
  1154  			originalFieldValue, ok = originalList.([]interface{})
  1155  			if !ok {
  1156  				return mergepatch.ErrBadArgType(originalFieldValue, originalList)
  1157  			}
  1158  		}
  1159  		if foundPatch {
  1160  			patchFieldValue, ok = patchList.([]interface{})
  1161  			if !ok {
  1162  				return mergepatch.ErrBadArgType(patchFieldValue, patchList)
  1163  			}
  1164  		}
  1165  		subschema, patchMeta, err = schema.LookupPatchMetadataForSlice(originalKey)
  1166  		if err != nil {
  1167  			return err
  1168  		}
  1169  		_, patchStrategy, err = extractRetainKeysPatchStrategy(patchMeta.GetPatchStrategies())
  1170  		if err != nil {
  1171  			return err
  1172  		}
  1173  		// Check for consistency between the element order list and the field it applies to
  1174  		err = validatePatchWithSetOrderList(patchFieldValue, typedSetElementOrderList, patchMeta.GetPatchMergeKey())
  1175  		if err != nil {
  1176  			return err
  1177  		}
  1178  
  1179  		switch {
  1180  		case foundOriginal && !foundPatch:
  1181  			// no change to list contents
  1182  			merged = originalFieldValue
  1183  		case !foundOriginal && foundPatch:
  1184  			// list was added
  1185  			merged = patchFieldValue
  1186  		case foundOriginal && foundPatch:
  1187  			merged, err = mergeSliceHandler(originalList, patchList, subschema,
  1188  				patchStrategy, patchMeta.GetPatchMergeKey(), false, mergeOptions)
  1189  			if err != nil {
  1190  				return err
  1191  			}
  1192  		case !foundOriginal && !foundPatch:
  1193  			continue
  1194  		}
  1195  
  1196  		// Split all items into patch items and server-only items and then enforce the order.
  1197  		var patchItems, serverOnlyItems []interface{}
  1198  		if len(patchMeta.GetPatchMergeKey()) == 0 {
  1199  			// Primitives doesn't need merge key to do partitioning.
  1200  			patchItems, serverOnlyItems = partitionPrimitivesByPresentInList(merged, typedSetElementOrderList)
  1201  
  1202  		} else {
  1203  			// Maps need merge key to do partitioning.
  1204  			patchItems, serverOnlyItems, err = partitionMapsByPresentInList(merged, typedSetElementOrderList, patchMeta.GetPatchMergeKey())
  1205  			if err != nil {
  1206  				return err
  1207  			}
  1208  		}
  1209  
  1210  		elementType, err := sliceElementType(originalFieldValue, patchFieldValue)
  1211  		if err != nil {
  1212  			return err
  1213  		}
  1214  		kind := elementType.Kind()
  1215  		// normalize merged list
  1216  		// typedSetElementOrderList contains all the relative order in typedPatchList,
  1217  		// so don't need to use typedPatchList
  1218  		both, err := normalizeElementOrder(patchItems, serverOnlyItems, typedSetElementOrderList, originalFieldValue, patchMeta.GetPatchMergeKey(), kind)
  1219  		if err != nil {
  1220  			return err
  1221  		}
  1222  		original[originalKey] = both
  1223  		// delete patch list from patch to prevent process again in the future
  1224  		delete(patch, originalKey)
  1225  	}
  1226  	return nil
  1227  }
  1228  
  1229  // partitionPrimitivesByPresentInList partitions elements into 2 slices, the first containing items present in partitionBy, the other not.
  1230  func partitionPrimitivesByPresentInList(original, partitionBy []interface{}) ([]interface{}, []interface{}) {
  1231  	patch := make([]interface{}, 0, len(original))
  1232  	serverOnly := make([]interface{}, 0, len(original))
  1233  	inPatch := map[interface{}]bool{}
  1234  	for _, v := range partitionBy {
  1235  		inPatch[v] = true
  1236  	}
  1237  	for _, v := range original {
  1238  		if !inPatch[v] {
  1239  			serverOnly = append(serverOnly, v)
  1240  		} else {
  1241  			patch = append(patch, v)
  1242  		}
  1243  	}
  1244  	return patch, serverOnly
  1245  }
  1246  
  1247  // partitionMapsByPresentInList partitions elements into 2 slices, the first containing items present in partitionBy, the other not.
  1248  func partitionMapsByPresentInList(original, partitionBy []interface{}, mergeKey string) ([]interface{}, []interface{}, error) {
  1249  	patch := make([]interface{}, 0, len(original))
  1250  	serverOnly := make([]interface{}, 0, len(original))
  1251  	for _, v := range original {
  1252  		typedV, ok := v.(map[string]interface{})
  1253  		if !ok {
  1254  			return nil, nil, mergepatch.ErrBadArgType(typedV, v)
  1255  		}
  1256  		mergeKeyValue, foundMergeKey := typedV[mergeKey]
  1257  		if !foundMergeKey {
  1258  			return nil, nil, mergepatch.ErrNoMergeKey(typedV, mergeKey)
  1259  		}
  1260  		_, _, found, err := findMapInSliceBasedOnKeyValue(partitionBy, mergeKey, mergeKeyValue)
  1261  		if err != nil {
  1262  			return nil, nil, err
  1263  		}
  1264  		if !found {
  1265  			serverOnly = append(serverOnly, v)
  1266  		} else {
  1267  			patch = append(patch, v)
  1268  		}
  1269  	}
  1270  	return patch, serverOnly, nil
  1271  }
  1272  
  1273  // Merge fields from a patch map into the original map. Note: This may modify
  1274  // both the original map and the patch because getting a deep copy of a map in
  1275  // golang is highly non-trivial.
  1276  // flag mergeOptions.MergeParallelList controls if using the parallel list to delete or keeping the list.
  1277  // If patch contains any null field (e.g. field_1: null) that is not
  1278  // present in original, then to propagate it to the end result use
  1279  // mergeOptions.IgnoreUnmatchedNulls == false.
  1280  func mergeMap(original, patch map[string]interface{}, schema LookupPatchMeta, mergeOptions MergeOptions) (map[string]interface{}, error) {
  1281  	if v, ok := patch[directiveMarker]; ok {
  1282  		return handleDirectiveInMergeMap(v, patch)
  1283  	}
  1284  
  1285  	// nil is an accepted value for original to simplify logic in other places.
  1286  	// If original is nil, replace it with an empty map and then apply the patch.
  1287  	if original == nil {
  1288  		original = map[string]interface{}{}
  1289  	}
  1290  
  1291  	err := applyRetainKeysDirective(original, patch, mergeOptions)
  1292  	if err != nil {
  1293  		return nil, err
  1294  	}
  1295  
  1296  	// Process $setElementOrder list and other lists sharing the same key.
  1297  	// When not merging the directive, it will make sure $setElementOrder list exist only in original.
  1298  	// When merging the directive, it will process $setElementOrder and its patch list together.
  1299  	// This function will delete the merged elements from patch so they will not be reprocessed
  1300  	err = mergePatchIntoOriginal(original, patch, schema, mergeOptions)
  1301  	if err != nil {
  1302  		return nil, err
  1303  	}
  1304  
  1305  	// Start merging the patch into the original.
  1306  	for k, patchV := range patch {
  1307  		skipProcessing, isDeleteList, noPrefixKey, err := preprocessDeletionListForMerging(k, original, patchV, mergeOptions.MergeParallelList)
  1308  		if err != nil {
  1309  			return nil, err
  1310  		}
  1311  		if skipProcessing {
  1312  			continue
  1313  		}
  1314  		if len(noPrefixKey) > 0 {
  1315  			k = noPrefixKey
  1316  		}
  1317  
  1318  		// If the value of this key is null, delete the key if it exists in the
  1319  		// original. Otherwise, check if we want to preserve it or skip it.
  1320  		// Preserving the null value is useful when we want to send an explicit
  1321  		// delete to the API server.
  1322  		if patchV == nil {
  1323  			delete(original, k)
  1324  			if mergeOptions.IgnoreUnmatchedNulls {
  1325  				continue
  1326  			}
  1327  		}
  1328  
  1329  		_, ok := original[k]
  1330  		if !ok {
  1331  			if !isDeleteList {
  1332  				// If it's not in the original document, just take the patch value.
  1333  				if mergeOptions.IgnoreUnmatchedNulls {
  1334  					discardNullValuesFromPatch(patchV)
  1335  				}
  1336  				original[k] = patchV
  1337  			}
  1338  			continue
  1339  		}
  1340  
  1341  		originalType := reflect.TypeOf(original[k])
  1342  		patchType := reflect.TypeOf(patchV)
  1343  		if originalType != patchType {
  1344  			if !isDeleteList {
  1345  				if mergeOptions.IgnoreUnmatchedNulls {
  1346  					discardNullValuesFromPatch(patchV)
  1347  				}
  1348  				original[k] = patchV
  1349  			}
  1350  			continue
  1351  		}
  1352  		// If they're both maps or lists, recurse into the value.
  1353  		switch originalType.Kind() {
  1354  		case reflect.Map:
  1355  			subschema, patchMeta, err2 := schema.LookupPatchMetadataForStruct(k)
  1356  			if err2 != nil {
  1357  				return nil, err2
  1358  			}
  1359  			_, patchStrategy, err2 := extractRetainKeysPatchStrategy(patchMeta.GetPatchStrategies())
  1360  			if err2 != nil {
  1361  				return nil, err2
  1362  			}
  1363  			original[k], err = mergeMapHandler(original[k], patchV, subschema, patchStrategy, mergeOptions)
  1364  		case reflect.Slice:
  1365  			subschema, patchMeta, err2 := schema.LookupPatchMetadataForSlice(k)
  1366  			if err2 != nil {
  1367  				return nil, err2
  1368  			}
  1369  			_, patchStrategy, err2 := extractRetainKeysPatchStrategy(patchMeta.GetPatchStrategies())
  1370  			if err2 != nil {
  1371  				return nil, err2
  1372  			}
  1373  			original[k], err = mergeSliceHandler(original[k], patchV, subschema, patchStrategy, patchMeta.GetPatchMergeKey(), isDeleteList, mergeOptions)
  1374  		default:
  1375  			original[k] = patchV
  1376  		}
  1377  		if err != nil {
  1378  			return nil, err
  1379  		}
  1380  	}
  1381  	return original, nil
  1382  }
  1383  
  1384  // discardNullValuesFromPatch discards all null property values from patch.
  1385  // It traverses all slices and map types.
  1386  func discardNullValuesFromPatch(patchV interface{}) {
  1387  	switch patchV := patchV.(type) {
  1388  	case map[string]interface{}:
  1389  		for k, v := range patchV {
  1390  			if v == nil {
  1391  				delete(patchV, k)
  1392  			} else {
  1393  				discardNullValuesFromPatch(v)
  1394  			}
  1395  		}
  1396  	case []interface{}:
  1397  		for _, v := range patchV {
  1398  			discardNullValuesFromPatch(v)
  1399  		}
  1400  	}
  1401  }
  1402  
  1403  // mergeMapHandler handles how to merge `patchV` whose key is `key` with `original` respecting
  1404  // fieldPatchStrategy and mergeOptions.
  1405  func mergeMapHandler(original, patch interface{}, schema LookupPatchMeta,
  1406  	fieldPatchStrategy string, mergeOptions MergeOptions) (map[string]interface{}, error) {
  1407  	typedOriginal, typedPatch, err := mapTypeAssertion(original, patch)
  1408  	if err != nil {
  1409  		return nil, err
  1410  	}
  1411  
  1412  	if fieldPatchStrategy != replaceDirective {
  1413  		return mergeMap(typedOriginal, typedPatch, schema, mergeOptions)
  1414  	} else {
  1415  		return typedPatch, nil
  1416  	}
  1417  }
  1418  
  1419  // mergeSliceHandler handles how to merge `patchV` whose key is `key` with `original` respecting
  1420  // fieldPatchStrategy, fieldPatchMergeKey, isDeleteList and mergeOptions.
  1421  func mergeSliceHandler(original, patch interface{}, schema LookupPatchMeta,
  1422  	fieldPatchStrategy, fieldPatchMergeKey string, isDeleteList bool, mergeOptions MergeOptions) ([]interface{}, error) {
  1423  	typedOriginal, typedPatch, err := sliceTypeAssertion(original, patch)
  1424  	if err != nil {
  1425  		return nil, err
  1426  	}
  1427  
  1428  	if fieldPatchStrategy == mergeDirective {
  1429  		return mergeSlice(typedOriginal, typedPatch, schema, fieldPatchMergeKey, mergeOptions, isDeleteList)
  1430  	} else {
  1431  		return typedPatch, nil
  1432  	}
  1433  }
  1434  
  1435  // Merge two slices together. Note: This may modify both the original slice and
  1436  // the patch because getting a deep copy of a slice in golang is highly
  1437  // non-trivial.
  1438  func mergeSlice(original, patch []interface{}, schema LookupPatchMeta, mergeKey string, mergeOptions MergeOptions, isDeleteList bool) ([]interface{}, error) {
  1439  	if len(original) == 0 && len(patch) == 0 {
  1440  		return original, nil
  1441  	}
  1442  
  1443  	// All the values must be of the same type, but not a list.
  1444  	t, err := sliceElementType(original, patch)
  1445  	if err != nil {
  1446  		return nil, err
  1447  	}
  1448  
  1449  	var merged []interface{}
  1450  	kind := t.Kind()
  1451  	// If the elements are not maps, merge the slices of scalars.
  1452  	if kind != reflect.Map {
  1453  		if mergeOptions.MergeParallelList && isDeleteList {
  1454  			return deleteFromSlice(original, patch), nil
  1455  		}
  1456  		// Maybe in the future add a "concat" mode that doesn't
  1457  		// deduplicate.
  1458  		both := append(original, patch...)
  1459  		merged = deduplicateScalars(both)
  1460  
  1461  	} else {
  1462  		if mergeKey == "" {
  1463  			return nil, fmt.Errorf("cannot merge lists without merge key for %s", schema.Name())
  1464  		}
  1465  
  1466  		original, patch, err = mergeSliceWithSpecialElements(original, patch, mergeKey)
  1467  		if err != nil {
  1468  			return nil, err
  1469  		}
  1470  
  1471  		merged, err = mergeSliceWithoutSpecialElements(original, patch, mergeKey, schema, mergeOptions)
  1472  		if err != nil {
  1473  			return nil, err
  1474  		}
  1475  	}
  1476  
  1477  	// enforce the order
  1478  	var patchItems, serverOnlyItems []interface{}
  1479  	if len(mergeKey) == 0 {
  1480  		patchItems, serverOnlyItems = partitionPrimitivesByPresentInList(merged, patch)
  1481  	} else {
  1482  		patchItems, serverOnlyItems, err = partitionMapsByPresentInList(merged, patch, mergeKey)
  1483  		if err != nil {
  1484  			return nil, err
  1485  		}
  1486  	}
  1487  	return normalizeElementOrder(patchItems, serverOnlyItems, patch, original, mergeKey, kind)
  1488  }
  1489  
  1490  // mergeSliceWithSpecialElements handles special elements with directiveMarker
  1491  // before merging the slices. It returns a updated `original` and a patch without special elements.
  1492  // original and patch must be slices of maps, they should be checked before calling this function.
  1493  func mergeSliceWithSpecialElements(original, patch []interface{}, mergeKey string) ([]interface{}, []interface{}, error) {
  1494  	patchWithoutSpecialElements := []interface{}{}
  1495  	replace := false
  1496  	for _, v := range patch {
  1497  		typedV := v.(map[string]interface{})
  1498  		patchType, ok := typedV[directiveMarker]
  1499  		if !ok {
  1500  			patchWithoutSpecialElements = append(patchWithoutSpecialElements, v)
  1501  		} else {
  1502  			switch patchType {
  1503  			case deleteDirective:
  1504  				mergeValue, ok := typedV[mergeKey]
  1505  				if ok {
  1506  					var err error
  1507  					original, err = deleteMatchingEntries(original, mergeKey, mergeValue)
  1508  					if err != nil {
  1509  						return nil, nil, err
  1510  					}
  1511  				} else {
  1512  					return nil, nil, mergepatch.ErrNoMergeKey(typedV, mergeKey)
  1513  				}
  1514  			case replaceDirective:
  1515  				replace = true
  1516  				// Continue iterating through the array to prune any other $patch elements.
  1517  			case mergeDirective:
  1518  				return nil, nil, fmt.Errorf("merging lists cannot yet be specified in the patch")
  1519  			default:
  1520  				return nil, nil, mergepatch.ErrBadPatchType(patchType, typedV)
  1521  			}
  1522  		}
  1523  	}
  1524  	if replace {
  1525  		return patchWithoutSpecialElements, nil, nil
  1526  	}
  1527  	return original, patchWithoutSpecialElements, nil
  1528  }
  1529  
  1530  // delete all matching entries (based on merge key) from a merging list
  1531  func deleteMatchingEntries(original []interface{}, mergeKey string, mergeValue interface{}) ([]interface{}, error) {
  1532  	for {
  1533  		_, originalKey, found, err := findMapInSliceBasedOnKeyValue(original, mergeKey, mergeValue)
  1534  		if err != nil {
  1535  			return nil, err
  1536  		}
  1537  
  1538  		if !found {
  1539  			break
  1540  		}
  1541  		// Delete the element at originalKey.
  1542  		original = append(original[:originalKey], original[originalKey+1:]...)
  1543  	}
  1544  	return original, nil
  1545  }
  1546  
  1547  // mergeSliceWithoutSpecialElements merges slices with non-special elements.
  1548  // original and patch must be slices of maps, they should be checked before calling this function.
  1549  func mergeSliceWithoutSpecialElements(original, patch []interface{}, mergeKey string, schema LookupPatchMeta, mergeOptions MergeOptions) ([]interface{}, error) {
  1550  	for _, v := range patch {
  1551  		typedV := v.(map[string]interface{})
  1552  		mergeValue, ok := typedV[mergeKey]
  1553  		if !ok {
  1554  			return nil, mergepatch.ErrNoMergeKey(typedV, mergeKey)
  1555  		}
  1556  
  1557  		// If we find a value with this merge key value in original, merge the
  1558  		// maps. Otherwise append onto original.
  1559  		originalMap, originalKey, found, err := findMapInSliceBasedOnKeyValue(original, mergeKey, mergeValue)
  1560  		if err != nil {
  1561  			return nil, err
  1562  		}
  1563  
  1564  		if found {
  1565  			var mergedMaps interface{}
  1566  			var err error
  1567  			// Merge into original.
  1568  			mergedMaps, err = mergeMap(originalMap, typedV, schema, mergeOptions)
  1569  			if err != nil {
  1570  				return nil, err
  1571  			}
  1572  
  1573  			original[originalKey] = mergedMaps
  1574  		} else {
  1575  			original = append(original, v)
  1576  		}
  1577  	}
  1578  	return original, nil
  1579  }
  1580  
  1581  // deleteFromSlice uses the parallel list to delete the items in a list of scalars
  1582  func deleteFromSlice(current, toDelete []interface{}) []interface{} {
  1583  	toDeleteMap := map[interface{}]interface{}{}
  1584  	processed := make([]interface{}, 0, len(current))
  1585  	for _, v := range toDelete {
  1586  		toDeleteMap[v] = true
  1587  	}
  1588  	for _, v := range current {
  1589  		if _, found := toDeleteMap[v]; !found {
  1590  			processed = append(processed, v)
  1591  		}
  1592  	}
  1593  	return processed
  1594  }
  1595  
  1596  // This method no longer panics if any element of the slice is not a map.
  1597  func findMapInSliceBasedOnKeyValue(m []interface{}, key string, value interface{}) (map[string]interface{}, int, bool, error) {
  1598  	for k, v := range m {
  1599  		typedV, ok := v.(map[string]interface{})
  1600  		if !ok {
  1601  			return nil, 0, false, fmt.Errorf("value for key %v is not a map", k)
  1602  		}
  1603  
  1604  		valueToMatch, ok := typedV[key]
  1605  		if ok && valueToMatch == value {
  1606  			return typedV, k, true, nil
  1607  		}
  1608  	}
  1609  
  1610  	return nil, 0, false, nil
  1611  }
  1612  
  1613  // This function takes a JSON map and sorts all the lists that should be merged
  1614  // by key. This is needed by tests because in JSON, list order is significant,
  1615  // but in Strategic Merge Patch, merge lists do not have significant order.
  1616  // Sorting the lists allows for order-insensitive comparison of patched maps.
  1617  func sortMergeListsByName(mapJSON []byte, schema LookupPatchMeta) ([]byte, error) {
  1618  	var m map[string]interface{}
  1619  	err := json.Unmarshal(mapJSON, &m)
  1620  	if err != nil {
  1621  		return nil, mergepatch.ErrBadJSONDoc
  1622  	}
  1623  
  1624  	newM, err := sortMergeListsByNameMap(m, schema)
  1625  	if err != nil {
  1626  		return nil, err
  1627  	}
  1628  
  1629  	return json.Marshal(newM)
  1630  }
  1631  
  1632  // Function sortMergeListsByNameMap recursively sorts the merge lists by its mergeKey in a map.
  1633  func sortMergeListsByNameMap(s map[string]interface{}, schema LookupPatchMeta) (map[string]interface{}, error) {
  1634  	newS := map[string]interface{}{}
  1635  	for k, v := range s {
  1636  		if k == retainKeysDirective {
  1637  			typedV, ok := v.([]interface{})
  1638  			if !ok {
  1639  				return nil, mergepatch.ErrBadPatchFormatForRetainKeys
  1640  			}
  1641  			v = sortScalars(typedV)
  1642  		} else if strings.HasPrefix(k, deleteFromPrimitiveListDirectivePrefix) {
  1643  			typedV, ok := v.([]interface{})
  1644  			if !ok {
  1645  				return nil, mergepatch.ErrBadPatchFormatForPrimitiveList
  1646  			}
  1647  			v = sortScalars(typedV)
  1648  		} else if strings.HasPrefix(k, setElementOrderDirectivePrefix) {
  1649  			_, ok := v.([]interface{})
  1650  			if !ok {
  1651  				return nil, mergepatch.ErrBadPatchFormatForSetElementOrderList
  1652  			}
  1653  		} else if k != directiveMarker {
  1654  			// recurse for map and slice.
  1655  			switch typedV := v.(type) {
  1656  			case map[string]interface{}:
  1657  				subschema, _, err := schema.LookupPatchMetadataForStruct(k)
  1658  				if err != nil {
  1659  					return nil, err
  1660  				}
  1661  				v, err = sortMergeListsByNameMap(typedV, subschema)
  1662  				if err != nil {
  1663  					return nil, err
  1664  				}
  1665  			case []interface{}:
  1666  				subschema, patchMeta, err := schema.LookupPatchMetadataForSlice(k)
  1667  				if err != nil {
  1668  					return nil, err
  1669  				}
  1670  				_, patchStrategy, err := extractRetainKeysPatchStrategy(patchMeta.GetPatchStrategies())
  1671  				if err != nil {
  1672  					return nil, err
  1673  				}
  1674  				if patchStrategy == mergeDirective {
  1675  					var err error
  1676  					v, err = sortMergeListsByNameArray(typedV, subschema, patchMeta.GetPatchMergeKey(), true)
  1677  					if err != nil {
  1678  						return nil, err
  1679  					}
  1680  				}
  1681  			}
  1682  		}
  1683  
  1684  		newS[k] = v
  1685  	}
  1686  
  1687  	return newS, nil
  1688  }
  1689  
  1690  // Function sortMergeListsByNameMap recursively sorts the merge lists by its mergeKey in an array.
  1691  func sortMergeListsByNameArray(s []interface{}, schema LookupPatchMeta, mergeKey string, recurse bool) ([]interface{}, error) {
  1692  	if len(s) == 0 {
  1693  		return s, nil
  1694  	}
  1695  
  1696  	// We don't support lists of lists yet.
  1697  	t, err := sliceElementType(s)
  1698  	if err != nil {
  1699  		return nil, err
  1700  	}
  1701  
  1702  	// If the elements are not maps...
  1703  	if t.Kind() != reflect.Map {
  1704  		// Sort the elements, because they may have been merged out of order.
  1705  		return deduplicateAndSortScalars(s), nil
  1706  	}
  1707  
  1708  	// Elements are maps - if one of the keys of the map is a map or a
  1709  	// list, we may need to recurse into it.
  1710  	newS := []interface{}{}
  1711  	for _, elem := range s {
  1712  		if recurse {
  1713  			typedElem := elem.(map[string]interface{})
  1714  			newElem, err := sortMergeListsByNameMap(typedElem, schema)
  1715  			if err != nil {
  1716  				return nil, err
  1717  			}
  1718  
  1719  			newS = append(newS, newElem)
  1720  		} else {
  1721  			newS = append(newS, elem)
  1722  		}
  1723  	}
  1724  
  1725  	// Sort the maps.
  1726  	newS = sortMapsBasedOnField(newS, mergeKey)
  1727  	return newS, nil
  1728  }
  1729  
  1730  func sortMapsBasedOnField(m []interface{}, fieldName string) []interface{} {
  1731  	mapM := mapSliceFromSlice(m)
  1732  	ss := SortableSliceOfMaps{mapM, fieldName}
  1733  	sort.Sort(ss)
  1734  	newS := sliceFromMapSlice(ss.s)
  1735  	return newS
  1736  }
  1737  
  1738  func mapSliceFromSlice(m []interface{}) []map[string]interface{} {
  1739  	newM := []map[string]interface{}{}
  1740  	for _, v := range m {
  1741  		vt := v.(map[string]interface{})
  1742  		newM = append(newM, vt)
  1743  	}
  1744  
  1745  	return newM
  1746  }
  1747  
  1748  func sliceFromMapSlice(s []map[string]interface{}) []interface{} {
  1749  	newS := []interface{}{}
  1750  	for _, v := range s {
  1751  		newS = append(newS, v)
  1752  	}
  1753  
  1754  	return newS
  1755  }
  1756  
  1757  type SortableSliceOfMaps struct {
  1758  	s []map[string]interface{}
  1759  	k string // key to sort on
  1760  }
  1761  
  1762  func (ss SortableSliceOfMaps) Len() int {
  1763  	return len(ss.s)
  1764  }
  1765  
  1766  func (ss SortableSliceOfMaps) Less(i, j int) bool {
  1767  	iStr := fmt.Sprintf("%v", ss.s[i][ss.k])
  1768  	jStr := fmt.Sprintf("%v", ss.s[j][ss.k])
  1769  	return sort.StringsAreSorted([]string{iStr, jStr})
  1770  }
  1771  
  1772  func (ss SortableSliceOfMaps) Swap(i, j int) {
  1773  	tmp := ss.s[i]
  1774  	ss.s[i] = ss.s[j]
  1775  	ss.s[j] = tmp
  1776  }
  1777  
  1778  func deduplicateAndSortScalars(s []interface{}) []interface{} {
  1779  	s = deduplicateScalars(s)
  1780  	return sortScalars(s)
  1781  }
  1782  
  1783  func sortScalars(s []interface{}) []interface{} {
  1784  	ss := SortableSliceOfScalars{s}
  1785  	sort.Sort(ss)
  1786  	return ss.s
  1787  }
  1788  
  1789  func deduplicateScalars(s []interface{}) []interface{} {
  1790  	// Clever algorithm to deduplicate.
  1791  	length := len(s) - 1
  1792  	for i := 0; i < length; i++ {
  1793  		for j := i + 1; j <= length; j++ {
  1794  			if s[i] == s[j] {
  1795  				s[j] = s[length]
  1796  				s = s[0:length]
  1797  				length--
  1798  				j--
  1799  			}
  1800  		}
  1801  	}
  1802  
  1803  	return s
  1804  }
  1805  
  1806  type SortableSliceOfScalars struct {
  1807  	s []interface{}
  1808  }
  1809  
  1810  func (ss SortableSliceOfScalars) Len() int {
  1811  	return len(ss.s)
  1812  }
  1813  
  1814  func (ss SortableSliceOfScalars) Less(i, j int) bool {
  1815  	iStr := fmt.Sprintf("%v", ss.s[i])
  1816  	jStr := fmt.Sprintf("%v", ss.s[j])
  1817  	return sort.StringsAreSorted([]string{iStr, jStr})
  1818  }
  1819  
  1820  func (ss SortableSliceOfScalars) Swap(i, j int) {
  1821  	tmp := ss.s[i]
  1822  	ss.s[i] = ss.s[j]
  1823  	ss.s[j] = tmp
  1824  }
  1825  
  1826  // Returns the type of the elements of N slice(s). If the type is different,
  1827  // another slice or undefined, returns an error.
  1828  func sliceElementType(slices ...[]interface{}) (reflect.Type, error) {
  1829  	var prevType reflect.Type
  1830  	for _, s := range slices {
  1831  		// Go through elements of all given slices and make sure they are all the same type.
  1832  		for _, v := range s {
  1833  			currentType := reflect.TypeOf(v)
  1834  			if prevType == nil {
  1835  				prevType = currentType
  1836  				// We don't support lists of lists yet.
  1837  				if prevType.Kind() == reflect.Slice {
  1838  					return nil, mergepatch.ErrNoListOfLists
  1839  				}
  1840  			} else {
  1841  				if prevType != currentType {
  1842  					return nil, fmt.Errorf("list element types are not identical: %v", fmt.Sprint(slices))
  1843  				}
  1844  				prevType = currentType
  1845  			}
  1846  		}
  1847  	}
  1848  
  1849  	if prevType == nil {
  1850  		return nil, fmt.Errorf("no elements in any of the given slices")
  1851  	}
  1852  
  1853  	return prevType, nil
  1854  }
  1855  
  1856  // MergingMapsHaveConflicts returns true if the left and right JSON interface
  1857  // objects overlap with different values in any key. All keys are required to be
  1858  // strings. Since patches of the same Type have congruent keys, this is valid
  1859  // for multiple patch types. This method supports strategic merge patch semantics.
  1860  func MergingMapsHaveConflicts(left, right map[string]interface{}, schema LookupPatchMeta) (bool, error) {
  1861  	return mergingMapFieldsHaveConflicts(left, right, schema, "", "")
  1862  }
  1863  
  1864  func mergingMapFieldsHaveConflicts(
  1865  	left, right interface{},
  1866  	schema LookupPatchMeta,
  1867  	fieldPatchStrategy, fieldPatchMergeKey string,
  1868  ) (bool, error) {
  1869  	switch leftType := left.(type) {
  1870  	case map[string]interface{}:
  1871  		rightType, ok := right.(map[string]interface{})
  1872  		if !ok {
  1873  			return true, nil
  1874  		}
  1875  		leftMarker, okLeft := leftType[directiveMarker]
  1876  		rightMarker, okRight := rightType[directiveMarker]
  1877  		// if one or the other has a directive marker,
  1878  		// then we need to consider that before looking at the individual keys,
  1879  		// since a directive operates on the whole map.
  1880  		if okLeft || okRight {
  1881  			// if one has a directive marker and the other doesn't,
  1882  			// then we have a conflict, since one is deleting or replacing the whole map,
  1883  			// and the other is doing things to individual keys.
  1884  			if okLeft != okRight {
  1885  				return true, nil
  1886  			}
  1887  			// if they both have markers, but they are not the same directive,
  1888  			// then we have a conflict because they're doing different things to the map.
  1889  			if leftMarker != rightMarker {
  1890  				return true, nil
  1891  			}
  1892  		}
  1893  		if fieldPatchStrategy == replaceDirective {
  1894  			return false, nil
  1895  		}
  1896  		// Check the individual keys.
  1897  		return mapsHaveConflicts(leftType, rightType, schema)
  1898  
  1899  	case []interface{}:
  1900  		rightType, ok := right.([]interface{})
  1901  		if !ok {
  1902  			return true, nil
  1903  		}
  1904  		return slicesHaveConflicts(leftType, rightType, schema, fieldPatchStrategy, fieldPatchMergeKey)
  1905  	case string, float64, bool, int64, nil:
  1906  		return !reflect.DeepEqual(left, right), nil
  1907  	default:
  1908  		return true, fmt.Errorf("unknown type: %v", reflect.TypeOf(left))
  1909  	}
  1910  }
  1911  
  1912  func mapsHaveConflicts(typedLeft, typedRight map[string]interface{}, schema LookupPatchMeta) (bool, error) {
  1913  	for key, leftValue := range typedLeft {
  1914  		if key != directiveMarker && key != retainKeysDirective {
  1915  			if rightValue, ok := typedRight[key]; ok {
  1916  				var subschema LookupPatchMeta
  1917  				var patchMeta PatchMeta
  1918  				var patchStrategy string
  1919  				var err error
  1920  				switch leftValue.(type) {
  1921  				case []interface{}:
  1922  					subschema, patchMeta, err = schema.LookupPatchMetadataForSlice(key)
  1923  					if err != nil {
  1924  						return true, err
  1925  					}
  1926  					_, patchStrategy, err = extractRetainKeysPatchStrategy(patchMeta.patchStrategies)
  1927  					if err != nil {
  1928  						return true, err
  1929  					}
  1930  				case map[string]interface{}:
  1931  					subschema, patchMeta, err = schema.LookupPatchMetadataForStruct(key)
  1932  					if err != nil {
  1933  						return true, err
  1934  					}
  1935  					_, patchStrategy, err = extractRetainKeysPatchStrategy(patchMeta.patchStrategies)
  1936  					if err != nil {
  1937  						return true, err
  1938  					}
  1939  				}
  1940  
  1941  				if hasConflicts, err := mergingMapFieldsHaveConflicts(leftValue, rightValue,
  1942  					subschema, patchStrategy, patchMeta.GetPatchMergeKey()); hasConflicts {
  1943  					return true, err
  1944  				}
  1945  			}
  1946  		}
  1947  	}
  1948  
  1949  	return false, nil
  1950  }
  1951  
  1952  func slicesHaveConflicts(
  1953  	typedLeft, typedRight []interface{},
  1954  	schema LookupPatchMeta,
  1955  	fieldPatchStrategy, fieldPatchMergeKey string,
  1956  ) (bool, error) {
  1957  	elementType, err := sliceElementType(typedLeft, typedRight)
  1958  	if err != nil {
  1959  		return true, err
  1960  	}
  1961  
  1962  	if fieldPatchStrategy == mergeDirective {
  1963  		// Merging lists of scalars have no conflicts by definition
  1964  		// So we only need to check further if the elements are maps
  1965  		if elementType.Kind() != reflect.Map {
  1966  			return false, nil
  1967  		}
  1968  
  1969  		// Build a map for each slice and then compare the two maps
  1970  		leftMap, err := sliceOfMapsToMapOfMaps(typedLeft, fieldPatchMergeKey)
  1971  		if err != nil {
  1972  			return true, err
  1973  		}
  1974  
  1975  		rightMap, err := sliceOfMapsToMapOfMaps(typedRight, fieldPatchMergeKey)
  1976  		if err != nil {
  1977  			return true, err
  1978  		}
  1979  
  1980  		return mapsOfMapsHaveConflicts(leftMap, rightMap, schema)
  1981  	}
  1982  
  1983  	// Either we don't have type information, or these are non-merging lists
  1984  	if len(typedLeft) != len(typedRight) {
  1985  		return true, nil
  1986  	}
  1987  
  1988  	// Sort scalar slices to prevent ordering issues
  1989  	// We have no way to sort non-merging lists of maps
  1990  	if elementType.Kind() != reflect.Map {
  1991  		typedLeft = deduplicateAndSortScalars(typedLeft)
  1992  		typedRight = deduplicateAndSortScalars(typedRight)
  1993  	}
  1994  
  1995  	// Compare the slices element by element in order
  1996  	// This test will fail if the slices are not sorted
  1997  	for i := range typedLeft {
  1998  		if hasConflicts, err := mergingMapFieldsHaveConflicts(typedLeft[i], typedRight[i], schema, "", ""); hasConflicts {
  1999  			return true, err
  2000  		}
  2001  	}
  2002  
  2003  	return false, nil
  2004  }
  2005  
  2006  func sliceOfMapsToMapOfMaps(slice []interface{}, mergeKey string) (map[string]interface{}, error) {
  2007  	result := make(map[string]interface{}, len(slice))
  2008  	for _, value := range slice {
  2009  		typedValue, ok := value.(map[string]interface{})
  2010  		if !ok {
  2011  			return nil, fmt.Errorf("invalid element type in merging list:%v", slice)
  2012  		}
  2013  
  2014  		mergeValue, ok := typedValue[mergeKey]
  2015  		if !ok {
  2016  			return nil, fmt.Errorf("cannot find merge key `%s` in merging list element:%v", mergeKey, typedValue)
  2017  		}
  2018  
  2019  		result[fmt.Sprintf("%s", mergeValue)] = typedValue
  2020  	}
  2021  
  2022  	return result, nil
  2023  }
  2024  
  2025  func mapsOfMapsHaveConflicts(typedLeft, typedRight map[string]interface{}, schema LookupPatchMeta) (bool, error) {
  2026  	for key, leftValue := range typedLeft {
  2027  		if rightValue, ok := typedRight[key]; ok {
  2028  			if hasConflicts, err := mergingMapFieldsHaveConflicts(leftValue, rightValue, schema, "", ""); hasConflicts {
  2029  				return true, err
  2030  			}
  2031  		}
  2032  	}
  2033  
  2034  	return false, nil
  2035  }
  2036  
  2037  // CreateThreeWayMergePatch reconciles a modified configuration with an original configuration,
  2038  // while preserving any changes or deletions made to the original configuration in the interim,
  2039  // and not overridden by the current configuration. All three documents must be passed to the
  2040  // method as json encoded content. It will return a strategic merge patch, or an error if any
  2041  // of the documents is invalid, or if there are any preconditions that fail against the modified
  2042  // configuration, or, if overwrite is false and there are conflicts between the modified and current
  2043  // configurations. Conflicts are defined as keys changed differently from original to modified
  2044  // than from original to current. In other words, a conflict occurs if modified changes any key
  2045  // in a way that is different from how it is changed in current (e.g., deleting it, changing its
  2046  // value). We also propagate values fields that do not exist in original but are explicitly
  2047  // defined in modified.
  2048  func CreateThreeWayMergePatch(original, modified, current []byte, schema LookupPatchMeta, overwrite bool, fns ...mergepatch.PreconditionFunc) ([]byte, error) {
  2049  	originalMap := map[string]interface{}{}
  2050  	if len(original) > 0 {
  2051  		if err := json.Unmarshal(original, &originalMap); err != nil {
  2052  			return nil, mergepatch.ErrBadJSONDoc
  2053  		}
  2054  	}
  2055  
  2056  	modifiedMap := map[string]interface{}{}
  2057  	if len(modified) > 0 {
  2058  		if err := json.Unmarshal(modified, &modifiedMap); err != nil {
  2059  			return nil, mergepatch.ErrBadJSONDoc
  2060  		}
  2061  	}
  2062  
  2063  	currentMap := map[string]interface{}{}
  2064  	if len(current) > 0 {
  2065  		if err := json.Unmarshal(current, &currentMap); err != nil {
  2066  			return nil, mergepatch.ErrBadJSONDoc
  2067  		}
  2068  	}
  2069  
  2070  	// The patch is the difference from current to modified without deletions, plus deletions
  2071  	// from original to modified. To find it, we compute deletions, which are the deletions from
  2072  	// original to modified, and delta, which is the difference from current to modified without
  2073  	// deletions, and then apply delta to deletions as a patch, which should be strictly additive.
  2074  	deltaMapDiffOptions := DiffOptions{
  2075  		IgnoreDeletions: true,
  2076  		SetElementOrder: true,
  2077  	}
  2078  	deltaMap, err := diffMaps(currentMap, modifiedMap, schema, deltaMapDiffOptions)
  2079  	if err != nil {
  2080  		return nil, err
  2081  	}
  2082  	deletionsMapDiffOptions := DiffOptions{
  2083  		SetElementOrder:           true,
  2084  		IgnoreChangesAndAdditions: true,
  2085  	}
  2086  	deletionsMap, err := diffMaps(originalMap, modifiedMap, schema, deletionsMapDiffOptions)
  2087  	if err != nil {
  2088  		return nil, err
  2089  	}
  2090  
  2091  	mergeOptions := MergeOptions{}
  2092  	patchMap, err := mergeMap(deletionsMap, deltaMap, schema, mergeOptions)
  2093  	if err != nil {
  2094  		return nil, err
  2095  	}
  2096  
  2097  	// Apply the preconditions to the patch, and return an error if any of them fail.
  2098  	for _, fn := range fns {
  2099  		if !fn(patchMap) {
  2100  			return nil, mergepatch.NewErrPreconditionFailed(patchMap)
  2101  		}
  2102  	}
  2103  
  2104  	// If overwrite is false, and the patch contains any keys that were changed differently,
  2105  	// then return a conflict error.
  2106  	if !overwrite {
  2107  		changeMapDiffOptions := DiffOptions{}
  2108  		changedMap, err := diffMaps(originalMap, currentMap, schema, changeMapDiffOptions)
  2109  		if err != nil {
  2110  			return nil, err
  2111  		}
  2112  
  2113  		hasConflicts, err := MergingMapsHaveConflicts(patchMap, changedMap, schema)
  2114  		if err != nil {
  2115  			return nil, err
  2116  		}
  2117  
  2118  		if hasConflicts {
  2119  			return nil, mergepatch.NewErrConflict(mergepatch.ToYAMLOrError(patchMap), mergepatch.ToYAMLOrError(changedMap))
  2120  		}
  2121  	}
  2122  
  2123  	return json.Marshal(patchMap)
  2124  }
  2125  
  2126  func ItemAddedToModifiedSlice(original, modified string) bool { return original > modified }
  2127  
  2128  func ItemRemovedFromModifiedSlice(original, modified string) bool { return original < modified }
  2129  
  2130  func ItemMatchesOriginalAndModifiedSlice(original, modified string) bool { return original == modified }
  2131  
  2132  func CreateDeleteDirective(mergeKey string, mergeKeyValue interface{}) map[string]interface{} {
  2133  	return map[string]interface{}{mergeKey: mergeKeyValue, directiveMarker: deleteDirective}
  2134  }
  2135  
  2136  func mapTypeAssertion(original, patch interface{}) (map[string]interface{}, map[string]interface{}, error) {
  2137  	typedOriginal, ok := original.(map[string]interface{})
  2138  	if !ok {
  2139  		return nil, nil, mergepatch.ErrBadArgType(typedOriginal, original)
  2140  	}
  2141  	typedPatch, ok := patch.(map[string]interface{})
  2142  	if !ok {
  2143  		return nil, nil, mergepatch.ErrBadArgType(typedPatch, patch)
  2144  	}
  2145  	return typedOriginal, typedPatch, nil
  2146  }
  2147  
  2148  func sliceTypeAssertion(original, patch interface{}) ([]interface{}, []interface{}, error) {
  2149  	typedOriginal, ok := original.([]interface{})
  2150  	if !ok {
  2151  		return nil, nil, mergepatch.ErrBadArgType(typedOriginal, original)
  2152  	}
  2153  	typedPatch, ok := patch.([]interface{})
  2154  	if !ok {
  2155  		return nil, nil, mergepatch.ErrBadArgType(typedPatch, patch)
  2156  	}
  2157  	return typedOriginal, typedPatch, nil
  2158  }
  2159  
  2160  // extractRetainKeysPatchStrategy process patch strategy, which is a string may contains multiple
  2161  // patch strategies separated by ",". It returns a boolean var indicating if it has
  2162  // retainKeys strategies and a string for the other strategy.
  2163  func extractRetainKeysPatchStrategy(strategies []string) (bool, string, error) {
  2164  	switch len(strategies) {
  2165  	case 0:
  2166  		return false, "", nil
  2167  	case 1:
  2168  		singleStrategy := strategies[0]
  2169  		switch singleStrategy {
  2170  		case retainKeysStrategy:
  2171  			return true, "", nil
  2172  		default:
  2173  			return false, singleStrategy, nil
  2174  		}
  2175  	case 2:
  2176  		switch {
  2177  		case strategies[0] == retainKeysStrategy:
  2178  			return true, strategies[1], nil
  2179  		case strategies[1] == retainKeysStrategy:
  2180  			return true, strategies[0], nil
  2181  		default:
  2182  			return false, "", fmt.Errorf("unexpected patch strategy: %v", strategies)
  2183  		}
  2184  	default:
  2185  		return false, "", fmt.Errorf("unexpected patch strategy: %v", strategies)
  2186  	}
  2187  }
  2188  
  2189  // hasAdditionalNewField returns if original map has additional key with non-nil value than modified.
  2190  func hasAdditionalNewField(original, modified map[string]interface{}) bool {
  2191  	for k, v := range original {
  2192  		if v == nil {
  2193  			continue
  2194  		}
  2195  		if _, found := modified[k]; !found {
  2196  			return true
  2197  		}
  2198  	}
  2199  	return false
  2200  }