fix(kubectl): explain crds with the same resource name with builtin objects
Kubernetes-commit: 397f107a0886999e0d45955dfe460112edd9ac5e
This commit is contained in:
		
							parent
							
								
									5c6d6fa24d
								
							
						
					
					
						commit
						b9bc004f47
					
				| 
						 | 
					@ -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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue