Commit aedeccda authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #28352 from vefimova/fix_22986-1

Automatic merge from submit-queue Added warning msg for `kubectl get` - added warning description regarding terminated pods to `get` long help message - added printing of warning message in case of `get pods` if there are hidden pods Fixes #22986 (initiall PR and discussion are here #26417) ## **Output examples:** ### # kubectl get pods ``` NAME READY STATUS RESTARTS AGE dapi-test-pod1 0/1 Terminating 0 22h liveness-http 0/1 CrashLoopBackOff 11245 22d ubuntu1-1206318548-oh9tc 0/1 CrashLoopBackOff 2336 8d info: 1 completed object(s) was(were) not shown in pods list. Pass --show-all to see all objects. ``` ### # kubectl get pods,namespaces ``` NAME READY STATUS RESTARTS AGE po/dapi-test-pod1 0/1 Terminating 0 22h po/liveness-http 1/1 Running 11242 22d po/ubuntu1-1206318548-oh9tc 0/1 CrashLoopBackOff 2335 8d info: 1 completed object(s) was(were) not shown in pods list. Pass --show-all to see all objects. NAME STATUS AGE ns/default Active 89d ns/kube-system Active 41d ``` ### # kubectl get pods -a ``` NAME READY STATUS RESTARTS AGE busybox 0/1 Error 0 27d dapi-test-pod1 0/1 Terminating 0 22h liveness-http 0/1 CrashLoopBackOff 11245 22d ubuntu1-1206318548-oh9tc 0/1 CrashLoopBackOff 2336 8d ``` ### # kubectl get -h ``` Display one or many resources. Possible resource types include (case insensitive): pods (aka 'po'), services (aka 'svc'), deployments (aka 'deploy'), replicasets (aka 'rs'), replicationcontrollers (aka 'rc'), nodes (aka 'no'), events (aka 'ev'), limitranges (aka 'limits'), persistentvolumes (aka 'pv'), persistentvolumeclaims (aka 'pvc'), resourcequotas (aka 'quota'), namespaces (aka 'ns'), serviceaccounts (aka 'sa'), ingresses (aka 'ing'), horizontalpodautoscalers (aka 'hpa'), daemonsets (aka 'ds'), configmaps (aka 'cm'), componentstatuses (aka 'cs), endpoints (aka 'ep'), petsets (alpha feature, may be unstable) and secrets. This command will hide resources that have completed. For instance, pods that are in the Succeeded or Failed phases. You can see the full results for any resource by providing the '--show-all' flag. By specifying the output as 'template' and providing a Go template as the value of the --template flag, you can filter the attributes of the fetched resource(s). Examples: ......... ````
parents b1737900 f20c40ed
...@@ -233,7 +233,7 @@ Find more information at https://github.com/kubernetes/kubernetes.`, ...@@ -233,7 +233,7 @@ Find more information at https://github.com/kubernetes/kubernetes.`,
// From this point and forward we get warnings on flags that contain "_" separators // From this point and forward we get warnings on flags that contain "_" separators
cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc) cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)
cmds.AddCommand(NewCmdGet(f, out)) cmds.AddCommand(NewCmdGet(f, out, err))
cmds.AddCommand(set.NewCmdSet(f, out)) cmds.AddCommand(set.NewCmdSet(f, out))
cmds.AddCommand(NewCmdDescribe(f, out)) cmds.AddCommand(NewCmdDescribe(f, out))
cmds.AddCommand(NewCmdCreate(f, out)) cmds.AddCommand(NewCmdCreate(f, out))
......
...@@ -165,6 +165,10 @@ func (t *testPrinter) HandledResources() []string { ...@@ -165,6 +165,10 @@ func (t *testPrinter) HandledResources() []string {
return []string{} return []string{}
} }
func (t *testPrinter) FinishPrint(output io.Writer, res string) error {
return nil
}
type testDescriber struct { type testDescriber struct {
Name, Namespace string Name, Namespace string
Settings kubectl.DescriberSettings Settings kubectl.DescriberSettings
......
...@@ -44,6 +44,9 @@ var ( ...@@ -44,6 +44,9 @@ var (
`) + kubectl.PossibleResourceTypes + dedent.Dedent(` `) + kubectl.PossibleResourceTypes + dedent.Dedent(`
This command will hide resources that have completed. For instance, pods that are in the Succeeded or Failed phases.
You can see the full results for any resource by providing the '--show-all' flag.
By specifying the output as 'template' and providing a Go template as the value By specifying the output as 'template' and providing a Go template as the value
of the --template flag, you can filter the attributes of the fetched resource(s).`) of the --template flag, you can filter the attributes of the fetched resource(s).`)
get_example = dedent.Dedent(` get_example = dedent.Dedent(`
...@@ -74,7 +77,7 @@ var ( ...@@ -74,7 +77,7 @@ var (
// NewCmdGet creates a command object for the generic "get" action, which // NewCmdGet creates a command object for the generic "get" action, which
// retrieves one or more resources from a server. // retrieves one or more resources from a server.
func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command { func NewCmdGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command {
options := &GetOptions{} options := &GetOptions{}
// retrieve a list of handled resources from printer as valid args // retrieve a list of handled resources from printer as valid args
...@@ -94,7 +97,7 @@ func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -94,7 +97,7 @@ func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command {
Long: get_long, Long: get_long,
Example: get_example, Example: get_example,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
err := RunGet(f, out, cmd, args, options) err := RunGet(f, out, errOut, cmd, args, options)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
}, },
SuggestFor: []string{"list", "ps"}, SuggestFor: []string{"list", "ps"},
...@@ -118,7 +121,7 @@ func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -118,7 +121,7 @@ func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command {
// RunGet implements the generic Get command // RunGet implements the generic Get command
// TODO: convert all direct flag accessors to a struct and pass that instead of cmd // TODO: convert all direct flag accessors to a struct and pass that instead of cmd
func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *GetOptions) error { func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Command, args []string, options *GetOptions) error {
selector := cmdutil.GetFlagString(cmd, "selector") selector := cmdutil.GetFlagString(cmd, "selector")
allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces") allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces")
showKind := cmdutil.GetFlagBool(cmd, "show-kind") showKind := cmdutil.GetFlagBool(cmd, "show-kind")
...@@ -177,7 +180,6 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -177,7 +180,6 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
if err != nil { if err != nil {
return err return err
} }
obj, err := r.Object() obj, err := r.Object()
if err != nil { if err != nil {
return err return err
...@@ -203,6 +205,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -203,6 +205,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
if err := printer.PrintObj(obj, out); err != nil { if err := printer.PrintObj(obj, out); err != nil {
return fmt.Errorf("unable to output the provided object: %v", err) return fmt.Errorf("unable to output the provided object: %v", err)
} }
printer.FinishPrint(errOut, mapping.Resource)
} }
// print watched changes // print watched changes
...@@ -218,7 +221,11 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -218,7 +221,11 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
first = false first = false
return nil return nil
} }
return printer.PrintObj(e.Object, out) err := printer.PrintObj(e.Object, out)
if err == nil {
printer.FinishPrint(errOut, mapping.Resource)
}
return err
}) })
return nil return nil
} }
...@@ -265,6 +272,10 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -265,6 +272,10 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
if err != nil { if err != nil {
return err return err
} }
res := ""
if len(infos) > 0 {
res = infos[0].ResourceMapping().Resource
}
obj, err := resource.AsVersionedObject(infos, !singular, version, f.JSONEncoder()) obj, err := resource.AsVersionedObject(infos, !singular, version, f.JSONEncoder())
if err != nil { if err != nil {
...@@ -274,6 +285,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -274,6 +285,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
if err := printer.PrintObj(obj, out); err != nil { if err := printer.PrintObj(obj, out); err != nil {
allErrs = append(allErrs, err) allErrs = append(allErrs, err)
} }
printer.FinishPrint(errOut, res)
return utilerrors.NewAggregate(allErrs) return utilerrors.NewAggregate(allErrs)
} }
...@@ -322,7 +334,6 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -322,7 +334,6 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
printer = nil printer = nil
var lastMapping *meta.RESTMapping var lastMapping *meta.RESTMapping
w := kubectl.GetNewTabWriter(out) w := kubectl.GetNewTabWriter(out)
defer w.Flush()
if mustPrintWithKinds(objs, infos, sorter) { if mustPrintWithKinds(objs, infos, sorter) {
showKind = true showKind = true
...@@ -339,6 +350,10 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -339,6 +350,10 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
original = infos[ix].Object original = infos[ix].Object
} }
if printer == nil || lastMapping == nil || mapping == nil || mapping.Resource != lastMapping.Resource { if printer == nil || lastMapping == nil || mapping == nil || mapping.Resource != lastMapping.Resource {
if printer != nil {
w.Flush()
printer.FinishPrint(errOut, lastMapping.Resource)
}
printer, err = f.PrinterForMapping(cmd, mapping, allNamespaces) printer, err = f.PrinterForMapping(cmd, mapping, allNamespaces)
if err != nil { if err != nil {
allErrs = append(allErrs, err) allErrs = append(allErrs, err)
...@@ -375,6 +390,10 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -375,6 +390,10 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
continue continue
} }
} }
w.Flush()
if printer != nil {
printer.FinishPrint(errOut, lastMapping.Resource)
}
return utilerrors.NewAggregate(allErrs) return utilerrors.NewAggregate(allErrs)
} }
......
...@@ -127,8 +127,9 @@ func TestGetUnknownSchemaObject(t *testing.T) { ...@@ -127,8 +127,9 @@ func TestGetUnknownSchemaObject(t *testing.T) {
tf.Namespace = "test" tf.Namespace = "test"
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}} tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Run(cmd, []string{"type", "foo"}) cmd.Run(cmd, []string{"type", "foo"})
...@@ -203,12 +204,13 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) { ...@@ -203,12 +204,13 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
tf.Namespace = "test" tf.Namespace = "test"
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}} tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("output", "json") cmd.Flags().Set("output", "json")
cmd.Flags().Set("output-version", test.outputVersion) cmd.Flags().Set("output-version", test.outputVersion)
err := RunGet(f, buf, cmd, []string{"type/foo", "replicationcontrollers/foo"}, &GetOptions{}) err := RunGet(f, buf, errBuf, cmd, []string{"type/foo", "replicationcontrollers/foo"}, &GetOptions{})
if err != nil { if err != nil {
t.Errorf("%s: unexpected error: %v", k, err) t.Errorf("%s: unexpected error: %v", k, err)
continue continue
...@@ -246,8 +248,9 @@ func TestGetSchemaObject(t *testing.T) { ...@@ -246,8 +248,9 @@ func TestGetSchemaObject(t *testing.T) {
tf.Namespace = "test" tf.Namespace = "test"
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &unversioned.GroupVersion{Version: "v1"}}} tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &unversioned.GroupVersion{Version: "v1"}}}
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.Run(cmd, []string{"replicationcontrollers", "foo"}) cmd.Run(cmd, []string{"replicationcontrollers", "foo"})
if !strings.Contains(buf.String(), "\"foo\"") { if !strings.Contains(buf.String(), "\"foo\"") {
...@@ -266,8 +269,9 @@ func TestGetObjects(t *testing.T) { ...@@ -266,8 +269,9 @@ func TestGetObjects(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Run(cmd, []string{"pods", "foo"}) cmd.Run(cmd, []string{"pods", "foo"})
...@@ -312,7 +316,9 @@ func TestGetSortedObjects(t *testing.T) { ...@@ -312,7 +316,9 @@ func TestGetSortedObjects(t *testing.T) {
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &unversioned.GroupVersion{Version: "v1"}}} tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &unversioned.GroupVersion{Version: "v1"}}}
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
// sorting with metedata.name // sorting with metedata.name
...@@ -342,8 +348,9 @@ func TestGetObjectsIdentifiedByFile(t *testing.T) { ...@@ -342,8 +348,9 @@ func TestGetObjectsIdentifiedByFile(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("filename", "../../../examples/storage/cassandra/cassandra-controller.yaml") cmd.Flags().Set("filename", "../../../examples/storage/cassandra/cassandra-controller.yaml")
cmd.Run(cmd, []string{}) cmd.Run(cmd, []string{})
...@@ -369,8 +376,9 @@ func TestGetListObjects(t *testing.T) { ...@@ -369,8 +376,9 @@ func TestGetListObjects(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Run(cmd, []string{"pods"}) cmd.Run(cmd, []string{"pods"})
...@@ -412,8 +420,9 @@ func TestGetAllListObjects(t *testing.T) { ...@@ -412,8 +420,9 @@ func TestGetAllListObjects(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("show-all", "true") cmd.Flags().Set("show-all", "true")
cmd.Run(cmd, []string{"pods"}) cmd.Run(cmd, []string{"pods"})
...@@ -442,8 +451,9 @@ func TestGetListComponentStatus(t *testing.T) { ...@@ -442,8 +451,9 @@ func TestGetListComponentStatus(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Run(cmd, []string{"componentstatuses"}) cmd.Run(cmd, []string{"componentstatuses"})
...@@ -481,8 +491,9 @@ func TestGetMultipleTypeObjects(t *testing.T) { ...@@ -481,8 +491,9 @@ func TestGetMultipleTypeObjects(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Run(cmd, []string{"pods,services"}) cmd.Run(cmd, []string{"pods,services"})
...@@ -521,8 +532,9 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) { ...@@ -521,8 +532,9 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
tf.Namespace = "test" tf.Namespace = "test"
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}} tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("output", "json") cmd.Flags().Set("output", "json")
...@@ -583,8 +595,9 @@ func TestGetMultipleTypeObjectsWithSelector(t *testing.T) { ...@@ -583,8 +595,9 @@ func TestGetMultipleTypeObjectsWithSelector(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("selector", "a=b") cmd.Flags().Set("selector", "a=b")
...@@ -632,8 +645,9 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) { ...@@ -632,8 +645,9 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Run(cmd, []string{"services/bar", "node/foo"}) cmd.Run(cmd, []string{"services/bar", "node/foo"})
...@@ -659,8 +673,9 @@ func TestGetByNameForcesFlag(t *testing.T) { ...@@ -659,8 +673,9 @@ func TestGetByNameForcesFlag(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Run(cmd, []string{"pods", "foo"}) cmd.Run(cmd, []string{"pods", "foo"})
...@@ -770,8 +785,9 @@ func TestWatchSelector(t *testing.T) { ...@@ -770,8 +785,9 @@ func TestWatchSelector(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("watch", "true") cmd.Flags().Set("watch", "true")
...@@ -809,8 +825,9 @@ func TestWatchResource(t *testing.T) { ...@@ -809,8 +825,9 @@ func TestWatchResource(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("watch", "true") cmd.Flags().Set("watch", "true")
...@@ -847,7 +864,9 @@ func TestWatchResourceIdentifiedByFile(t *testing.T) { ...@@ -847,7 +864,9 @@ func TestWatchResourceIdentifiedByFile(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("watch", "true") cmd.Flags().Set("watch", "true")
...@@ -886,8 +905,9 @@ func TestWatchOnlyResource(t *testing.T) { ...@@ -886,8 +905,9 @@ func TestWatchOnlyResource(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("watch-only", "true") cmd.Flags().Set("watch-only", "true")
...@@ -930,8 +950,9 @@ func TestWatchOnlyList(t *testing.T) { ...@@ -930,8 +950,9 @@ func TestWatchOnlyList(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdGet(f, buf) cmd := NewCmdGet(f, buf, errBuf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("watch-only", "true") cmd.Flags().Set("watch-only", "true")
......
...@@ -155,6 +155,10 @@ type CustomColumnsPrinter struct { ...@@ -155,6 +155,10 @@ type CustomColumnsPrinter struct {
NoHeaders bool NoHeaders bool
} }
func (s *CustomColumnsPrinter) FinishPrint(w io.Writer, res string) error {
return nil
}
func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error { func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
w := tabwriter.NewWriter(out, columnwidth, tabwidth, padding, padding_character, flags) w := tabwriter.NewWriter(out, columnwidth, tabwidth, padding, padding_character, flags)
......
...@@ -147,6 +147,9 @@ type ResourcePrinter interface { ...@@ -147,6 +147,9 @@ type ResourcePrinter interface {
// Print receives a runtime object, formats it and prints it to a writer. // Print receives a runtime object, formats it and prints it to a writer.
PrintObj(runtime.Object, io.Writer) error PrintObj(runtime.Object, io.Writer) error
HandledResources() []string HandledResources() []string
//Can be used to print out warning/clarifications if needed
//after all objects were printed
FinishPrint(io.Writer, string) error
} }
// ResourcePrinterFunc is a function that can print objects // ResourcePrinterFunc is a function that can print objects
...@@ -162,6 +165,10 @@ func (fn ResourcePrinterFunc) HandledResources() []string { ...@@ -162,6 +165,10 @@ func (fn ResourcePrinterFunc) HandledResources() []string {
return []string{} return []string{}
} }
func (fn ResourcePrinterFunc) FinishPrint(io.Writer, string) error {
return nil
}
// VersionedPrinter takes runtime objects and ensures they are converted to a given API version // VersionedPrinter takes runtime objects and ensures they are converted to a given API version
// prior to being passed to a nested printer. // prior to being passed to a nested printer.
type VersionedPrinter struct { type VersionedPrinter struct {
...@@ -179,6 +186,10 @@ func NewVersionedPrinter(printer ResourcePrinter, converter runtime.ObjectConver ...@@ -179,6 +186,10 @@ func NewVersionedPrinter(printer ResourcePrinter, converter runtime.ObjectConver
} }
} }
func (p *VersionedPrinter) FinishPrint(w io.Writer, res string) error {
return nil
}
// PrintObj implements ResourcePrinter // PrintObj implements ResourcePrinter
func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error { func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
if len(p.versions) == 0 { if len(p.versions) == 0 {
...@@ -211,6 +222,10 @@ type NamePrinter struct { ...@@ -211,6 +222,10 @@ type NamePrinter struct {
Typer runtime.ObjectTyper Typer runtime.ObjectTyper
} }
func (p *NamePrinter) FinishPrint(w io.Writer, res string) error {
return nil
}
// PrintObj is an implementation of ResourcePrinter.PrintObj which decodes the object // PrintObj is an implementation of ResourcePrinter.PrintObj which decodes the object
// and print "resource/name" pair. If the object is a List, print all items in it. // and print "resource/name" pair. If the object is a List, print all items in it.
func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error { func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
...@@ -259,6 +274,10 @@ func (p *NamePrinter) HandledResources() []string { ...@@ -259,6 +274,10 @@ func (p *NamePrinter) HandledResources() []string {
type JSONPrinter struct { type JSONPrinter struct {
} }
func (p *JSONPrinter) FinishPrint(w io.Writer, res string) error {
return nil
}
// PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer. // PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer.
func (p *JSONPrinter) PrintObj(obj runtime.Object, w io.Writer) error { func (p *JSONPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
switch obj := obj.(type) { switch obj := obj.(type) {
...@@ -291,6 +310,10 @@ type YAMLPrinter struct { ...@@ -291,6 +310,10 @@ type YAMLPrinter struct {
converter runtime.ObjectConvertor converter runtime.ObjectConvertor
} }
func (p *YAMLPrinter) FinishPrint(w io.Writer, res string) error {
return nil
}
// PrintObj prints the data as YAML. // PrintObj prints the data as YAML.
func (p *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error { func (p *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
switch obj := obj.(type) { switch obj := obj.(type) {
...@@ -319,6 +342,7 @@ func (p *YAMLPrinter) HandledResources() []string { ...@@ -319,6 +342,7 @@ func (p *YAMLPrinter) HandledResources() []string {
type handlerEntry struct { type handlerEntry struct {
columns []string columns []string
printFunc reflect.Value printFunc reflect.Value
args []reflect.Value
} }
type PrintOptions struct { type PrintOptions struct {
...@@ -338,9 +362,10 @@ type PrintOptions struct { ...@@ -338,9 +362,10 @@ type PrintOptions struct {
// will only be printed if the object type changes. This makes it useful for printing items // will only be printed if the object type changes. This makes it useful for printing items
// received from watches. // received from watches.
type HumanReadablePrinter struct { type HumanReadablePrinter struct {
handlerMap map[reflect.Type]*handlerEntry handlerMap map[reflect.Type]*handlerEntry
options PrintOptions options PrintOptions
lastType reflect.Type lastType reflect.Type
hiddenObjNum int
} }
// NewHumanReadablePrinter creates a HumanReadablePrinter. // NewHumanReadablePrinter creates a HumanReadablePrinter.
...@@ -384,6 +409,7 @@ func (h *HumanReadablePrinter) Handler(columns []string, printFunc interface{}) ...@@ -384,6 +409,7 @@ func (h *HumanReadablePrinter) Handler(columns []string, printFunc interface{})
glog.Errorf("Unable to add print handler: %v", err) glog.Errorf("Unable to add print handler: %v", err)
return err return err
} }
objType := printFuncValue.Type().In(0) objType := printFuncValue.Type().In(0)
h.handlerMap[objType] = &handlerEntry{ h.handlerMap[objType] = &handlerEntry{
columns: columns, columns: columns,
...@@ -431,6 +457,14 @@ func (h *HumanReadablePrinter) HandledResources() []string { ...@@ -431,6 +457,14 @@ func (h *HumanReadablePrinter) HandledResources() []string {
return keys return keys
} }
func (h *HumanReadablePrinter) FinishPrint(output io.Writer, res string) error {
if !h.options.NoHeaders && !h.options.ShowAll && h.hiddenObjNum > 0 {
_, err := fmt.Fprintf(output, " info: %d completed object(s) was(were) not shown in %s list. Pass --show-all to see all objects.\n\n", h.hiddenObjNum, res)
return err
}
return nil
}
// NOTE: When adding a new resource type here, please update the list // NOTE: When adding a new resource type here, please update the list
// pkg/kubectl/cmd/get.go to reflect the new resource type. // pkg/kubectl/cmd/get.go to reflect the new resource type.
var podColumns = []string{"NAME", "READY", "STATUS", "RESTARTS", "AGE"} var podColumns = []string{"NAME", "READY", "STATUS", "RESTARTS", "AGE"}
...@@ -471,10 +505,40 @@ var clusterColumns = []string{"NAME", "STATUS", "VERSION", "AGE"} ...@@ -471,10 +505,40 @@ var clusterColumns = []string{"NAME", "STATUS", "VERSION", "AGE"}
var networkPolicyColumns = []string{"NAME", "POD-SELECTOR", "AGE"} var networkPolicyColumns = []string{"NAME", "POD-SELECTOR", "AGE"}
var certificateSigningRequestColumns = []string{"NAME", "AGE", "REQUESTOR", "CONDITION"} var certificateSigningRequestColumns = []string{"NAME", "AGE", "REQUESTOR", "CONDITION"}
func (h *HumanReadablePrinter) printPod(pod *api.Pod, w io.Writer, options PrintOptions) error {
reason := string(pod.Status.Phase)
// if not printing all pods, skip terminated pods (default)
if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) {
h.hiddenObjNum++
return nil
}
if err := printPodBase(pod, w, options); err != nil {
return err
}
return nil
}
func (h *HumanReadablePrinter) printPodList(podList *api.PodList, w io.Writer, options PrintOptions) error {
for _, pod := range podList.Items {
reason := string(pod.Status.Phase)
// if not printing all pods, skip terminated pods (default)
if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) {
h.hiddenObjNum++
continue
}
if err := printPodBase(&pod, w, options); err != nil {
return err
}
}
return nil
}
// addDefaultHandlers adds print handlers for default Kubernetes types. // addDefaultHandlers adds print handlers for default Kubernetes types.
func (h *HumanReadablePrinter) addDefaultHandlers() { func (h *HumanReadablePrinter) addDefaultHandlers() {
h.Handler(podColumns, printPod) h.Handler(podColumns, h.printPodList)
h.Handler(podColumns, printPodList) h.Handler(podColumns, h.printPod)
h.Handler(podTemplateColumns, printPodTemplate) h.Handler(podTemplateColumns, printPodTemplate)
h.Handler(podTemplateColumns, printPodTemplateList) h.Handler(podTemplateColumns, printPodTemplateList)
h.Handler(replicationControllerColumns, printReplicationController) h.Handler(replicationControllerColumns, printReplicationController)
...@@ -617,10 +681,6 @@ func translateTimestamp(timestamp unversioned.Time) string { ...@@ -617,10 +681,6 @@ func translateTimestamp(timestamp unversioned.Time) string {
return shortHumanDuration(time.Now().Sub(timestamp.Time)) return shortHumanDuration(time.Now().Sub(timestamp.Time))
} }
func printPod(pod *api.Pod, w io.Writer, options PrintOptions) error {
return printPodBase(pod, w, options)
}
func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error { func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error {
name := formatResourceName(options.Kind, pod.Name, options.WithKind) name := formatResourceName(options.Kind, pod.Name, options.WithKind)
namespace := pod.Namespace namespace := pod.Namespace
...@@ -630,10 +690,6 @@ func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error { ...@@ -630,10 +690,6 @@ func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error {
readyContainers := 0 readyContainers := 0
reason := string(pod.Status.Phase) reason := string(pod.Status.Phase)
// if not printing all pods, skip terminated pods (default)
if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) {
return nil
}
if pod.Status.Reason != "" { if pod.Status.Reason != "" {
reason = pod.Status.Reason reason = pod.Status.Reason
} }
...@@ -731,15 +787,6 @@ func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error { ...@@ -731,15 +787,6 @@ func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error {
return nil return nil
} }
func printPodList(podList *api.PodList, w io.Writer, options PrintOptions) error {
for _, pod := range podList.Items {
if err := printPodBase(&pod, w, options); err != nil {
return err
}
}
return nil
}
func printPodTemplate(pod *api.PodTemplate, w io.Writer, options PrintOptions) error { func printPodTemplate(pod *api.PodTemplate, w io.Writer, options PrintOptions) error {
name := formatResourceName(options.Kind, pod.Name, options.WithKind) name := formatResourceName(options.Kind, pod.Name, options.WithKind)
...@@ -2183,6 +2230,10 @@ func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) { ...@@ -2183,6 +2230,10 @@ func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) {
}, nil }, nil
} }
func (p *TemplatePrinter) FinishPrint(w io.Writer, res string) error {
return nil
}
// PrintObj formats the obj with the Go Template. // PrintObj formats the obj with the Go Template.
func (p *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error { func (p *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
data, err := json.Marshal(obj) data, err := json.Marshal(obj)
...@@ -2330,6 +2381,10 @@ func NewJSONPathPrinter(tmpl string) (*JSONPathPrinter, error) { ...@@ -2330,6 +2381,10 @@ func NewJSONPathPrinter(tmpl string) (*JSONPathPrinter, error) {
return &JSONPathPrinter{tmpl, j}, nil return &JSONPathPrinter{tmpl, j}, nil
} }
func (j *JSONPathPrinter) FinishPrint(w io.Writer, res string) error {
return nil
}
// PrintObj formats the obj with the JSONPath Template. // PrintObj formats the obj with the JSONPath Template.
func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error { func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
var queryObj interface{} = obj var queryObj interface{} = obj
......
...@@ -1148,14 +1148,18 @@ func TestPrintPod(t *testing.T) { ...@@ -1148,14 +1148,18 @@ func TestPrintPod(t *testing.T) {
} }
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
printer := HumanReadablePrinter{hiddenObjNum: 0}
for _, test := range tests { for _, test := range tests {
printPod(&test.pod, buf, PrintOptions{false, false, false, false, true, false, false, "", []string{}}) printer.printPod(&test.pod, buf, PrintOptions{false, false, false, false, true, false, false, "", []string{}})
// We ignore time // We ignore time
if !strings.HasPrefix(buf.String(), test.expect) { if !strings.HasPrefix(buf.String(), test.expect) {
t.Fatalf("Expected: %s, got: %s", test.expect, buf.String()) t.Fatalf("Expected: %s, got: %s", test.expect, buf.String())
} }
buf.Reset() buf.Reset()
} }
if printer.hiddenObjNum > 0 {
t.Fatalf("Expected hidden pods: 0, got: %d", printer.hiddenObjNum)
}
} }
func TestPrintNonTerminatedPod(t *testing.T) { func TestPrintNonTerminatedPod(t *testing.T) {
...@@ -1241,14 +1245,18 @@ func TestPrintNonTerminatedPod(t *testing.T) { ...@@ -1241,14 +1245,18 @@ func TestPrintNonTerminatedPod(t *testing.T) {
} }
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
printer := HumanReadablePrinter{hiddenObjNum: 0}
for _, test := range tests { for _, test := range tests {
printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, false, false, "", []string{}}) printer.printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, false, false, "", []string{}})
// We ignore time // We ignore time
if !strings.HasPrefix(buf.String(), test.expect) { if !strings.HasPrefix(buf.String(), test.expect) {
t.Fatalf("Expected: %s, got: %s", test.expect, buf.String()) t.Fatalf("Expected: %s, got: %s", test.expect, buf.String())
} }
buf.Reset() buf.Reset()
} }
if printer.hiddenObjNum != 2 {
t.Fatalf("Expected hidden pods: 2, got: %d", printer.hiddenObjNum)
}
} }
func TestPrintPodWithLabels(t *testing.T) { func TestPrintPodWithLabels(t *testing.T) {
...@@ -1301,14 +1309,18 @@ func TestPrintPodWithLabels(t *testing.T) { ...@@ -1301,14 +1309,18 @@ func TestPrintPodWithLabels(t *testing.T) {
} }
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
printer := HumanReadablePrinter{hiddenObjNum: 0}
for _, test := range tests { for _, test := range tests {
printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, false, false, "", test.labelColumns}) printer.printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, false, false, "", test.labelColumns})
// We ignore time // We ignore time
if !strings.HasPrefix(buf.String(), test.startsWith) || !strings.HasSuffix(buf.String(), test.endsWith) { if !strings.HasPrefix(buf.String(), test.startsWith) || !strings.HasSuffix(buf.String(), test.endsWith) {
t.Fatalf("Expected to start with: %s and end with: %s, but got: %s", test.startsWith, test.endsWith, buf.String()) t.Fatalf("Expected to start with: %s and end with: %s, but got: %s", test.startsWith, test.endsWith, buf.String())
} }
buf.Reset() buf.Reset()
} }
if printer.hiddenObjNum > 0 {
t.Fatalf("Expected hidden pods: 0, got: %d", printer.hiddenObjNum)
}
} }
type stringTestList []struct { type stringTestList []struct {
...@@ -1507,12 +1519,17 @@ func TestPrintPodShowLabels(t *testing.T) { ...@@ -1507,12 +1519,17 @@ func TestPrintPodShowLabels(t *testing.T) {
} }
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
printer := HumanReadablePrinter{hiddenObjNum: 0}
for _, test := range tests { for _, test := range tests {
printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, test.showLabels, false, "", []string{}}) printer.printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, test.showLabels, false, "", []string{}})
// We ignore time // We ignore time
if !strings.HasPrefix(buf.String(), test.startsWith) || !strings.HasSuffix(buf.String(), test.endsWith) { if !strings.HasPrefix(buf.String(), test.startsWith) || !strings.HasSuffix(buf.String(), test.endsWith) {
t.Fatalf("Expected to start with: %s and end with: %s, but got: %s", test.startsWith, test.endsWith, buf.String()) t.Fatalf("Expected to start with: %s and end with: %s, but got: %s", test.startsWith, test.endsWith, buf.String())
} }
buf.Reset() buf.Reset()
} }
if printer.hiddenObjNum > 0 {
t.Fatalf("Expected hidden pods: 0, got: %d", printer.hiddenObjNum)
}
} }
...@@ -40,6 +40,10 @@ type SortingPrinter struct { ...@@ -40,6 +40,10 @@ type SortingPrinter struct {
Decoder runtime.Decoder Decoder runtime.Decoder
} }
func (s *SortingPrinter) FinishPrint(w io.Writer, res string) error {
return nil
}
func (s *SortingPrinter) PrintObj(obj runtime.Object, out io.Writer) error { func (s *SortingPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
if !meta.IsListType(obj) { if !meta.IsListType(obj) {
return s.Delegate.PrintObj(obj, out) return s.Delegate.PrintObj(obj, out)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment