Kubectl explain now also prints the Kind and APIVersion of the resource

pull/6/head
Marko Luksa 2017-11-13 15:12:33 +01:00
parent 710523ed7d
commit c77d5d0f90
5 changed files with 50 additions and 14 deletions

View File

@ -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 fmt.Errorf("Couldn't find resource for %q", gvk)
} }
return explain.PrintModelDescription(fieldsPath, out, schema, recursive) return explain.PrintModelDescription(fieldsPath, out, schema, gvk, recursive)
} }

View File

@ -16,6 +16,7 @@ go_library(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//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", "//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
], ],
) )

View File

@ -21,6 +21,7 @@ import (
"strings" "strings"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kube-openapi/pkg/util/proto" "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. // PrintModelDescription prints the description of a specific model or dot path.
// If recursive, all components nested within the fields of the schema will be // If recursive, all components nested within the fields of the schema will be
// printed. // 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 := "" fieldName := ""
if len(fieldsPath) != 0 { if len(fieldsPath) != 0 {
fieldName = fieldsPath[len(fieldsPath)-1] fieldName = fieldsPath[len(fieldsPath)-1]
@ -60,5 +61,5 @@ func PrintModelDescription(fieldsPath []string, w io.Writer, schema proto.Schema
} }
b := fieldsPrinterBuilder{Recursive: recursive} b := fieldsPrinterBuilder{Recursive: recursive}
f := &Formatter{Writer: w, Wrap: 80} f := &Formatter{Writer: w, Wrap: 80}
return PrintModel(fieldName, f, b, schema) return PrintModel(fieldName, f, b, schema, gvk)
} }

View File

@ -16,7 +16,10 @@ limitations under the License.
package explain 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. // fieldIndentLevel is the level of indentation for fields.
const fieldIndentLevel = 3 const fieldIndentLevel = 3
@ -33,11 +36,19 @@ type modelPrinter struct {
Descriptions []string Descriptions []string
Writer *Formatter Writer *Formatter
Builder fieldsPrinterBuilder Builder fieldsPrinterBuilder
GVK schema.GroupVersionKind
Error error Error error
} }
var _ proto.SchemaVisitor = &modelPrinter{} 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 // PrintDescription prints the description for a given schema. There
// might be multiple description, since we collect descriptions when we // might be multiple description, since we collect descriptions when we
// go through references, arrays and maps. // 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. // VisitKind prints a full resource with its fields.
func (m *modelPrinter) VisitKind(k *proto.Kind) { func (m *modelPrinter) VisitKind(k *proto.Kind) {
if err := m.PrintKindAndVersion(); err != nil {
m.Error = err
return
}
if m.Type == "" { if m.Type == "" {
m.Type = GetTypeName(k) m.Type = GetTypeName(k)
} }
@ -103,10 +119,15 @@ func (m *modelPrinter) VisitMap(om *proto.Map) {
// VisitPrimitive prints a field type and its description. // VisitPrimitive prints a field type and its description.
func (m *modelPrinter) VisitPrimitive(p *proto.Primitive) { func (m *modelPrinter) VisitPrimitive(p *proto.Primitive) {
if err := m.PrintKindAndVersion(); err != nil {
m.Error = err
return
}
if m.Type == "" { if m.Type == "" {
m.Type = GetTypeName(p) 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 m.Error = err
return return
} }
@ -120,8 +141,8 @@ func (m *modelPrinter) VisitReference(r proto.Reference) {
} }
// PrintModel prints the description of a schema in writer. // PrintModel prints the description of a schema in writer.
func PrintModel(name string, writer *Formatter, builder fieldsPrinterBuilder, schema proto.Schema) error { func PrintModel(name string, writer *Formatter, builder fieldsPrinterBuilder, schema proto.Schema, gvk schema.GroupVersionKind) error {
m := &modelPrinter{Name: name, Writer: writer, Builder: builder} m := &modelPrinter{Name: name, Writer: writer, Builder: builder, GVK: gvk}
schema.Accept(m) schema.Accept(m)
return m.Error return m.Error
} }

View File

@ -24,11 +24,12 @@ import (
) )
func TestModel(t *testing.T) { func TestModel(t *testing.T) {
schema := resources.LookupResource(schema.GroupVersionKind{ gvk := schema.GroupVersionKind{
Group: "", Group: "",
Version: "v1", Version: "v1",
Kind: "OneKind", Kind: "OneKind",
}) }
schema := resources.LookupResource(gvk)
if schema == nil { if schema == nil {
t.Fatal("Couldn't find schema v1.OneKind") t.Fatal("Couldn't find schema v1.OneKind")
} }
@ -38,7 +39,10 @@ func TestModel(t *testing.T) {
want string want string
}{ }{
{ {
want: `DESCRIPTION: want: `KIND: OneKind
VERSION: v1
DESCRIPTION:
OneKind has a short description OneKind has a short description
FIELDS: FIELDS:
@ -58,7 +62,10 @@ FIELDS:
path: []string{}, path: []string{},
}, },
{ {
want: `RESOURCE: field1 <Object> want: `KIND: OneKind
VERSION: v1
RESOURCE: field1 <Object>
DESCRIPTION: DESCRIPTION:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac
@ -90,7 +97,10 @@ FIELDS:
path: []string{"field1"}, path: []string{"field1"},
}, },
{ {
want: `FIELD: string <string> want: `KIND: OneKind
VERSION: v1
FIELD: string <string>
DESCRIPTION: DESCRIPTION:
This string must be a string This string must be a string
@ -98,7 +108,10 @@ DESCRIPTION:
path: []string{"field1", "string"}, path: []string{"field1", "string"},
}, },
{ {
want: `FIELD: array <[]integer> want: `KIND: OneKind
VERSION: v1
FIELD: array <[]integer>
DESCRIPTION: DESCRIPTION:
This array must be an array of int This array must be an array of int
@ -111,7 +124,7 @@ DESCRIPTION:
for _, test := range tests { for _, test := range tests {
buf := bytes.Buffer{} 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) t.Fatalf("Failed to PrintModelDescription for path %v: %v", test.path, err)
} }
got := buf.String() got := buf.String()