Merge pull request #42369 from smarterclayton/get_warning

Automatic merge from submit-queue

Output of `kubectl get` is inconsistent for pods

Builds on top of fixes from #42283, only the last two commits are new. Reverts behavior of #39042 which was inconsistent and confusing.

Fixes #15853
pull/6/head
Kubernetes Submit Queue 2017-03-03 23:12:38 -08:00 committed by GitHub
commit db4fbf5958
5 changed files with 37 additions and 50 deletions

View File

@ -76,7 +76,7 @@ kube::test::object_assert() {
local args=${5:-}
for j in $(seq 1 ${tries}); do
res=$(eval kubectl get "${kube_flags[@]}" ${args} $object -o go-template=\"$request\")
res=$(eval kubectl get -a "${kube_flags[@]}" ${args} $object -o go-template=\"$request\")
if [[ "$res" =~ ^$expected$ ]]; then
echo -n ${green}
echo "$(kube::test::get_caller 3): Successful get $object $request: $res"
@ -103,7 +103,7 @@ kube::test::get_object_jsonpath_assert() {
local request=$2
local expected=$3
res=$(eval kubectl get "${kube_flags[@]}" $object -o jsonpath=\"$request\")
res=$(eval kubectl get -a "${kube_flags[@]}" $object -o jsonpath=\"$request\")
if [[ "$res" =~ ^$expected$ ]]; then
echo -n ${green}

View File

@ -1106,6 +1106,10 @@ run_kubectl_get_tests() {
# Post-condition: The text "No resources found" should be part of the output
kube::test::if_has_string "${output_message}" 'No resources found'
# Command
output_message=$(kubectl get pods --ignore-not-found 2>&1 "${kube_flags[@]}")
# Post-condition: The text "No resources found" should not be part of the output
kube::test::if_has_not_string "${output_message}" 'No resources found'
# Command
output_message=$(kubectl get pods 2>&1 "${kube_flags[@]}" -o wide)
# Post-condition: The text "No resources found" should be part of the output
kube::test::if_has_string "${output_message}" 'No resources found'

View File

@ -54,11 +54,12 @@ var (
` + valid_resources + `
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.
This command will hide resources that have completed, such as 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).`)
of the --template flag, you can filter the attributes of the fetched resources.`)
get_example = templates.Examples(`
# List all pods in ps output format.
@ -184,13 +185,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
return cmdutil.UsageError(cmd, usageString)
}
// always show resources when getting by name or filename, or if the output
// is machine-consumable, or if multiple resource kinds were requested.
if cmdutil.OutputsRawFormat(cmd) {
if !cmd.Flag("show-all").Changed {
cmd.Flag("show-all").Value.Set("true")
}
}
export := cmdutil.GetFlagBool(cmd, "export")
filterFuncs := f.DefaultResourceFilterFunc()
@ -249,7 +243,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
}
// print the current object
filteredResourceCount := 0
if !isWatchOnly {
var objsToPrint []runtime.Object
if isList {
@ -262,8 +255,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
return fmt.Errorf("unable to output the provided object: %v", err)
}
}
filteredResourceCount++
cmdutil.PrintFilterCount(filteredResourceCount, mapping.Resource, filterOpts)
}
// print watched changes
@ -273,7 +264,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
}
first := true
filteredResourceCount = 0
intr := interrupt.New(nil, w.Stop)
intr.Run(func() error {
_, err := watch.Until(0, w, func(e watch.Event) (bool, error) {
@ -286,8 +276,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
if err != nil {
return false, err
}
filteredResourceCount++
cmdutil.PrintFilterCount(filteredResourceCount, mapping.Resource, filterOpts)
return false, nil
})
return err
@ -340,11 +328,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
return utilerrors.Reduce(utilerrors.Flatten(utilerrors.NewAggregate(errs)))
}
res := ""
if len(infos) > 0 {
res = infos[0].ResourceMapping().Resource
}
var obj runtime.Object
if !singleItemImplied || len(infos) > 1 {
// we have more than one item, so coerce all items into a list
@ -365,7 +348,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
isList := meta.IsListType(obj)
if isList {
filteredResourceCount, items, err := cmdutil.FilterResourceList(obj, filterFuncs, filterOpts)
_, items, err := cmdutil.FilterResourceList(obj, filterFuncs, filterOpts)
if err != nil {
return err
}
@ -389,23 +372,17 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
if err := printer.PrintObj(list, out); err != nil {
errs = append(errs, err)
}
cmdutil.PrintFilterCount(filteredResourceCount, res, filterOpts)
return utilerrors.Reduce(utilerrors.Flatten(utilerrors.NewAggregate(errs)))
}
filteredResourceCount := 0
if isFiltered, err := filterFuncs.Filter(obj, filterOpts); !isFiltered {
if err != nil {
glog.V(2).Infof("Unable to filter resource: %v", err)
} else if err := printer.PrintObj(obj, out); err != nil {
errs = append(errs, err)
}
} else if isFiltered {
filteredResourceCount++
}
cmdutil.PrintFilterCount(filteredResourceCount, res, filterOpts)
return utilerrors.Reduce(utilerrors.Flatten(utilerrors.NewAggregate(errs)))
}
@ -415,9 +392,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
if err != nil {
allErrs = append(allErrs, err)
}
if len(infos) == 0 && len(allErrs) == 0 && !options.IgnoreNotFound {
outputEmptyListWarning(errOut)
}
objs := make([]runtime.Object, len(infos))
for ix := range infos {
@ -440,12 +414,12 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
printer = nil
var lastMapping *meta.RESTMapping
w := printers.GetNewTabWriter(out)
filteredResourceCount := 0
if resource.MultipleTypesRequested(args) || cmdutil.MustPrintWithKinds(objs, infos, sorter) {
showKind = true
}
filteredResourceCount := 0
for ix := range objs {
var mapping *meta.RESTMapping
var original runtime.Object
@ -459,7 +433,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
if printer == nil || lastMapping == nil || mapping == nil || mapping.Resource != lastMapping.Resource {
if printer != nil {
w.Flush()
cmdutil.PrintFilterCount(filteredResourceCount, lastMapping.Resource, filterOpts)
}
printer, err = f.PrinterForMapping(cmd, mapping, allNamespaces)
if err != nil {
@ -531,14 +504,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
}
}
w.Flush()
if printer != nil && lastMapping != nil {
cmdutil.PrintFilterCount(filteredResourceCount, lastMapping.Resource, filterOpts)
}
cmdutil.PrintFilterCount(errOut, len(objs), filteredResourceCount, len(allErrs), "", filterOpts, options.IgnoreNotFound)
return utilerrors.NewAggregate(allErrs)
}
// outputEmptyListWarning outputs a warning indicating that no items are available to display
func outputEmptyListWarning(out io.Writer) error {
_, err := fmt.Fprintf(out, "%s\n", "No resources found.")
return err
}

View File

@ -229,10 +229,11 @@ func TestGetObjectsFiltered(t *testing.T) {
{args: []string{"pods", "foo"}, flags: map[string]string{"show-all": "false"}, resp: first, expect: []runtime.Object{first}},
{args: []string{"pods"}, flags: map[string]string{"show-all": "true"}, resp: pods, expect: []runtime.Object{first, second}},
{args: []string{"pods/foo"}, resp: first, expect: []runtime.Object{first}},
{args: []string{"pods"}, flags: map[string]string{"output": "yaml"}, resp: pods, expect: []runtime.Object{first, second}},
{args: []string{"pods"}, flags: map[string]string{"output": "yaml"}, resp: pods, expect: []runtime.Object{second}},
{args: []string{}, flags: map[string]string{"filename": "../../../examples/storage/cassandra/cassandra-controller.yaml"}, resp: pods, expect: []runtime.Object{first, second}},
{args: []string{"pods"}, resp: pods, expect: []runtime.Object{second}},
{args: []string{"pods"}, flags: map[string]string{"show-all": "true", "output": "yaml"}, resp: pods, expect: []runtime.Object{first, second}},
{args: []string{"pods"}, flags: map[string]string{"show-all": "false"}, resp: pods, expect: []runtime.Object{second}},
}
@ -731,8 +732,8 @@ func TestGetByFormatForcesFlag(t *testing.T) {
cmd.Run(cmd, []string{"pods"})
showAllFlag, _ := cmd.Flags().GetBool("show-all")
if !showAllFlag {
t.Errorf("expected showAll to be true when getting resource by name")
if showAllFlag {
t.Errorf("expected showAll to not be true when getting resource")
}
}

View File

@ -698,9 +698,26 @@ func FilterResourceList(obj runtime.Object, filterFuncs kubectl.Filters, filterO
return filterCount, list, nil
}
func PrintFilterCount(hiddenObjNum int, resource string, options *printers.PrintOptions) {
if !options.NoHeaders && !options.ShowAll && hiddenObjNum > 0 {
glog.V(2).Infof(" info: %d completed object(s) was(were) not shown in %s list. Pass --show-all to see all objects.\n\n", hiddenObjNum, resource)
// PrintFilterCount displays informational messages based on the number of resources found, hidden, or
// config flags shown.
func PrintFilterCount(out io.Writer, found, hidden, errors int, resource string, options *printers.PrintOptions, ignoreNotFound bool) {
switch {
case errors > 0 || ignoreNotFound:
// print nothing
case found <= hidden:
if found == 0 {
fmt.Fprintln(out, "No resources found.")
} else {
fmt.Fprintln(out, "No resources found, use --show-all to see completed objects.")
}
case hidden > 0 && !options.ShowAll && !options.NoHeaders:
if glog.V(2) {
if hidden > 1 {
fmt.Fprintf(out, "info: %d objects not shown, use --show-all to see completed objects.\n", hidden)
} else {
fmt.Fprintf(out, "info: 1 object not shown, use --show-all to see completed objects.\n")
}
}
}
}