fix(kubectl): explain crds with the same resource name with builtin objects

Kubernetes-commit: 397f107a0886999e0d45955dfe460112edd9ac5e
This commit is contained in:
knight42 2020-03-26 16:07:06 +08:00 committed by Kubernetes Publisher
parent 5c6d6fa24d
commit b9bc004f47
3 changed files with 24 additions and 24 deletions

View File

@ -123,19 +123,14 @@ func (o *ExplainOptions) Run(args []string) error {
// TODO: After we figured out the new syntax to separate group and resource, allow // TODO: After we figured out the new syntax to separate group and resource, allow
// the users to use it in explain (kubectl explain <group><syntax><resource>). // the users to use it in explain (kubectl explain <group><syntax><resource>).
// Refer to issue #16039 for why we do this. Refer to PR #15808 that used "/" syntax. // Refer to issue #16039 for why we do this. Refer to PR #15808 that used "/" syntax.
inModel, fieldsPath, err := explain.SplitAndParseResourceRequest(args[0], o.Mapper) fullySpecifiedGVR, fieldsPath, err := explain.SplitAndParseResourceRequest(args[0], o.Mapper)
if err != nil { if err != nil {
return err return err
} }
// TODO: We should deduce the group for a resource by discovering the supported resources at server. gvk, _ := o.Mapper.KindFor(fullySpecifiedGVR)
fullySpecifiedGVR, groupResource := schema.ParseResourceArg(inModel)
gvk := schema.GroupVersionKind{}
if fullySpecifiedGVR != nil {
gvk, _ = o.Mapper.KindFor(*fullySpecifiedGVR)
}
if gvk.Empty() { if gvk.Empty() {
gvk, err = o.Mapper.KindFor(groupResource.WithVersion("")) gvk, err = o.Mapper.KindFor(fullySpecifiedGVR.GroupResource().WithVersion(""))
if err != nil { if err != nil {
return err return err
} }
@ -151,7 +146,7 @@ func (o *ExplainOptions) Run(args []string) error {
schema := o.Schema.LookupResource(gvk) schema := o.Schema.LookupResource(gvk)
if schema == nil { if schema == nil {
return fmt.Errorf("Couldn't find resource for %q", gvk) return fmt.Errorf("couldn't find resource for %q", gvk)
} }
return explain.PrintModelDescription(fieldsPath, o.Out, schema, gvk, recursive) return explain.PrintModelDescription(fieldsPath, o.Out, schema, gvk, recursive)

View File

@ -20,9 +20,10 @@ import (
"io" "io"
"strings" "strings"
"k8s.io/kube-openapi/pkg/util/proto"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kube-openapi/pkg/util/proto"
) )
type fieldsPrinter interface { type fieldsPrinter interface {
@ -43,10 +44,13 @@ func splitDotNotation(model string) (string, []string) {
} }
// SplitAndParseResourceRequest separates the users input into a model and fields // SplitAndParseResourceRequest separates the users input into a model and fields
func SplitAndParseResourceRequest(inResource string, mapper meta.RESTMapper) (string, []string, error) { func SplitAndParseResourceRequest(inResource string, mapper meta.RESTMapper) (schema.GroupVersionResource, []string, error) {
inResource, fieldsPath := splitDotNotation(inResource) inResource, fieldsPath := splitDotNotation(inResource)
inResource, _ = mapper.ResourceSingularizer(inResource) gvr, err := mapper.ResourceFor(schema.GroupVersionResource{Resource: inResource})
return inResource, fieldsPath, nil if err != nil {
return schema.GroupVersionResource{}, nil, err
}
return gvr, fieldsPath, nil
} }
// PrintModelDescription prints the description of a specific model or dot path. // PrintModelDescription prints the description of a specific model or dot path.

View File

@ -21,37 +21,38 @@ import (
"testing" "testing"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper" "k8s.io/apimachinery/pkg/api/meta/testrestmapper"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubectl/pkg/scheme" "k8s.io/kubectl/pkg/scheme"
) )
func TestSplitAndParseResourceRequest(t *testing.T) { func TestSplitAndParseResourceRequest(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
inresource string inResource string
expectedInResource string expectedGVR schema.GroupVersionResource
expectedFieldsPath []string expectedFieldsPath []string
expectedErr bool expectedErr bool
}{ }{
{ {
name: "no trailing period", name: "no trailing period",
inresource: "field1.field2.field3", inResource: "pods.field2.field3",
expectedInResource: "field1", expectedGVR: schema.GroupVersionResource{Resource: "pods", Version: "v1"},
expectedFieldsPath: []string{"field2", "field3"}, expectedFieldsPath: []string{"field2", "field3"},
}, },
{ {
name: "trailing period with correct fieldsPath", name: "trailing period with correct fieldsPath",
inresource: "field1.field2.field3.", inResource: "service.field2.field3.",
expectedInResource: "field1", expectedGVR: schema.GroupVersionResource{Resource: "services", Version: "v1"},
expectedFieldsPath: []string{"field2", "field3"}, expectedFieldsPath: []string{"field2", "field3"},
}, },
{ {
name: "trailing period with incorrect fieldsPath", name: "trailing period with incorrect fieldsPath",
inresource: "field1.field2.field3.", inResource: "node.field2.field3.",
expectedInResource: "field1", expectedGVR: schema.GroupVersionResource{Resource: "nodes", Version: "v1"},
expectedFieldsPath: []string{"field2", "field3", ""}, expectedFieldsPath: []string{"field2", "field3", ""},
expectedErr: true, expectedErr: true,
}, },
@ -60,13 +61,13 @@ func TestSplitAndParseResourceRequest(t *testing.T) {
mapper := testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...) mapper := testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...)
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
gotInResource, gotFieldsPath, err := SplitAndParseResourceRequest(tt.inresource, mapper) gotGVR, gotFieldsPath, err := SplitAndParseResourceRequest(tt.inResource, mapper)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
if !reflect.DeepEqual(tt.expectedInResource, gotInResource) && !tt.expectedErr { if !reflect.DeepEqual(tt.expectedGVR, gotGVR) && !tt.expectedErr {
t.Errorf("%s: expected inresource: %s, got: %s", tt.name, tt.expectedInResource, gotInResource) t.Errorf("%s: expected inResource: %s, got: %s", tt.name, tt.expectedGVR, gotGVR)
} }
if !reflect.DeepEqual(tt.expectedFieldsPath, gotFieldsPath) && !tt.expectedErr { if !reflect.DeepEqual(tt.expectedFieldsPath, gotFieldsPath) && !tt.expectedErr {