Skip to content

Commit

Permalink
Merge pull request kubernetes#55689 from luksa/kubectl_explain_kind_v…
Browse files Browse the repository at this point in the history
…ersion

Automatic merge from submit-queue. 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>.

Make kubectl explain print the Kind and APIVersion of the resource

**What this PR does / why we need it**:
Kubectl explain currently doesn't print out the Kind and APIversion of the resource being explained. When running `kubectl explain hpa.spec`, for example, there is no way of knowing whether you're looking at the `autoscaling/v1` or the `autoscaling/v2beta1` version. 
Also, `kubectl explain` is often used as a reference when writing YAML/JSON object manifests. It allows you to look up everything except the API version. Currently, you either need to know the API Version of a resource by heart or look it up in the online API docs. 
This PR fixes both problems by having `kubectl explain` print out the full Kind and APIVersion of the resource it is explaining.

Here are a few examples of the new output:
```
$ kubectl explain deploy
KIND:     Deployment
VERSION:  extensions/v1beta1

DESCRIPTION:
...


$ kubectl explain hpa.spec
KIND:     HorizontalPodAutoscaler
VERSION:  autoscaling/v1

RESOURCE: spec <Object>

DESCRIPTION:
...


$ kubectl explain hpa.spec.maxReplicas
KIND:     HorizontalPodAutoscaler
VERSION:  autoscaling/v1

FIELD:    maxReplicas <integer>

DESCRIPTION:
...


$ kubectl explain hpa.spec --recursive
KIND:     HorizontalPodAutoscaler
VERSION:  autoscaling/v1

RESOURCE: spec <Object>

DESCRIPTION:
     behaviour of autoscaler. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status.

     specification of a horizontal pod autoscaler.

FIELDS:
   maxReplicas	<integer>
   minReplicas	<integer>
   scaleTargetRef	<Object>
      apiVersion	<string>
      kind	<string>
      name	<string>
   targetCPUUtilizationPercentage	<integer>
```

**Release note**:

```release-note
Kubectl explain now prints out the Kind and API version of the resource being explained
```
  • Loading branch information
Kubernetes Submit Queue authored Dec 15, 2017
2 parents 722cb7a + c77d5d0 commit 761fdea
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 14 deletions.
2 changes: 1 addition & 1 deletion pkg/kubectl/cmd/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,5 @@ func RunExplain(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, ar
return fmt.Errorf("Couldn't find resource for %q", gvk)
}

return explain.PrintModelDescription(fieldsPath, out, schema, recursive)
return explain.PrintModelDescription(fieldsPath, out, schema, gvk, recursive)
}
1 change: 1 addition & 0 deletions pkg/kubectl/explain/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
],
)
Expand Down
5 changes: 3 additions & 2 deletions pkg/kubectl/explain/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"strings"

"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kube-openapi/pkg/util/proto"
)

