package util import ( "fmt" clusterv2 "github.com/RafaySystems/rcloud-base/proto/types/controller" apixv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "github.com/RafaySystems/rcloud-base/pkg/controller/scheme" jp "github.com/evanphx/json-patch" "k8s.io/apimachinery/pkg/runtime/schema" jmp "k8s.io/apimachinery/pkg/util/jsonmergepatch" mp "k8s.io/apimachinery/pkg/util/mergepatch" sp "k8s.io/apimachinery/pkg/util/strategicpatch" ) var knownMergePatchGroups = func() map[string]struct{} { return map[string]struct{}{ clusterv2.GroupVersion.Group: {}, apixv1.GroupName: {}, } }() func isKnowMergePatchGroup(gvk schema.GroupVersionKind) bool { if _, ok := knownMergePatchGroups[gvk.Group]; ok { return true } return false } // IsStrategicMergePatch returns true if gvk is present in the registerd scheme func IsStrategicMergePatch(gvk schema.GroupVersionKind) bool { return scheme.Scheme.Recognizes(gvk) && !isKnowMergePatchGroup(gvk) } // CreateStrategicMergePatch creates strategic merge patch for original and modified func CreateStrategicMergePatch(gvk schema.GroupVersionKind, original, current, modified []byte) ([]byte, error) { obj, err := scheme.Scheme.New(gvk) if err != nil { return nil, fmt.Errorf("unable to create new k8s object %s", err) } var patchMeta sp.PatchMetaFromStruct patchMeta, err = sp.NewPatchMetaFromStruct(obj) if err != nil { err = fmt.Errorf("unable to lookup patch meta %s", err.Error()) return nil, err } ret, err := sp.CreateThreeWayMergePatch(original, modified, current, patchMeta, true, mp.RequireKeyUnchanged("apiVersion"), mp.RequireKeyUnchanged("kind"), mp.RequireMetadataKeyUnchanged("name")) if err != nil { err = fmt.Errorf("unable to create strategic merge patch %s", err.Error()) } return ret, err } // ApplyStrategicMergePatch applies strategic merge patch on orginal func ApplyStrategicMergePatch(gvk schema.GroupVersionKind, original, patch []byte) ([]byte, error) { obj, err := scheme.Scheme.New(gvk) if err != nil { return nil, fmt.Errorf("unable to create new k8s object %s", err) } fb, err := sp.StrategicMergePatch(original, patch, obj) if err != nil { return nil, fmt.Errorf("unable to strategic merge patch %s", err.Error()) } return fb, nil } // CreateJSONMergePatch creates JSON merge patch between original, current and modified func CreateJSONMergePatch(original, current, modified []byte) ([]byte, error) { ret, err := jmp.CreateThreeWayJSONMergePatch(original, modified, current, mp.RequireKeyUnchanged("apiVersion"), mp.RequireKeyUnchanged("kind"), mp.RequireMetadataKeyUnchanged("name")) if err != nil { err = fmt.Errorf("unable to create json merge patch %s", err.Error()) } return ret, err } // ApplyJSONMergePatch applies JSON merge patch onto the original document func ApplyJSONMergePatch(original, patch []byte) ([]byte, error) { fb, err := jp.MergePatch(original, patch) if err != nil { return nil, fmt.Errorf("unable to json merge patch %s", err.Error()) } return fb, nil }