[Question] why does it not preserve changes when invoke `CreateThreeWayMergePatch` function with nil annotations
chengjingtao opened this issue · 4 comments
chengjingtao commented
When I using CreateThreeWayMergePatch to genernate patch, I found a strange behaviors
// original
{
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": {
"name": "test",
"namespace": "ns",
"annotations": null
}
}
// modified // same as original
{
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": {
"name": "test",
"namespace": "ns",
"annotations": null
}
}
// current // do some change based on original
{
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": {
"name": "test",
"namespace": "ns",
"annotations": {
"a": "a1"
}
}
}
after invoke CreateThreeWayMergePatch
, it will generate a patch like that {"metadata":{"annotations":null}}
, just not preserve the change on annotations.
My Question is: "why does it not preserve annotations changes? is this expected?"
This seems to easily lead to the following conflicts
- controller 1: reconcile resources as expected (same as original)
- controller 2: add some annotations
- controller 1: reconcile resources as expected (same as original) : clean all annotations.
the code is here
package main
import (
"encoding/json"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"log"
)
func main() {
patch := createPatch(nil)
log.Printf("when expected annotations is nil: patch: %s \n", string(patch))
patch = createPatch(map[string]string{})
log.Printf("when expected annotations is empty: patch: %s \n", string(patch))
}
func createPatch(annotations map[string]string) []byte {
expected := &unstructured.Unstructured{
Object: map[string]interface{}{
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": map[string]interface{}{
"name": "test",
"namespace": "ns",
"annotations": annotations,
},
},
}
versionedObject := &v1.Deployment{}
bts, _ := json.Marshal(expected)
_ = json.Unmarshal(bts, versionedObject)
existing := &unstructured.Unstructured{
Object: map[string]interface{}{
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": map[string]interface{}{
"name": "test",
"namespace": "ns",
"annotations": map[string]string{
"a": "a1",
"b": "b1",
},
},
},
}
patchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObject)
if err != nil {
log.Fatal("new patch meta:" + err.Error())
}
expectedJSON, _ := json.Marshal(expected)
existingJSON, _ := json.Marshal(existing)
patch, err := strategicpatch.CreateThreeWayMergePatch(expectedJSON, expectedJSON, existingJSON, patchMeta, true)
if err != nil {
log.Fatal(err)
}
return patch
}
result is :
when expected annotations is nil: patch: {"metadata":{"annotations":null}}
when expected annotations is empty: patch: {}