Merge pull request #55218 from chentao1596/optimize-error-nomatchkind

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>.

Print apiVersion info when failed to execute kubectl apply -f XXX.yaml

**What this PR does / why we need it**:

Fixes https://github.com/kubernetes/kubernetes/issues/55216

**Special notes for your reviewer**:

**Release note**:

```release-note

```
pull/6/head
Kubernetes Submit Queue 2018-01-04 20:43:20 -08:00 committed by GitHub
commit 23c87f0ca7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 88 additions and 35 deletions

View File

@ -34,7 +34,7 @@ import (
// namespace> tuple to a unversioned.APIResource struct. // namespace> tuple to a unversioned.APIResource struct.
func (gc *GarbageCollector) apiResource(apiVersion, kind string) (*metav1.APIResource, error) { func (gc *GarbageCollector) apiResource(apiVersion, kind string) (*metav1.APIResource, error) {
fqKind := schema.FromAPIVersionAndKind(apiVersion, kind) fqKind := schema.FromAPIVersionAndKind(apiVersion, kind)
mapping, err := gc.restMapper.RESTMapping(fqKind.GroupKind(), apiVersion) mapping, err := gc.restMapper.RESTMapping(fqKind.GroupKind(), fqKind.Version)
if err != nil { if err != nil {
return nil, newRESTMappingError(kind, apiVersion) return nil, newRESTMappingError(kind, apiVersion)
} }

View File

@ -52,6 +52,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
], ],
) )

View File

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
) )
// AmbiguousResourceError is returned if the RESTMapper finds multiple matches for a resource // AmbiguousResourceError is returned if the RESTMapper finds multiple matches for a resource
@ -85,11 +86,26 @@ func (e *NoResourceMatchError) Error() string {
// NoKindMatchError is returned if the RESTMapper can't find any match for a kind // NoKindMatchError is returned if the RESTMapper can't find any match for a kind
type NoKindMatchError struct { type NoKindMatchError struct {
PartialKind schema.GroupVersionKind // GroupKind is the API group and kind that was searched
GroupKind schema.GroupKind
// SearchedVersions is the optional list of versions the search was restricted to
SearchedVersions []string
} }
func (e *NoKindMatchError) Error() string { func (e *NoKindMatchError) Error() string {
return fmt.Sprintf("no matches for %v", e.PartialKind) searchedVersions := sets.NewString()
for _, v := range e.SearchedVersions {
searchedVersions.Insert(schema.GroupVersion{Group: e.GroupKind.Group, Version: v}.String())
}
switch len(searchedVersions) {
case 0:
return fmt.Sprintf("no matches for kind %q in group %q", e.GroupKind.Kind, e.GroupKind.Group)
case 1:
return fmt.Sprintf("no matches for kind %q in version %q", e.GroupKind.Kind, searchedVersions.List()[0])
default:
return fmt.Sprintf("no matches for kind %q in versions %q", e.GroupKind.Kind, searchedVersions.List())
}
} }
func IsNoMatchError(err error) bool { func IsNoMatchError(err error) bool {

View File

@ -179,7 +179,7 @@ func (m MultiRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*
if len(errors) > 0 { if len(errors) > 0 {
return nil, utilerrors.NewAggregate(errors) return nil, utilerrors.NewAggregate(errors)
} }
return nil, &NoKindMatchError{PartialKind: gk.WithVersion("")} return nil, &NoKindMatchError{GroupKind: gk, SearchedVersions: versions}
} }
// RESTMappings returns all possible RESTMappings for the provided group kind, or an error // RESTMappings returns all possible RESTMappings for the provided group kind, or an error
@ -204,7 +204,7 @@ func (m MultiRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) (
return nil, utilerrors.NewAggregate(errors) return nil, utilerrors.NewAggregate(errors)
} }
if len(allMappings) == 0 { if len(allMappings) == 0 {
return nil, &NoKindMatchError{PartialKind: gk.WithVersion("")} return nil, &NoKindMatchError{GroupKind: gk, SearchedVersions: versions}
} }
return allMappings, nil return allMappings, nil
} }

View File

