update RESTMapping API to be properly typed

This commit is contained in:
deads2k 2015-11-16 16:24:59 -05:00
parent 5c4fb5bcbe
commit 8679925847
17 changed files with 142 additions and 119 deletions

View File

@ -74,20 +74,22 @@ func TestInterfacesFor(t *testing.T) {
} }
func TestRESTMapper(t *testing.T) { func TestRESTMapper(t *testing.T) {
if v, k, err := latest.GroupOrDie("").RESTMapper.VersionAndKindForResource("replicationcontrollers"); err != nil || v != "v1" || k != "ReplicationController" { gv := unversioned.GroupVersion{Group: "", Version: "v1"}
t.Errorf("unexpected version mapping: %s %s %v", v, k, err) rcGVK := gv.WithKind("ReplicationController")
podTemplateGVK := gv.WithKind("PodTemplate")
if gvk, err := latest.GroupOrDie("").RESTMapper.KindFor("replicationcontrollers"); err != nil || gvk != rcGVK {
t.Errorf("unexpected version mapping: %v %v", gvk, err)
} }
expectedGroupVersion := unversioned.GroupVersion{Version: "v1"} if m, err := latest.GroupOrDie("").RESTMapper.RESTMapping(podTemplateGVK.GroupKind(), ""); err != nil || m.GroupVersionKind != podTemplateGVK || m.Resource != "podtemplates" {
if m, err := latest.GroupOrDie("").RESTMapper.RESTMapping("PodTemplate", ""); err != nil || m.GroupVersionKind.GroupVersion() != expectedGroupVersion || m.Resource != "podtemplates" {
t.Errorf("unexpected version mapping: %#v %v", m, err) t.Errorf("unexpected version mapping: %#v %v", m, err)
} }
for _, version := range latest.GroupOrDie("").Versions { for _, version := range latest.GroupOrDie("").Versions {
currGroupVersion := unversioned.GroupVersion{Version: version} currGroupVersion := unversioned.GroupVersion{Version: version}
mapping, err := latest.GroupOrDie("").RESTMapper.RESTMapping("ReplicationController", currGroupVersion.String()) mapping, err := latest.GroupOrDie("").RESTMapper.RESTMapping(rcGVK.GroupKind(), currGroupVersion.String())
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }

View File

@ -150,7 +150,8 @@ type RESTMapper interface {
// KindFor takes a resource and returns back the unambiguous Kind (GroupVersionKind) // KindFor takes a resource and returns back the unambiguous Kind (GroupVersionKind)
KindFor(resource string) (unversioned.GroupVersionKind, error) KindFor(resource string) (unversioned.GroupVersionKind, error)
RESTMapping(kind string, versions ...string) (*RESTMapping, error) RESTMapping(gk unversioned.GroupKind, versions ...string) (*RESTMapping, error)
AliasesForResource(resource string) ([]string, bool) AliasesForResource(resource string) ([]string, bool)
ResourceSingularizer(resource string) (singular string, err error) ResourceSingularizer(resource string) (singular string, err error)
ResourceIsValid(resource string) bool ResourceIsValid(resource string) bool

View File

@ -174,77 +174,60 @@ func (m *DefaultRESTMapper) KindFor(resource string) (unversioned.GroupVersionKi
} }
// RESTMapping returns a struct representing the resource path and conversion interfaces a // RESTMapping returns a struct representing the resource path and conversion interfaces a
// RESTClient should use to operate on the provided kind in order of versions. If a version search // RESTClient should use to operate on the provided group/kind in order of versions. If a version search
// order is not provided, the search order provided to DefaultRESTMapper will be used to resolve which // order is not provided, the search order provided to DefaultRESTMapper will be used to resolve which
// APIVersion should be used to access the named kind. // version should be used to access the named group/kind.
// TODO version here in this RESTMapper means just APIVersion, but the RESTMapper API is intended to handle multiple groups func (m *DefaultRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*RESTMapping, error) {
// So this API is broken. The RESTMapper test made it clear that versions here were API versions, but the code tries to use
// them with group/version tuples.
// TODO this should probably become RESTMapping(GroupKind, versions ...string)
func (m *DefaultRESTMapper) RESTMapping(kind string, versions ...string) (*RESTMapping, error) {
// TODO, this looks really strange, but once this API is update, the version detection becomes clean again
// because you won't be able to request cross-group kinds
hadVersion := false
for _, gvString := range versions {
currGroupVersion, err := unversioned.ParseGroupVersion(gvString)
if err != nil {
return nil, err
}
if len(currGroupVersion.Version) != 0 {
hadVersion = true
}
}
// Pick an appropriate version // Pick an appropriate version
var groupVersion *unversioned.GroupVersion var gvk *unversioned.GroupVersionKind
for _, v := range versions { hadVersion := false
if len(v) == 0 { for _, version := range versions {
if len(version) == 0 {
continue continue
} }
currGroupVersion, err := unversioned.ParseGroupVersion(v)
if err != nil {
return nil, err
}
currGVK := currGroupVersion.WithKind(kind) currGVK := gk.WithVersion(version)
hadVersion = true
if _, ok := m.kindToPluralResource[currGVK]; ok { if _, ok := m.kindToPluralResource[currGVK]; ok {
groupVersion = &currGroupVersion gvk = &currGVK
break break
} }
} }
// Use the default preferred versions // Use the default preferred versions
if !hadVersion && (groupVersion == nil) { if !hadVersion && (gvk == nil) {
for _, currGroupVersion := range m.defaultGroupVersions { for _, gv := range m.defaultGroupVersions {
currGVK := currGroupVersion.WithKind(kind) if gv.Group != gk.Group {
continue
}
currGVK := gk.WithVersion(gv.Version)
if _, ok := m.kindToPluralResource[currGVK]; ok { if _, ok := m.kindToPluralResource[currGVK]; ok {
groupVersion = &currGroupVersion gvk = &currGVK
break break
} }
} }
} }
if groupVersion == nil { if gvk == nil {
return nil, fmt.Errorf("no kind named %q is registered in versions %q", kind, versions) return nil, fmt.Errorf("no kind named %q is registered in versions %q", gk, versions)
} }
gvk := groupVersion.WithKind(kind)
// Ensure we have a REST mapping // Ensure we have a REST mapping
resource, ok := m.kindToPluralResource[gvk] resource, ok := m.kindToPluralResource[*gvk]
if !ok { if !ok {
found := []unversioned.GroupVersion{} found := []unversioned.GroupVersion{}
for _, gv := range m.defaultGroupVersions { for _, gv := range m.defaultGroupVersions {
if _, ok := m.kindToPluralResource[gvk]; ok { if _, ok := m.kindToPluralResource[*gvk]; ok {
found = append(found, gv) found = append(found, gv)
} }
} }
if len(found) > 0 { if len(found) > 0 {
return nil, fmt.Errorf("object with kind %q exists in versions %v, not %v", kind, found, *groupVersion) return nil, fmt.Errorf("object with kind %q exists in versions %v, not %v", gvk.Kind, found, gvk.GroupVersion().String())
} }
return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported object", groupVersion, kind) return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported object", gvk.GroupVersion().String(), gvk.Kind)
} }
// Ensure we have a REST scope // Ensure we have a REST scope
scope, ok := m.kindToScope[gvk] scope, ok := m.kindToScope[*gvk]
if !ok { if !ok {
return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", gvk.GroupVersion().String(), gvk.Kind) return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", gvk.GroupVersion().String(), gvk.Kind)
} }
@ -256,7 +239,7 @@ func (m *DefaultRESTMapper) RESTMapping(kind string, versions ...string) (*RESTM
retVal := &RESTMapping{ retVal := &RESTMapping{
Resource: resource, Resource: resource,
GroupVersionKind: gvk, GroupVersionKind: *gvk,
Scope: scope, Scope: scope,
Codec: interfaces.Codec, Codec: interfaces.Codec,
@ -320,12 +303,12 @@ func (m MultiRESTMapper) KindFor(resource string) (gvk unversioned.GroupVersionK
return return
} }
// RESTMapping provides the REST mapping for the resource based on the resource // RESTMapping provides the REST mapping for the resource based on the
// kind and version. This implementation supports multiple REST schemas and // kind and version. This implementation supports multiple REST schemas and
// return the first match. // return the first match.
func (m MultiRESTMapper) RESTMapping(kind string, versions ...string) (mapping *RESTMapping, err error) { func (m MultiRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
for _, t := range m { for _, t := range m {
mapping, err = t.RESTMapping(kind, versions...) mapping, err = t.RESTMapping(gk, versions...)
if err == nil { if err == nil {
return return
} }

View File

@ -115,7 +115,7 @@ func TestRESTMapperVersionAndKindForResource(t *testing.T) {
if len(testCase.ExpectedGVK.Kind) != 0 { if len(testCase.ExpectedGVK.Kind) != 0 {
mapper.Add(testCase.ExpectedGVK, RESTScopeNamespace, testCase.MixedCase) mapper.Add(testCase.ExpectedGVK, RESTScopeNamespace, testCase.MixedCase)
} }
v, k, err := mapper.VersionAndKindForResource(testCase.Resource) actualGVK, err := mapper.KindFor(testCase.Resource)
hasErr := err != nil hasErr := err != nil
if hasErr != testCase.Err { if hasErr != testCase.Err {
@ -126,13 +126,6 @@ func TestRESTMapperVersionAndKindForResource(t *testing.T) {
continue continue
} }
actualGV, err := unversioned.ParseGroupVersion(v)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
}
actualGVK := unversioned.NewGroupVersionKind(actualGV, k)
if actualGVK != testCase.ExpectedGVK { if actualGVK != testCase.ExpectedGVK {
t.Errorf("%d: unexpected version and kind: e=%s a=%s", i, testCase.ExpectedGVK, actualGVK) t.Errorf("%d: unexpected version and kind: e=%s a=%s", i, testCase.ExpectedGVK, actualGVK)
} }
@ -153,15 +146,15 @@ func TestRESTMapperGroupForResource(t *testing.T) {
for i, testCase := range testCases { for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{testCase.GroupVersionKind.GroupVersion()}, fakeInterfaces) mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{testCase.GroupVersionKind.GroupVersion()}, fakeInterfaces)
mapper.Add(testCase.GroupVersionKind, RESTScopeNamespace, false) mapper.Add(testCase.GroupVersionKind, RESTScopeNamespace, false)
g, err := mapper.GroupForResource(testCase.Resource) actualGVK, err := mapper.KindFor(testCase.Resource)
if testCase.Err { if testCase.Err {
if err == nil { if err == nil {
t.Errorf("%d: expected error", i) t.Errorf("%d: expected error", i)
} }
} else if err != nil { } else if err != nil {
t.Errorf("%d: unexpected error: %v", i, err) t.Errorf("%d: unexpected error: %v", i, err)
} else if g != testCase.GroupVersionKind.Group { } else if actualGVK != testCase.GroupVersionKind {
t.Errorf("%d: expected group %q, got %q", i, testCase.GroupVersionKind.Group, g) t.Errorf("%d: expected group %q, got %q", i, testCase.GroupVersionKind, actualGVK)
} }
} }
} }
@ -268,12 +261,13 @@ func TestRESTMapperRESTMapping(t *testing.T) {
mapper := NewDefaultRESTMapper(testCase.DefaultVersions, fakeInterfaces) mapper := NewDefaultRESTMapper(testCase.DefaultVersions, fakeInterfaces)
mapper.Add(internalGroupVersion.WithKind("InternalObject"), RESTScopeNamespace, testCase.MixedCase) mapper.Add(internalGroupVersion.WithKind("InternalObject"), RESTScopeNamespace, testCase.MixedCase)
deprecatedGroupVersionStrings := []string{} preferredVersions := []string{}
for _, gv := range testCase.APIGroupVersions { for _, gv := range testCase.APIGroupVersions {
deprecatedGroupVersionStrings = append(deprecatedGroupVersionStrings, gv.String()) preferredVersions = append(preferredVersions, gv.Version)
} }
gk := unversioned.GroupKind{Group: testGroup, Kind: testCase.Kind}
mapping, err := mapper.RESTMapping(testCase.Kind, deprecatedGroupVersionStrings...) mapping, err := mapper.RESTMapping(gk, preferredVersions...)
hasErr := err != nil hasErr := err != nil
if hasErr != testCase.Err { if hasErr != testCase.Err {
t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err) t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err)
@ -304,13 +298,15 @@ func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
expectedGroupVersion1 := unversioned.GroupVersion{Group: "tgroup", Version: "test1"} expectedGroupVersion1 := unversioned.GroupVersion{Group: "tgroup", Version: "test1"}
expectedGroupVersion2 := unversioned.GroupVersion{Group: "tgroup", Version: "test2"} expectedGroupVersion2 := unversioned.GroupVersion{Group: "tgroup", Version: "test2"}
expectedGroupVersion3 := unversioned.GroupVersion{Group: "tgroup", Version: "test3"} expectedGroupVersion3 := unversioned.GroupVersion{Group: "tgroup", Version: "test3"}
internalObjectGK := unversioned.GroupKind{Group: "tgroup", Kind: "InternalObject"}
otherObjectGK := unversioned.GroupKind{Group: "tgroup", Kind: "OtherObject"}
mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, fakeInterfaces) mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, fakeInterfaces)
mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace, false) mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace, false)
mapper.Add(expectedGroupVersion2.WithKind("OtherObject"), RESTScopeNamespace, false) mapper.Add(expectedGroupVersion2.WithKind("OtherObject"), RESTScopeNamespace, false)
// pick default matching object kind based on search order // pick default matching object kind based on search order
mapping, err := mapper.RESTMapping("OtherObject") mapping, err := mapper.RESTMapping(otherObjectGK)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
@ -318,7 +314,7 @@ func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
t.Errorf("unexpected mapping: %#v", mapping) t.Errorf("unexpected mapping: %#v", mapping)
} }
mapping, err = mapper.RESTMapping("InternalObject") mapping, err = mapper.RESTMapping(internalObjectGK)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
@ -327,28 +323,28 @@ func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
} }
// mismatch of version // mismatch of version
mapping, err = mapper.RESTMapping("InternalObject", expectedGroupVersion2.String()) mapping, err = mapper.RESTMapping(internalObjectGK, expectedGroupVersion2.Version)
if err == nil { if err == nil {
t.Errorf("unexpected non-error") t.Errorf("unexpected non-error")
} }
mapping, err = mapper.RESTMapping("OtherObject", expectedGroupVersion1.String()) mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion1.Version)
if err == nil { if err == nil {
t.Errorf("unexpected non-error") t.Errorf("unexpected non-error")
} }
// not in the search versions // not in the search versions
mapping, err = mapper.RESTMapping("OtherObject", expectedGroupVersion3.String()) mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version)
if err == nil { if err == nil {
t.Errorf("unexpected non-error") t.Errorf("unexpected non-error")
} }
// explicit search order // explicit search order
mapping, err = mapper.RESTMapping("OtherObject", expectedGroupVersion3.String(), expectedGroupVersion1.String()) mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version, expectedGroupVersion1.Version)
if err == nil { if err == nil {
t.Errorf("unexpected non-error") t.Errorf("unexpected non-error")
} }
mapping, err = mapper.RESTMapping("OtherObject", expectedGroupVersion3.String(), expectedGroupVersion2.String()) mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version, expectedGroupVersion2.Version)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
@ -360,10 +356,11 @@ func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
func TestRESTMapperReportsErrorOnBadVersion(t *testing.T) { func TestRESTMapperReportsErrorOnBadVersion(t *testing.T) {
expectedGroupVersion1 := unversioned.GroupVersion{Group: "tgroup", Version: "test1"} expectedGroupVersion1 := unversioned.GroupVersion{Group: "tgroup", Version: "test1"}
expectedGroupVersion2 := unversioned.GroupVersion{Group: "tgroup", Version: "test2"} expectedGroupVersion2 := unversioned.GroupVersion{Group: "tgroup", Version: "test2"}
internalObjectGK := unversioned.GroupKind{Group: "tgroup", Kind: "InternalObject"}
mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, unmatchedVersionInterfaces) mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, unmatchedVersionInterfaces)
mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace, false) mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace, false)
_, err := mapper.RESTMapping("InternalObject", expectedGroupVersion1.String()) _, err := mapper.RESTMapping(internalObjectGK, expectedGroupVersion1.Version)
if err == nil { if err == nil {
t.Errorf("unexpected non-error") t.Errorf("unexpected non-error")
} }

