Kubectl label command accepts a filename param

This commit is contained in:
feihujiang 2015-08-05 11:43:48 +08:00
parent a6148e79c3
commit 4b9afc516e
6 changed files with 89 additions and 6 deletions

View File

@ -747,6 +747,12 @@ _kubectl_label()
flags_completion=() flags_completion=()
flags+=("--all") flags+=("--all")
flags+=("--filename=")
flags_with_completion+=("--filename")
flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
two_word_flags+=("-f")
flags_with_completion+=("-f")
flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
flags+=("--help") flags+=("--help")
flags+=("-h") flags+=("-h")
flags+=("--no-headers") flags+=("--no-headers")

View File

@ -26,6 +26,10 @@ If \-\-resource\-version is specified, then updates will use this resource versi
\fB\-\-all\fP=false \fB\-\-all\fP=false
select all resources in the namespace of the specified resource types select all resources in the namespace of the specified resource types
.PP
\fB\-f\fP, \fB\-\-filename\fP=[]
Filename, directory, or URL to a file identifying the resource to update the labels
.PP .PP
\fB\-h\fP, \fB\-\-help\fP=false \fB\-h\fP, \fB\-\-help\fP=false
help for label help for label
@ -176,6 +180,9 @@ $ kubectl label \-\-overwrite pods foo status=unhealthy
# Update all pods in the namespace # Update all pods in the namespace
$ kubectl label pods \-\-all status=unhealthy $ kubectl label pods \-\-all status=unhealthy
# Update a pod identified by the type and name in "pod.json"
$ kubectl label \-f pod.json status=unhealthy
# Update pod 'foo' only if the resource is unchanged from version 1. # Update pod 'foo' only if the resource is unchanged from version 1.
$ kubectl label pods foo status=unhealthy \-\-resource\-version=1 $ kubectl label pods foo status=unhealthy \-\-resource\-version=1

View File

@ -45,7 +45,7 @@ If --overwrite is true, then existing labels can be overwritten, otherwise attem
If --resource-version is specified, then updates will use this resource version, otherwise the existing resource-version will be used. If --resource-version is specified, then updates will use this resource version, otherwise the existing resource-version will be used.
``` ```
kubectl label [--overwrite] TYPE NAME KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version] kubectl label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]
``` ```
### Examples ### Examples
@ -60,6 +60,9 @@ $ kubectl label --overwrite pods foo status=unhealthy
# Update all pods in the namespace # Update all pods in the namespace
$ kubectl label pods --all status=unhealthy $ kubectl label pods --all status=unhealthy
# Update a pod identified by the type and name in "pod.json"
$ kubectl label -f pod.json status=unhealthy
# Update pod 'foo' only if the resource is unchanged from version 1. # Update pod 'foo' only if the resource is unchanged from version 1.
$ kubectl label pods foo status=unhealthy --resource-version=1 $ kubectl label pods foo status=unhealthy --resource-version=1
@ -72,6 +75,7 @@ $ kubectl label pods foo bar-
``` ```
--all[=false]: select all resources in the namespace of the specified resource types --all[=false]: select all resources in the namespace of the specified resource types
-f, --filename=[]: Filename, directory, or URL to a file identifying the resource to update the labels
-h, --help[=false]: help for label -h, --help[=false]: help for label
--no-headers[=false]: When using the default output, don't print headers. --no-headers[=false]: When using the default output, don't print headers.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide. -o, --output="": Output format. One of: json|yaml|template|templatefile|wide.
@ -116,7 +120,7 @@ $ kubectl label pods foo bar-
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-12 23:41:01.309176995 +0000 UTC ###### Auto generated by spf13/cobra at 2015-08-13 02:21:16.349210188 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS --> <!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_label.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_label.md?pixel)]()

