@@ -16,6 +16,7 @@ import (
16
16
"k8s.io/apimachinery/pkg/labels"
17
17
"k8s.io/apimachinery/pkg/runtime"
18
18
"k8s.io/apimachinery/pkg/types"
19
+ "k8s.io/apimachinery/pkg/util/strategicpatch"
19
20
"k8s.io/apimachinery/pkg/util/validation/field"
20
21
"k8s.io/client-go/tools/cache"
21
22
"k8s.io/klog/v2"
@@ -24,9 +25,25 @@ import (
24
25
"open-cluster-management.io/sdk-go/pkg/cloudevents/generic"
25
26
)
26
27
27
- // Patch applies the patch to a resource with the patch type.
28
- func Patch [T generic.ResourceObject ](patchType types.PatchType , work T , patchData []byte ) (resource T , err error ) {
29
- workData , err := json .Marshal (work )
28
+ // Patch applies the given patch to a `generic.ResourceObject` using the specified patch type.
29
+ //
30
+ // Parameters:
31
+ // - patchType: The type of patch to apply (JSONPatchType, MergePatchType and StrategicMergePatchType are supported).
32
+ // - original: The resource object to be patched.
33
+ // - patchData: The raw patch data.
34
+ //
35
+ // Returns:
36
+ // - The patched resource object.
37
+ // - An error if the patching fails at any step.
38
+ //
39
+ // Notes on StrategicMergePatch:
40
+ // - Strategic Merge Patch (SMP) is a Kubernetes-specific patch type.
41
+ // - It relies on **struct tags** (e.g., `patchStrategy` and `patchMergeKey`) defined in the Go types
42
+ // of Kubernetes API objects to determine how to merge lists and maps (e.g., merge by key instead of replacing).
43
+ // - SMP **only works** on known Kubernetes built-in API types (e.g., corev1.Pod) that have these metadata tags.
44
+ // - It will **fail or behave incorrectly** if used on CRDs or custom types that don’t have the necessary tags.
45
+ func Patch [T generic.ResourceObject ](patchType types.PatchType , original T , patchData []byte ) (resource T , err error ) {
46
+ originalData , err := json .Marshal (original )
30
47
if err != nil {
31
48
return resource , err
32
49
}
@@ -39,26 +56,30 @@ func Patch[T generic.ResourceObject](patchType types.PatchType, work T, patchDat
39
56
if err != nil {
40
57
return resource , err
41
58
}
42
- patchedData , err = patchObj .Apply (workData )
59
+ patchedData , err = patchObj .Apply (originalData )
43
60
if err != nil {
44
61
return resource , err
45
62
}
46
-
47
63
case types .MergePatchType :
48
- patchedData , err = jsonpatch .MergePatch (workData , patchData )
64
+ patchedData , err = jsonpatch .MergePatch (originalData , patchData )
65
+ if err != nil {
66
+ return resource , err
67
+ }
68
+ case types .StrategicMergePatchType :
69
+ patchedData , err = strategicpatch .StrategicMergePatch (originalData , patchData , original )
49
70
if err != nil {
50
71
return resource , err
51
72
}
52
73
default :
53
74
return resource , fmt .Errorf ("unsupported patch type: %s" , patchType )
54
75
}
55
76
56
- patchedWork := new (T )
57
- if err := json .Unmarshal (patchedData , patchedWork ); err != nil {
77
+ patchedResource := new (T )
78
+ if err := json .Unmarshal (patchedData , patchedResource ); err != nil {
58
79
return resource , err
59
80
}
60
81
61
- return * patchedWork , nil
82
+ return * patchedResource , nil
62
83
}
63
84
64
85
// ListResourcesWithOptions retrieves the resources from store which matches the options.
0 commit comments