Expand Down Expand Up @@ -51,7 +52,7 @@ func SplitAndParseResourceRequest(inResource string, mapper meta.RESTMapper) (st
// PrintModelDescription prints the description of a specific model or dot path.
// If recursive, all components nested within the fields of the schema will be
// printed.
func PrintModelDescription(fieldsPath []string, w io.Writer, schema proto.Schema, recursive bool) error {
func PrintModelDescription(fieldsPath []string, w io.Writer, schema proto.Schema, gvk schema.GroupVersionKind, recursive bool) error {
fieldName := ""
if len(fieldsPath) != 0 {
fieldName = fieldsPath[len(fieldsPath)-1]
Expand All @@ -64,5 +65,5 @@ func PrintModelDescription(fieldsPath []string, w io.Writer, schema proto.Schema
}
b := fieldsPrinterBuilder{Recursive: recursive}
f := &Formatter{Writer: w, Wrap: 80}
return PrintModel(fieldName, f, b, schema)
return PrintModel(fieldName, f, b, schema, gvk)
}
29 changes: 25 additions & 4 deletions pkg/kubectl/explain/model_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ limitations under the License.

package explain

import "k8s.io/kube-openapi/pkg/util/proto"
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kube-openapi/pkg/util/proto"
)

// fieldIndentLevel is the level of indentation for fields.
const fieldIndentLevel = 3
Expand All @@ -33,11 +36,19 @@ type modelPrinter struct {
Descriptions []string
Writer *Formatter
Builder fieldsPrinterBuilder
GVK schema.GroupVersionKind
Error error
}

var _ proto.SchemaVisitor = &modelPrinter{}

func (m *modelPrinter) PrintKindAndVersion() error {
if err := m.Writer.Write("KIND: %s", m.GVK.Kind); err != nil {
return err
}
return m.Writer.Write("VERSION: %s\n", m.GVK.GroupVersion())
}

// PrintDescription prints the description for a given schema. There
// might be multiple description, since we collect descriptions when we
// go through references, arrays and maps.
Expand Down Expand Up @@ -73,6 +84,11 @@ func (m *modelPrinter) VisitArray(a *proto.Array) {

// VisitKind prints a full resource with its fields.
func (m *modelPrinter) VisitKind(k *proto.Kind) {
if err := m.PrintKindAndVersion(); err != nil {
m.Error = err
return
}

if m.Type == "" {
m.Type = GetTypeName(k)
}
Expand Down Expand Up @@ -103,10 +119,15 @@ func (m *modelPrinter) VisitMap(om *proto.Map) {

// VisitPrimitive prints a field type and its description.
func (m *modelPrinter) VisitPrimitive(p *proto.Primitive) {
if err := m.PrintKindAndVersion(); err != nil {
m.Error = err
return
}

if m.Type == "" {
m.Type = GetTypeName(p)
}
if err := m.Writer.Write("FIELD: %s <%s>\n", m.Name, m.Type); err != nil {
if err := m.Writer.Write("FIELD: %s <%s>\n", m.Name, m.Type); err != nil {
m.Error = err
return
}
Expand All @@ -120,8 +141,8 @@ func (m *modelPrinter) VisitReference(r proto.Reference) {
}

// PrintModel prints the description of a schema in writer.
func PrintModel(name string, writer *Formatter, builder fieldsPrinterBuilder, schema proto.Schema) error {
m := &modelPrinter{Name: name, Writer: writer, Builder: builder}
func PrintModel(name string, writer *Formatter, builder fieldsPrinterBuilder, schema proto.Schema, gvk schema.GroupVersionKind) error {
m := &modelPrinter{Name: name, Writer: writer, Builder: builder, GVK: gvk}
schema.Accept(m)
return m.Error
}
27 changes: 20 additions & 7 deletions pkg/kubectl/explain/model_printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ import (
)

func TestModel(t *testing.T) {
schema := resources.LookupResource(schema.GroupVersionKind{
gvk := schema.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "OneKind",
})
}
schema := resources.LookupResource(gvk)
if schema == nil {
t.Fatal("Couldn't find schema v1.OneKind")
}
Expand All @@ -38,7 +39,10 @@ func TestModel(t *testing.T) {
want string
}{
{
want: `DESCRIPTION:
want: `KIND: OneKind
VERSION: v1
DESCRIPTION:
OneKind has a short description
FIELDS:
Expand All @@ -58,7 +62,10 @@ FIELDS:
path: []string{},
},
{
want: `RESOURCE: field1 <Object>
want: `KIND: OneKind
VERSION: v1
RESOURCE: field1 <Object>
DESCRIPTION:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac
Expand Down Expand Up @@ -90,15 +97,21 @@ FIELDS:
path: []string{"field1"},
},
{
want: `FIELD: string <string>
want: `KIND: OneKind
VERSION: v1
FIELD: string <string>
DESCRIPTION:
This string must be a string
`,
path: []string{"field1", "string"},
},
{
want: `FIELD: array <[]integer>
want: `KIND: OneKind
VERSION: v1
FIELD: array <[]integer>
DESCRIPTION:
This array must be an array of int
Expand All @@ -111,7 +124,7 @@ DESCRIPTION:

for _, test := range tests {
buf := bytes.Buffer{}
if err := PrintModelDescription(test.path, &buf, schema, false); err != nil {
if err := PrintModelDescription(test.path, &buf, schema, gvk, false); err != nil {
t.Fatalf("Failed to PrintModelDescription for path %v: %v", test.path, err)
}
got := buf.String()
Expand Down

0 comments on commit 761fdea

Please sign in to comment.