func (o *openAPI) findCommonParameters(routes []restful.Route) (map[interface{}]spec.Parameter, error) { commonParamsMap := make(map[interface{}]spec.Parameter, 0) paramOpsCountByName := make(map[interface{}]int, 0) paramNameKindToDataMap := make(map[interface{}]restful.ParameterData, 0) for _, route := range routes { routeParamDuplicateMap := make(map[interface{}]bool) s := "" for _, param := range route.ParameterDocs { m, _ := json.Marshal(param.Data()) s += string(m) + "\n" key := mapKeyFromParam(param) if routeParamDuplicateMap[key] { msg, _ := json.Marshal(route.ParameterDocs) return commonParamsMap, fmt.Errorf("duplicate parameter %v for route %v, %v.", param.Data().Name, string(msg), s) } routeParamDuplicateMap[key] = true paramOpsCountByName[key]++ paramNameKindToDataMap[key] = param.Data() } } for key, count := range paramOpsCountByName { if count == len(routes) { openAPIParam, err := o.buildParameter(paramNameKindToDataMap[key]) if err != nil { return commonParamsMap, err } commonParamsMap[key] = openAPIParam } } return commonParamsMap, nil }
// CreateTwoWayMergePatch creates a patch that can be passed to StrategicMergePatch from an original // document and a modified document, which are passed to the method as json encoded content. It will // return a patch that yields the modified document when applied to the original document, or an error // if either of the two documents is invalid. func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, fns ...PreconditionFunc) ([]byte, error) { originalMap := map[string]interface{}{} if len(original) > 0 { if err := json.Unmarshal(original, &originalMap); err != nil { return nil, errBadJSONDoc } } modifiedMap := map[string]interface{}{} if len(modified) > 0 { if err := json.Unmarshal(modified, &modifiedMap); err != nil { return nil, errBadJSONDoc } } t, err := getTagStructType(dataStruct) if err != nil { return nil, err } patchMap, err := diffMaps(originalMap, modifiedMap, t, false, false) if err != nil { return nil, err } // Apply the preconditions to the patch, and return an error if any of them fail. for _, fn := range fns { if !fn(patchMap) { return nil, newErrPreconditionFailed(patchMap) } } return json.Marshal(patchMap) }
// StrategicMergePatch applies a strategic merge patch. The patch and the original document // must be json encoded content. A patch can be created from an original and a modified document // by calling CreateStrategicMergePatch. func StrategicMergePatch(original, patch []byte, dataStruct interface{}) ([]byte, error) { if original == nil { original = []byte("{}") } if patch == nil { patch = []byte("{}") } originalMap := map[string]interface{}{} err := json.Unmarshal(original, &originalMap) if err != nil { return nil, errBadJSONDoc } patchMap := map[string]interface{}{} err = json.Unmarshal(patch, &patchMap) if err != nil { return nil, errBadJSONDoc } result, err := StrategicMergeMapPatch(originalMap, patchMap, dataStruct) if err != nil { return nil, err } return json.Marshal(result) }
func serilizeOrDie(t *testing.T, object interface{}) []byte { data, err := json.Marshal(object) if err != nil { t.Fatal(err) } return data }
// This function takes a JSON map and sorts all the lists that should be merged // by key. This is needed by tests because in JSON, list order is significant, // but in Strategic Merge Patch, merge lists do not have significant order. // Sorting the lists allows for order-insensitive comparison of patched maps. func sortMergeListsByName(mapJSON []byte, dataStruct interface{}) ([]byte, error) { var m map[string]interface{} err := json.Unmarshal(mapJSON, &m) if err != nil { return nil, err } newM, err := sortMergeListsByNameMap(m, reflect.TypeOf(dataStruct)) if err != nil { return nil, err } return json.Marshal(newM) }
func BenchmarkToFromUnstructuredViaJSON(b *testing.B) { items := benchmarkItems() size := len(items) b.ResetTimer() for i := 0; i < b.N; i++ { data, err := json.Marshal(&items[i%size]) if err != nil { b.Fatalf("unexpected error: %v", err) } unstr := map[string]interface{}{} if err := json.Unmarshal(data, &unstr); err != nil { b.Fatalf("unexpected error: %v", err) } data, err = json.Marshal(unstr) if err != nil { b.Fatalf("unexpected error: %v", err) } obj := v1.Pod{} if err := json.Unmarshal(data, &obj); err != nil { b.Fatalf("unexpected error: %v", err) } } b.StopTimer() }
// CreateTwoWayMergePatch creates a patch that can be passed to StrategicMergePatch from an original // document and a modified document, which are passed to the method as json encoded content. It will // return a patch that yields the modified document when applied to the original document, or an error // if either of the two documents is invalid. func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, fns ...PreconditionFunc) ([]byte, error) { originalMap := map[string]interface{}{} if len(original) > 0 { if err := json.Unmarshal(original, &originalMap); err != nil { return nil, errBadJSONDoc } } modifiedMap := map[string]interface{}{} if len(modified) > 0 { if err := json.Unmarshal(modified, &modifiedMap); err != nil { return nil, errBadJSONDoc } } patchMap, err := CreateTwoWayMergeMapPatch(originalMap, modifiedMap, dataStruct, fns...) if err != nil { return nil, err } return json.Marshal(patchMap) }
// CreateThreeWayMergePatch reconciles a modified configuration with an original configuration, // while preserving any changes or deletions made to the original configuration in the interim, // and not overridden by the current configuration. All three documents must be passed to the // method as json encoded content. It will return a strategic merge patch, or an error if any // of the documents is invalid, or if there are any preconditions that fail against the modified // configuration, or, if overwrite is false and there are conflicts between the modified and current // configurations. Conflicts are defined as keys changed differently from original to modified // than from original to current. In other words, a conflict occurs if modified changes any key // in a way that is different from how it is changed in current (e.g., deleting it, changing its // value). func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct interface{}, overwrite bool, fns ...PreconditionFunc) ([]byte, error) { originalMap := map[string]interface{}{} if len(original) > 0 { if err := json.Unmarshal(original, &originalMap); err != nil { return nil, errBadJSONDoc } } modifiedMap := map[string]interface{}{} if len(modified) > 0 { if err := json.Unmarshal(modified, &modifiedMap); err != nil { return nil, errBadJSONDoc } } currentMap := map[string]interface{}{} if len(current) > 0 { if err := json.Unmarshal(current, ¤tMap); err != nil { return nil, errBadJSONDoc } } t, err := getTagStructType(dataStruct) if err != nil { return nil, err } // The patch is the difference from current to modified without deletions, plus deletions // from original to modified. To find it, we compute deletions, which are the deletions from // original to modified, and delta, which is the difference from current to modified without // deletions, and then apply delta to deletions as a patch, which should be strictly additive. deltaMap, err := diffMaps(currentMap, modifiedMap, t, false, true) if err != nil { return nil, err } deletionsMap, err := diffMaps(originalMap, modifiedMap, t, true, false) if err != nil { return nil, err } patchMap, err := mergeMap(deletionsMap, deltaMap, t, false) if err != nil { return nil, err } // Apply the preconditions to the patch, and return an error if any of them fail. for _, fn := range fns { if !fn(patchMap) { return nil, newErrPreconditionFailed(patchMap) } } // If overwrite is false, and the patch contains any keys that were changed differently, // then return a conflict error. if !overwrite { changedMap, err := diffMaps(originalMap, currentMap, t, false, false) if err != nil { return nil, err } hasConflicts, err := MergingMapsHaveConflicts(patchMap, changedMap, dataStruct) if err != nil { return nil, err } if hasConflicts { return nil, newErrConflict(toYAMLOrError(patchMap), toYAMLOrError(changedMap)) } } return json.Marshal(patchMap) }
func doRoundTrip(t *testing.T, group testapi.TestGroup, kind string) { // We do fuzzing on the internal version of the object, and only then // convert to the external version. This is because custom fuzzing // function are only supported for internal objects. internalObj, err := api.Scheme.New(group.InternalGroupVersion().WithKind(kind)) if err != nil { t.Fatalf("Couldn't create internal object %v: %v", kind, err) } seed := rand.Int63() apitesting.FuzzerFor(t, group.InternalGroupVersion(), rand.NewSource(seed)). // We are explicitly overwriting custom fuzzing functions, to ensure // that InitContainers and their statuses are not generated. This is // because in thise test we are simply doing json operations, in which // those disappear. Funcs( func(s *api.PodSpec, c fuzz.Continue) { c.FuzzNoCustom(s) s.InitContainers = nil }, func(s *api.PodStatus, c fuzz.Continue) { c.FuzzNoCustom(s) s.InitContainerStatuses = nil }, ).Fuzz(internalObj) item, err := api.Scheme.New(group.GroupVersion().WithKind(kind)) if err != nil { t.Fatalf("Couldn't create external object %v: %v", kind, err) } if err := api.Scheme.Convert(internalObj, item, nil); err != nil { t.Fatalf("Conversion for %v failed: %v", kind, err) } data, err := json.Marshal(item) if err != nil { t.Errorf("Error when marshaling object: %v", err) return } unstr := make(map[string]interface{}) err = json.Unmarshal(data, &unstr) if err != nil { t.Errorf("Error when unmarshaling to unstructured: %v", err) return } data, err = json.Marshal(unstr) if err != nil { t.Errorf("Error when marshaling unstructured: %v", err) return } unmarshalledObj := reflect.New(reflect.TypeOf(item).Elem()).Interface() err = json.Unmarshal(data, &unmarshalledObj) if err != nil { t.Errorf("Error when unmarshaling to object: %v", err) return } if !api.Semantic.DeepEqual(item, unmarshalledObj) { t.Errorf("Object changed during JSON operations, diff: %v", diff.ObjectReflectDiff(item, unmarshalledObj)) return } // TODO; Enable the following part of test once to/from unstructured // format conversions are implemented. /* newUnstr := make(map[string]interface{}) err = unstructured.NewConverter().ToUnstructured(item, &newUnstr) if err != nil { t.Errorf("ToUnstructured failed: %v", err) return } newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object) err = unstructured.NewConverter().FromUnstructured(newUnstr, newObj) if err != nil { t.Errorf("FromUnstructured failed: %v", err) return } if !api.Semantic.DeepEqual(item, newObj) { t.Errorf("Object changed, diff: %v", diff.ObjectReflectDiff(item, newObj)) } */ }