mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 05:03:09 +00:00
Revert "support patch list of primitives"
This reverts commit 34891ad9f6
.
This commit is contained in:
parent
18f4395f80
commit
3cc294b1e0
@ -591,11 +591,11 @@ func patchResource(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
currentPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, currentObjectJS, versionedObj, strategicpatch.SMPatchVersionLatest)
|
currentPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, currentObjectJS, versionedObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
originalPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, originalPatchedObjJS, versionedObj, strategicpatch.SMPatchVersionLatest)
|
originalPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, originalPatchedObjJS, versionedObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
case api.StrategicMergePatchType:
|
case api.StrategicMergePatchType:
|
||||||
patch, err = strategicpatch.CreateStrategicMergePatch(originalObjJS, changedJS, versionedObj, strategicpatch.SMPatchVersionLatest)
|
patch, err = strategicpatch.CreateStrategicMergePatch(originalObjJS, changedJS, versionedObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
||||||
return
|
return
|
||||||
|
@ -244,9 +244,7 @@ func (e *eventLogger) eventObserve(newEvent *api.Event) (*api.Event, []byte, err
|
|||||||
|
|
||||||
newData, _ := json.Marshal(event)
|
newData, _ := json.Marshal(event)
|
||||||
oldData, _ := json.Marshal(eventCopy2)
|
oldData, _ := json.Marshal(eventCopy2)
|
||||||
// TODO: need to figure out if we need to let eventObserve() use the new behavior of StrategicMergePatch.
|
patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event)
|
||||||
// Currently default to old behavior now. Ref: issue #35936
|
|
||||||
patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event, strategicpatch.SMPatchVersion_1_0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// record our new observation
|
// record our new observation
|
||||||
|
@ -59,10 +59,6 @@ type nodeStatusUpdater struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (nsu *nodeStatusUpdater) UpdateNodeStatuses() error {
|
func (nsu *nodeStatusUpdater) UpdateNodeStatuses() error {
|
||||||
smPatchVersion, err := strategicpatch.GetServerSupportedSMPatchVersion(nsu.kubeClient.Discovery())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
nodesToUpdate := nsu.actualStateOfWorld.GetVolumesToReportAttached()
|
nodesToUpdate := nsu.actualStateOfWorld.GetVolumesToReportAttached()
|
||||||
for nodeName, attachedVolumes := range nodesToUpdate {
|
for nodeName, attachedVolumes := range nodesToUpdate {
|
||||||
nodeObj, exists, err := nsu.nodeInformer.GetStore().GetByKey(string(nodeName))
|
nodeObj, exists, err := nsu.nodeInformer.GetStore().GetByKey(string(nodeName))
|
||||||
@ -112,7 +108,7 @@ func (nsu *nodeStatusUpdater) UpdateNodeStatuses() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
patchBytes, err :=
|
patchBytes, err :=
|
||||||
strategicpatch.CreateStrategicMergePatch(oldData, newData, node, smPatchVersion)
|
strategicpatch.CreateStrategicMergePatch(oldData, newData, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to CreateStrategicMergePatch for node %q. %v",
|
"failed to CreateStrategicMergePatch for node %q. %v",
|
||||||
|
@ -194,7 +194,6 @@ go_test(
|
|||||||
"//pkg/util/strings:go_default_library",
|
"//pkg/util/strings:go_default_library",
|
||||||
"//pkg/util/term:go_default_library",
|
"//pkg/util/term:go_default_library",
|
||||||
"//pkg/util/wait:go_default_library",
|
"//pkg/util/wait:go_default_library",
|
||||||
"//pkg/version:go_default_library",
|
|
||||||
"//pkg/watch:go_default_library",
|
"//pkg/watch:go_default_library",
|
||||||
"//pkg/watch/versioned:go_default_library",
|
"//pkg/watch/versioned:go_default_library",
|
||||||
"//vendor:github.com/spf13/cobra",
|
"//vendor:github.com/spf13/cobra",
|
||||||
|
@ -223,12 +223,6 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
|
|||||||
}
|
}
|
||||||
outputObj = obj
|
outputObj = obj
|
||||||
} else {
|
} else {
|
||||||
// retrieves server version to determine which SMPatchVersion to use.
|
|
||||||
smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
name, namespace := info.Name, info.Namespace
|
name, namespace := info.Name, info.Namespace
|
||||||
oldData, err := json.Marshal(obj)
|
oldData, err := json.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -245,7 +239,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, smPatchVersion)
|
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
|
||||||
createdPatch := err == nil
|
createdPatch := err == nil
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(2).Infof("couldn't compute patch: %v", err)
|
glog.V(2).Infof("couldn't compute patch: %v", err)
|
||||||
|
@ -24,6 +24,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||||
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
"k8s.io/kubernetes/pkg/client/restclient/fake"
|
"k8s.io/kubernetes/pkg/client/restclient/fake"
|
||||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
@ -392,7 +394,7 @@ func TestAnnotateErrors(t *testing.T) {
|
|||||||
f, tf, _, _ := cmdtesting.NewAPIFactory()
|
f, tf, _, _ := cmdtesting.NewAPIFactory()
|
||||||
tf.Printer = &testPrinter{}
|
tf.Printer = &testPrinter{}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
cmd := NewCmdAnnotate(f, buf)
|
cmd := NewCmdAnnotate(f, buf)
|
||||||
@ -430,12 +432,6 @@ func TestAnnotateObject(t *testing.T) {
|
|||||||
switch req.Method {
|
switch req.Method {
|
||||||
case "GET":
|
case "GET":
|
||||||
switch req.URL.Path {
|
switch req.URL.Path {
|
||||||
case "/version":
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case "/namespaces/test/pods/foo":
|
case "/namespaces/test/pods/foo":
|
||||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
|
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
|
||||||
default:
|
default:
|
||||||
@ -457,7 +453,7 @@ func TestAnnotateObject(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
cmd := NewCmdAnnotate(f, buf)
|
cmd := NewCmdAnnotate(f, buf)
|
||||||
@ -486,12 +482,6 @@ func TestAnnotateObjectFromFile(t *testing.T) {
|
|||||||
switch req.Method {
|
switch req.Method {
|
||||||
case "GET":
|
case "GET":
|
||||||
switch req.URL.Path {
|
switch req.URL.Path {
|
||||||
case "/version":
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case "/namespaces/test/replicationcontrollers/cassandra":
|
case "/namespaces/test/replicationcontrollers/cassandra":
|
||||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
|
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
|
||||||
default:
|
default:
|
||||||
@ -513,7 +503,7 @@ func TestAnnotateObjectFromFile(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
cmd := NewCmdAnnotate(f, buf)
|
cmd := NewCmdAnnotate(f, buf)
|
||||||
@ -542,7 +532,7 @@ func TestAnnotateLocal(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
cmd := NewCmdAnnotate(f, buf)
|
cmd := NewCmdAnnotate(f, buf)
|
||||||
@ -572,12 +562,6 @@ func TestAnnotateMultipleObjects(t *testing.T) {
|
|||||||
switch req.Method {
|
switch req.Method {
|
||||||
case "GET":
|
case "GET":
|
||||||
switch req.URL.Path {
|
switch req.URL.Path {
|
||||||
case "/version":
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case "/namespaces/test/pods":
|
case "/namespaces/test/pods":
|
||||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil
|
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil
|
||||||
default:
|
default:
|
||||||
@ -601,7 +585,7 @@ func TestAnnotateMultipleObjects(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
cmd := NewCmdAnnotate(f, buf)
|
cmd := NewCmdAnnotate(f, buf)
|
||||||
|
@ -195,11 +195,6 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *App
|
|||||||
visitedUids := sets.NewString()
|
visitedUids := sets.NewString()
|
||||||
visitedNamespaces := sets.NewString()
|
visitedNamespaces := sets.NewString()
|
||||||
|
|
||||||
smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
err = r.Visit(func(info *resource.Info, err error) error {
|
err = r.Visit(func(info *resource.Info, err error) error {
|
||||||
// In this method, info.Object contains the object retrieved from the server
|
// In this method, info.Object contains the object retrieved from the server
|
||||||
@ -270,13 +265,13 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *App
|
|||||||
gracePeriod: options.GracePeriod,
|
gracePeriod: options.GracePeriod,
|
||||||
}
|
}
|
||||||
|
|
||||||
patchBytes, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name, smPatchVersion)
|
patchBytes, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patchBytes, info), info.Source, err)
|
return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patchBytes, info), info.Source, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmdutil.ShouldRecord(cmd, info) {
|
if cmdutil.ShouldRecord(cmd, info) {
|
||||||
patch, err := cmdutil.ChangeResourcePatch(info, f.Command(), smPatchVersion)
|
patch, err := cmdutil.ChangeResourcePatch(info, f.Command())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -512,7 +507,7 @@ type patcher struct {
|
|||||||
gracePeriod int
|
gracePeriod int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string, smPatchVersion strategicpatch.StrategicMergePatchVersion) ([]byte, error) {
|
func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string) ([]byte, error) {
|
||||||
// Serialize the current configuration of the object from the server.
|
// Serialize the current configuration of the object from the server.
|
||||||
current, err := runtime.Encode(p.encoder, obj)
|
current, err := runtime.Encode(p.encoder, obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -536,8 +531,7 @@ func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, names
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute a three way strategic merge patch to send to server.
|
// Compute a three way strategic merge patch to send to server.
|
||||||
patch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, versionedObject, p.overwrite, smPatchVersion)
|
patch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, versionedObject, p.overwrite)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
format := "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor:"
|
format := "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor:"
|
||||||
return nil, cmdutil.AddSourceToErr(fmt.Sprintf(format, original, modified, current), source, err)
|
return nil, cmdutil.AddSourceToErr(fmt.Sprintf(format, original, modified, current), source, err)
|
||||||
@ -547,9 +541,9 @@ func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, names
|
|||||||
return patch, err
|
return patch, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *patcher) patch(current runtime.Object, modified []byte, source, namespace, name string, smPatchVersion strategicpatch.StrategicMergePatchVersion) ([]byte, error) {
|
func (p *patcher) patch(current runtime.Object, modified []byte, source, namespace, name string) ([]byte, error) {
|
||||||
var getErr error
|
var getErr error
|
||||||
patchBytes, err := p.patchSimple(current, modified, source, namespace, name, smPatchVersion)
|
patchBytes, err := p.patchSimple(current, modified, source, namespace, name)
|
||||||
for i := 1; i <= maxPatchRetry && errors.IsConflict(err); i++ {
|
for i := 1; i <= maxPatchRetry && errors.IsConflict(err); i++ {
|
||||||
if i > triesBeforeBackOff {
|
if i > triesBeforeBackOff {
|
||||||
p.backOff.Sleep(backOffPeriod)
|
p.backOff.Sleep(backOffPeriod)
|
||||||
@ -558,7 +552,7 @@ func (p *patcher) patch(current runtime.Object, modified []byte, source, namespa
|
|||||||
if getErr != nil {
|
if getErr != nil {
|
||||||
return nil, getErr
|
return nil, getErr
|
||||||
}
|
}
|
||||||
patchBytes, err = p.patchSimple(current, modified, source, namespace, name, smPatchVersion)
|
patchBytes, err = p.patchSimple(current, modified, source, namespace, name)
|
||||||
}
|
}
|
||||||
if err != nil && p.force {
|
if err != nil && p.force {
|
||||||
patchBytes, err = p.deleteAndCreate(modified, namespace, name)
|
patchBytes, err = p.deleteAndCreate(modified, namespace, name)
|
||||||
|
@ -188,12 +188,6 @@ func TestApplyObject(t *testing.T) {
|
|||||||
NegotiatedSerializer: ns,
|
NegotiatedSerializer: ns,
|
||||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
switch p, m := req.URL.Path, req.Method; {
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
case p == "/version" && m == "GET":
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case p == pathRC && m == "GET":
|
case p == pathRC && m == "GET":
|
||||||
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
|
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
|
||||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
|
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
|
||||||
@ -208,7 +202,6 @@ func TestApplyObject(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
cmd := NewCmdApply(f, buf)
|
cmd := NewCmdApply(f, buf)
|
||||||
@ -237,12 +230,6 @@ func TestApplyRetry(t *testing.T) {
|
|||||||
NegotiatedSerializer: ns,
|
NegotiatedSerializer: ns,
|
||||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
switch p, m := req.URL.Path, req.Method; {
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
case p == "/version" && m == "GET":
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case p == pathRC && m == "GET":
|
case p == pathRC && m == "GET":
|
||||||
getCount++
|
getCount++
|
||||||
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
|
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
|
||||||
@ -266,7 +253,6 @@ func TestApplyRetry(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
cmd := NewCmdApply(f, buf)
|
cmd := NewCmdApply(f, buf)
|
||||||
@ -296,12 +282,6 @@ func TestApplyNonExistObject(t *testing.T) {
|
|||||||
NegotiatedSerializer: ns,
|
NegotiatedSerializer: ns,
|
||||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
switch p, m := req.URL.Path, req.Method; {
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
case p == "/version" && m == "GET":
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case p == "/api/v1/namespaces/test" && m == "GET":
|
case p == "/api/v1/namespaces/test" && m == "GET":
|
||||||
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
|
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
|
||||||
case p == pathNameRC && m == "GET":
|
case p == pathNameRC && m == "GET":
|
||||||
@ -316,7 +296,6 @@ func TestApplyNonExistObject(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
cmd := NewCmdApply(f, buf)
|
cmd := NewCmdApply(f, buf)
|
||||||
@ -352,12 +331,6 @@ func testApplyMultipleObjects(t *testing.T, asList bool) {
|
|||||||
NegotiatedSerializer: ns,
|
NegotiatedSerializer: ns,
|
||||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
switch p, m := req.URL.Path, req.Method; {
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
case p == "/version" && m == "GET":
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case p == pathRC && m == "GET":
|
case p == pathRC && m == "GET":
|
||||||
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
|
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
|
||||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
|
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
|
||||||
@ -379,7 +352,6 @@ func testApplyMultipleObjects(t *testing.T, asList bool) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
cmd := NewCmdApply(f, buf)
|
cmd := NewCmdApply(f, buf)
|
||||||
|
@ -39,13 +39,8 @@ import (
|
|||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/util/strings"
|
"k8s.io/kubernetes/pkg/util/strings"
|
||||||
"k8s.io/kubernetes/pkg/version"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var serverVersion_1_5_0 = version.Info{
|
|
||||||
GitVersion: "v1.5.0",
|
|
||||||
}
|
|
||||||
|
|
||||||
func initTestErrorHandler(t *testing.T) {
|
func initTestErrorHandler(t *testing.T) {
|
||||||
cmdutil.BehaviorOnFatal(func(str string, code int) {
|
cmdutil.BehaviorOnFatal(func(str string, code int) {
|
||||||
t.Errorf("Error running command (exit code %d): %s", code, str)
|
t.Errorf("Error running command (exit code %d): %s", code, str)
|
||||||
|
@ -291,7 +291,7 @@ func runEdit(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args
|
|||||||
|
|
||||||
switch editMode {
|
switch editMode {
|
||||||
case NormalEditMode:
|
case NormalEditMode:
|
||||||
err = visitToPatch(originalObj, updates, f, mapper, resourceMapper, encoder, out, errOut, defaultVersion, &results, file)
|
err = visitToPatch(originalObj, updates, mapper, resourceMapper, encoder, out, errOut, defaultVersion, &results, file)
|
||||||
case EditBeforeCreateMode:
|
case EditBeforeCreateMode:
|
||||||
err = visitToCreate(updates, mapper, resourceMapper, out, errOut, defaultVersion, &results, file)
|
err = visitToCreate(updates, mapper, resourceMapper, out, errOut, defaultVersion, &results, file)
|
||||||
default:
|
default:
|
||||||
@ -415,22 +415,9 @@ func getMapperAndResult(f cmdutil.Factory, args []string, options *resource.File
|
|||||||
return mapper, resourceMapper, r, cmdNamespace, err
|
return mapper, resourceMapper, r, cmdNamespace, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func visitToPatch(originalObj runtime.Object, updates *resource.Info,
|
func visitToPatch(originalObj runtime.Object, updates *resource.Info, mapper meta.RESTMapper, resourceMapper *resource.Mapper, encoder runtime.Encoder, out, errOut io.Writer, defaultVersion unversioned.GroupVersion, results *editResults, file string) error {
|
||||||
f cmdutil.Factory,
|
|
||||||
mapper meta.RESTMapper, resourceMapper *resource.Mapper,
|
|
||||||
encoder runtime.Encoder,
|
|
||||||
out, errOut io.Writer,
|
|
||||||
defaultVersion unversioned.GroupVersion,
|
|
||||||
results *editResults,
|
|
||||||
file string) error {
|
|
||||||
|
|
||||||
smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
patchVisitor := resource.NewFlattenListVisitor(updates, resourceMapper)
|
patchVisitor := resource.NewFlattenListVisitor(updates, resourceMapper)
|
||||||
err = patchVisitor.Visit(func(info *resource.Info, incomingErr error) error {
|
err := patchVisitor.Visit(func(info *resource.Info, incomingErr error) error {
|
||||||
currOriginalObj := originalObj
|
currOriginalObj := originalObj
|
||||||
|
|
||||||
// if we're editing a list, then navigate the list to find the item that we're currently trying to edit
|
// if we're editing a list, then navigate the list to find the item that we're currently trying to edit
|
||||||
@ -491,7 +478,7 @@ func visitToPatch(originalObj runtime.Object, updates *resource.Info,
|
|||||||
|
|
||||||
preconditions := []strategicpatch.PreconditionFunc{strategicpatch.RequireKeyUnchanged("apiVersion"),
|
preconditions := []strategicpatch.PreconditionFunc{strategicpatch.RequireKeyUnchanged("apiVersion"),
|
||||||
strategicpatch.RequireKeyUnchanged("kind"), strategicpatch.RequireMetadataKeyUnchanged("name")}
|
strategicpatch.RequireKeyUnchanged("kind"), strategicpatch.RequireMetadataKeyUnchanged("name")}
|
||||||
patch, err := strategicpatch.CreateTwoWayMergePatch(originalJS, editedJS, currOriginalObj, smPatchVersion, preconditions...)
|
patch, err := strategicpatch.CreateTwoWayMergePatch(originalJS, editedJS, currOriginalObj, preconditions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err)
|
glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err)
|
||||||
if strategicpatch.IsPreconditionFailed(err) {
|
if strategicpatch.IsPreconditionFailed(err) {
|
||||||
|
@ -192,14 +192,6 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
smPatchVersion := strategicpatch.SMPatchVersionLatest
|
|
||||||
if !o.local {
|
|
||||||
smPatchVersion, err = cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// only apply resource version locking on a single resource
|
// only apply resource version locking on a single resource
|
||||||
if !one && len(o.resourceVersion) > 0 {
|
if !one && len(o.resourceVersion) > 0 {
|
||||||
return fmt.Errorf("--resource-version may only be used with a single resource")
|
return fmt.Errorf("--resource-version may only be used with a single resource")
|
||||||
@ -254,7 +246,7 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
|||||||
if !reflect.DeepEqual(oldData, newData) {
|
if !reflect.DeepEqual(oldData, newData) {
|
||||||
dataChangeMsg = "labeled"
|
dataChangeMsg = "labeled"
|
||||||
}
|
}
|
||||||
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, smPatchVersion)
|
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
|
||||||
createdPatch := err == nil
|
createdPatch := err == nil
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(2).Infof("couldn't compute patch: %v", err)
|
glog.V(2).Infof("couldn't compute patch: %v", err)
|
||||||
|
@ -354,12 +354,6 @@ func TestLabelForResourceFromFile(t *testing.T) {
|
|||||||
switch req.Method {
|
switch req.Method {
|
||||||
case "GET":
|
case "GET":
|
||||||
switch req.URL.Path {
|
switch req.URL.Path {
|
||||||
case "/version":
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case "/namespaces/test/replicationcontrollers/cassandra":
|
case "/namespaces/test/replicationcontrollers/cassandra":
|
||||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
|
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
|
||||||
default:
|
default:
|
||||||
@ -381,7 +375,7 @@ func TestLabelForResourceFromFile(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
cmd := NewCmdLabel(f, buf)
|
cmd := NewCmdLabel(f, buf)
|
||||||
@ -443,12 +437,6 @@ func TestLabelMultipleObjects(t *testing.T) {
|
|||||||
switch req.Method {
|
switch req.Method {
|
||||||
case "GET":
|
case "GET":
|
||||||
switch req.URL.Path {
|
switch req.URL.Path {
|
||||||
case "/version":
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case "/namespaces/test/pods":
|
case "/namespaces/test/pods":
|
||||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil
|
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil
|
||||||
default:
|
default:
|
||||||
@ -472,7 +460,7 @@ func TestLabelMultipleObjects(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
cmd := NewCmdLabel(f, buf)
|
cmd := NewCmdLabel(f, buf)
|
||||||
|
@ -154,14 +154,6 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
smPatchVersion := strategicpatch.SMPatchVersionLatest
|
|
||||||
if !options.Local {
|
|
||||||
smPatchVersion, err = cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
err = r.Visit(func(info *resource.Info, err error) error {
|
err = r.Visit(func(info *resource.Info, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -185,7 +177,7 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||||||
// don't bother checking for failures of this replace, because a failure to indicate the hint doesn't fail the command
|
// don't bother checking for failures of this replace, because a failure to indicate the hint doesn't fail the command
|
||||||
// also, don't force the replacement. If the replacement fails on a resourceVersion conflict, then it means this
|
// also, don't force the replacement. If the replacement fails on a resourceVersion conflict, then it means this
|
||||||
// record hint is likely to be invalid anyway, so avoid the bad hint
|
// record hint is likely to be invalid anyway, so avoid the bad hint
|
||||||
patch, err := cmdutil.ChangeResourcePatch(info, f.Command(), smPatchVersion)
|
patch, err := cmdutil.ChangeResourcePatch(info, f.Command())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
helper.Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch)
|
helper.Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch)
|
||||||
}
|
}
|
||||||
|
@ -34,12 +34,6 @@ func TestPatchObject(t *testing.T) {
|
|||||||
NegotiatedSerializer: ns,
|
NegotiatedSerializer: ns,
|
||||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
switch p, m := req.URL.Path, req.Method; {
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
case p == "/version" && m == "GET":
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case p == "/namespaces/test/services/frontend" && (m == "PATCH" || m == "GET"):
|
case p == "/namespaces/test/services/frontend" && (m == "PATCH" || m == "GET"):
|
||||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &svc.Items[0])}, nil
|
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &svc.Items[0])}, nil
|
||||||
default:
|
default:
|
||||||
@ -49,7 +43,6 @@ func TestPatchObject(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
cmd := NewCmdPatch(f, buf)
|
cmd := NewCmdPatch(f, buf)
|
||||||
@ -73,12 +66,6 @@ func TestPatchObjectFromFile(t *testing.T) {
|
|||||||
NegotiatedSerializer: ns,
|
NegotiatedSerializer: ns,
|
||||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
switch p, m := req.URL.Path, req.Method; {
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
case p == "/version" && m == "GET":
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case p == "/namespaces/test/services/frontend" && (m == "PATCH" || m == "GET"):
|
case p == "/namespaces/test/services/frontend" && (m == "PATCH" || m == "GET"):
|
||||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &svc.Items[0])}, nil
|
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &svc.Items[0])}, nil
|
||||||
default:
|
default:
|
||||||
@ -88,7 +75,6 @@ func TestPatchObjectFromFile(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
cmd := NewCmdPatch(f, buf)
|
cmd := NewCmdPatch(f, buf)
|
||||||
|
@ -38,7 +38,6 @@ import (
|
|||||||
type PauseConfig struct {
|
type PauseConfig struct {
|
||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
|
|
||||||
f cmdutil.Factory
|
|
||||||
Pauser func(info *resource.Info) (bool, error)
|
Pauser func(info *resource.Info) (bool, error)
|
||||||
Mapper meta.RESTMapper
|
Mapper meta.RESTMapper
|
||||||
Typer runtime.ObjectTyper
|
Typer runtime.ObjectTyper
|
||||||
@ -100,7 +99,6 @@ func (o *PauseConfig) CompletePause(f cmdutil.Factory, cmd *cobra.Command, out i
|
|||||||
return cmdutil.UsageError(cmd, cmd.Use)
|
return cmdutil.UsageError(cmd, cmd.Use)
|
||||||
}
|
}
|
||||||
|
|
||||||
o.f = f
|
|
||||||
o.Mapper, o.Typer = f.Object()
|
o.Mapper, o.Typer = f.Object()
|
||||||
o.Encoder = f.JSONEncoder()
|
o.Encoder = f.JSONEncoder()
|
||||||
|
|
||||||
@ -134,7 +132,7 @@ func (o *PauseConfig) CompletePause(f cmdutil.Factory, cmd *cobra.Command, out i
|
|||||||
|
|
||||||
func (o PauseConfig) RunPause() error {
|
func (o PauseConfig) RunPause() error {
|
||||||
allErrs := []error{}
|
allErrs := []error{}
|
||||||
for _, patch := range set.CalculatePatches(o.f, o.Infos, o.Encoder, false, o.Pauser) {
|
for _, patch := range set.CalculatePatches(o.Infos, o.Encoder, o.Pauser) {
|
||||||
info := patch.Info
|
info := patch.Info
|
||||||
if patch.Err != nil {
|
if patch.Err != nil {
|
||||||
allErrs = append(allErrs, fmt.Errorf("error: %s %q %v", info.Mapping.Resource, info.Name, patch.Err))
|
allErrs = append(allErrs, fmt.Errorf("error: %s %q %v", info.Mapping.Resource, info.Name, patch.Err))
|
||||||
|
@ -38,7 +38,6 @@ import (
|
|||||||
type ResumeConfig struct {
|
type ResumeConfig struct {
|
||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
|
|
||||||
f cmdutil.Factory
|
|
||||||
Resumer func(object *resource.Info) (bool, error)
|
Resumer func(object *resource.Info) (bool, error)
|
||||||
Mapper meta.RESTMapper
|
Mapper meta.RESTMapper
|
||||||
Typer runtime.ObjectTyper
|
Typer runtime.ObjectTyper
|
||||||
@ -98,7 +97,6 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, out
|
|||||||
return cmdutil.UsageError(cmd, cmd.Use)
|
return cmdutil.UsageError(cmd, cmd.Use)
|
||||||
}
|
}
|
||||||
|
|
||||||
o.f = f
|
|
||||||
o.Mapper, o.Typer = f.Object()
|
o.Mapper, o.Typer = f.Object()
|
||||||
o.Encoder = f.JSONEncoder()
|
o.Encoder = f.JSONEncoder()
|
||||||
|
|
||||||
@ -138,7 +136,7 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, out
|
|||||||
|
|
||||||
func (o ResumeConfig) RunResume() error {
|
func (o ResumeConfig) RunResume() error {
|
||||||
allErrs := []error{}
|
allErrs := []error{}
|
||||||
for _, patch := range set.CalculatePatches(o.f, o.Infos, o.Encoder, false, o.Resumer) {
|
for _, patch := range set.CalculatePatches(o.Infos, o.Encoder, o.Resumer) {
|
||||||
info := patch.Info
|
info := patch.Info
|
||||||
|
|
||||||
if patch.Err != nil {
|
if patch.Err != nil {
|
||||||
|
@ -139,11 +139,6 @@ func RunScale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||||||
return fmt.Errorf("cannot use --resource-version with multiple resources")
|
return fmt.Errorf("cannot use --resource-version with multiple resources")
|
||||||
}
|
}
|
||||||
|
|
||||||
smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
counter := 0
|
counter := 0
|
||||||
err = r.Visit(func(info *resource.Info, err error) error {
|
err = r.Visit(func(info *resource.Info, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -169,7 +164,7 @@ func RunScale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmdutil.ShouldRecord(cmd, info) {
|
if cmdutil.ShouldRecord(cmd, info) {
|
||||||
patchBytes, err := cmdutil.ChangeResourcePatch(info, f.Command(), smPatchVersion)
|
patchBytes, err := cmdutil.ChangeResourcePatch(info, f.Command())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
||||||
@ -61,7 +61,7 @@ func handlePodUpdateError(out io.Writer, err error, resource string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ok := cmdutil.PrintErrorWithCauses(err, out); ok {
|
if ok := kcmdutil.PrintErrorWithCauses(err, out); ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,20 +120,8 @@ type Patch struct {
|
|||||||
// CalculatePatches calls the mutation function on each provided info object, and generates a strategic merge patch for
|
// CalculatePatches calls the mutation function on each provided info object, and generates a strategic merge patch for
|
||||||
// the changes in the object. Encoder must be able to encode the info into the appropriate destination type. If mutateFn
|
// the changes in the object. Encoder must be able to encode the info into the appropriate destination type. If mutateFn
|
||||||
// returns false, the object is not included in the final list of patches.
|
// returns false, the object is not included in the final list of patches.
|
||||||
// If local is true, it will be default to use SMPatchVersionLatest to calculate a patch without contacting the server to
|
func CalculatePatches(infos []*resource.Info, encoder runtime.Encoder, mutateFn func(*resource.Info) (bool, error)) []*Patch {
|
||||||
// get the server supported SMPatchVersion. If you are using a patch's Patch field generated in local mode, be careful.
|
|
||||||
// If local is false, it will talk to the server to check which StategicMergePatchVersion to use.
|
|
||||||
func CalculatePatches(f cmdutil.Factory, infos []*resource.Info, encoder runtime.Encoder, local bool, mutateFn func(*resource.Info) (bool, error)) []*Patch {
|
|
||||||
var patches []*Patch
|
var patches []*Patch
|
||||||
smPatchVersion := strategicpatch.SMPatchVersionLatest
|
|
||||||
var err error
|
|
||||||
if !local {
|
|
||||||
smPatchVersion, err = cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
|
|
||||||
if err != nil {
|
|
||||||
return patches
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, info := range infos {
|
for _, info := range infos {
|
||||||
patch := &Patch{Info: info}
|
patch := &Patch{Info: info}
|
||||||
patch.Before, patch.Err = runtime.Encode(encoder, info.Object)
|
patch.Before, patch.Err = runtime.Encode(encoder, info.Object)
|
||||||
@ -168,7 +156,7 @@ func CalculatePatches(f cmdutil.Factory, infos []*resource.Info, encoder runtime
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
patch.Patch, patch.Err = strategicpatch.CreateTwoWayMergePatch(patch.Before, patch.After, versioned, smPatchVersion)
|
patch.Patch, patch.Err = strategicpatch.CreateTwoWayMergePatch(patch.Before, patch.After, versioned)
|
||||||
}
|
}
|
||||||
return patches
|
return patches
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||||
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
|
// ImageOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
|
||||||
@ -36,7 +35,6 @@ import (
|
|||||||
type ImageOptions struct {
|
type ImageOptions struct {
|
||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
|
|
||||||
f cmdutil.Factory
|
|
||||||
Mapper meta.RESTMapper
|
Mapper meta.RESTMapper
|
||||||
Typer runtime.ObjectTyper
|
Typer runtime.ObjectTyper
|
||||||
Infos []*resource.Info
|
Infos []*resource.Info
|
||||||
@ -110,7 +108,6 @@ func NewCmdImage(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||||
o.f = f
|
|
||||||
o.Mapper, o.Typer = f.Object()
|
o.Mapper, o.Typer = f.Object()
|
||||||
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
|
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
|
||||||
o.Encoder = f.JSONEncoder()
|
o.Encoder = f.JSONEncoder()
|
||||||
@ -165,7 +162,7 @@ func (o *ImageOptions) Validate() error {
|
|||||||
func (o *ImageOptions) Run() error {
|
func (o *ImageOptions) Run() error {
|
||||||
allErrs := []error{}
|
allErrs := []error{}
|
||||||
|
|
||||||
patches := CalculatePatches(o.f, o.Infos, o.Encoder, o.Local, func(info *resource.Info) (bool, error) {
|
patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) (bool, error) {
|
||||||
transformed := false
|
transformed := false
|
||||||
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error {
|
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error {
|
||||||
for name, image := range o.ContainerImages {
|
for name, image := range o.ContainerImages {
|
||||||
@ -189,14 +186,6 @@ func (o *ImageOptions) Run() error {
|
|||||||
return transformed, err
|
return transformed, err
|
||||||
})
|
})
|
||||||
|
|
||||||
smPatchVersion := strategicpatch.SMPatchVersionLatest
|
|
||||||
var err error
|
|
||||||
if !o.Local {
|
|
||||||
smPatchVersion, err = cmdutil.GetServerSupportedSMPatchVersionFromFactory(o.f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, patch := range patches {
|
for _, patch := range patches {
|
||||||
info := patch.Info
|
info := patch.Info
|
||||||
if patch.Err != nil {
|
if patch.Err != nil {
|
||||||
@ -223,7 +212,7 @@ func (o *ImageOptions) Run() error {
|
|||||||
|
|
||||||
// record this change (for rollout history)
|
// record this change (for rollout history)
|
||||||
if o.Record || cmdutil.ContainsChangeCause(info) {
|
if o.Record || cmdutil.ContainsChangeCause(info) {
|
||||||
if patch, err := cmdutil.ChangeResourcePatch(info, o.ChangeCause, smPatchVersion); err == nil {
|
if patch, err := cmdutil.ChangeResourcePatch(info, o.ChangeCause); err == nil {
|
||||||
if obj, err = resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch); err != nil {
|
if obj, err = resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch); err != nil {
|
||||||
fmt.Fprintf(o.Err, "WARNING: changes to %s/%s can't be recorded: %v\n", info.Mapping.Resource, info.Name, err)
|
fmt.Fprintf(o.Err, "WARNING: changes to %s/%s can't be recorded: %v\n", info.Mapping.Resource, info.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,6 @@ var (
|
|||||||
type ResourcesOptions struct {
|
type ResourcesOptions struct {
|
||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
|
|
||||||
f cmdutil.Factory
|
|
||||||
Mapper meta.RESTMapper
|
Mapper meta.RESTMapper
|
||||||
Typer runtime.ObjectTyper
|
Typer runtime.ObjectTyper
|
||||||
Infos []*resource.Info
|
Infos []*resource.Info
|
||||||
@ -125,7 +124,6 @@ func NewCmdResources(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||||
o.f = f
|
|
||||||
o.Mapper, o.Typer = f.Object()
|
o.Mapper, o.Typer = f.Object()
|
||||||
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
|
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
|
||||||
o.Encoder = f.JSONEncoder()
|
o.Encoder = f.JSONEncoder()
|
||||||
@ -176,7 +174,7 @@ func (o *ResourcesOptions) Validate() error {
|
|||||||
|
|
||||||
func (o *ResourcesOptions) Run() error {
|
func (o *ResourcesOptions) Run() error {
|
||||||
allErrs := []error{}
|
allErrs := []error{}
|
||||||
patches := CalculatePatches(o.f, o.Infos, o.Encoder, cmdutil.GetDryRunFlag(o.Cmd), func(info *resource.Info) (bool, error) {
|
patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) (bool, error) {
|
||||||
transformed := false
|
transformed := false
|
||||||
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error {
|
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error {
|
||||||
containers, _ := selectContainers(spec.Containers, o.ContainerSelector)
|
containers, _ := selectContainers(spec.Containers, o.ContainerSelector)
|
||||||
|
@ -321,11 +321,6 @@ func (o TaintOptions) RunTaint() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(o.f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.Visit(func(info *resource.Info, err error) error {
|
return r.Visit(func(info *resource.Info, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -348,7 +343,7 @@ func (o TaintOptions) RunTaint() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, smPatchVersion)
|
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
|
||||||
createdPatch := err == nil
|
createdPatch := err == nil
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(2).Infof("couldn't compute patch: %v", err)
|
glog.V(2).Infof("couldn't compute patch: %v", err)
|
||||||
|
@ -252,6 +252,7 @@ func TestTaint(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
oldNode, expectNewNode := generateNodeAndTaintedNode(test.oldTaints, test.newTaints)
|
oldNode, expectNewNode := generateNodeAndTaintedNode(test.oldTaints, test.newTaints)
|
||||||
|
|
||||||
new_node := &api.Node{}
|
new_node := &api.Node{}
|
||||||
tainted := false
|
tainted := false
|
||||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||||
@ -261,12 +262,6 @@ func TestTaint(t *testing.T) {
|
|||||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
m := &MyReq{req}
|
m := &MyReq{req}
|
||||||
switch {
|
switch {
|
||||||
case m.isFor("GET", "/version"):
|
|
||||||
resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
case m.isFor("GET", "/nodes/node-name"):
|
case m.isFor("GET", "/nodes/node-name"):
|
||||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, oldNode)}, nil
|
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, oldNode)}, nil
|
||||||
case m.isFor("PATCH", "/nodes/node-name"), m.isFor("PUT", "/nodes/node-name"):
|
case m.isFor("PATCH", "/nodes/node-name"), m.isFor("PUT", "/nodes/node-name"):
|
||||||
|
@ -521,7 +521,7 @@ func RecordChangeCause(obj runtime.Object, changeCause string) error {
|
|||||||
|
|
||||||
// ChangeResourcePatch creates a strategic merge patch between the origin input resource info
|
// ChangeResourcePatch creates a strategic merge patch between the origin input resource info
|
||||||
// and the annotated with change-cause input resource info.
|
// and the annotated with change-cause input resource info.
|
||||||
func ChangeResourcePatch(info *resource.Info, changeCause string, smPatchVersion strategicpatch.StrategicMergePatchVersion) ([]byte, error) {
|
func ChangeResourcePatch(info *resource.Info, changeCause string) ([]byte, error) {
|
||||||
oldData, err := json.Marshal(info.Object)
|
oldData, err := json.Marshal(info.Object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -533,7 +533,7 @@ func ChangeResourcePatch(info *resource.Info, changeCause string, smPatchVersion
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return strategicpatch.CreateTwoWayMergePatch(oldData, newData, info.Object, smPatchVersion)
|
return strategicpatch.CreateTwoWayMergePatch(oldData, newData, info.Object)
|
||||||
}
|
}
|
||||||
|
|
||||||
// containsChangeCause checks if input resource info contains change-cause annotation.
|
// containsChangeCause checks if input resource info contains change-cause annotation.
|
||||||
@ -725,13 +725,3 @@ func RequireNoArguments(c *cobra.Command, args []string) {
|
|||||||
CheckErr(UsageError(c, fmt.Sprintf(`unknown command %q`, strings.Join(args, " "))))
|
CheckErr(UsageError(c, fmt.Sprintf(`unknown command %q`, strings.Join(args, " "))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetServerSupportedSMPatchVersionFromFactory is a wrapper of GetServerSupportedSMPatchVersion(),
|
|
||||||
// It takes a Factory, returns the max version the server supports.
|
|
||||||
func GetServerSupportedSMPatchVersionFromFactory(f Factory) (strategicpatch.StrategicMergePatchVersion, error) {
|
|
||||||
clientSet, err := f.ClientSet()
|
|
||||||
if err != nil {
|
|
||||||
return strategicpatch.Unknown, err
|
|
||||||
}
|
|
||||||
return strategicpatch.GetServerSupportedSMPatchVersion(clientSet.Discovery())
|
|
||||||
}
|
|
||||||
|
@ -15,7 +15,6 @@ go_library(
|
|||||||
srcs = ["patch.go"],
|
srcs = ["patch.go"],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/client/typed/discovery:go_default_library",
|
|
||||||
"//pkg/util/json:go_default_library",
|
"//pkg/util/json:go_default_library",
|
||||||
"//third_party/forked/golang/json:go_default_library",
|
"//third_party/forked/golang/json:go_default_library",
|
||||||
"//vendor:github.com/davecgh/go-spew/spew",
|
"//vendor:github.com/davecgh/go-spew/spew",
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
|
||||||
"k8s.io/kubernetes/pkg/util/json"
|
"k8s.io/kubernetes/pkg/util/json"
|
||||||
forkedjson "k8s.io/kubernetes/third_party/forked/golang/json"
|
forkedjson "k8s.io/kubernetes/third_party/forked/golang/json"
|
||||||
|
|
||||||
@ -39,20 +38,11 @@ import (
|
|||||||
// Some of the content of this package was borrowed with minor adaptations from
|
// Some of the content of this package was borrowed with minor adaptations from
|
||||||
// evanphx/json-patch and openshift/origin.
|
// evanphx/json-patch and openshift/origin.
|
||||||
|
|
||||||
type StrategicMergePatchVersion string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
directiveMarker = "$patch"
|
directiveMarker = "$patch"
|
||||||
deleteDirective = "delete"
|
deleteDirective = "delete"
|
||||||
replaceDirective = "replace"
|
replaceDirective = "replace"
|
||||||
mergeDirective = "merge"
|
mergeDirective = "merge"
|
||||||
mergePrimitivesListDirective = "mergeprimitiveslist"
|
|
||||||
|
|
||||||
// different versions of StrategicMergePatch
|
|
||||||
SMPatchVersion_1_0 StrategicMergePatchVersion = "v1.0.0"
|
|
||||||
SMPatchVersion_1_5 StrategicMergePatchVersion = "v1.5.0"
|
|
||||||
Unknown StrategicMergePatchVersion = "Unknown"
|
|
||||||
SMPatchVersionLatest = SMPatchVersion_1_5
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsPreconditionFailed returns true if the provided error indicates
|
// IsPreconditionFailed returns true if the provided error indicates
|
||||||
@ -97,7 +87,6 @@ func IsConflict(err error) bool {
|
|||||||
|
|
||||||
var errBadJSONDoc = fmt.Errorf("Invalid JSON document")
|
var errBadJSONDoc = fmt.Errorf("Invalid JSON document")
|
||||||
var errNoListOfLists = fmt.Errorf("Lists of lists are not supported")
|
var errNoListOfLists = fmt.Errorf("Lists of lists are not supported")
|
||||||
var errNoElementsInSlice = fmt.Errorf("no elements in any of the given slices")
|
|
||||||
|
|
||||||
// The following code is adapted from github.com/openshift/origin/pkg/util/jsonmerge.
|
// The following code is adapted from github.com/openshift/origin/pkg/util/jsonmerge.
|
||||||
// Instead of defining a Delta that holds an original, a patch and a set of preconditions,
|
// Instead of defining a Delta that holds an original, a patch and a set of preconditions,
|
||||||
@ -144,15 +133,15 @@ func RequireMetadataKeyUnchanged(key string) PreconditionFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: Use the synonym CreateTwoWayMergePatch, instead.
|
// Deprecated: Use the synonym CreateTwoWayMergePatch, instead.
|
||||||
func CreateStrategicMergePatch(original, modified []byte, dataStruct interface{}, smPatchVersion StrategicMergePatchVersion) ([]byte, error) {
|
func CreateStrategicMergePatch(original, modified []byte, dataStruct interface{}) ([]byte, error) {
|
||||||
return CreateTwoWayMergePatch(original, modified, dataStruct, smPatchVersion)
|
return CreateTwoWayMergePatch(original, modified, dataStruct)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTwoWayMergePatch creates a patch that can be passed to StrategicMergePatch from an original
|
// 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
|
// 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
|
// 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.
|
// if either of the two documents is invalid.
|
||||||
func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, smPatchVersion StrategicMergePatchVersion, fns ...PreconditionFunc) ([]byte, error) {
|
func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, fns ...PreconditionFunc) ([]byte, error) {
|
||||||
originalMap := map[string]interface{}{}
|
originalMap := map[string]interface{}{}
|
||||||
if len(original) > 0 {
|
if len(original) > 0 {
|
||||||
if err := json.Unmarshal(original, &originalMap); err != nil {
|
if err := json.Unmarshal(original, &originalMap); err != nil {
|
||||||
@ -172,7 +161,7 @@ func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, s
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
patchMap, err := diffMaps(originalMap, modifiedMap, t, false, false, smPatchVersion)
|
patchMap, err := diffMaps(originalMap, modifiedMap, t, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -188,7 +177,7 @@ func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a (recursive) strategic merge patch that yields modified when applied to original.
|
// Returns a (recursive) strategic merge patch that yields modified when applied to original.
|
||||||
func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreChangesAndAdditions, ignoreDeletions bool, smPatchVersion StrategicMergePatchVersion) (map[string]interface{}, error) {
|
func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreChangesAndAdditions, ignoreDeletions bool) (map[string]interface{}, error) {
|
||||||
patch := map[string]interface{}{}
|
patch := map[string]interface{}{}
|
||||||
if t.Kind() == reflect.Ptr {
|
if t.Kind() == reflect.Ptr {
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
@ -241,7 +230,7 @@ func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreC
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
patchValue, err := diffMaps(originalValueTyped, modifiedValueTyped, fieldType, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion)
|
patchValue, err := diffMaps(originalValueTyped, modifiedValueTyped, fieldType, ignoreChangesAndAdditions, ignoreDeletions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -259,25 +248,13 @@ func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreC
|
|||||||
}
|
}
|
||||||
|
|
||||||
if fieldPatchStrategy == mergeDirective {
|
if fieldPatchStrategy == mergeDirective {
|
||||||
patchValue, err := diffLists(originalValueTyped, modifiedValueTyped, fieldType.Elem(), fieldPatchMergeKey, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion)
|
patchValue, err := diffLists(originalValueTyped, modifiedValueTyped, fieldType.Elem(), fieldPatchMergeKey, ignoreChangesAndAdditions, ignoreDeletions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if patchValue == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch typedPatchValue := patchValue.(type) {
|
if len(patchValue) > 0 {
|
||||||
case []interface{}:
|
patch[key] = patchValue
|
||||||
if len(typedPatchValue) > 0 {
|
|
||||||
patch[key] = typedPatchValue
|
|
||||||
}
|
|
||||||
case map[string]interface{}:
|
|
||||||
if len(typedPatchValue) > 0 {
|
|
||||||
patch[key] = typedPatchValue
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("invalid type of patch: %v", reflect.TypeOf(patchValue))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
@ -307,7 +284,7 @@ func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreC
|
|||||||
|
|
||||||
// Returns a (recursive) strategic merge patch that yields modified when applied to original,
|
// Returns a (recursive) strategic merge patch that yields modified when applied to original,
|
||||||
// for a pair of lists with merge semantics.
|
// for a pair of lists with merge semantics.
|
||||||
func diffLists(original, modified []interface{}, t reflect.Type, mergeKey string, ignoreChangesAndAdditions, ignoreDeletions bool, smPatchVersion StrategicMergePatchVersion) (interface{}, error) {
|
func diffLists(original, modified []interface{}, t reflect.Type, mergeKey string, ignoreChangesAndAdditions, ignoreDeletions bool) ([]interface{}, error) {
|
||||||
if len(original) == 0 {
|
if len(original) == 0 {
|
||||||
if len(modified) == 0 || ignoreChangesAndAdditions {
|
if len(modified) == 0 || ignoreChangesAndAdditions {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -321,14 +298,12 @@ func diffLists(original, modified []interface{}, t reflect.Type, mergeKey string
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var patch interface{}
|
var patch []interface{}
|
||||||
|
|
||||||
if elementType.Kind() == reflect.Map {
|
if elementType.Kind() == reflect.Map {
|
||||||
patch, err = diffListsOfMaps(original, modified, t, mergeKey, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion)
|
patch, err = diffListsOfMaps(original, modified, t, mergeKey, ignoreChangesAndAdditions, ignoreDeletions)
|
||||||
} else if elementType.Kind() == reflect.Slice {
|
} else if !ignoreChangesAndAdditions {
|
||||||
err = errNoListOfLists
|
patch, err = diffListsOfScalars(original, modified)
|
||||||
} else {
|
|
||||||
patch, err = diffListsOfScalars(original, modified, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -340,23 +315,8 @@ func diffLists(original, modified []interface{}, t reflect.Type, mergeKey string
|
|||||||
|
|
||||||
// Returns a (recursive) strategic merge patch that yields modified when applied to original,
|
// Returns a (recursive) strategic merge patch that yields modified when applied to original,
|
||||||
// for a pair of lists of scalars with merge semantics.
|
// for a pair of lists of scalars with merge semantics.
|
||||||
func diffListsOfScalars(original, modified []interface{}, ignoreChangesAndAdditions, ignoreDeletions bool, smPatchVersion StrategicMergePatchVersion) (interface{}, error) {
|
func diffListsOfScalars(original, modified []interface{}) ([]interface{}, error) {
|
||||||
originalScalars := uniqifyAndSortScalars(original)
|
if len(modified) == 0 {
|
||||||
modifiedScalars := uniqifyAndSortScalars(modified)
|
|
||||||
|
|
||||||
switch smPatchVersion {
|
|
||||||
case SMPatchVersion_1_5:
|
|
||||||
return diffListsOfScalarsIntoMap(originalScalars, modifiedScalars, ignoreChangesAndAdditions, ignoreDeletions)
|
|
||||||
case SMPatchVersion_1_0:
|
|
||||||
return diffListsOfScalarsIntoSlice(originalScalars, modifiedScalars, ignoreChangesAndAdditions, ignoreDeletions)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("Unknown StrategicMergePatchVersion: %v", smPatchVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func diffListsOfScalarsIntoSlice(originalScalars, modifiedScalars []interface{}, ignoreChangesAndAdditions, ignoreDeletions bool) ([]interface{}, error) {
|
|
||||||
originalIndex, modifiedIndex := 0, 0
|
|
||||||
if len(modifiedScalars) == 0 {
|
|
||||||
// There is no need to check the length of original because there is no way to create
|
// There is no need to check the length of original because there is no way to create
|
||||||
// a patch that deletes a scalar from a list of scalars with merge semantics.
|
// a patch that deletes a scalar from a list of scalars with merge semantics.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -364,14 +324,18 @@ func diffListsOfScalarsIntoSlice(originalScalars, modifiedScalars []interface{},
|
|||||||
|
|
||||||
patch := []interface{}{}
|
patch := []interface{}{}
|
||||||
|
|
||||||
|
originalScalars := uniqifyAndSortScalars(original)
|
||||||
|
modifiedScalars := uniqifyAndSortScalars(modified)
|
||||||
|
originalIndex, modifiedIndex := 0, 0
|
||||||
|
|
||||||
loopB:
|
loopB:
|
||||||
for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ {
|
for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ {
|
||||||
for ; originalIndex < len(originalScalars); originalIndex++ {
|
for ; originalIndex < len(originalScalars); originalIndex++ {
|
||||||
originalString := fmt.Sprintf("%v", originalScalars[originalIndex])
|
originalString := fmt.Sprintf("%v", original[originalIndex])
|
||||||
modifiedString := fmt.Sprintf("%v", modifiedScalars[modifiedIndex])
|
modifiedString := fmt.Sprintf("%v", modified[modifiedIndex])
|
||||||
if originalString >= modifiedString {
|
if originalString >= modifiedString {
|
||||||
if originalString != modifiedString {
|
if originalString != modifiedString {
|
||||||
patch = append(patch, modifiedScalars[modifiedIndex])
|
patch = append(patch, modified[modifiedIndex])
|
||||||
}
|
}
|
||||||
|
|
||||||
continue loopB
|
continue loopB
|
||||||
@ -385,57 +349,7 @@ loopB:
|
|||||||
|
|
||||||
// Add any remaining items found only in modified
|
// Add any remaining items found only in modified
|
||||||
for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ {
|
for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ {
|
||||||
patch = append(patch, modifiedScalars[modifiedIndex])
|
patch = append(patch, modified[modifiedIndex])
|
||||||
}
|
|
||||||
|
|
||||||
return patch, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func diffListsOfScalarsIntoMap(originalScalars, modifiedScalars []interface{}, ignoreChangesAndAdditions, ignoreDeletions bool) (map[string]interface{}, error) {
|
|
||||||
originalIndex, modifiedIndex := 0, 0
|
|
||||||
patch := map[string]interface{}{}
|
|
||||||
patch[directiveMarker] = mergePrimitivesListDirective
|
|
||||||
|
|
||||||
for originalIndex < len(originalScalars) && modifiedIndex < len(modifiedScalars) {
|
|
||||||
originalString := fmt.Sprintf("%v", originalScalars[originalIndex])
|
|
||||||
modifiedString := fmt.Sprintf("%v", modifiedScalars[modifiedIndex])
|
|
||||||
|
|
||||||
// objects are identical
|
|
||||||
if originalString == modifiedString {
|
|
||||||
originalIndex++
|
|
||||||
modifiedIndex++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if originalString > modifiedString {
|
|
||||||
if !ignoreChangesAndAdditions {
|
|
||||||
modifiedValue := modifiedScalars[modifiedIndex]
|
|
||||||
patch[modifiedString] = modifiedValue
|
|
||||||
}
|
|
||||||
modifiedIndex++
|
|
||||||
} else {
|
|
||||||
if !ignoreDeletions {
|
|
||||||
patch[originalString] = nil
|
|
||||||
}
|
|
||||||
originalIndex++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete any remaining items found only in original
|
|
||||||
if !ignoreDeletions {
|
|
||||||
for ; originalIndex < len(originalScalars); originalIndex++ {
|
|
||||||
originalString := fmt.Sprintf("%v", originalScalars[originalIndex])
|
|
||||||
patch[originalString] = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add any remaining items found only in modified
|
|
||||||
if !ignoreChangesAndAdditions {
|
|
||||||
for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ {
|
|
||||||
modifiedString := fmt.Sprintf("%v", modifiedScalars[modifiedIndex])
|
|
||||||
modifiedValue := modifiedScalars[modifiedIndex]
|
|
||||||
patch[modifiedString] = modifiedValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return patch, nil
|
return patch, nil
|
||||||
@ -446,7 +360,7 @@ var errBadArgTypeFmt = "expected a %s, but received a %s"
|
|||||||
|
|
||||||
// Returns a (recursive) strategic merge patch that yields modified when applied to original,
|
// Returns a (recursive) strategic merge patch that yields modified when applied to original,
|
||||||
// for a pair of lists of maps with merge semantics.
|
// for a pair of lists of maps with merge semantics.
|
||||||
func diffListsOfMaps(original, modified []interface{}, t reflect.Type, mergeKey string, ignoreChangesAndAdditions, ignoreDeletions bool, smPatchVersion StrategicMergePatchVersion) ([]interface{}, error) {
|
func diffListsOfMaps(original, modified []interface{}, t reflect.Type, mergeKey string, ignoreChangesAndAdditions, ignoreDeletions bool) ([]interface{}, error) {
|
||||||
patch := make([]interface{}, 0)
|
patch := make([]interface{}, 0)
|
||||||
|
|
||||||
originalSorted, err := sortMergeListsByNameArray(original, t, mergeKey, false)
|
originalSorted, err := sortMergeListsByNameArray(original, t, mergeKey, false)
|
||||||
@ -492,7 +406,7 @@ loopB:
|
|||||||
if originalString >= modifiedString {
|
if originalString >= modifiedString {
|
||||||
if originalString == modifiedString {
|
if originalString == modifiedString {
|
||||||
// Merge key values are equal, so recurse
|
// Merge key values are equal, so recurse
|
||||||
patchValue, err := diffMaps(originalMap, modifiedMap, t, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion)
|
patchValue, err := diffMaps(originalMap, modifiedMap, t, ignoreChangesAndAdditions, ignoreDeletions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -628,15 +542,7 @@ func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[strin
|
|||||||
return map[string]interface{}{}, nil
|
return map[string]interface{}{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if v == mergePrimitivesListDirective {
|
return nil, fmt.Errorf(errBadPatchTypeFmt, v, patch)
|
||||||
// delete the directiveMarker's key-value pair to avoid delta map and delete map
|
|
||||||
// overlaping with each other when calculating a ThreeWayDiff for list of Primitives.
|
|
||||||
// Otherwise, the overlaping will cause it calling LookupPatchMetadata() which will
|
|
||||||
// return an error since the metadata shows it's a slice but it is actually a map.
|
|
||||||
delete(original, directiveMarker)
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf(errBadPatchTypeFmt, v, patch)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// nil is an accepted value for original to simplify logic in other places.
|
// nil is an accepted value for original to simplify logic in other places.
|
||||||
@ -672,9 +578,7 @@ func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[strin
|
|||||||
// If they're both maps or lists, recurse into the value.
|
// If they're both maps or lists, recurse into the value.
|
||||||
originalType := reflect.TypeOf(original[k])
|
originalType := reflect.TypeOf(original[k])
|
||||||
patchType := reflect.TypeOf(patchV)
|
patchType := reflect.TypeOf(patchV)
|
||||||
// check if we are trying to merge a slice with a map for list of primitives
|
if originalType == patchType {
|
||||||
isMergeSliceOfPrimitivesWithAPatchMap := originalType != nil && patchType != nil && originalType.Kind() == reflect.Slice && patchType.Kind() == reflect.Map
|
|
||||||
if originalType == patchType || isMergeSliceOfPrimitivesWithAPatchMap {
|
|
||||||
// First find the fieldPatchStrategy and fieldPatchMergeKey.
|
// First find the fieldPatchStrategy and fieldPatchMergeKey.
|
||||||
fieldType, fieldPatchStrategy, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadata(t, k)
|
fieldType, fieldPatchStrategy, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadata(t, k)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -696,8 +600,9 @@ func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[strin
|
|||||||
if originalType.Kind() == reflect.Slice && fieldPatchStrategy == mergeDirective {
|
if originalType.Kind() == reflect.Slice && fieldPatchStrategy == mergeDirective {
|
||||||
elemType := fieldType.Elem()
|
elemType := fieldType.Elem()
|
||||||
typedOriginal := original[k].([]interface{})
|
typedOriginal := original[k].([]interface{})
|
||||||
|
typedPatch := patchV.([]interface{})
|
||||||
var err error
|
var err error
|
||||||
original[k], err = mergeSlice(typedOriginal, patchV, elemType, fieldPatchMergeKey)
|
original[k], err = mergeSlice(typedOriginal, typedPatch, elemType, fieldPatchMergeKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -718,34 +623,13 @@ func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[strin
|
|||||||
// Merge two slices together. Note: This may modify both the original slice and
|
// Merge two slices together. Note: This may modify both the original slice and
|
||||||
// the patch because getting a deep copy of a slice in golang is highly
|
// the patch because getting a deep copy of a slice in golang is highly
|
||||||
// non-trivial.
|
// non-trivial.
|
||||||
// The patch could be a map[string]interface{} representing a slice of primitives.
|
func mergeSlice(original, patch []interface{}, elemType reflect.Type, mergeKey string) ([]interface{}, error) {
|
||||||
// If the patch map doesn't has the specific directiveMarker (mergePrimitivesListDirective),
|
if len(original) == 0 && len(patch) == 0 {
|
||||||
// it returns an error. Please check patch_test.go and find the test case named
|
|
||||||
// "merge lists of scalars for list of primitives" to see what the patch looks like.
|
|
||||||
// Patch is still []interface{} for all the other types.
|
|
||||||
func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type, mergeKey string) ([]interface{}, error) {
|
|
||||||
t, err := sliceElementType(original)
|
|
||||||
if err != nil && err != errNoElementsInSlice {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if patchMap, ok := patch.(map[string]interface{}); ok {
|
|
||||||
// We try to merge the original slice with a patch map only when the map has
|
|
||||||
// a specific directiveMarker. Otherwise, this patch will be treated as invalid.
|
|
||||||
if directiveValue, ok := patchMap[directiveMarker]; ok && directiveValue == mergePrimitivesListDirective {
|
|
||||||
return mergeSliceOfScalarsWithPatchMap(original, patchMap)
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("Unable to merge a slice with an invalid map")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedPatch := patch.([]interface{})
|
|
||||||
if len(original) == 0 && len(typedPatch) == 0 {
|
|
||||||
return original, nil
|
return original, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// All the values must be of the same type, but not a list.
|
// All the values must be of the same type, but not a list.
|
||||||
t, err = sliceElementType(original, typedPatch)
|
t, err := sliceElementType(original, patch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -754,7 +638,7 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type
|
|||||||
if t.Kind() != reflect.Map {
|
if t.Kind() != reflect.Map {
|
||||||
// Maybe in the future add a "concat" mode that doesn't
|
// Maybe in the future add a "concat" mode that doesn't
|
||||||
// uniqify.
|
// uniqify.
|
||||||
both := append(original, typedPatch...)
|
both := append(original, patch...)
|
||||||
return uniqifyScalars(both), nil
|
return uniqifyScalars(both), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,7 +649,7 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type
|
|||||||
// First look for any special $patch elements.
|
// First look for any special $patch elements.
|
||||||
patchWithoutSpecialElements := []interface{}{}
|
patchWithoutSpecialElements := []interface{}{}
|
||||||
replace := false
|
replace := false
|
||||||
for _, v := range typedPatch {
|
for _, v := range patch {
|
||||||
typedV := v.(map[string]interface{})
|
typedV := v.(map[string]interface{})
|
||||||
patchType, ok := typedV[directiveMarker]
|
patchType, ok := typedV[directiveMarker]
|
||||||
if ok {
|
if ok {
|
||||||
@ -801,10 +685,10 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type
|
|||||||
return patchWithoutSpecialElements, nil
|
return patchWithoutSpecialElements, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
typedPatch = patchWithoutSpecialElements
|
patch = patchWithoutSpecialElements
|
||||||
|
|
||||||
// Merge patch into original.
|
// Merge patch into original.
|
||||||
for _, v := range typedPatch {
|
for _, v := range patch {
|
||||||
// Because earlier we confirmed that all the elements are maps.
|
// Because earlier we confirmed that all the elements are maps.
|
||||||
typedV := v.(map[string]interface{})
|
typedV := v.(map[string]interface{})
|
||||||
mergeValue, ok := typedV[mergeKey]
|
mergeValue, ok := typedV[mergeKey]
|
||||||
@ -837,36 +721,6 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type
|
|||||||
return original, nil
|
return original, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// mergeSliceOfScalarsWithPatchMap merges the original slice with a patch map and
|
|
||||||
// returns an uniqified and sorted slice of primitives.
|
|
||||||
// The patch map must have the specific directiveMarker (mergePrimitivesListDirective).
|
|
||||||
func mergeSliceOfScalarsWithPatchMap(original []interface{}, patch map[string]interface{}) ([]interface{}, error) {
|
|
||||||
// make sure the patch has the specific directiveMarker ()
|
|
||||||
if directiveValue, ok := patch[directiveMarker]; ok && directiveValue != mergePrimitivesListDirective {
|
|
||||||
return nil, fmt.Errorf("Unable to merge a slice with an invalid map")
|
|
||||||
}
|
|
||||||
delete(patch, directiveMarker)
|
|
||||||
output := make([]interface{}, 0, len(original)+len(patch))
|
|
||||||
for _, value := range original {
|
|
||||||
valueString := fmt.Sprintf("%v", value)
|
|
||||||
if v, ok := patch[valueString]; ok {
|
|
||||||
if v != nil {
|
|
||||||
output = append(output, v)
|
|
||||||
}
|
|
||||||
delete(patch, valueString)
|
|
||||||
} else {
|
|
||||||
output = append(output, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, value := range patch {
|
|
||||||
if value != nil {
|
|
||||||
output = append(output, value)
|
|
||||||
}
|
|
||||||
// No action required to delete items that missing from the original slice.
|
|
||||||
}
|
|
||||||
return uniqifyAndSortScalars(output), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method no longer panics if any element of the slice is not a map.
|
// This method no longer panics if any element of the slice is not a map.
|
||||||
func findMapInSliceBasedOnKeyValue(m []interface{}, key string, value interface{}) (map[string]interface{}, int, bool, error) {
|
func findMapInSliceBasedOnKeyValue(m []interface{}, key string, value interface{}) (map[string]interface{}, int, bool, error) {
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
@ -1092,7 +946,7 @@ func sliceElementType(slices ...[]interface{}) (reflect.Type, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if prevType == nil {
|
if prevType == nil {
|
||||||
return nil, errNoElementsInSlice
|
return nil, fmt.Errorf("no elements in any of the given slices")
|
||||||
}
|
}
|
||||||
|
|
||||||
return prevType, nil
|
return prevType, nil
|
||||||
@ -1181,10 +1035,6 @@ func mergingMapFieldsHaveConflicts(
|
|||||||
if leftMarker != rightMarker {
|
if leftMarker != rightMarker {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if leftMarker == mergePrimitivesListDirective && rightMarker == mergePrimitivesListDirective {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the individual keys.
|
// Check the individual keys.
|
||||||
@ -1207,29 +1057,12 @@ func mergingMapFieldsHaveConflicts(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mapsHaveConflicts(typedLeft, typedRight map[string]interface{}, structType reflect.Type) (bool, error) {
|
func mapsHaveConflicts(typedLeft, typedRight map[string]interface{}, structType reflect.Type) (bool, error) {
|
||||||
isForListOfPrimitives := false
|
|
||||||
if leftDirective, ok := typedLeft[directiveMarker]; ok {
|
|
||||||
if rightDirective, ok := typedRight[directiveMarker]; ok {
|
|
||||||
if leftDirective == mergePrimitivesListDirective && rightDirective == rightDirective {
|
|
||||||
isForListOfPrimitives = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for key, leftValue := range typedLeft {
|
for key, leftValue := range typedLeft {
|
||||||
if key != directiveMarker {
|
if key != directiveMarker {
|
||||||
if rightValue, ok := typedRight[key]; ok {
|
if rightValue, ok := typedRight[key]; ok {
|
||||||
var fieldType reflect.Type
|
fieldType, fieldPatchStrategy, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadata(structType, key)
|
||||||
var fieldPatchStrategy, fieldPatchMergeKey string
|
if err != nil {
|
||||||
var err error
|
return true, err
|
||||||
if isForListOfPrimitives {
|
|
||||||
fieldType = reflect.TypeOf(leftValue)
|
|
||||||
fieldPatchStrategy = ""
|
|
||||||
fieldPatchMergeKey = ""
|
|
||||||
} else {
|
|
||||||
fieldType, fieldPatchStrategy, fieldPatchMergeKey, err = forkedjson.LookupPatchMetadata(structType, key)
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasConflicts, err := mergingMapFieldsHaveConflicts(leftValue, rightValue,
|
if hasConflicts, err := mergingMapFieldsHaveConflicts(leftValue, rightValue,
|
||||||
@ -1339,7 +1172,7 @@ func mapsOfMapsHaveConflicts(typedLeft, typedRight map[string]interface{}, struc
|
|||||||
// than from original to current. In other words, a conflict occurs if modified changes any key
|
// 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
|
// in a way that is different from how it is changed in current (e.g., deleting it, changing its
|
||||||
// value).
|
// value).
|
||||||
func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct interface{}, overwrite bool, smPatchVersion StrategicMergePatchVersion, fns ...PreconditionFunc) ([]byte, error) {
|
func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct interface{}, overwrite bool, fns ...PreconditionFunc) ([]byte, error) {
|
||||||
originalMap := map[string]interface{}{}
|
originalMap := map[string]interface{}{}
|
||||||
if len(original) > 0 {
|
if len(original) > 0 {
|
||||||
if err := json.Unmarshal(original, &originalMap); err != nil {
|
if err := json.Unmarshal(original, &originalMap); err != nil {
|
||||||
@ -1370,12 +1203,12 @@ func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct int
|
|||||||
// from original to modified. To find it, we compute deletions, which are the deletions from
|
// 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
|
// 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.
|
// deletions, and then apply delta to deletions as a patch, which should be strictly additive.
|
||||||
deltaMap, err := diffMaps(currentMap, modifiedMap, t, false, true, smPatchVersion)
|
deltaMap, err := diffMaps(currentMap, modifiedMap, t, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
deletionsMap, err := diffMaps(originalMap, modifiedMap, t, true, false, smPatchVersion)
|
deletionsMap, err := diffMaps(originalMap, modifiedMap, t, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1395,7 +1228,7 @@ func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct int
|
|||||||
// If overwrite is false, and the patch contains any keys that were changed differently,
|
// If overwrite is false, and the patch contains any keys that were changed differently,
|
||||||
// then return a conflict error.
|
// then return a conflict error.
|
||||||
if !overwrite {
|
if !overwrite {
|
||||||
changedMap, err := diffMaps(originalMap, currentMap, t, false, false, smPatchVersion)
|
changedMap, err := diffMaps(originalMap, currentMap, t, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1430,20 +1263,3 @@ func toYAML(v interface{}) (string, error) {
|
|||||||
|
|
||||||
return string(y), nil
|
return string(y), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetServerSupportedSMPatchVersion takes a discoveryClient,
|
|
||||||
// returns the max StrategicMergePatch version supported
|
|
||||||
func GetServerSupportedSMPatchVersion(discoveryClient discovery.DiscoveryInterface) (StrategicMergePatchVersion, error) {
|
|
||||||
serverVersion, err := discoveryClient.ServerVersion()
|
|
||||||
if err != nil {
|
|
||||||
return Unknown, err
|
|
||||||
}
|
|
||||||
serverGitVersion := serverVersion.GitVersion
|
|
||||||
if serverGitVersion >= string(SMPatchVersion_1_5) {
|
|
||||||
return SMPatchVersion_1_5, nil
|
|
||||||
}
|
|
||||||
if serverGitVersion >= string(SMPatchVersion_1_5) {
|
|
||||||
return SMPatchVersion_1_0, nil
|
|
||||||
}
|
|
||||||
return Unknown, fmt.Errorf("The version is too old: %v\n", serverVersion)
|
|
||||||
}
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user