View File

@ -22,6 +22,21 @@ import (
"strings" "strings"
) )
// GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying
// concepts during lookup stages without having partially valid types
type GroupKind struct {
Group string
Kind string
}
func (gk GroupKind) WithVersion(version string) GroupVersionKind {
return GroupVersionKind{Group: gk.Group, Version: version, Kind: gk.Kind}
}
func (gk *GroupKind) String() string {
return gk.Group + ", Kind=" + gk.Kind
}
// GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion // GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion
// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling // to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling
type GroupVersionKind struct { type GroupVersionKind struct {
@ -35,6 +50,10 @@ func NewGroupVersionKind(gv GroupVersion, kind string) GroupVersionKind {
return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind} return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind}
} }
func (gvk GroupVersionKind) GroupKind() GroupKind {
return GroupKind{Group: gvk.Group, Kind: gvk.Kind}
}
func (gvk GroupVersionKind) GroupVersion() GroupVersion { func (gvk GroupVersionKind) GroupVersion() GroupVersion {
return GroupVersion{Group: gvk.Group, Version: gvk.Version} return GroupVersion{Group: gvk.Group, Version: gvk.Version}
} }

View File

@ -54,23 +54,19 @@ func TestInterfacesFor(t *testing.T) {
} }
func TestRESTMapper(t *testing.T) { func TestRESTMapper(t *testing.T) {
expectedGroupVersion := unversioned.GroupVersion{Group: "componentconfig", Version: "v1alpha1"} gv := unversioned.GroupVersion{Group: "componentconfig", Version: "v1alpha1"}
proxyGVK := gv.WithKind("KubeProxyConfiguration")
if v, k, err := latest.GroupOrDie("componentconfig").RESTMapper.VersionAndKindForResource("kubeproxyconfiguration"); err != nil || v != expectedGroupVersion.String() || k != "KubeProxyConfiguration" { if gvk, err := latest.GroupOrDie("componentconfig").RESTMapper.KindFor("kubeproxyconfiguration"); err != nil || gvk != proxyGVK {
t.Errorf("unexpected version mapping: %q %q %v", v, k, err) t.Errorf("unexpected version mapping: %v %v", gvk, err)
} }
if m, err := latest.GroupOrDie("componentconfig").RESTMapper.RESTMapping("KubeProxyConfiguration", ""); err != nil || m.GroupVersionKind.GroupVersion() != expectedGroupVersion || m.Resource != "kubeproxyconfigurations" { if m, err := latest.GroupOrDie("componentconfig").RESTMapper.RESTMapping(proxyGVK.GroupKind(), ""); err != nil || m.GroupVersionKind != proxyGVK || m.Resource != "kubeproxyconfigurations" {
t.Errorf("unexpected version mapping: %#v %v", m, err) t.Errorf("unexpected version mapping: %#v %v", m, err)
} }
for _, groupVersionString := range latest.GroupOrDie("componentconfig").GroupVersions { for _, version := range latest.GroupOrDie("componentconfig").Versions {
gv, err := unversioned.ParseGroupVersion(groupVersionString) mapping, err := latest.GroupOrDie("componentconfig").RESTMapper.RESTMapping(proxyGVK.GroupKind(), version)
if err != nil {
t.Errorf("unexpected error: %v", err)
continue
}
mapping, err := latest.GroupOrDie("componentconfig").RESTMapper.RESTMapping("KubeProxyConfiguration", gv.String())
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
continue continue

View File

@ -75,20 +75,20 @@ func TestInterfacesFor(t *testing.T) {
} }
func TestRESTMapper(t *testing.T) { func TestRESTMapper(t *testing.T) {
expectedGroupVersion := unversioned.GroupVersion{Group: "extensions", Version: "v1beta1"} gv := unversioned.GroupVersion{Group: "extensions", Version: "v1beta1"}
hpaGVK := gv.WithKind("HorizontalPodAutoscaler")
daemonSetGVK := gv.WithKind("DaemonSet")
if v, k, err := latest.GroupOrDie("extensions").RESTMapper.VersionAndKindForResource("horizontalpodautoscalers"); err != nil || v != expectedGroupVersion.String() || k != "HorizontalPodAutoscaler" { if gvk, err := latest.GroupOrDie("extensions").RESTMapper.KindFor("horizontalpodautoscalers"); err != nil || gvk != hpaGVK {
t.Errorf("unexpected version mapping: %s %s %v", v, k, err) t.Errorf("unexpected version mapping: %v %v", gvk, err)
} }
if m, err := latest.GroupOrDie("extensions").RESTMapper.RESTMapping("DaemonSet", ""); err != nil || m.GroupVersionKind.GroupVersion() != expectedGroupVersion || m.Resource != "daemonsets" { if m, err := latest.GroupOrDie("extensions").RESTMapper.RESTMapping(daemonSetGVK.GroupKind(), ""); err != nil || m.GroupVersionKind != daemonSetGVK || m.Resource != "daemonsets" {
t.Errorf("unexpected version mapping: %#v %v", m, err) t.Errorf("unexpected version mapping: %#v %v", m, err)
} }
for _, groupVersionString := range latest.GroupOrDie("extensions").GroupVersions { for _, version := range latest.GroupOrDie("extensions").Versions {
gv, err := unversioned.ParseGroupVersion(groupVersionString) mapping, err := latest.GroupOrDie("extensions").RESTMapper.RESTMapping(hpaGVK.GroupKind(), version)
mapping, err := latest.GroupOrDie("extensions").RESTMapper.RESTMapping("HorizontalPodAutoscaler", gv.String())
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }

View File

@ -126,13 +126,15 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
if err != nil { if err != nil {
return nil, err return nil, err
} }
gvk := a.group.GroupVersion.WithKind(kind)
versionedPtr, err := a.group.Creater.New(a.group.GroupVersion.String(), kind) versionedPtr, err := a.group.Creater.New(a.group.GroupVersion.String(), kind)
if err != nil { if err != nil {
return nil, err return nil, err
} }
versionedObject := indirectArbitraryPointer(versionedPtr) versionedObject := indirectArbitraryPointer(versionedPtr)
mapping, err := a.group.Mapper.RESTMapping(kind, a.group.GroupVersion.String()) mapping, err := a.group.Mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -148,7 +150,9 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
if err != nil { if err != nil {
return nil, err return nil, err
} }
parentMapping, err := a.group.Mapper.RESTMapping(parentKind, a.group.GroupVersion.String()) parentGVK := a.group.GroupVersion.WithKind(parentKind)
parentMapping, err := a.group.Mapper.RESTMapping(parentGVK.GroupKind(), parentGVK.Version)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -25,6 +25,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -370,10 +371,15 @@ func createGeneratedObject(f *cmdutil.Factory, cmd *cobra.Command, generator kub
} }
mapper, typer := f.Object() mapper, typer := f.Object()
version, kind, err := typer.ObjectVersionAndKind(obj) gvString, kind, err := typer.ObjectVersionAndKind(obj)
if err != nil { if err != nil {
return nil, "", nil, nil, err return nil, "", nil, nil, err
} }
gv, err := unversioned.ParseGroupVersion(gvString)
if err != nil {
return nil, "", nil, nil, err
}
gvk := gv.WithKind(kind)
if len(overrides) > 0 { if len(overrides) > 0 {
obj, err = cmdutil.Merge(obj, overrides, kind) obj, err = cmdutil.Merge(obj, overrides, kind)
@ -382,7 +388,7 @@ func createGeneratedObject(f *cmdutil.Factory, cmd *cobra.Command, generator kub
} }
} }
mapping, err := mapper.RESTMapping(kind, version) mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil { if err != nil {
return nil, "", nil, nil, err return nil, "", nil, nil, err
} }

View File

@ -567,12 +567,16 @@ func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
// PrintObject prints an api object given command line flags to modify the output format // PrintObject prints an api object given command line flags to modify the output format
func (f *Factory) PrintObject(cmd *cobra.Command, obj runtime.Object, out io.Writer) error { func (f *Factory) PrintObject(cmd *cobra.Command, obj runtime.Object, out io.Writer) error {
mapper, _ := f.Object() mapper, _ := f.Object()
_, kind, err := api.Scheme.ObjectVersionAndKind(obj) gvString, kind, err := api.Scheme.ObjectVersionAndKind(obj)
if err != nil {
return err
}
gv, err := unversioned.ParseGroupVersion(gvString)
if err != nil { if err != nil {
return err return err
} }
mapping, err := mapper.RESTMapping(kind) mapping, err := mapper.RESTMapping(unversioned.GroupKind{Group: gv.Group, Kind: kind})
if err != nil { if err != nil {
return err return err
} }

View File

@ -51,13 +51,13 @@ type OutputVersionMapper struct {
} }
// RESTMapping implements meta.RESTMapper by prepending the output version to the preferred version list. // RESTMapping implements meta.RESTMapper by prepending the output version to the preferred version list.
func (m OutputVersionMapper) RESTMapping(kind string, versions ...string) (*meta.RESTMapping, error) { func (m OutputVersionMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*meta.RESTMapping, error) {
mapping, err := m.RESTMapper.RESTMapping(kind, m.OutputVersion) mapping, err := m.RESTMapper.RESTMapping(gk, m.OutputVersion)
if err == nil { if err == nil {
return mapping, nil return mapping, nil
} }
return m.RESTMapper.RESTMapping(kind, versions...) return m.RESTMapper.RESTMapping(gk, versions...)
} }
// ShortcutExpander is a RESTMapper that can be used for Kubernetes // ShortcutExpander is a RESTMapper that can be used for Kubernetes

View File

@ -430,7 +430,7 @@ func (b *Builder) resourceMappings() ([]*meta.RESTMapping, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
mapping, err := b.mapper.RESTMapping(gvk.Kind, gvk.GroupVersion().String()) mapping, err := b.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -450,7 +450,7 @@ func (b *Builder) resourceTupleMappings() (map[string]*meta.RESTMapping, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
mapping, err := b.mapper.RESTMapping(gvk.Kind, gvk.GroupVersion().String()) mapping, err := b.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -59,7 +59,7 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
if kind == "" { if kind == "" {
return nil, fmt.Errorf("kind not set in %q", source) return nil, fmt.Errorf("kind not set in %q", source)
} }
mapping, err := m.RESTMapping(kind, version) mapping, err := m.RESTMapping(unversioned.GroupKind{Group: gv.Group, Kind: kind}, gv.Version)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to recognize %q: %v", source, err) return nil, fmt.Errorf("unable to recognize %q: %v", source, err)
} }
@ -97,11 +97,15 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
// if the object cannot be introspected. Name and namespace will be set into Info // if the object cannot be introspected. Name and namespace will be set into Info
// if the mapping's MetadataAccessor can retrieve them. // if the mapping's MetadataAccessor can retrieve them.
func (m *Mapper) InfoForObject(obj runtime.Object) (*Info, error) { func (m *Mapper) InfoForObject(obj runtime.Object) (*Info, error) {
version, kind, err := m.ObjectVersionAndKind(obj) gvString, kind, err := m.ObjectVersionAndKind(obj)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to get type info from the object %q: %v", reflect.TypeOf(obj), err) return nil, fmt.Errorf("unable to get type info from the object %q: %v", reflect.TypeOf(obj), err)
} }
mapping, err := m.RESTMapping(kind, version) gv, err := unversioned.ParseGroupVersion(gvString)
if err != nil {
return nil, fmt.Errorf("unable to parse group/version from %q: %v", gvString, err)
}
mapping, err := m.RESTMapping(unversioned.GroupKind{Group: gv.Group, Kind: kind}, gv.Version)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to recognize %q: %v", kind, err) return nil, fmt.Errorf("unable to recognize %q: %v", kind, err)
} }

View File

@ -52,17 +52,24 @@ func (t *thirdPartyResourceDataMapper) KindFor(resource string) (unversioned.Gro
return t.mapper.KindFor(resource) return t.mapper.KindFor(resource)
} }
func (t *thirdPartyResourceDataMapper) RESTMapping(kind string, groupVersions ...string) (*meta.RESTMapping, error) { func (t *thirdPartyResourceDataMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*meta.RESTMapping, error) {
if len(groupVersions) != 1 { if len(versions) != 1 {
return nil, fmt.Errorf("unexpected set of groupVersions: %v", groupVersions) return nil, fmt.Errorf("unexpected set of versions: %v", versions)
} }
if groupVersions[0] != apiutil.GetGroupVersion(t.group, t.version) { if gk.Group != t.group {
return nil, fmt.Errorf("unknown version %s expected %s", groupVersions[0], apiutil.GetGroupVersion(t.group, t.version)) return nil, fmt.Errorf("unknown group %q expected %s", gk.Group, t.group)
} }
if kind != "ThirdPartyResourceData" { if gk.Kind != "ThirdPartyResourceData" {
return nil, fmt.Errorf("unknown kind %s expected %s", kind, t.kind) return nil, fmt.Errorf("unknown kind %s expected %s", gk.Kind, t.kind)
} }
mapping, err := t.mapper.RESTMapping("ThirdPartyResourceData", latest.GroupOrDie("extensions").GroupVersion) if versions[0] != t.version {
return nil, fmt.Errorf("unknown version %q expected %q", versions[0], t.version)
}
// TODO figure out why we're doing this rewriting
extensionGK := unversioned.GroupKind{Group: "extensions", Kind: "ThirdPartyResourceData"}
mapping, err := t.mapper.RESTMapping(extensionGK, latest.GroupOrDie("extensions").Version)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -52,7 +52,7 @@ func (p *provision) Admit(a admission.Attributes) (err error) {
if err != nil { if err != nil {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }
mapping, err := api.RESTMapper.RESTMapping(gvk.Kind, gvk.GroupVersion().String()) mapping, err := api.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil { if err != nil {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }

View File

@ -53,7 +53,7 @@ func (e *exists) Admit(a admission.Attributes) (err error) {
if err != nil { if err != nil {
return errors.NewInternalError(err) return errors.NewInternalError(err)
} }
mapping, err := api.RESTMapper.RESTMapping(gvk.Kind, gvk.GroupVersion().String()) mapping, err := api.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil { if err != nil {
return errors.NewInternalError(err) return errors.NewInternalError(err)
} }

View File

@ -61,7 +61,7 @@ func (l *lifecycle) Admit(a admission.Attributes) (err error) {
if err != nil { if err != nil {
return errors.NewInternalError(err) return errors.NewInternalError(err)
} }
mapping, err := api.RESTMapper.RESTMapping(gvk.Kind, gvk.GroupVersion().String()) mapping, err := api.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil { if err != nil {
return errors.NewInternalError(err) return errors.NewInternalError(err)
} }