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 { | 			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
											
										
									
								
							
		Reference in New Issue
	
	Block a user
	 ymqytw
					ymqytw