in pkg/controllers/workapplier/drift_detection_takeover.go [165:270]
func organizeJSONPatchIntoFleetPatchDetails(patch jsondiff.Patch, manifestObjMap map[string]interface{}) ([]fleetv1beta1.PatchDetail, error) {
// Pre-allocate the slice for the patch details. The organization procedure typically will yield
// the same number of PatchDetail items as the JSON patch operations.
details := make([]fleetv1beta1.PatchDetail, 0, len(patch))
// A side note: here Fleet takes an expedient approach processing null JSON paths, by treating
// null paths as empty strings.
// Process only the first 100 ops.
// TO-DO (chenyu1): Impose additional size limits.
for idx := 0; idx < len(patch) && idx < patchDetailPerObjLimit; idx++ {
op := patch[idx]
pathPtr, err := jsonpointer.Parse(op.Path)
if err != nil {
// An invalid path is found; normally this should not happen.
wrappedErr := fmt.Errorf("failed to parse the JSON path %s: %w", op.Path, err)
_ = controller.NewUnexpectedBehaviorError(wrappedErr)
return nil, wrappedErr
}
fromPtr, err := jsonpointer.Parse(op.From)
if err != nil {
// An invalid path is found; normally this should not happen.
wrappedErr := fmt.Errorf("failed to parse the JSON path %s: %w", op.From, err)
_ = controller.NewUnexpectedBehaviorError(wrappedErr)
return nil, wrappedErr
}
switch op.Type {
case jsondiff.OperationAdd:
details = append(details, fleetv1beta1.PatchDetail{
Path: op.Path,
ValueInMember: fmt.Sprint(op.Value),
})
case jsondiff.OperationRemove:
// Fleet here skips validation as the JSON data is just marshalled.
hubValue, err := pathPtr.Eval(manifestObjMap)
if err != nil {
wrappedErr := fmt.Errorf("failed to evaluate the JSON path %s in the manifest object: %w", op.Path, err)
_ = controller.NewUnexpectedBehaviorError(wrappedErr)
return nil, wrappedErr
}
details = append(details, fleetv1beta1.PatchDetail{
Path: op.Path,
ValueInHub: fmt.Sprintf("%v", hubValue),
})
case jsondiff.OperationReplace:
// Fleet here skips validation as the JSON data is just marshalled.
hubValue, err := pathPtr.Eval(manifestObjMap)
if err != nil {
wrappedErr := fmt.Errorf("failed to evaluate the JSON path %s in the manifest object: %w", op.Path, err)
_ = controller.NewUnexpectedBehaviorError(wrappedErr)
return nil, wrappedErr
}
details = append(details, fleetv1beta1.PatchDetail{
Path: op.Path,
ValueInMember: fmt.Sprint(op.Value),
ValueInHub: fmt.Sprintf("%v", hubValue),
})
case jsondiff.OperationMove:
// Normally the Move operation will not be returned as factorization is disabled
// for the JSON patch calculation process; however, Fleet here still processes them
// just in case.
//
// Each Move operation will be parsed into two separate operations.
hubValue, err := fromPtr.Eval(manifestObjMap)
if err != nil {
wrappedErr := fmt.Errorf("failed to evaluate the JSON path %s in the manifest object: %w", op.Path, err)
_ = controller.NewUnexpectedBehaviorError(wrappedErr)
return nil, wrappedErr
}
details = append(details, fleetv1beta1.PatchDetail{
Path: op.From,
ValueInHub: fmt.Sprintf("%v", hubValue),
})
details = append(details, fleetv1beta1.PatchDetail{
Path: op.Path,
ValueInMember: fmt.Sprintf("%v", hubValue),
})
case jsondiff.OperationCopy:
// Normally the Copy operation will not be returned as factorization is disabled
// for the JSON patch calculation process; however, Fleet here still processes them
// just in case.
//
// Each Copy operation will be parsed into an Add operation.
hubValue, err := fromPtr.Eval(manifestObjMap)
if err != nil {
wrappedErr := fmt.Errorf("failed to evaluate the JSON path %s in the manifest object: %w", op.Path, err)
_ = controller.NewUnexpectedBehaviorError(wrappedErr)
return nil, wrappedErr
}
details = append(details, fleetv1beta1.PatchDetail{
Path: op.Path,
ValueInMember: fmt.Sprintf("%v", hubValue),
})
case jsondiff.OperationTest:
// The Test op is a no-op in Fleet's use case. Normally it will not be returned, either.
default:
// An unexpected op is returned.
wrappedErr := fmt.Errorf("an unexpected JSON patch operation is returned (%s)", op)
_ = controller.NewUnexpectedBehaviorError(wrappedErr)
return nil, wrappedErr
}
}
return details, nil
}