From f9b498e341bf2c1116c8d5df72f7b713e4a368bd Mon Sep 17 00:00:00 2001 From: deads2k Date: Tue, 6 Sep 2016 14:03:36 -0400 Subject: [PATCH] add group prefix matching for kubectl usage --- hack/make-rules/test-cmd.sh | 3 + pkg/api/meta/restmapper.go | 39 ++++++++++- pkg/api/meta/restmapper_test.go | 115 ++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 1 deletion(-) diff --git a/hack/make-rules/test-cmd.sh b/hack/make-rules/test-cmd.sh index e77b06dfe9..fef91859b7 100755 --- a/hack/make-rules/test-cmd.sh +++ b/hack/make-rules/test-cmd.sh @@ -947,6 +947,9 @@ __EOF__ kube::test::if_has_string "${output_message}" 'extensions/v1beta1' output_message=$(kubectl get hpa.autoscaling -o=jsonpath='{.items[0].apiVersion}' 2>&1 "${kube_flags[@]}") kube::test::if_has_string "${output_message}" 'autoscaling/v1' + # tests kubectl group prefix matching + output_message=$(kubectl get hpa.autoscal -o=jsonpath='{.items[0].apiVersion}' 2>&1 "${kube_flags[@]}") + kube::test::if_has_string "${output_message}" 'autoscaling/v1' # Clean up # Note that we should delete hpa first, otherwise it may fight with the rc reaper. kubectl delete hpa frontend "${kube_flags[@]}" diff --git a/pkg/api/meta/restmapper.go b/pkg/api/meta/restmapper.go index bcf85ff9d6..29fdaaa35e 100644 --- a/pkg/api/meta/restmapper.go +++ b/pkg/api/meta/restmapper.go @@ -223,8 +223,8 @@ func (m *DefaultRESTMapper) ResourcesFor(input unversioned.GroupVersionResource) ret := []unversioned.GroupVersionResource{} switch { - // fully qualified. Find the exact match case hasGroup && hasVersion: + // fully qualified. Find the exact match for plural, singular := range m.pluralToSingular { if singular == resource { ret = append(ret, plural) @@ -237,16 +237,37 @@ func (m *DefaultRESTMapper) ResourcesFor(input unversioned.GroupVersionResource) } case hasGroup: + // given a group, prefer an exact match. If you don't find one, resort to a prefix match on group + foundExactMatch := false requestedGroupResource := resource.GroupResource() for plural, singular := range m.pluralToSingular { if singular.GroupResource() == requestedGroupResource { + foundExactMatch = true ret = append(ret, plural) } if plural.GroupResource() == requestedGroupResource { + foundExactMatch = true ret = append(ret, plural) } } + // if you didn't find an exact match, match on group prefixing. This allows storageclass.storage to match + // storageclass.storage.k8s.io + if !foundExactMatch { + for plural, singular := range m.pluralToSingular { + if !strings.HasPrefix(plural.Group, requestedGroupResource.Group) { + continue + } + if singular.Resource == requestedGroupResource.Resource { + ret = append(ret, plural) + } + if plural.Resource == requestedGroupResource.Resource { + ret = append(ret, plural) + } + } + + } + case hasVersion: for plural, singular := range m.pluralToSingular { if singular.Version == resource.Version && singular.Resource == resource.Resource { @@ -309,13 +330,29 @@ func (m *DefaultRESTMapper) KindsFor(input unversioned.GroupVersionResource) ([] } case hasGroup: + foundExactMatch := false requestedGroupResource := resource.GroupResource() for currResource, currKind := range m.resourceToKind { if currResource.GroupResource() == requestedGroupResource { + foundExactMatch = true ret = append(ret, currKind) } } + // if you didn't find an exact match, match on group prefixing. This allows storageclass.storage to match + // storageclass.storage.k8s.io + if !foundExactMatch { + for currResource, currKind := range m.resourceToKind { + if !strings.HasPrefix(currResource.Group, requestedGroupResource.Group) { + continue + } + if currResource.Resource == requestedGroupResource.Resource { + ret = append(ret, currKind) + } + } + + } + case hasVersion: for currResource, currKind := range m.resourceToKind { if currResource.Version == resource.Version && currResource.Resource == resource.Resource { diff --git a/pkg/api/meta/restmapper_test.go b/pkg/api/meta/restmapper_test.go index 11d7c11be0..a8bff20337 100644 --- a/pkg/api/meta/restmapper_test.go +++ b/pkg/api/meta/restmapper_test.go @@ -130,6 +130,62 @@ func TestRESTMapperKindsFor(t *testing.T) { ExpectedKinds []unversioned.GroupVersionKind ExpectedKindErr string }{ + { + // exact matches are prefered + Name: "groups, with group exact", + PreferredOrder: []unversioned.GroupVersion{ + {Group: "first-group-1", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []unversioned.GroupVersionKind{ + {Group: "first-group-1", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + PartialResourceToRequest: unversioned.GroupVersionResource{Group: "first-group", Resource: "my-kind"}, + + ExpectedKinds: []unversioned.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + }, + + { + // group prefixes work + Name: "groups, with group prefix", + PreferredOrder: []unversioned.GroupVersion{ + {Group: "second-group", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []unversioned.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + }, + PartialResourceToRequest: unversioned.GroupVersionResource{Group: "first", Resource: "my-kind"}, + + ExpectedKinds: []unversioned.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + }, + + { + // group prefixes can be ambiguous + Name: "groups, with ambiguous group prefix", + PreferredOrder: []unversioned.GroupVersion{ + {Group: "first-group-1", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []unversioned.GroupVersionKind{ + {Group: "first-group-1", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + PartialResourceToRequest: unversioned.GroupVersionResource{Group: "first", Resource: "my-kind"}, + + ExpectedKinds: []unversioned.GroupVersionKind{ + {Group: "first-group-1", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + ExpectedKindErr: " matches multiple kinds ", + }, + { Name: "ambiguous groups, with preference order", PreferredOrder: []unversioned.GroupVersion{ @@ -243,6 +299,65 @@ func TestRESTMapperResourcesFor(t *testing.T) { ExpectedResources []unversioned.GroupVersionResource ExpectedResourceErr string }{ + { + // exact matches are prefered + Name: "groups, with group exact", + PreferredOrder: []unversioned.GroupVersion{ + {Group: "first-group-1", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []unversioned.GroupVersionKind{ + {Group: "first-group-1", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + PluralPartialResourceToRequest: unversioned.GroupVersionResource{Group: "first-group", Resource: "my-kinds"}, + SingularPartialResourceToRequest: unversioned.GroupVersionResource{Group: "first-group", Resource: "my-kind"}, + + ExpectedResources: []unversioned.GroupVersionResource{ + {Group: "first-group", Version: "first-version", Resource: "my-kinds"}, + }, + }, + + { + // group prefixes work + Name: "groups, with group prefix", + PreferredOrder: []unversioned.GroupVersion{ + {Group: "second-group", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []unversioned.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + }, + PluralPartialResourceToRequest: unversioned.GroupVersionResource{Group: "first", Resource: "my-kinds"}, + SingularPartialResourceToRequest: unversioned.GroupVersionResource{Group: "first", Resource: "my-kind"}, + + ExpectedResources: []unversioned.GroupVersionResource{ + {Group: "first-group", Version: "first-version", Resource: "my-kinds"}, + }, + }, + + { + // group prefixes can be ambiguous + Name: "groups, with ambiguous group prefix", + PreferredOrder: []unversioned.GroupVersion{ + {Group: "first-group-1", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []unversioned.GroupVersionKind{ + {Group: "first-group-1", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + PluralPartialResourceToRequest: unversioned.GroupVersionResource{Group: "first", Resource: "my-kinds"}, + SingularPartialResourceToRequest: unversioned.GroupVersionResource{Group: "first", Resource: "my-kind"}, + + ExpectedResources: []unversioned.GroupVersionResource{ + {Group: "first-group-1", Version: "first-version", Resource: "my-kinds"}, + {Group: "first-group", Version: "first-version", Resource: "my-kinds"}, + }, + ExpectedResourceErr: " matches multiple resources ", + }, + { Name: "ambiguous groups, with preference order", PreferredOrder: []unversioned.GroupVersion{