From c77d5d0f9031876409171b90128712a28a54fcb3 Mon Sep 17 00:00:00 2001 From: Marko Luksa Date: Mon, 13 Nov 2017 15:12:33 +0100 Subject: [PATCH] Kubectl explain now also prints the Kind and APIVersion of the resource --- pkg/kubectl/cmd/explain.go | 2 +- pkg/kubectl/explain/BUILD | 1 + pkg/kubectl/explain/explain.go | 5 ++-- pkg/kubectl/explain/model_printer.go | 29 +++++++++++++++++++---- pkg/kubectl/explain/model_printer_test.go | 27 +++++++++++++++------ 5 files changed, 50 insertions(+), 14 deletions(-) diff --git a/pkg/kubectl/cmd/explain.go b/pkg/kubectl/cmd/explain.go index a339df7c811..d1ecf3d65d4 100644 --- a/pkg/kubectl/cmd/explain.go +++ b/pkg/kubectl/cmd/explain.go @@ -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) } diff --git a/pkg/kubectl/explain/BUILD b/pkg/kubectl/explain/BUILD index 6792dbf6bf1..cbb5f7b4bd7 100644 --- a/pkg/kubectl/explain/BUILD +++ b/pkg/kubectl/explain/BUILD @@ -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", ], ) diff --git a/pkg/kubectl/explain/explain.go b/pkg/kubectl/explain/explain.go index a0dcc389a2d..4d2d1841dce 100644 --- a/pkg/kubectl/explain/explain.go +++ b/pkg/kubectl/explain/explain.go @@ -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" ) @@ -47,7 +48,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] @@ -60,5 +61,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) } diff --git a/pkg/kubectl/explain/model_printer.go b/pkg/kubectl/explain/model_printer.go index 82ad99fac42..64f5bb4487a 100644 --- a/pkg/kubectl/explain/model_printer.go +++ b/pkg/kubectl/explain/model_printer.go @@ -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 @@ -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. @@ -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) } @@ -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 } @@ -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 } diff --git a/pkg/kubectl/explain/model_printer_test.go b/pkg/kubectl/explain/model_printer_test.go index 66b9b07eafc..42c0f424723 100644 --- a/pkg/kubectl/explain/model_printer_test.go +++ b/pkg/kubectl/explain/model_printer_test.go @@ -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") } @@ -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: @@ -58,7 +62,10 @@ FIELDS: path: []string{}, }, { - want: `RESOURCE: field1 + want: `KIND: OneKind +VERSION: v1 + +RESOURCE: field1 DESCRIPTION: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac @@ -90,7 +97,10 @@ FIELDS: path: []string{"field1"}, }, { - want: `FIELD: string + want: `KIND: OneKind +VERSION: v1 + +FIELD: string DESCRIPTION: This string must be a string @@ -98,7 +108,10 @@ DESCRIPTION: 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 @@ -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()