Merge pull request #51750 from jianhuiz/kubectl-custom-colume-not-found

Automatic merge from submit-queue (batch tested with PRs 51750, 53195, 53384, 53410). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

outputs `<none>` for colums not found

**What this PR does / why we need it**:

outputs `<none>` for columns specified by `-o custom-columns` but not found in object

currently kubectl outputs an error of "xxx is not found" when a column is not in the returned json (omitted because of empty value or no such field in the object type at all). This PR suppress this error but outputs `<none>` at that field. This makes it convenient to output the objects details, especially when getting objects of different type in one command.

example:
```
$ kubectl get deploy,rs,po -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,REPLICAS:.status.replicas
NAMESPACE   NAME                      REPLICAS
default     deck                      1
default     deck-433074128            1
default     deck-433074128-vxcg9      <none>
```

**Special notes for your reviewer**:

**Release note**:

```release-note
outputs `<none>` for columns specified by `-o custom-columns` but not found in object
```


@kubernetes/kubectl-reviewers
This commit is contained in:
Kubernetes Submit Queue 2017-10-05 06:08:54 -07:00 committed by GitHub
commit ecfff6620c
2 changed files with 24 additions and 4 deletions

View File

@ -176,7 +176,7 @@ func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error
}
parsers := make([]*jsonpath.JSONPath, len(s.Columns))
for ix := range s.Columns {
parsers[ix] = jsonpath.New(fmt.Sprintf("column%d", ix))
parsers[ix] = jsonpath.New(fmt.Sprintf("column%d", ix)).AllowMissingKeys(true)
if err := parsers[ix].Parse(s.Columns[ix].FieldSpec); err != nil {
return err
}
@ -226,10 +226,10 @@ func (s *CustomColumnsPrinter) printOneObject(obj runtime.Object, parsers []*jso
if err != nil {
return err
}
if len(values) == 0 || len(values[0]) == 0 {
fmt.Fprintf(out, "<none>\t")
}
valueStrings := []string{}
if len(values) == 0 || len(values[0]) == 0 {
valueStrings = append(valueStrings, "<none>")
}
for arrIx := range values {
for valIx := range values[arrIx] {
valueStrings = append(valueStrings, fmt.Sprintf("%v", values[arrIx][valIx].Interface()))

View File

@ -284,6 +284,26 @@ bar
obj: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}, TypeMeta: metav1.TypeMeta{APIVersion: "baz"}},
expectedOutput: `NAME API_VERSION
foo baz
`,
},
{
columns: []printers.Column{
{
Header: "NAME",
FieldSpec: "{.metadata.name}",
},
{
Header: "API_VERSION",
FieldSpec: "{.apiVersion}",
},
{
Header: "NOT_FOUND",
FieldSpec: "{.notFound}",
},
},
obj: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}, TypeMeta: metav1.TypeMeta{APIVersion: "baz"}},
expectedOutput: `NAME API_VERSION NOT_FOUND
foo baz <none>
`,
},
}