Merge pull request #9993 from mikedanese/re-patch

reenable patch serverside using strategic-merge-patch
pull/6/head
Satnam Singh 2015-06-18 14:13:10 -07:00
commit d2c2f7e35e
9 changed files with 65 additions and 28 deletions

View File

@ -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=()
}

View File

@ -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)]()

View File

@ -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

View File

@ -141,6 +141,7 @@ for version in "${kube_api_versions[@]}"; do
rc_status_replicas_field=".status.replicas"
rc_container_image_field=".spec.template.spec.containers"
port_field="(index .spec.ports 0).port"
image_field="(index .spec.containers 0).image"
# Passing no arguments to create is an error
! kubectl create
@ -306,6 +307,14 @@ for version in "${kube_api_versions[@]}"; do
# Post-condition: valid-pod POD is running
kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'valid-pod:'
## --patch update pod can change image
# Pre-condition: valid-pod POD is running
kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'valid-pod:'
# Command
kubectl update "${kube_flags[@]}" pod valid-pod --patch='{"spec":{"containers":[{"name": "kubernetes-serve-hostname", "image": "nginx"}]}}'
# Post-condition: valid-pod POD has image nginx
kube::test::get_object_assert pods "{{range.items}}{{$image_field}}:{{end}}" 'nginx:'
### Overwriting an existing label is not permitted
# Pre-condition: name is valid-pod
kube::test::get_object_assert 'pod valid-pod' "{{${labels_field}.name}}" 'valid-pod'
@ -615,6 +624,15 @@ __EOF__
kube::test::describe_object_assert nodes "127.0.0.1" "Name:" "Labels:" "CreationTimestamp:" "Conditions:" "Addresses:" "Capacity:" "Pods:"
### --patch update can mark node unschedulable
# Pre-condition: node is schedulable
kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
kubectl update "${kube_flags[@]}" nodes "127.0.0.1" --patch='{"spec":{"unschedulable":true}}'
# Post-condition: node is unschedulable
kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" 'true'
kubectl update "${kube_flags[@]}" nodes "127.0.0.1" --patch='{"spec":{"unschedulable":null}}'
# Post-condition: node is schedulable
kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
###########
# Nodes #

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}