diff --git a/hack/make-rules/test-cmd.sh b/hack/make-rules/test-cmd.sh index 53c57f7540..78bffa085c 100755 --- a/hack/make-rules/test-cmd.sh +++ b/hack/make-rules/test-cmd.sh @@ -808,6 +808,16 @@ __EOF__ [ "$(EDITOR=cat kubectl edit --windows-line-endings pod/valid-pod | file - | grep CRLF)" ] [ ! "$(EDITOR=cat kubectl edit --windows-line-endings=false pod/valid-pod | file - | grep CRLF)" ] + ### Label POD YAML file locally without effecting the live pod. + # Pre-condition: name is valid-pod + kube::test::get_object_assert 'pod valid-pod' "{{${labels_field}.name}}" 'valid-pod' + # Command + output_message=$(kubectl label --local --overwrite -f hack/testdata/pod.yaml name=localonlyvalue -o yaml "${kube_flags[@]}") + echo $output_message + # Post-condition: name is still valid-pod in the live pod, but command output is the new value + kube::test::get_object_assert 'pod valid-pod' "{{${labels_field}.name}}" 'valid-pod' + kube::test::if_has_string "${output_message}" "localonlyvalue" + ### 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' diff --git a/pkg/kubectl/cmd/label.go b/pkg/kubectl/cmd/label.go index dbdfe6d296..c42d440fe6 100644 --- a/pkg/kubectl/cmd/label.go +++ b/pkg/kubectl/cmd/label.go @@ -93,6 +93,7 @@ func NewCmdLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command { } cmdutil.AddPrinterFlags(cmd) cmd.Flags().Bool("overwrite", false, "If true, allow labels to be overwritten, otherwise reject label updates that overwrite existing labels.") + cmd.Flags().Bool("local", false, "If true, label will NOT contact api-server but run locally.") 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().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.") @@ -188,6 +189,7 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri all := cmdutil.GetFlagBool(cmd, "all") overwrite := cmdutil.GetFlagBool(cmd, "overwrite") resourceVersion := cmdutil.GetFlagString(cmd, "resource-version") + local := cmdutil.GetFlagBool(cmd, "local") cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { @@ -203,11 +205,13 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, options). - SelectorParam(selector). - ResourceTypeOrNameArgs(all, resources...). - Flatten(). - Latest() + Flatten() + if !local { + b = b.SelectorParam(selector). + ResourceTypeOrNameArgs(all, resources...). + Latest() + } one := false r := b.Do().IntoSingular(&one) if err := r.Err(); err != nil { @@ -227,7 +231,7 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri var outputObj runtime.Object dataChangeMsg := "not labeled" - if cmdutil.GetDryRunFlag(cmd) { + if cmdutil.GetDryRunFlag(cmd) || local { err = labelFunc(info.Object, overwrite, resourceVersion, lbls, remove) if err != nil { return err diff --git a/pkg/kubectl/cmd/label_test.go b/pkg/kubectl/cmd/label_test.go index fb3e753d53..2828fa84b0 100644 --- a/pkg/kubectl/cmd/label_test.go +++ b/pkg/kubectl/cmd/label_test.go @@ -383,6 +383,34 @@ func TestLabelForResourceFromFile(t *testing.T) { } } +func TestLabelLocal(t *testing.T) { + f, tf, _, ns := NewAPIFactory() + tf.Client = &fake.RESTClient{ + NegotiatedSerializer: ns, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) + return nil, nil + }), + } + tf.Namespace = "test" + tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}} + + buf := bytes.NewBuffer([]byte{}) + cmd := NewCmdLabel(f, buf) + cmd.Flags().Set("local", "true") + options := &resource.FilenameOptions{ + Filenames: []string{"../../../examples/storage/cassandra/cassandra-controller.yaml"}, + } + + err := RunLabel(f, buf, cmd, []string{"a=b"}, options) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !strings.Contains(buf.String(), "labeled") { + t.Errorf("did not set labels: %s", buf.String()) + } +} + func TestLabelMultipleObjects(t *testing.T) { pods, _, _ := testData() f, tf, codec, ns := NewAPIFactory()