mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 10:18:13 +00:00 
			
		
		
		
	Revert "support patch list of primitives"
This reverts commit 34891ad9f6.
			
			
This commit is contained in:
		| @@ -591,11 +591,11 @@ func patchResource( | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			currentPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, currentObjectJS, versionedObj, strategicpatch.SMPatchVersionLatest) | ||||
| 			currentPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, currentObjectJS, versionedObj) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			originalPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, originalPatchedObjJS, versionedObj, strategicpatch.SMPatchVersionLatest) | ||||
| 			originalPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, originalPatchedObjJS, versionedObj) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|   | ||||
| @@ -213,7 +213,7 @@ func (tc *patchTestCase) Run(t *testing.T) { | ||||
| 			continue | ||||
|  | ||||
| 		case api.StrategicMergePatchType: | ||||
| 			patch, err = strategicpatch.CreateStrategicMergePatch(originalObjJS, changedJS, versionedObj, strategicpatch.SMPatchVersionLatest) | ||||
| 			patch, err = strategicpatch.CreateStrategicMergePatch(originalObjJS, changedJS, versionedObj) | ||||
| 			if err != nil { | ||||
| 				t.Errorf("%s: unexpected error: %v", tc.name, err) | ||||
| 				return | ||||
|   | ||||
| @@ -244,9 +244,7 @@ func (e *eventLogger) eventObserve(newEvent *api.Event) (*api.Event, []byte, err | ||||
|  | ||||
| 		newData, _ := json.Marshal(event) | ||||
| 		oldData, _ := json.Marshal(eventCopy2) | ||||
| 		// TODO: need to figure out if we need to let eventObserve() use the new behavior of StrategicMergePatch. | ||||
| 		// Currently default to old behavior now. Ref: issue #35936 | ||||
| 		patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event, strategicpatch.SMPatchVersion_1_0) | ||||
| 		patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event) | ||||
| 	} | ||||
|  | ||||
| 	// record our new observation | ||||
|   | ||||
| @@ -59,10 +59,6 @@ type nodeStatusUpdater struct { | ||||
| } | ||||
|  | ||||
| func (nsu *nodeStatusUpdater) UpdateNodeStatuses() error { | ||||
| 	smPatchVersion, err := strategicpatch.GetServerSupportedSMPatchVersion(nsu.kubeClient.Discovery()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	nodesToUpdate := nsu.actualStateOfWorld.GetVolumesToReportAttached() | ||||
| 	for nodeName, attachedVolumes := range nodesToUpdate { | ||||
| 		nodeObj, exists, err := nsu.nodeInformer.GetStore().GetByKey(string(nodeName)) | ||||
| @@ -112,7 +108,7 @@ func (nsu *nodeStatusUpdater) UpdateNodeStatuses() error { | ||||
| 		} | ||||
|  | ||||
| 		patchBytes, err := | ||||
| 			strategicpatch.CreateStrategicMergePatch(oldData, newData, node, smPatchVersion) | ||||
| 			strategicpatch.CreateStrategicMergePatch(oldData, newData, node) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf( | ||||
| 				"failed to CreateStrategicMergePatch for node %q. %v", | ||||
|   | ||||
| @@ -194,7 +194,6 @@ go_test( | ||||
|         "//pkg/util/strings:go_default_library", | ||||
|         "//pkg/util/term:go_default_library", | ||||
|         "//pkg/util/wait:go_default_library", | ||||
|         "//pkg/version:go_default_library", | ||||
|         "//pkg/watch:go_default_library", | ||||
|         "//pkg/watch/versioned:go_default_library", | ||||
|         "//vendor:github.com/spf13/cobra", | ||||
|   | ||||
| @@ -223,12 +223,6 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro | ||||
| 			} | ||||
| 			outputObj = obj | ||||
| 		} 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 | ||||
| 			oldData, err := json.Marshal(obj) | ||||
| 			if err != nil { | ||||
| @@ -245,7 +239,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, smPatchVersion) | ||||
| 			patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj) | ||||
| 			createdPatch := err == nil | ||||
| 			if err != nil { | ||||
| 				glog.V(2).Infof("couldn't compute patch: %v", err) | ||||
|   | ||||
| @@ -24,6 +24,8 @@ import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"k8s.io/kubernetes/pkg/api" | ||||
| 	"k8s.io/kubernetes/pkg/apimachinery/registered" | ||||
| 	"k8s.io/kubernetes/pkg/client/restclient" | ||||
| 	"k8s.io/kubernetes/pkg/client/restclient/fake" | ||||
| 	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" | ||||
| 	"k8s.io/kubernetes/pkg/runtime" | ||||
| @@ -392,7 +394,7 @@ func TestAnnotateErrors(t *testing.T) { | ||||
| 		f, tf, _, _ := cmdtesting.NewAPIFactory() | ||||
| 		tf.Printer = &testPrinter{} | ||||
| 		tf.Namespace = "test" | ||||
| 		tf.ClientConfig = defaultClientConfig() | ||||
| 		tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}} | ||||
|  | ||||
| 		buf := bytes.NewBuffer([]byte{}) | ||||
| 		cmd := NewCmdAnnotate(f, buf) | ||||
| @@ -430,12 +432,6 @@ func TestAnnotateObject(t *testing.T) { | ||||
| 			switch req.Method { | ||||
| 			case "GET": | ||||
| 				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": | ||||
| 					return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil | ||||
| 				default: | ||||
| @@ -457,7 +453,7 @@ func TestAnnotateObject(t *testing.T) { | ||||
| 		}), | ||||
| 	} | ||||
| 	tf.Namespace = "test" | ||||
| 	tf.ClientConfig = defaultClientConfig() | ||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}} | ||||
|  | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
| 	cmd := NewCmdAnnotate(f, buf) | ||||
| @@ -486,12 +482,6 @@ func TestAnnotateObjectFromFile(t *testing.T) { | ||||
| 			switch req.Method { | ||||
| 			case "GET": | ||||
| 				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": | ||||
| 					return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil | ||||
| 				default: | ||||
| @@ -513,7 +503,7 @@ func TestAnnotateObjectFromFile(t *testing.T) { | ||||
| 		}), | ||||
| 	} | ||||
| 	tf.Namespace = "test" | ||||
| 	tf.ClientConfig = defaultClientConfig() | ||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}} | ||||
|  | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
| 	cmd := NewCmdAnnotate(f, buf) | ||||
| @@ -542,7 +532,7 @@ func TestAnnotateLocal(t *testing.T) { | ||||
| 		}), | ||||
| 	} | ||||
| 	tf.Namespace = "test" | ||||
| 	tf.ClientConfig = defaultClientConfig() | ||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}} | ||||
|  | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
| 	cmd := NewCmdAnnotate(f, buf) | ||||
| @@ -572,12 +562,6 @@ func TestAnnotateMultipleObjects(t *testing.T) { | ||||
| 			switch req.Method { | ||||
| 			case "GET": | ||||
| 				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": | ||||
| 					return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil | ||||
| 				default: | ||||
| @@ -601,7 +585,7 @@ func TestAnnotateMultipleObjects(t *testing.T) { | ||||
| 		}), | ||||
| 	} | ||||
| 	tf.Namespace = "test" | ||||
| 	tf.ClientConfig = defaultClientConfig() | ||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}} | ||||
|  | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
| 	cmd := NewCmdAnnotate(f, buf) | ||||
|   | ||||
| @@ -195,11 +195,6 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *App | ||||
| 	visitedUids := sets.NewString() | ||||
| 	visitedNamespaces := sets.NewString() | ||||
|  | ||||
| 	smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(f) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	count := 0 | ||||
| 	err = r.Visit(func(info *resource.Info, err error) error { | ||||
| 		// 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, | ||||
| 			} | ||||
|  | ||||
| 			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 { | ||||
| 				return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patchBytes, info), info.Source, err) | ||||
| 			} | ||||
|  | ||||
| 			if cmdutil.ShouldRecord(cmd, info) { | ||||
| 				patch, err := cmdutil.ChangeResourcePatch(info, f.Command(), smPatchVersion) | ||||
| 				patch, err := cmdutil.ChangeResourcePatch(info, f.Command()) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| @@ -512,7 +507,7 @@ type patcher struct { | ||||
| 	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. | ||||
| 	current, err := runtime.Encode(p.encoder, obj) | ||||
| 	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. | ||||
| 	patch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, versionedObject, p.overwrite, smPatchVersion) | ||||
|  | ||||
| 	patch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, versionedObject, p.overwrite) | ||||
| 	if err != nil { | ||||
| 		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) | ||||
| @@ -547,9 +541,9 @@ func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, names | ||||
| 	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 | ||||
| 	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++ { | ||||
| 		if i > triesBeforeBackOff { | ||||
| 			p.backOff.Sleep(backOffPeriod) | ||||
| @@ -558,7 +552,7 @@ func (p *patcher) patch(current runtime.Object, modified []byte, source, namespa | ||||
| 		if getErr != nil { | ||||
| 			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 { | ||||
| 		patchBytes, err = p.deleteAndCreate(modified, namespace, name) | ||||
|   | ||||
| @@ -188,12 +188,6 @@ func TestApplyObject(t *testing.T) { | ||||
| 		NegotiatedSerializer: ns, | ||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||
| 			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": | ||||
| 				bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC)) | ||||
| 				return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil | ||||
| @@ -208,7 +202,6 @@ func TestApplyObject(t *testing.T) { | ||||
| 		}), | ||||
| 	} | ||||
| 	tf.Namespace = "test" | ||||
| 	tf.ClientConfig = defaultClientConfig() | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
|  | ||||
| 	cmd := NewCmdApply(f, buf) | ||||
| @@ -237,12 +230,6 @@ func TestApplyRetry(t *testing.T) { | ||||
| 		NegotiatedSerializer: ns, | ||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||
| 			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": | ||||
| 				getCount++ | ||||
| 				bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC)) | ||||
| @@ -266,7 +253,6 @@ func TestApplyRetry(t *testing.T) { | ||||
| 		}), | ||||
| 	} | ||||
| 	tf.Namespace = "test" | ||||
| 	tf.ClientConfig = defaultClientConfig() | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
|  | ||||
| 	cmd := NewCmdApply(f, buf) | ||||
| @@ -296,12 +282,6 @@ func TestApplyNonExistObject(t *testing.T) { | ||||
| 		NegotiatedSerializer: ns, | ||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||
| 			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": | ||||
| 				return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil | ||||
| 			case p == pathNameRC && m == "GET": | ||||
| @@ -316,7 +296,6 @@ func TestApplyNonExistObject(t *testing.T) { | ||||
| 		}), | ||||
| 	} | ||||
| 	tf.Namespace = "test" | ||||
| 	tf.ClientConfig = defaultClientConfig() | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
|  | ||||
| 	cmd := NewCmdApply(f, buf) | ||||
| @@ -352,12 +331,6 @@ func testApplyMultipleObjects(t *testing.T, asList bool) { | ||||
| 		NegotiatedSerializer: ns, | ||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||
| 			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": | ||||
| 				bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC)) | ||||
| 				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.ClientConfig = defaultClientConfig() | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
|  | ||||
| 	cmd := NewCmdApply(f, buf) | ||||
|   | ||||
| @@ -39,13 +39,8 @@ import ( | ||||
| 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | ||||
| 	"k8s.io/kubernetes/pkg/runtime" | ||||
| 	"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) { | ||||
| 	cmdutil.BehaviorOnFatal(func(str string, code int) { | ||||
| 		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 { | ||||
| 			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: | ||||
| 				err = visitToCreate(updates, mapper, resourceMapper, out, errOut, defaultVersion, &results, file) | ||||
| 			default: | ||||
| @@ -415,22 +415,9 @@ func getMapperAndResult(f cmdutil.Factory, args []string, options *resource.File | ||||
| 	return mapper, resourceMapper, r, cmdNamespace, err | ||||
| } | ||||
|  | ||||
| func visitToPatch(originalObj runtime.Object, updates *resource.Info, | ||||
| 	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 | ||||
| 	} | ||||
|  | ||||
| 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 { | ||||
| 	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 | ||||
|  | ||||
| 		// 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"), | ||||
| 			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 { | ||||
| 			glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err) | ||||
| 			if strategicpatch.IsPreconditionFailed(err) { | ||||
|   | ||||
| @@ -192,14 +192,6 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error { | ||||
| 		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 | ||||
| 	if !one && len(o.resourceVersion) > 0 { | ||||
| 		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) { | ||||
| 				dataChangeMsg = "labeled" | ||||
| 			} | ||||
| 			patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, smPatchVersion) | ||||
| 			patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj) | ||||
| 			createdPatch := err == nil | ||||
| 			if err != nil { | ||||
| 				glog.V(2).Infof("couldn't compute patch: %v", err) | ||||
|   | ||||
| @@ -354,12 +354,6 @@ func TestLabelForResourceFromFile(t *testing.T) { | ||||
| 			switch req.Method { | ||||
| 			case "GET": | ||||
| 				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": | ||||
| 					return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil | ||||
| 				default: | ||||
| @@ -381,7 +375,7 @@ func TestLabelForResourceFromFile(t *testing.T) { | ||||
| 		}), | ||||
| 	} | ||||
| 	tf.Namespace = "test" | ||||
| 	tf.ClientConfig = defaultClientConfig() | ||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}} | ||||
|  | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
| 	cmd := NewCmdLabel(f, buf) | ||||
| @@ -443,12 +437,6 @@ func TestLabelMultipleObjects(t *testing.T) { | ||||
| 			switch req.Method { | ||||
| 			case "GET": | ||||
| 				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": | ||||
| 					return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil | ||||
| 				default: | ||||
| @@ -472,7 +460,7 @@ func TestLabelMultipleObjects(t *testing.T) { | ||||
| 		}), | ||||
| 	} | ||||
| 	tf.Namespace = "test" | ||||
| 	tf.ClientConfig = defaultClientConfig() | ||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}} | ||||
|  | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
| 	cmd := NewCmdLabel(f, buf) | ||||
|   | ||||
| @@ -154,14 +154,6 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	smPatchVersion := strategicpatch.SMPatchVersionLatest | ||||
| 	if !options.Local { | ||||
| 		smPatchVersion, err = cmdutil.GetServerSupportedSMPatchVersionFromFactory(f) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	count := 0 | ||||
| 	err = r.Visit(func(info *resource.Info, err error) error { | ||||
| 		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 | ||||
| 				// 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 | ||||
| 				patch, err := cmdutil.ChangeResourcePatch(info, f.Command(), smPatchVersion) | ||||
| 				patch, err := cmdutil.ChangeResourcePatch(info, f.Command()) | ||||
| 				if err == nil { | ||||
| 					helper.Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch) | ||||
| 				} | ||||
|   | ||||
| @@ -34,12 +34,6 @@ func TestPatchObject(t *testing.T) { | ||||
| 		NegotiatedSerializer: ns, | ||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||
| 			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"): | ||||
| 				return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &svc.Items[0])}, nil | ||||
| 			default: | ||||
| @@ -49,7 +43,6 @@ func TestPatchObject(t *testing.T) { | ||||
| 		}), | ||||
| 	} | ||||
| 	tf.Namespace = "test" | ||||
| 	tf.ClientConfig = defaultClientConfig() | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
|  | ||||
| 	cmd := NewCmdPatch(f, buf) | ||||
| @@ -73,12 +66,6 @@ func TestPatchObjectFromFile(t *testing.T) { | ||||
| 		NegotiatedSerializer: ns, | ||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||
| 			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"): | ||||
| 				return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &svc.Items[0])}, nil | ||||
| 			default: | ||||
| @@ -88,7 +75,6 @@ func TestPatchObjectFromFile(t *testing.T) { | ||||
| 		}), | ||||
| 	} | ||||
| 	tf.Namespace = "test" | ||||
| 	tf.ClientConfig = defaultClientConfig() | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
|  | ||||
| 	cmd := NewCmdPatch(f, buf) | ||||
|   | ||||
| @@ -38,7 +38,6 @@ import ( | ||||
| type PauseConfig struct { | ||||
| 	resource.FilenameOptions | ||||
|  | ||||
| 	f       cmdutil.Factory | ||||
| 	Pauser  func(info *resource.Info) (bool, error) | ||||
| 	Mapper  meta.RESTMapper | ||||
| 	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) | ||||
| 	} | ||||
|  | ||||
| 	o.f = f | ||||
| 	o.Mapper, o.Typer = f.Object() | ||||
| 	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 { | ||||
| 	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 | ||||
| 		if patch.Err != nil { | ||||
| 			allErrs = append(allErrs, fmt.Errorf("error: %s %q %v", info.Mapping.Resource, info.Name, patch.Err)) | ||||
|   | ||||
| @@ -38,7 +38,6 @@ import ( | ||||
| type ResumeConfig struct { | ||||
| 	resource.FilenameOptions | ||||
|  | ||||
| 	f       cmdutil.Factory | ||||
| 	Resumer func(object *resource.Info) (bool, error) | ||||
| 	Mapper  meta.RESTMapper | ||||
| 	Typer   runtime.ObjectTyper | ||||
| @@ -98,7 +97,6 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, out | ||||
| 		return cmdutil.UsageError(cmd, cmd.Use) | ||||
| 	} | ||||
|  | ||||
| 	o.f = f | ||||
| 	o.Mapper, o.Typer = f.Object() | ||||
| 	o.Encoder = f.JSONEncoder() | ||||
|  | ||||
| @@ -138,7 +136,7 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, out | ||||
|  | ||||
| func (o ResumeConfig) RunResume() 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 | ||||
|  | ||||
| 		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") | ||||
| 	} | ||||
|  | ||||
| 	smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(f) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	counter := 0 | ||||
| 	err = r.Visit(func(info *resource.Info, err error) error { | ||||
| 		if err != nil { | ||||
| @@ -169,7 +164,7 @@ func RunScale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin | ||||
| 			return err | ||||
| 		} | ||||
| 		if cmdutil.ShouldRecord(cmd, info) { | ||||
| 			patchBytes, err := cmdutil.ChangeResourcePatch(info, f.Command(), smPatchVersion) | ||||
| 			patchBytes, err := cmdutil.ChangeResourcePatch(info, f.Command()) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|   | ||||
| @@ -23,7 +23,7 @@ import ( | ||||
|  | ||||
| 	"k8s.io/kubernetes/pkg/api" | ||||
| 	"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/runtime" | ||||
| 	"k8s.io/kubernetes/pkg/util/strategicpatch" | ||||
| @@ -61,7 +61,7 @@ func handlePodUpdateError(out io.Writer, err error, resource string) { | ||||
| 				return | ||||
| 			} | ||||
| 		} else { | ||||
| 			if ok := cmdutil.PrintErrorWithCauses(err, out); ok { | ||||
| 			if ok := kcmdutil.PrintErrorWithCauses(err, out); ok { | ||||
| 				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 | ||||
| // 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. | ||||
| // If local is true, it will be default to use SMPatchVersionLatest to calculate a patch without contacting the server to | ||||
| // 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 { | ||||
| func CalculatePatches(infos []*resource.Info, encoder runtime.Encoder, mutateFn func(*resource.Info) (bool, error)) []*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 { | ||||
| 		patch := &Patch{Info: info} | ||||
| 		patch.Before, patch.Err = runtime.Encode(encoder, info.Object) | ||||
| @@ -168,7 +156,7 @@ func CalculatePatches(f cmdutil.Factory, infos []*resource.Info, encoder runtime | ||||
| 			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 | ||||
| } | ||||
|   | ||||
| @@ -28,7 +28,6 @@ import ( | ||||
| 	"k8s.io/kubernetes/pkg/kubectl/resource" | ||||
| 	"k8s.io/kubernetes/pkg/runtime" | ||||
| 	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 | ||||
| @@ -36,7 +35,6 @@ import ( | ||||
| type ImageOptions struct { | ||||
| 	resource.FilenameOptions | ||||
|  | ||||
| 	f           cmdutil.Factory | ||||
| 	Mapper      meta.RESTMapper | ||||
| 	Typer       runtime.ObjectTyper | ||||
| 	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 { | ||||
| 	o.f = f | ||||
| 	o.Mapper, o.Typer = f.Object() | ||||
| 	o.UpdatePodSpecForObject = f.UpdatePodSpecForObject | ||||
| 	o.Encoder = f.JSONEncoder() | ||||
| @@ -165,7 +162,7 @@ func (o *ImageOptions) Validate() error { | ||||
| func (o *ImageOptions) Run() 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 | ||||
| 		_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error { | ||||
| 			for name, image := range o.ContainerImages { | ||||
| @@ -189,14 +186,6 @@ func (o *ImageOptions) Run() error { | ||||
| 		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 { | ||||
| 		info := patch.Info | ||||
| 		if patch.Err != nil { | ||||
| @@ -223,7 +212,7 @@ func (o *ImageOptions) Run() error { | ||||
|  | ||||
| 		// record this change (for rollout history) | ||||
| 		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 { | ||||
| 					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 { | ||||
| 	resource.FilenameOptions | ||||
|  | ||||
| 	f                 cmdutil.Factory | ||||
| 	Mapper            meta.RESTMapper | ||||
| 	Typer             runtime.ObjectTyper | ||||
| 	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 { | ||||
| 	o.f = f | ||||
| 	o.Mapper, o.Typer = f.Object() | ||||
| 	o.UpdatePodSpecForObject = f.UpdatePodSpecForObject | ||||
| 	o.Encoder = f.JSONEncoder() | ||||
| @@ -176,7 +174,7 @@ func (o *ResourcesOptions) Validate() error { | ||||
|  | ||||
| func (o *ResourcesOptions) Run() 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 | ||||
| 		_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error { | ||||
| 			containers, _ := selectContainers(spec.Containers, o.ContainerSelector) | ||||
|   | ||||
| @@ -321,11 +321,6 @@ func (o TaintOptions) RunTaint() error { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(o.f) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return r.Visit(func(info *resource.Info, err error) error { | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| @@ -348,7 +343,7 @@ func (o TaintOptions) RunTaint() error { | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, smPatchVersion) | ||||
| 		patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj) | ||||
| 		createdPatch := err == nil | ||||
| 		if err != nil { | ||||
| 			glog.V(2).Infof("couldn't compute patch: %v", err) | ||||
|   | ||||
| @@ -252,6 +252,7 @@ func TestTaint(t *testing.T) { | ||||
|  | ||||
| 	for _, test := range tests { | ||||
| 		oldNode, expectNewNode := generateNodeAndTaintedNode(test.oldTaints, test.newTaints) | ||||
|  | ||||
| 		new_node := &api.Node{} | ||||
| 		tainted := false | ||||
| 		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) { | ||||
| 				m := &MyReq{req} | ||||
| 				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"): | ||||
| 					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"): | ||||
|   | ||||
| @@ -521,7 +521,7 @@ func RecordChangeCause(obj runtime.Object, changeCause string) error { | ||||
|  | ||||
| // ChangeResourcePatch creates a strategic merge patch between the origin 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) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| @@ -533,7 +533,7 @@ func ChangeResourcePatch(info *resource.Info, changeCause string, smPatchVersion | ||||
| 	if err != nil { | ||||
| 		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. | ||||
| @@ -725,13 +725,3 @@ func RequireNoArguments(c *cobra.Command, args []string) { | ||||
| 		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"], | ||||
|     tags = ["automanaged"], | ||||
|     deps = [ | ||||
|         "//pkg/client/typed/discovery:go_default_library", | ||||
|         "//pkg/util/json:go_default_library", | ||||
|         "//third_party/forked/golang/json:go_default_library", | ||||
|         "//vendor:github.com/davecgh/go-spew/spew", | ||||
|   | ||||
| @@ -21,7 +21,6 @@ import ( | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
|  | ||||
| 	"k8s.io/kubernetes/pkg/client/typed/discovery" | ||||
| 	"k8s.io/kubernetes/pkg/util/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 | ||||
| // evanphx/json-patch and openshift/origin. | ||||
|  | ||||
| type StrategicMergePatchVersion string | ||||
|  | ||||
| const ( | ||||
| 	directiveMarker  = "$patch" | ||||
| 	deleteDirective  = "delete" | ||||
| 	replaceDirective = "replace" | ||||
| 	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 | ||||
| @@ -97,7 +87,6 @@ func IsConflict(err error) bool { | ||||
|  | ||||
| var errBadJSONDoc = fmt.Errorf("Invalid JSON document") | ||||
| 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. | ||||
| // 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. | ||||
| func CreateStrategicMergePatch(original, modified []byte, dataStruct interface{}, smPatchVersion StrategicMergePatchVersion) ([]byte, error) { | ||||
| 	return CreateTwoWayMergePatch(original, modified, dataStruct, smPatchVersion) | ||||
| func CreateStrategicMergePatch(original, modified []byte, dataStruct interface{}) ([]byte, error) { | ||||
| 	return CreateTwoWayMergePatch(original, modified, dataStruct) | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| // 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. | ||||
| 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{}{} | ||||
| 	if len(original) > 0 { | ||||
| 		if err := json.Unmarshal(original, &originalMap); err != nil { | ||||
| @@ -172,7 +161,7 @@ func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, s | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	patchMap, err := diffMaps(originalMap, modifiedMap, t, false, false, smPatchVersion) | ||||
| 	patchMap, err := diffMaps(originalMap, modifiedMap, t, false, false) | ||||
| 	if err != nil { | ||||
| 		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. | ||||
| 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{}{} | ||||
| 	if t.Kind() == reflect.Ptr { | ||||
| 		t = t.Elem() | ||||
| @@ -241,7 +230,7 @@ func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreC | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			patchValue, err := diffMaps(originalValueTyped, modifiedValueTyped, fieldType, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion) | ||||
| 			patchValue, err := diffMaps(originalValueTyped, modifiedValueTyped, fieldType, ignoreChangesAndAdditions, ignoreDeletions) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| @@ -259,25 +248,13 @@ func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreC | ||||
| 			} | ||||
|  | ||||
| 			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 { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				if patchValue == nil { | ||||
| 					continue | ||||
| 				} | ||||
|  | ||||
| 				switch typedPatchValue := patchValue.(type) { | ||||
| 				case []interface{}: | ||||
| 					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)) | ||||
| 				if len(patchValue) > 0 { | ||||
| 					patch[key] = patchValue | ||||
| 				} | ||||
|  | ||||
| 				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, | ||||
| // 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(modified) == 0 || ignoreChangesAndAdditions { | ||||
| 			return nil, nil | ||||
| @@ -321,14 +298,12 @@ func diffLists(original, modified []interface{}, t reflect.Type, mergeKey string | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var patch interface{} | ||||
| 	var patch []interface{} | ||||
|  | ||||
| 	if elementType.Kind() == reflect.Map { | ||||
| 		patch, err = diffListsOfMaps(original, modified, t, mergeKey, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion) | ||||
| 	} else if elementType.Kind() == reflect.Slice { | ||||
| 		err = errNoListOfLists | ||||
| 	} else { | ||||
| 		patch, err = diffListsOfScalars(original, modified, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion) | ||||
| 		patch, err = diffListsOfMaps(original, modified, t, mergeKey, ignoreChangesAndAdditions, ignoreDeletions) | ||||
| 	} else if !ignoreChangesAndAdditions { | ||||
| 		patch, err = diffListsOfScalars(original, modified) | ||||
| 	} | ||||
|  | ||||
| 	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, | ||||
| // for a pair of lists of scalars with merge semantics. | ||||
| func diffListsOfScalars(original, modified []interface{}, ignoreChangesAndAdditions, ignoreDeletions bool, smPatchVersion StrategicMergePatchVersion) (interface{}, error) { | ||||
| 	originalScalars := uniqifyAndSortScalars(original) | ||||
| 	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 { | ||||
| func diffListsOfScalars(original, modified []interface{}) ([]interface{}, error) { | ||||
| 	if len(modified) == 0 { | ||||
| 		// 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. | ||||
| 		return nil, nil | ||||
| @@ -364,14 +324,18 @@ func diffListsOfScalarsIntoSlice(originalScalars, modifiedScalars []interface{}, | ||||
|  | ||||
| 	patch := []interface{}{} | ||||
|  | ||||
| 	originalScalars := uniqifyAndSortScalars(original) | ||||
| 	modifiedScalars := uniqifyAndSortScalars(modified) | ||||
| 	originalIndex, modifiedIndex := 0, 0 | ||||
|  | ||||
| loopB: | ||||
| 	for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ { | ||||
| 		for ; originalIndex < len(originalScalars); originalIndex++ { | ||||
| 			originalString := fmt.Sprintf("%v", originalScalars[originalIndex]) | ||||
| 			modifiedString := fmt.Sprintf("%v", modifiedScalars[modifiedIndex]) | ||||
| 			originalString := fmt.Sprintf("%v", original[originalIndex]) | ||||
| 			modifiedString := fmt.Sprintf("%v", modified[modifiedIndex]) | ||||
| 			if originalString >= modifiedString { | ||||
| 				if originalString != modifiedString { | ||||
| 					patch = append(patch, modifiedScalars[modifiedIndex]) | ||||
| 					patch = append(patch, modified[modifiedIndex]) | ||||
| 				} | ||||
|  | ||||
| 				continue loopB | ||||
| @@ -385,57 +349,7 @@ loopB: | ||||
|  | ||||
| 	// Add any remaining items found only in modified | ||||
| 	for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ { | ||||
| 		patch = append(patch, modifiedScalars[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 | ||||
| 		} | ||||
| 		patch = append(patch, modified[modifiedIndex]) | ||||
| 	} | ||||
|  | ||||
| 	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, | ||||
| // 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) | ||||
|  | ||||
| 	originalSorted, err := sortMergeListsByNameArray(original, t, mergeKey, false) | ||||
| @@ -492,7 +406,7 @@ loopB: | ||||
| 			if originalString >= modifiedString { | ||||
| 				if originalString == modifiedString { | ||||
| 					// 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 { | ||||
| 						return nil, err | ||||
| 					} | ||||
| @@ -628,16 +542,8 @@ func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[strin | ||||
| 			return map[string]interface{}{}, nil | ||||
| 		} | ||||
|  | ||||
| 		if v == mergePrimitivesListDirective { | ||||
| 			// 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. | ||||
| 	// If original is nil, replace it with an empty map and then apply the patch. | ||||
| @@ -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. | ||||
| 		originalType := reflect.TypeOf(original[k]) | ||||
| 		patchType := reflect.TypeOf(patchV) | ||||
| 		// check if we are trying to merge a slice with a map for list of primitives | ||||
| 		isMergeSliceOfPrimitivesWithAPatchMap := originalType != nil && patchType != nil && originalType.Kind() == reflect.Slice && patchType.Kind() == reflect.Map | ||||
| 		if originalType == patchType || isMergeSliceOfPrimitivesWithAPatchMap { | ||||
| 		if originalType == patchType { | ||||
| 			// First find the fieldPatchStrategy and fieldPatchMergeKey. | ||||
| 			fieldType, fieldPatchStrategy, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadata(t, k) | ||||
| 			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 { | ||||
| 				elemType := fieldType.Elem() | ||||
| 				typedOriginal := original[k].([]interface{}) | ||||
| 				typedPatch := patchV.([]interface{}) | ||||
| 				var err error | ||||
| 				original[k], err = mergeSlice(typedOriginal, patchV, elemType, fieldPatchMergeKey) | ||||
| 				original[k], err = mergeSlice(typedOriginal, typedPatch, elemType, fieldPatchMergeKey) | ||||
| 				if err != nil { | ||||
| 					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 | ||||
| // the patch because getting a deep copy of a slice in golang is highly | ||||
| // non-trivial. | ||||
| // The patch could be a map[string]interface{} representing a slice of primitives. | ||||
| // If the patch map doesn't has the specific directiveMarker (mergePrimitivesListDirective), | ||||
| // 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 { | ||||
| func mergeSlice(original, patch []interface{}, elemType reflect.Type, mergeKey string) ([]interface{}, error) { | ||||
| 	if len(original) == 0 && len(patch) == 0 { | ||||
| 		return original, nil | ||||
| 	} | ||||
|  | ||||
| 	// 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 { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -754,7 +638,7 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type | ||||
| 	if t.Kind() != reflect.Map { | ||||
| 		// Maybe in the future add a "concat" mode that doesn't | ||||
| 		// uniqify. | ||||
| 		both := append(original, typedPatch...) | ||||
| 		both := append(original, patch...) | ||||
| 		return uniqifyScalars(both), nil | ||||
| 	} | ||||
|  | ||||
| @@ -765,7 +649,7 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type | ||||
| 	// First look for any special $patch elements. | ||||
| 	patchWithoutSpecialElements := []interface{}{} | ||||
| 	replace := false | ||||
| 	for _, v := range typedPatch { | ||||
| 	for _, v := range patch { | ||||
| 		typedV := v.(map[string]interface{}) | ||||
| 		patchType, ok := typedV[directiveMarker] | ||||
| 		if ok { | ||||
| @@ -801,10 +685,10 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type | ||||
| 		return patchWithoutSpecialElements, nil | ||||
| 	} | ||||
|  | ||||
| 	typedPatch = patchWithoutSpecialElements | ||||
| 	patch = patchWithoutSpecialElements | ||||
|  | ||||
| 	// Merge patch into original. | ||||
| 	for _, v := range typedPatch { | ||||
| 	for _, v := range patch { | ||||
| 		// Because earlier we confirmed that all the elements are maps. | ||||
| 		typedV := v.(map[string]interface{}) | ||||
| 		mergeValue, ok := typedV[mergeKey] | ||||
| @@ -837,36 +721,6 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type | ||||
| 	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. | ||||
| func findMapInSliceBasedOnKeyValue(m []interface{}, key string, value interface{}) (map[string]interface{}, int, bool, error) { | ||||
| 	for k, v := range m { | ||||
| @@ -1092,7 +946,7 @@ func sliceElementType(slices ...[]interface{}) (reflect.Type, error) { | ||||
| 	} | ||||
|  | ||||
| 	if prevType == nil { | ||||
| 		return nil, errNoElementsInSlice | ||||
| 		return nil, fmt.Errorf("no elements in any of the given slices") | ||||
| 	} | ||||
|  | ||||
| 	return prevType, nil | ||||
| @@ -1181,10 +1035,6 @@ func mergingMapFieldsHaveConflicts( | ||||
| 				if leftMarker != rightMarker { | ||||
| 					return true, nil | ||||
| 				} | ||||
|  | ||||
| 				if leftMarker == mergePrimitivesListDirective && rightMarker == mergePrimitivesListDirective { | ||||
| 					return false, nil | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			// Check the individual keys. | ||||
| @@ -1207,30 +1057,13 @@ func mergingMapFieldsHaveConflicts( | ||||
| } | ||||
|  | ||||
| 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 { | ||||
| 		if key != directiveMarker { | ||||
| 			if rightValue, ok := typedRight[key]; ok { | ||||
| 				var fieldType reflect.Type | ||||
| 				var fieldPatchStrategy, fieldPatchMergeKey string | ||||
| 				var err error | ||||
| 				if isForListOfPrimitives { | ||||
| 					fieldType = reflect.TypeOf(leftValue) | ||||
| 					fieldPatchStrategy = "" | ||||
| 					fieldPatchMergeKey = "" | ||||
| 				} else { | ||||
| 					fieldType, fieldPatchStrategy, fieldPatchMergeKey, err = forkedjson.LookupPatchMetadata(structType, key) | ||||
| 				fieldType, fieldPatchStrategy, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadata(structType, key) | ||||
| 				if err != nil { | ||||
| 					return true, err | ||||
| 				} | ||||
| 				} | ||||
|  | ||||
| 				if hasConflicts, err := mergingMapFieldsHaveConflicts(leftValue, rightValue, | ||||
| 					fieldType, fieldPatchStrategy, fieldPatchMergeKey); hasConflicts { | ||||
| @@ -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 | ||||
| // in a way that is different from how it is changed in current (e.g., deleting it, changing its | ||||
| // 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{}{} | ||||
| 	if len(original) > 0 { | ||||
| 		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 | ||||
| 	// 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. | ||||
| 	deltaMap, err := diffMaps(currentMap, modifiedMap, t, false, true, smPatchVersion) | ||||
| 	deltaMap, err := diffMaps(currentMap, modifiedMap, t, false, true) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	deletionsMap, err := diffMaps(originalMap, modifiedMap, t, true, false, smPatchVersion) | ||||
| 	deletionsMap, err := diffMaps(originalMap, modifiedMap, t, true, false) | ||||
| 	if err != nil { | ||||
| 		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, | ||||
| 	// then return a conflict error. | ||||
| 	if !overwrite { | ||||
| 		changedMap, err := diffMaps(originalMap, currentMap, t, false, false, smPatchVersion) | ||||
| 		changedMap, err := diffMaps(originalMap, currentMap, t, false, false) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -1430,20 +1263,3 @@ func toYAML(v interface{}) (string, error) { | ||||
|  | ||||
| 	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
											
										
									
								
							
		Reference in New Issue
	
	Block a user
	 ymqytw
					ymqytw