@ -261,42 +261,78 @@ func TestMultiRESTMapperRESTMappings(t *testing.T) {
tcs := []struct { tcs := []struct {
name string name string
mapper MultiRESTMapper mapper MultiRESTMapper
input schema.GroupKind groupKind schema.GroupKind
result []*RESTMapping versions []string
err error result []*RESTMapping
err error
}{ }{
{ {
name: "empty", name: "empty with no versions",
mapper: MultiRESTMapper{}, mapper: MultiRESTMapper{},
input: schema.GroupKind{Kind: "Foo"}, groupKind: schema.GroupKind{Kind: "Foo"},
result: nil, result: nil,
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}}, err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}},
}, },
{ {
name: "ignore not found", name: "empty with one version",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "IGNORE_THIS"}}}}, mapper: MultiRESTMapper{},
input: schema.GroupKind{Kind: "Foo"}, groupKind: schema.GroupKind{Kind: "Foo"},
result: nil, versions: []string{"v1beta"},
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}}, result: nil,
err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1beta"}},
}, },
{ {
name: "accept first failure", name: "empty with multi(two) vesions",
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{mappings: []*RESTMapping{mapping1}}}, mapper: MultiRESTMapper{},
input: schema.GroupKind{Kind: "Foo"}, groupKind: schema.GroupKind{Kind: "Foo"},
result: nil, versions: []string{"v1beta", "v2"},
err: errors.New("fail on this"), result: nil,
err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1beta", "v2"}},
}, },
{ {
name: "return both", name: "ignore not found with kind not exist",
mapper: MultiRESTMapper{fixedRESTMapper{mappings: []*RESTMapping{mapping1}}, fixedRESTMapper{mappings: []*RESTMapping{mapping2}}}, mapper: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "IGNORE_THIS"}}}},
input: schema.GroupKind{Kind: "Foo"}, groupKind: schema.GroupKind{Kind: "Foo"},
result: []*RESTMapping{mapping1, mapping2}, versions: nil,
result: nil,
err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}},
},
{
name: "ignore not found with version not exist",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1"}}}},
groupKind: schema.GroupKind{Kind: "Foo"},
versions: []string{"v1beta"},
result: nil,
err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1beta"}},
},
{
name: "ignore not found with multi versions not exist",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1"}}}},
groupKind: schema.GroupKind{Kind: "Foo"},
versions: []string{"v1beta", "v2"},
result: nil,
err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1beta", "v2"}},
},
{
name: "accept first failure",
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{mappings: []*RESTMapping{mapping1}}},
groupKind: schema.GroupKind{Kind: "Foo"},
versions: []string{"v1beta"},
result: nil,
err: errors.New("fail on this"),
},
{
name: "return both",
mapper: MultiRESTMapper{fixedRESTMapper{mappings: []*RESTMapping{mapping1}}, fixedRESTMapper{mappings: []*RESTMapping{mapping2}}},
groupKind: schema.GroupKind{Kind: "Foo"},
versions: []string{"v1beta"},
result: []*RESTMapping{mapping1, mapping2},
}, },
} }
for _, tc := range tcs { for _, tc := range tcs {
actualResult, actualErr := tc.mapper.RESTMappings(tc.input) actualResult, actualErr := tc.mapper.RESTMappings(tc.groupKind, tc.versions...)
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) { if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
t.Errorf("%s: expected %v, got %v", tc.name, e, a) t.Errorf("%s: expected %v, got %v", tc.name, e, a)
} }

View File

@ -153,7 +153,7 @@ func kindMatches(pattern schema.GroupVersionKind, kind schema.GroupVersionKind)
} }
func (m PriorityRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) { func (m PriorityRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
mappings, err := m.Delegate.RESTMappings(gk) mappings, err := m.Delegate.RESTMappings(gk, versions...)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -234,13 +234,13 @@ func TestPriorityRESTMapperRESTMapping(t *testing.T) {
name: "empty", name: "empty",
mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{}}, mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{}},
input: schema.GroupKind{Kind: "Foo"}, input: schema.GroupKind{Kind: "Foo"},
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}}, err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}},
}, },
{ {
name: "ignore not found", name: "ignore not found",
mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "IGNORE_THIS"}}}}}, mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "IGNORE_THIS"}}}}},
input: schema.GroupKind{Kind: "Foo"}, input: schema.GroupKind{Kind: "Foo"},
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}}, err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}},
}, },
{ {
name: "accept first failure", name: "accept first failure",

View File

@ -472,7 +472,7 @@ func (m *DefaultRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string)
return nil, err return nil, err
} }
if len(mappings) == 0 { if len(mappings) == 0 {
return nil, &NoKindMatchError{PartialKind: gk.WithVersion("")} return nil, &NoKindMatchError{GroupKind: gk, SearchedVersions: versions}
} }
// since we rely on RESTMappings method // since we rely on RESTMappings method
// take the first match and return to the caller // take the first match and return to the caller
@ -510,7 +510,7 @@ func (m *DefaultRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string
} }
if len(potentialGVK) == 0 { if len(potentialGVK) == 0 {
return nil, &NoKindMatchError{PartialKind: gk.WithVersion("")} return nil, &NoKindMatchError{GroupKind: gk, SearchedVersions: versions}
} }
for _, gvk := range potentialGVK { for _, gvk := range potentialGVK {