View File

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "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"
@ -44,6 +45,9 @@ $ kubectl label --overwrite pods foo status=unhealthy
# Update all pods in the namespace # Update all pods in the namespace
$ kubectl label pods --all status=unhealthy $ kubectl label pods --all status=unhealthy
# Update a pod identified by the type and name in "pod.json"
$ kubectl label -f pod.json status=unhealthy
# Update pod 'foo' only if the resource is unchanged from version 1. # Update pod 'foo' only if the resource is unchanged from version 1.
$ kubectl label pods foo status=unhealthy --resource-version=1 $ kubectl label pods foo status=unhealthy --resource-version=1
@ -54,7 +58,7 @@ $ kubectl label pods foo bar-`
func NewCmdLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command { func NewCmdLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "label [--overwrite] TYPE NAME KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]", Use: "label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]",
Short: "Update the labels on a resource", Short: "Update the labels on a resource",
Long: fmt.Sprintf(label_long, util.LabelValueMaxLength), Long: fmt.Sprintf(label_long, util.LabelValueMaxLength),
Example: label_example, Example: label_example,
@ -68,6 +72,8 @@ func NewCmdLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command {
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on") cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on")
cmd.Flags().Bool("all", false, "select all resources in the namespace of the specified resource types") cmd.Flags().Bool("all", false, "select all resources in the namespace of the specified resource types")
cmd.Flags().String("resource-version", "", "If non-empty, the labels update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.") cmd.Flags().String("resource-version", "", "If non-empty, the labels update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.")
usage := "Filename, directory, or URL to a file identifying the resource to update the labels"
kubectl.AddJsonFilenameFlag(cmd, usage)
return cmd return cmd
} }
@ -149,7 +155,8 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
return cmdutil.UsageError(cmd, "all resources must be specified before label changes: %s", s) return cmdutil.UsageError(cmd, "all resources must be specified before label changes: %s", s)
} }
} }
if len(resources) < 1 { filenames := cmdutil.GetFlagStringSlice(cmd, "filename")
if len(resources) < 1 && len(filenames) == 0 {
return cmdutil.UsageError(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>") return cmdutil.UsageError(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>")
} }
if len(labelArgs) < 1 { if len(labelArgs) < 1 {
@ -161,7 +168,7 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
overwrite := cmdutil.GetFlagBool(cmd, "overwrite") overwrite := cmdutil.GetFlagBool(cmd, "overwrite")
resourceVersion := cmdutil.GetFlagString(cmd, "resource-version") resourceVersion := cmdutil.GetFlagString(cmd, "resource-version")
cmdNamespace, _, err := f.DefaultNamespace() cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil { if err != nil {
return err return err
} }
@ -170,11 +177,11 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
if err != nil { if err != nil {
return cmdutil.UsageError(cmd, err.Error()) return cmdutil.UsageError(cmd, err.Error())
} }
mapper, typer := f.Object() mapper, typer := f.Object()
b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
ContinueOnError(). ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, filenames...).
SelectorParam(selector). SelectorParam(selector).
ResourceTypeOrNameArgs(all, resources...). ResourceTypeOrNameArgs(all, resources...).
Flatten(). Flatten().
@ -185,6 +192,7 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
if err := r.Err(); err != nil { if err := r.Err(); err != nil {
return err return err
} }
// only apply resource version locking on a single resource // only apply resource version locking on a single resource
if !one && len(resourceVersion) > 0 { if !one && len(resourceVersion) > 0 {
return cmdutil.UsageError(cmd, "--resource-version may only be used with a single resource") return cmdutil.UsageError(cmd, "--resource-version may only be used with a single resource")

View File

@ -323,6 +323,60 @@ func TestLabelErrors(t *testing.T) {
} }
} }
func TestLabelForResourceFromFile(t *testing.T) {
pods, _, _ := 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 req.Method {
case "GET":
switch req.URL.Path {
case "/namespaces/test/pods/cassandra":
return &http.Response{StatusCode: 200, Body: objBody(codec, &pods.Items[0])}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
case "PUT":
switch req.URL.Path {
case "/namespaces/test/pods/cassandra":
return &http.Response{StatusCode: 200, Body: objBody(codec, &pods.Items[0])}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
default:
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
return nil, nil
}
}),
}
tf.Namespace = "test"
tf.ClientConfig = &client.Config{Version: testapi.Version()}
buf := bytes.NewBuffer([]byte{})
cmd := NewCmdLabel(f, buf)
cmd.Flags().Set("filename", "../../../examples/cassandra/cassandra.yaml")
cmd.SetOutput(buf)
err := RunLabel(f, buf, cmd, []string{"a=b"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if tf.Printer.(*testPrinter).Objects == nil {
t.Errorf("unexpected print to default printer")
}
if !reflect.DeepEqual(tf.Printer.(*testPrinter).Objects[0].(*api.Pod).Labels, map[string]string{"a": "b"}) {
t.Errorf("did not set labels: %#v", string(buf.Bytes()))
}
}
func TestLabelMultipleObjects(t *testing.T) { func TestLabelMultipleObjects(t *testing.T) {
pods, _, _ := testData() pods, _, _ := testData()

View File

@ -584,6 +584,10 @@ func (b *Builder) visitorResult() *Result {
if b.flatten { if b.flatten {
visitors = NewFlattenListVisitor(visitors, b.mapper) visitors = NewFlattenListVisitor(visitors, b.mapper)
} }
// must set namespace prior to fetching
if b.defaultNamespace {
visitors = NewDecoratedVisitor(visitors, SetNamespace(b.namespace))
}
visitors = NewDecoratedVisitor(visitors, RetrieveLatest) visitors = NewDecoratedVisitor(visitors, RetrieveLatest)
} }
return &Result{singular: singular, visitor: visitors, sources: b.paths} return &Result{singular: singular, visitor: visitors, sources: b.paths}