Merge pull request #12388 from feihujiang/kubectlPatchAcceptFileNameParam
Auto commit by PR queue bot
This commit is contained in:
@@ -17,11 +17,12 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
)
|
||||
@@ -36,13 +37,16 @@ Please refer to the models in https://htmlpreview.github.io/?https://github.com/
|
||||
# Partially update a node using strategic merge patch
|
||||
kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}'
|
||||
|
||||
# Partially update a node identified by the type and name specified in "node.json" using strategic merge patch
|
||||
kubectl patch -f node.json -p '{"spec":{"unschedulable":true}}'
|
||||
|
||||
# Update a container's image; spec.containers[*].name is required because it's a merge key
|
||||
kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'`
|
||||
)
|
||||
|
||||
func NewCmdPatch(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "patch TYPE NAME -p PATCH",
|
||||
Use: "patch (-f FILENAME | TYPE NAME) -p PATCH",
|
||||
Short: "Update field(s) of a resource by stdin.",
|
||||
Long: patch_long,
|
||||
Example: patch_example,
|
||||
@@ -56,11 +60,14 @@ func NewCmdPatch(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
cmd.Flags().StringP("patch", "p", "", "The patch to be applied to the resource JSON file.")
|
||||
cmd.MarkFlagRequired("patch")
|
||||
cmdutil.AddOutputFlagsForMutation(cmd)
|
||||
|
||||
usage := "Filename, directory, or URL to a file identifying the resource to update"
|
||||
kubectl.AddJsonFilenameFlag(cmd, usage)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunPatch(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, shortOutput bool) error {
|
||||
cmdNamespace, _, err := f.DefaultNamespace()
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -74,6 +81,7 @@ func RunPatch(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, cmdutil.GetFlagStringSlice(cmd, "filename")...).
|
||||
ResourceTypeOrNameArgs(false, args...).
|
||||
Flatten().
|
||||
Do()
|
||||
@@ -81,20 +89,21 @@ func RunPatch(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mapping, err := r.ResourceMapping()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := f.RESTClient(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
infos, err := r.Infos()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name, namespace := infos[0].Name, infos[0].Namespace
|
||||
if len(infos) > 1 {
|
||||
return fmt.Errorf("multiple resources provided")
|
||||
}
|
||||
info := infos[0]
|
||||
name, namespace := info.Name, info.Namespace
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := f.RESTClient(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
helper := resource.NewHelper(client, mapping)
|
||||
_, err = helper.Patch(namespace, name, api.StrategicMergePatchType, []byte(patch))
|
||||
|
@@ -55,3 +55,36 @@ func TestPatchObject(t *testing.T) {
|
||||
t.Errorf("unexpected output: %s", buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatchObjectFromFile(t *testing.T) {
|
||||
_, svc, _ := testData()
|
||||
|
||||
f, tf, codec := NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &client.FakeRESTClient{
|
||||
Codec: codec,
|
||||
Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == "/namespaces/test/services/frontend" && (m == "PATCH" || m == "GET"):
|
||||
return &http.Response{StatusCode: 200, Body: objBody(codec, &svc.Items[0])}, nil
|
||||
default:
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdPatch(f, buf)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("patch", `{"spec":{"type":"NodePort"}}`)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/frontend-service.yaml")
|
||||
cmd.Run(cmd, []string{})
|
||||
|
||||
// uses the name from the file, not the response
|
||||
if buf.String() != "frontend\n" {
|
||||
t.Errorf("unexpected output: %s", buf.String())
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user