From 3de11e2fa86b49e6583cff2b487b435e9e196be5 Mon Sep 17 00:00:00 2001 From: Mike Danese Date: Wed, 17 Jun 2015 16:56:55 -0700 Subject: [PATCH] reenable patch serverside using strategic-merge-patch --- contrib/completions/bash/kubectl | 2 ++ docs/kubectl_update.md | 6 +++++- docs/man/man1/kubectl-update.1 | 7 +++++++ pkg/client/fake.go | 5 +++++ pkg/kubectl/cmd/update.go | 32 ++++++++++-------------------- pkg/kubectl/interfaces.go | 2 ++ pkg/kubectl/resource/helper.go | 19 +++++++++++++----- pkg/kubectl/resource/interfaces.go | 2 ++ 8 files changed, 47 insertions(+), 28 deletions(-) diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl index adbaf2708f..dbf7584d3a 100644 --- a/contrib/completions/bash/kubectl +++ b/contrib/completions/bash/kubectl @@ -337,10 +337,12 @@ _kubectl_update() flags_completion+=("__handle_filename_extension_flag json|yaml|yml") flags+=("--help") flags+=("-h") + flags+=("--patch=") must_have_one_flag=() must_have_one_flag+=("--filename=") must_have_one_flag+=("-f") + must_have_one_flag+=("--patch=") must_have_one_noun=() } diff --git a/docs/kubectl_update.md b/docs/kubectl_update.md index 84ce14f5f6..d4b1adbac3 100644 --- a/docs/kubectl_update.md +++ b/docs/kubectl_update.md @@ -21,6 +21,9 @@ $ kubectl update -f pod.json // Update a pod based on the JSON passed into stdin. $ cat pod.json | kubectl update -f - + +// Partially update a node using strategic merge patch +kubectl --api-version=v1 update node k8s-node-1 --patch='{"spec":{"unschedulable":true}}' ``` ### Options @@ -28,6 +31,7 @@ $ cat pod.json | kubectl update -f - ``` -f, --filename=[]: Filename, directory, or URL to file to use to update the resource. -h, --help=false: help for update + --patch="": A JSON document to override the existing resource. The resource is downloaded, patched with the JSON, then updated. ``` ### Options inherited from parent commands @@ -62,6 +66,6 @@ $ cat pod.json | kubectl update -f - ### SEE ALSO * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra at 2015-05-29 01:11:24.431126385 +0000 UTC +###### Auto generated by spf13/cobra at 2015-06-18 19:03:00.935576604 +0000 UTC [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/kubectl_update.md?pixel)]() diff --git a/docs/man/man1/kubectl-update.1 b/docs/man/man1/kubectl-update.1 index 3441a6e09e..8feba20c61 100644 --- a/docs/man/man1/kubectl-update.1 +++ b/docs/man/man1/kubectl-update.1 @@ -28,6 +28,10 @@ JSON and YAML formats are accepted. \fB\-h\fP, \fB\-\-help\fP=false help for update +.PP +\fB\-\-patch\fP="" + A JSON document to override the existing resource. The resource is downloaded, patched with the JSON, then updated. + .SH OPTIONS INHERITED FROM PARENT COMMANDS .PP @@ -138,6 +142,9 @@ $ kubectl update \-f pod.json // Update a pod based on the JSON passed into stdin. $ cat pod.json | kubectl update \-f \- +// Partially update a node using strategic merge patch +kubectl \-\-api\-version=v1 update node k8s\-node\-1 \-\-patch='\{"spec":\{"unschedulable":true\}\}' + .fi .RE diff --git a/pkg/client/fake.go b/pkg/client/fake.go index 9aa059d945..a5f4c3eac2 100644 --- a/pkg/client/fake.go +++ b/pkg/client/fake.go @@ -20,6 +20,7 @@ import ( "net/http" "net/url" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" ) @@ -47,6 +48,10 @@ func (c *FakeRESTClient) Put() *Request { return NewRequest(c, "PUT", &url.URL{Host: "localhost"}, testapi.Version(), c.Codec) } +func (c *FakeRESTClient) Patch(_ api.PatchType) *Request { + return NewRequest(c, "PATCH", &url.URL{Host: "localhost"}, testapi.Version(), c.Codec) +} + func (c *FakeRESTClient) Post() *Request { return NewRequest(c, "POST", &url.URL{Host: "localhost"}, testapi.Version(), c.Codec) } diff --git a/pkg/kubectl/cmd/update.go b/pkg/kubectl/cmd/update.go index 24fea3a538..e68f7dd20e 100644 --- a/pkg/kubectl/cmd/update.go +++ b/pkg/kubectl/cmd/update.go @@ -22,6 +22,7 @@ import ( "github.com/spf13/cobra" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl" cmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource" @@ -36,7 +37,10 @@ JSON and YAML formats are accepted.` $ kubectl update -f pod.json // Update a pod based on the JSON passed into stdin. -$ cat pod.json | kubectl update -f -` +$ cat pod.json | kubectl update -f - + +// Partially update a node using strategic merge patch +kubectl --api-version=v1 update node k8s-node-1 --patch='{"spec":{"unschedulable":true}}'` ) func NewCmdUpdate(f *cmdutil.Factory, out io.Writer) *cobra.Command { @@ -54,9 +58,8 @@ func NewCmdUpdate(f *cmdutil.Factory, out io.Writer) *cobra.Command { usage := "Filename, directory, or URL to file to use to update the resource." kubectl.AddJsonFilenameFlag(cmd, &filenames, usage) cmd.MarkFlagRequired("filename") - // TODO: re-enable --patch and make it use strategic-merge-patch - // cmd.Flags().String("patch", "", "A JSON document to override the existing resource. The resource is downloaded, patched with the JSON, then updated.") - // cmd.MarkFlagRequired("patch") + cmd.Flags().String("patch", "", "A JSON document to override the existing resource. The resource is downloaded, patched with the JSON, then updated.") + cmd.MarkFlagRequired("patch") return cmd } @@ -71,7 +74,7 @@ func RunUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str return err } - /* patch := cmdutil.GetFlagString(cmd, "patch") + patch := cmdutil.GetFlagString(cmd, "patch") if len(filenames) == 0 && len(patch) == 0 { return cmdutil.UsageError(cmd, "Must specify --filename or --patch to update") } @@ -87,7 +90,7 @@ func RunUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str } fmt.Fprintf(out, "%s\n", name) return nil - } */ + } if len(filenames) == 0 { return cmdutil.UsageError(cmd, "Must specify --filename to update") } @@ -154,21 +157,6 @@ func updateWithPatch(cmd *cobra.Command, args []string, f *cmdutil.Factory, patc name, namespace := infos[0].Name, infos[0].Namespace helper := resource.NewHelper(client, mapping) - obj, err := helper.Get(namespace, name) - if err != nil { - return "", err - } - - patchedObj, err := cmdutil.Merge(obj, patch, mapping.Kind) - if err != nil { - return "", err - } - - data, err := helper.Codec.Encode(patchedObj) - if err != nil { - return "", err - } - - _, err = helper.Update(namespace, name, true, data) + _, err = helper.Patch(namespace, name, api.StrategicMergePatchType, []byte(patch)) return name, err } diff --git a/pkg/kubectl/interfaces.go b/pkg/kubectl/interfaces.go index e8c18a2122..9d8aaba780 100644 --- a/pkg/kubectl/interfaces.go +++ b/pkg/kubectl/interfaces.go @@ -17,6 +17,7 @@ limitations under the License. package kubectl import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" ) @@ -25,6 +26,7 @@ import ( type RESTClient interface { Get() *client.Request Post() *client.Request + Patch(api.PatchType) *client.Request Delete() *client.Request Put() *client.Request } diff --git a/pkg/kubectl/resource/helper.go b/pkg/kubectl/resource/helper.go index 81b7efc19c..3c95c4e093 100644 --- a/pkg/kubectl/resource/helper.go +++ b/pkg/kubectl/resource/helper.go @@ -17,6 +17,7 @@ limitations under the License. package resource import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" @@ -43,11 +44,10 @@ type Helper struct { // NewHelper creates a Helper from a ResourceMapping func NewHelper(client RESTClient, mapping *meta.RESTMapping) *Helper { return &Helper{ - RESTClient: client, - Resource: mapping.Resource, - Codec: mapping.Codec, - Versioner: mapping.MetadataAccessor, - + RESTClient: client, + Resource: mapping.Resource, + Codec: mapping.Codec, + Versioner: mapping.MetadataAccessor, NamespaceScoped: mapping.Scope.Name() == meta.RESTScopeNameNamespace, } } @@ -133,6 +133,15 @@ func (m *Helper) Create(namespace string, modify bool, data []byte) (runtime.Obj func (m *Helper) createResource(c RESTClient, resource, namespace string, data []byte) (runtime.Object, error) { return c.Post().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(resource).Body(data).Do().Get() } +func (m *Helper) Patch(namespace, name string, pt api.PatchType, data []byte) (runtime.Object, error) { + return m.RESTClient.Patch(pt). + NamespaceIfScoped(namespace, m.NamespaceScoped). + Resource(m.Resource). + Name(name). + Body(data). + Do(). + Get() +} func (m *Helper) Update(namespace, name string, overwrite bool, data []byte) (runtime.Object, error) { c := m.RESTClient diff --git a/pkg/kubectl/resource/interfaces.go b/pkg/kubectl/resource/interfaces.go index 07df2d7d10..264a3d53bc 100644 --- a/pkg/kubectl/resource/interfaces.go +++ b/pkg/kubectl/resource/interfaces.go @@ -17,6 +17,7 @@ limitations under the License. package resource import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" ) @@ -26,6 +27,7 @@ import ( type RESTClient interface { Get() *client.Request Post() *client.Request + Patch(api.PatchType) *client.Request Delete() *client.Request Put() *client.Request }