Merge pull request #18874 from ArtfulCoder/revert18442

Reverting 18442
This commit is contained in:
Abhi Shah 2015-12-17 17:31:52 -08:00
commit 08c2cba266
21 changed files with 135 additions and 699 deletions

View File

@ -78,7 +78,7 @@ func TestRESTMapper(t *testing.T) {
rcGVK := gv.WithKind("ReplicationController") rcGVK := gv.WithKind("ReplicationController")
podTemplateGVK := gv.WithKind("PodTemplate") podTemplateGVK := gv.WithKind("PodTemplate")
if gvk, err := latest.GroupOrDie(internal.GroupName).RESTMapper.KindFor(internal.SchemeGroupVersion.WithResource("replicationcontrollers")); err != nil || gvk != rcGVK { if gvk, err := latest.GroupOrDie(internal.GroupName).RESTMapper.KindFor("replicationcontrollers"); err != nil || gvk != rcGVK {
t.Errorf("unexpected version mapping: %v %v", gvk, err) t.Errorf("unexpected version mapping: %v %v", gvk, err)
} }

View File

@ -158,23 +158,12 @@ type RESTMapping struct {
// TODO(caesarxuchao): Add proper multi-group support so that kinds & resources are // TODO(caesarxuchao): Add proper multi-group support so that kinds & resources are
// scoped to groups. See http://issues.k8s.io/12413 and http://issues.k8s.io/10009. // scoped to groups. See http://issues.k8s.io/12413 and http://issues.k8s.io/10009.
type RESTMapper interface { type RESTMapper interface {
// KindFor takes a partial resource and returns back the single match. Returns an error if there are multiple matches // KindFor takes a resource and returns back the unambiguous Kind (GroupVersionKind)
KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) KindFor(resource string) (unversioned.GroupVersionKind, error)
// KindsFor takes a partial resource and returns back the list of potential kinds in priority order
KindsFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionKind, error)
// ResourceFor takes a partial resource and returns back the single match. Returns an error if there are multiple matches
ResourceFor(input unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error)
// ResourcesFor takes a partial resource and returns back the list of potential resource in priority order
ResourcesFor(input unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error)
RESTMapping(gk unversioned.GroupKind, 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 takes a partial resource and returns back whether or not the resource matches at least one kind
ResourceIsValid(resource unversioned.GroupVersionResource) bool
} }

View File

@ -19,11 +19,9 @@ package meta
import ( import (
"fmt" "fmt"
"sort"
"strings" "strings"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/util/sets"
) )
// Implements RESTScope interface // Implements RESTScope interface
@ -73,11 +71,11 @@ var RESTScopeRoot = &restScope{
type DefaultRESTMapper struct { type DefaultRESTMapper struct {
defaultGroupVersions []unversioned.GroupVersion defaultGroupVersions []unversioned.GroupVersion
resourceToKind map[unversioned.GroupVersionResource]unversioned.GroupVersionKind resourceToKind map[string]unversioned.GroupVersionKind
kindToPluralResource map[unversioned.GroupVersionKind]unversioned.GroupVersionResource kindToPluralResource map[unversioned.GroupVersionKind]string
kindToScope map[unversioned.GroupVersionKind]RESTScope kindToScope map[unversioned.GroupVersionKind]RESTScope
singularToPlural map[unversioned.GroupVersionResource]unversioned.GroupVersionResource singularToPlural map[string]string
pluralToSingular map[unversioned.GroupVersionResource]unversioned.GroupVersionResource pluralToSingular map[string]string
interfacesFunc VersionInterfacesFunc interfacesFunc VersionInterfacesFunc
} }
@ -94,11 +92,11 @@ type VersionInterfacesFunc func(version unversioned.GroupVersion) (*VersionInter
// to search when an object has no default version (set empty to return an error), // to search when an object has no default version (set empty to return an error),
// and a function that retrieves the correct codec and metadata for a given version. // and a function that retrieves the correct codec and metadata for a given version.
func NewDefaultRESTMapper(defaultGroupVersions []unversioned.GroupVersion, f VersionInterfacesFunc) *DefaultRESTMapper { func NewDefaultRESTMapper(defaultGroupVersions []unversioned.GroupVersion, f VersionInterfacesFunc) *DefaultRESTMapper {
resourceToKind := make(map[unversioned.GroupVersionResource]unversioned.GroupVersionKind) resourceToKind := make(map[string]unversioned.GroupVersionKind)
kindToPluralResource := make(map[unversioned.GroupVersionKind]unversioned.GroupVersionResource) kindToPluralResource := make(map[unversioned.GroupVersionKind]string)
kindToScope := make(map[unversioned.GroupVersionKind]RESTScope) kindToScope := make(map[unversioned.GroupVersionKind]RESTScope)
singularToPlural := make(map[unversioned.GroupVersionResource]unversioned.GroupVersionResource) singularToPlural := make(map[string]string)
pluralToSingular := make(map[unversioned.GroupVersionResource]unversioned.GroupVersionResource) pluralToSingular := make(map[string]string)
// TODO: verify name mappings work correctly when versions differ // TODO: verify name mappings work correctly when versions differ
return &DefaultRESTMapper{ return &DefaultRESTMapper{
@ -112,54 +110,45 @@ func NewDefaultRESTMapper(defaultGroupVersions []unversioned.GroupVersion, f Ver
} }
} }
func (m *DefaultRESTMapper) Add(kind unversioned.GroupVersionKind, scope RESTScope, mixedCase bool) { func (m *DefaultRESTMapper) Add(gvk unversioned.GroupVersionKind, scope RESTScope, mixedCase bool) {
plural, singular := KindToResource(kind, mixedCase) plural, singular := KindToResource(gvk.Kind, mixedCase)
lowerPlural := plural.GroupVersion().WithResource(strings.ToLower(plural.Resource))
lowerSingular := singular.GroupVersion().WithResource(strings.ToLower(singular.Resource))
m.singularToPlural[singular] = plural m.singularToPlural[singular] = plural
m.pluralToSingular[plural] = singular m.pluralToSingular[plural] = singular
m.singularToPlural[lowerSingular] = lowerPlural _, ok1 := m.resourceToKind[plural]
m.pluralToSingular[lowerPlural] = lowerSingular _, ok2 := m.resourceToKind[strings.ToLower(plural)]
if !ok1 && !ok2 {
if _, mixedCaseExists := m.resourceToKind[plural]; !mixedCaseExists { m.resourceToKind[plural] = gvk
m.resourceToKind[plural] = kind m.resourceToKind[singular] = gvk
m.resourceToKind[singular] = kind if strings.ToLower(plural) != plural {
m.resourceToKind[strings.ToLower(plural)] = gvk
m.resourceToKind[strings.ToLower(singular)] = gvk
}
} }
m.kindToPluralResource[gvk] = plural
if _, lowerCaseExists := m.resourceToKind[lowerPlural]; !lowerCaseExists && (lowerPlural != plural) { m.kindToScope[gvk] = scope
m.resourceToKind[lowerPlural] = kind
m.resourceToKind[lowerSingular] = kind
}
m.kindToPluralResource[kind] = plural
m.kindToScope[kind] = scope
} }
// KindToResource converts Kind to a resource name. // KindToResource converts Kind to a resource name.
func KindToResource(kind unversioned.GroupVersionKind, mixedCase bool) (plural, singular unversioned.GroupVersionResource) { func KindToResource(kind string, mixedCase bool) (plural, singular string) {
kindName := kind.Kind if len(kind) == 0 {
if len(kindName) == 0 {
return return
} }
if mixedCase { if mixedCase {
// Legacy support for mixed case names // Legacy support for mixed case names
singular = kind.GroupVersion().WithResource(strings.ToLower(kindName[:1]) + kindName[1:]) singular = strings.ToLower(kind[:1]) + kind[1:]
} else { } else {
singular = kind.GroupVersion().WithResource(strings.ToLower(kindName)) singular = strings.ToLower(kind)
} }
if strings.HasSuffix(singular, "endpoints") {
singularName := singular.Resource
if strings.HasSuffix(singularName, "endpoints") {
plural = singular plural = singular
} else { } else {
switch string(singularName[len(singularName)-1]) { switch string(singular[len(singular)-1]) {
case "s": case "s":
plural = kind.GroupVersion().WithResource(singularName + "es") plural = singular + "es"
case "y": case "y":
plural = kind.GroupVersion().WithResource(strings.TrimSuffix(singularName, "y") + "ies") plural = strings.TrimSuffix(singular, "y") + "ies"
default: default:
plural = kind.GroupVersion().WithResource(singularName + "s") plural = singular + "s"
} }
} }
return return
@ -167,240 +156,21 @@ func KindToResource(kind unversioned.GroupVersionKind, mixedCase bool) (plural,
// ResourceSingularizer implements RESTMapper // ResourceSingularizer implements RESTMapper
// It converts a resource name from plural to singular (e.g., from pods to pod) // It converts a resource name from plural to singular (e.g., from pods to pod)
// It must have exactly one match and it must match case perfectly. This is congruent with old functionality func (m *DefaultRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
func (m *DefaultRESTMapper) ResourceSingularizer(resourceType string) (string, error) {
partialResource := unversioned.GroupVersionResource{Resource: resourceType}
resource, err := m.ResourceFor(partialResource)
if err != nil {
return resourceType, err
}
singular, ok := m.pluralToSingular[resource] singular, ok := m.pluralToSingular[resource]
if !ok { if !ok {
return resourceType, fmt.Errorf("no singular of resource %v has been defined", resource) return resource, fmt.Errorf("no singular of resource %q has been defined", resource)
} }
return singular.Resource, nil return singular, nil
} }
func (m *DefaultRESTMapper) ResourcesFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) { // VersionAndKindForResource implements RESTMapper
hasResource := len(resource.Resource) > 0 func (m *DefaultRESTMapper) KindFor(resource string) (unversioned.GroupVersionKind, error) {
hasGroup := len(resource.Group) > 0 gvk, ok := m.resourceToKind[strings.ToLower(resource)]
hasVersion := len(resource.Version) > 0 if !ok {
return gvk, fmt.Errorf("in version and kind for resource, no resource %q has been defined", resource)
if !hasResource {
return nil, fmt.Errorf("a resource must be present, got: %v", resource)
} }
return gvk, nil
ret := []unversioned.GroupVersionResource{}
switch {
// fully qualified. Find the exact match
case hasGroup && hasVersion:
for plural, singular := range m.pluralToSingular {
if singular == resource {
ret = append(ret, plural)
break
}
if plural == resource {
ret = append(ret, plural)
break
}
}
case hasGroup:
requestedGroupResource := resource.GroupResource()
for currResource := range m.pluralToSingular {
if currResource.GroupResource() == requestedGroupResource {
ret = append(ret, currResource)
}
}
case hasVersion:
for currResource := range m.pluralToSingular {
if currResource.Version == resource.Version && currResource.Resource == resource.Resource {
ret = append(ret, currResource)
}
}
default:
for currResource := range m.pluralToSingular {
if currResource.Resource == resource.Resource {
ret = append(ret, currResource)
}
}
}
if len(ret) == 0 {
return nil, fmt.Errorf("no resource %v has been defined; known resources: %v", resource, m.pluralToSingular)
}
sort.Sort(resourceByPreferredGroupVersion{ret, m.defaultGroupVersions})
return ret, nil
}
func (m *DefaultRESTMapper) ResourceFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) {
resources, err := m.ResourcesFor(resource)
if err != nil {
return unversioned.GroupVersionResource{}, err
}
if len(resources) == 1 {
return resources[0], nil
}
return unversioned.GroupVersionResource{}, fmt.Errorf("%v is ambiguous, got: %v", resource, resources)
}
func (m *DefaultRESTMapper) KindsFor(input unversioned.GroupVersionResource) ([]unversioned.GroupVersionKind, error) {
resource := input.GroupVersion().WithResource(strings.ToLower(input.Resource))
hasResource := len(resource.Resource) > 0
hasGroup := len(resource.Group) > 0
hasVersion := len(resource.Version) > 0
if !hasResource {
return nil, fmt.Errorf("a resource must be present, got: %v", resource)
}
ret := []unversioned.GroupVersionKind{}
switch {
// fully qualified. Find the exact match
case hasGroup && hasVersion:
kind, exists := m.resourceToKind[resource]
if exists {
ret = append(ret, kind)
}
case hasGroup:
requestedGroupResource := resource.GroupResource()
for currResource, currKind := range m.resourceToKind {
if currResource.GroupResource() == requestedGroupResource {
ret = append(ret, currKind)
}
}
case hasVersion:
for currResource, currKind := range m.resourceToKind {
if currResource.Version == resource.Version && currResource.Resource == resource.Resource {
ret = append(ret, currKind)
}
}
default:
for currResource, currKind := range m.resourceToKind {
if currResource.Resource == resource.Resource {
ret = append(ret, currKind)
}
}
}
if len(ret) == 0 {
return nil, fmt.Errorf("no kind %v has been defined; known resources: %v", resource, m.pluralToSingular)
}
sort.Sort(kindByPreferredGroupVersion{ret, m.defaultGroupVersions})
return ret, nil
}
func (m *DefaultRESTMapper) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) {
kinds, err := m.KindsFor(resource)
if err != nil {
return unversioned.GroupVersionKind{}, err
}
// TODO for each group, choose the most preferred (first) version. This keeps us consistent with code today.
// eventually, we'll need a RESTMapper that is aware of what's available server-side and deconflicts that with
// user preferences
oneKindPerGroup := []unversioned.GroupVersionKind{}
groupsAdded := sets.String{}
for _, kind := range kinds {
if groupsAdded.Has(kind.Group) {
continue
}
oneKindPerGroup = append(oneKindPerGroup, kind)
groupsAdded.Insert(kind.Group)
}
if len(oneKindPerGroup) == 1 {
return oneKindPerGroup[0], nil
}
return unversioned.GroupVersionKind{}, fmt.Errorf("%v is ambiguous, got: %v", resource, kinds)
}
type kindByPreferredGroupVersion struct {
list []unversioned.GroupVersionKind
sortOrder []unversioned.GroupVersion
}
func (o kindByPreferredGroupVersion) Len() int { return len(o.list) }
func (o kindByPreferredGroupVersion) Swap(i, j int) { o.list[i], o.list[j] = o.list[j], o.list[i] }
func (o kindByPreferredGroupVersion) Less(i, j int) bool {
lhs := o.list[i]
rhs := o.list[j]
if lhs == rhs {
return false
}
if lhs.GroupVersion() == rhs.GroupVersion() {
return lhs.Kind < rhs.Kind
}
// otherwise, the difference is in the GroupVersion, so we need to sort with respect to the preferred order
lhsIndex := -1
rhsIndex := -1
for i := range o.sortOrder {
if o.sortOrder[i] == lhs.GroupVersion() {
lhsIndex = i
}
if o.sortOrder[i] == rhs.GroupVersion() {
rhsIndex = i
}
}
if rhsIndex == -1 {
return true
}
return lhsIndex < rhsIndex
}
type resourceByPreferredGroupVersion struct {
list []unversioned.GroupVersionResource
sortOrder []unversioned.GroupVersion
}
func (o resourceByPreferredGroupVersion) Len() int { return len(o.list) }
func (o resourceByPreferredGroupVersion) Swap(i, j int) { o.list[i], o.list[j] = o.list[j], o.list[i] }
func (o resourceByPreferredGroupVersion) Less(i, j int) bool {
lhs := o.list[i]
rhs := o.list[j]
if lhs == rhs {
return false
}
if lhs.GroupVersion() == rhs.GroupVersion() {
return lhs.Resource < rhs.Resource
}
// otherwise, the difference is in the GroupVersion, so we need to sort with respect to the preferred order
lhsIndex := -1
rhsIndex := -1
for i := range o.sortOrder {
if o.sortOrder[i] == lhs.GroupVersion() {
lhsIndex = i
}
if o.sortOrder[i] == rhs.GroupVersion() {
rhsIndex = i
}
}
if rhsIndex == -1 {
return true
}
return lhsIndex < rhsIndex
} }
// RESTMapping returns a struct representing the resource path and conversion interfaces a // RESTMapping returns a struct representing the resource path and conversion interfaces a
@ -468,7 +238,7 @@ func (m *DefaultRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...st
} }
retVal := &RESTMapping{ retVal := &RESTMapping{
Resource: resource.Resource, Resource: resource,
GroupVersionKind: *gvk, GroupVersionKind: *gvk,
Scope: scope, Scope: scope,
@ -499,8 +269,8 @@ func (m *DefaultRESTMapper) AliasesForResource(alias string) ([]string, bool) {
return nil, false return nil, false
} }
// ResourceIsValid takes a partial resource and checks if it's valid // ResourceIsValid takes a string (kind) and checks if it's a valid resource
func (m *DefaultRESTMapper) ResourceIsValid(resource unversioned.GroupVersionResource) bool { func (m *DefaultRESTMapper) ResourceIsValid(resource string) bool {
_, err := m.KindFor(resource) _, err := m.KindFor(resource)
return err == nil return err == nil
} }
@ -520,41 +290,10 @@ func (m MultiRESTMapper) ResourceSingularizer(resource string) (singular string,
return return
} }
func (m MultiRESTMapper) ResourcesFor(resource unversioned.GroupVersionResource) (gvk []unversioned.GroupVersionResource, err error) { // VersionAndKindForResource provides the Version and Kind mappings for the
for _, t := range m { // REST resources. This implementation supports multiple REST schemas and return
gvk, err = t.ResourcesFor(resource)
if err == nil {
return
}
}
return
}
// KindsFor provides the Kind mappings for the REST resources. This implementation supports multiple REST schemas and returns
// the first match. // the first match.
func (m MultiRESTMapper) KindsFor(resource unversioned.GroupVersionResource) (gvk []unversioned.GroupVersionKind, err error) { func (m MultiRESTMapper) KindFor(resource string) (gvk unversioned.GroupVersionKind, err error) {
for _, t := range m {
gvk, err = t.KindsFor(resource)
if err == nil {
return
}
}
return
}
func (m MultiRESTMapper) ResourceFor(resource unversioned.GroupVersionResource) (gvk unversioned.GroupVersionResource, err error) {
for _, t := range m {
gvk, err = t.ResourceFor(resource)
if err == nil {
return
}
}
return
}
// KindsFor provides the Kind mapping for the REST resources. This implementation supports multiple REST schemas and returns
// the first match.
func (m MultiRESTMapper) KindFor(resource unversioned.GroupVersionResource) (gvk unversioned.GroupVersionKind, err error) {
for _, t := range m { for _, t := range m {
gvk, err = t.KindFor(resource) gvk, err = t.KindFor(resource)
if err == nil { if err == nil {
@ -588,7 +327,7 @@ func (m MultiRESTMapper) AliasesForResource(alias string) (aliases []string, ok
} }
// ResourceIsValid takes a string (either group/kind or kind) and checks if it's a valid resource // ResourceIsValid takes a string (either group/kind or kind) and checks if it's a valid resource
func (m MultiRESTMapper) ResourceIsValid(resource unversioned.GroupVersionResource) bool { func (m MultiRESTMapper) ResourceIsValid(resource string) bool {
for _, t := range m { for _, t := range m {
if t.ResourceIsValid(resource) { if t.ResourceIsValid(resource) {
return true return true

View File

@ -20,8 +20,6 @@ import (
"errors" "errors"
"io" "io"
"net/url" "net/url"
"reflect"
"strings"
"testing" "testing"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
@ -94,23 +92,23 @@ func TestRESTMapperVersionAndKindForResource(t *testing.T) {
testGroupVersion := unversioned.GroupVersion{Group: testGroup, Version: testVersion} testGroupVersion := unversioned.GroupVersion{Group: testGroup, Version: testVersion}
testCases := []struct { testCases := []struct {
Resource unversioned.GroupVersionResource Resource string
GroupVersionToRegister unversioned.GroupVersion GroupVersionToRegister unversioned.GroupVersion
ExpectedGVK unversioned.GroupVersionKind ExpectedGVK unversioned.GroupVersionKind
MixedCase bool MixedCase bool
Err bool Err bool
}{ }{
{Resource: unversioned.GroupVersionResource{Resource: "internalobjec"}, Err: true}, {Resource: "internalobjec", Err: true},
{Resource: unversioned.GroupVersionResource{Resource: "internalObjec"}, Err: true}, {Resource: "internalObjec", Err: true},
{Resource: unversioned.GroupVersionResource{Resource: "internalobject"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")}, {Resource: "internalobject", ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: unversioned.GroupVersionResource{Resource: "internalobjects"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")}, {Resource: "internalobjects", ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: unversioned.GroupVersionResource{Resource: "internalobject"}, MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")}, {Resource: "internalobject", MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: unversioned.GroupVersionResource{Resource: "internalobjects"}, MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")}, {Resource: "internalobjects", MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: unversioned.GroupVersionResource{Resource: "internalObject"}, MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")}, {Resource: "internalObject", MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: unversioned.GroupVersionResource{Resource: "internalObjects"}, MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")}, {Resource: "internalObjects", MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
} }
for i, testCase := range testCases { for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{testGroupVersion}, fakeInterfaces) mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{testGroupVersion}, fakeInterfaces)
@ -136,19 +134,18 @@ func TestRESTMapperVersionAndKindForResource(t *testing.T) {
func TestRESTMapperGroupForResource(t *testing.T) { func TestRESTMapperGroupForResource(t *testing.T) {
testCases := []struct { testCases := []struct {
Resource unversioned.GroupVersionResource Resource string
GroupVersionKind unversioned.GroupVersionKind GroupVersionKind unversioned.GroupVersionKind
Err bool Err bool
}{ }{
{Resource: unversioned.GroupVersionResource{Resource: "myObject"}, GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}}, {Resource: "myObject", GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
{Resource: unversioned.GroupVersionResource{Resource: "myobject"}, GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi2", Version: "test", Kind: "MyObject"}}, {Resource: "myobject", GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi2", Version: "test", Kind: "MyObject"}},
{Resource: unversioned.GroupVersionResource{Resource: "myObje"}, Err: true, GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}}, {Resource: "myObje", Err: true, GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
{Resource: unversioned.GroupVersionResource{Resource: "myobje"}, Err: true, GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}}, {Resource: "myobje", Err: true, GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
} }
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)
actualGVK, err := mapper.KindFor(testCase.Resource) actualGVK, err := mapper.KindFor(testCase.Resource)
if testCase.Err { if testCase.Err {
if err == nil { if err == nil {
@ -162,230 +159,6 @@ func TestRESTMapperGroupForResource(t *testing.T) {
} }
} }
func TestRESTMapperKindsFor(t *testing.T) {
testCases := []struct {
Name string
PreferredOrder []unversioned.GroupVersion
KindsToRegister []unversioned.GroupVersionKind
PartialResourceToRequest unversioned.GroupVersionResource
ExpectedKinds []unversioned.GroupVersionKind
ExpectedKindErr string
}{
{
Name: "ambiguous groups, with preference order",
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: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PartialResourceToRequest: unversioned.GroupVersionResource{Resource: "my-kinds"},
ExpectedKinds: []unversioned.GroupVersionKind{
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
},
ExpectedKindErr: "is ambiguous",
},
{
Name: "ambiguous groups, with explicit group match",
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: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PartialResourceToRequest: unversioned.GroupVersionResource{Group: "first-group", Resource: "my-kinds"},
ExpectedKinds: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
},
},
{
Name: "ambiguous groups, with ambiguous version match",
PreferredOrder: []unversioned.GroupVersion{
{Group: "first-group", Version: "first-version"},
{Group: "second-group", Version: "first-version"},
},
KindsToRegister: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PartialResourceToRequest: unversioned.GroupVersionResource{Version: "first-version", Resource: "my-kinds"},
ExpectedKinds: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
},
ExpectedKindErr: "is ambiguous",
},
}
for _, testCase := range testCases {
tcName := testCase.Name
mapper := NewDefaultRESTMapper(testCase.PreferredOrder, fakeInterfaces)
for _, kind := range testCase.KindsToRegister {
mapper.Add(kind, RESTScopeNamespace, false)
}
actualKinds, err := mapper.KindsFor(testCase.PartialResourceToRequest)
if err != nil {
t.Errorf("%s: unexpected error: %v", tcName, err)
continue
}
if !reflect.DeepEqual(testCase.ExpectedKinds, actualKinds) {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKinds, actualKinds)
}
singleKind, err := mapper.KindFor(testCase.PartialResourceToRequest)
if err == nil && len(testCase.ExpectedKindErr) != 0 {
t.Errorf("%s: expected error: %v", tcName, testCase.ExpectedKindErr)
continue
}
if err != nil {
if len(testCase.ExpectedKindErr) == 0 {
t.Errorf("%s: unexpected error: %v", tcName, err)
continue
} else {
if !strings.Contains(err.Error(), testCase.ExpectedKindErr) {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKindErr, err)
continue
}
}
} else {
if testCase.ExpectedKinds[0] != singleKind {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKinds[0], singleKind)
}
}
}
}
func TestRESTMapperResourcesFor(t *testing.T) {
testCases := []struct {
Name string
PreferredOrder []unversioned.GroupVersion
KindsToRegister []unversioned.GroupVersionKind
PartialResourceToRequest unversioned.GroupVersionResource
ExpectedResources []unversioned.GroupVersionResource
ExpectedResourceErr string
}{
{
Name: "ambiguous groups, with preference order",
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: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PartialResourceToRequest: unversioned.GroupVersionResource{Resource: "my-kinds"},
ExpectedResources: []unversioned.GroupVersionResource{
{Group: "second-group", Version: "first-version", Resource: "my-kinds"},
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
},
ExpectedResourceErr: "is ambiguous",
},
{
Name: "ambiguous groups, with explicit group match",
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: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PartialResourceToRequest: unversioned.GroupVersionResource{Group: "first-group", Resource: "my-kinds"},
ExpectedResources: []unversioned.GroupVersionResource{
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
},
},
{
Name: "ambiguous groups, with ambiguous version match",
PreferredOrder: []unversioned.GroupVersion{
{Group: "first-group", Version: "first-version"},
{Group: "second-group", Version: "first-version"},
},
KindsToRegister: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PartialResourceToRequest: unversioned.GroupVersionResource{Version: "first-version", Resource: "my-kinds"},
ExpectedResources: []unversioned.GroupVersionResource{
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
{Group: "second-group", Version: "first-version", Resource: "my-kinds"},
},
ExpectedResourceErr: "is ambiguous",
},
}
for _, testCase := range testCases {
tcName := testCase.Name
mapper := NewDefaultRESTMapper(testCase.PreferredOrder, fakeInterfaces)
for _, kind := range testCase.KindsToRegister {
mapper.Add(kind, RESTScopeNamespace, false)
}
actualResources, err := mapper.ResourcesFor(testCase.PartialResourceToRequest)
if err != nil {
t.Errorf("%s: unexpected error: %v", tcName, err)
continue
}
if !reflect.DeepEqual(testCase.ExpectedResources, actualResources) {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResources, actualResources)
}
singleResource, err := mapper.ResourceFor(testCase.PartialResourceToRequest)
if err == nil && len(testCase.ExpectedResourceErr) != 0 {
t.Errorf("%s: expected error: %v", tcName, testCase.ExpectedResourceErr)
continue
}
if err != nil {
if len(testCase.ExpectedResourceErr) == 0 {
t.Errorf("%s: unexpected error: %v", tcName, err)
continue
} else {
if !strings.Contains(err.Error(), testCase.ExpectedResourceErr) {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResourceErr, err)
continue
}
}
} else {
if testCase.ExpectedResources[0] != singleResource {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResources[0], singleResource)
}
}
}
}
func TestKindToResource(t *testing.T) { func TestKindToResource(t *testing.T) {
testCases := []struct { testCases := []struct {
Kind string Kind string
@ -408,11 +181,9 @@ func TestKindToResource(t *testing.T) {
{Kind: "lowercase", MixedCase: false, Plural: "lowercases", Singular: "lowercase"}, {Kind: "lowercase", MixedCase: false, Plural: "lowercases", Singular: "lowercase"},
} }
for i, testCase := range testCases { for i, testCase := range testCases {
version := unversioned.GroupVersion{} plural, singular := KindToResource(testCase.Kind, testCase.MixedCase)
if singular != testCase.Singular || plural != testCase.Plural {
plural, singular := KindToResource(version.WithKind(testCase.Kind), testCase.MixedCase) t.Errorf("%d: unexpected plural and singular: %s %s", i, plural, singular)
if singular != version.WithResource(testCase.Singular) || plural != version.WithResource(testCase.Plural) {
t.Errorf("%d: unexpected plural and singular: %v %v", i, plural, singular)
} }
} }
} }
@ -453,7 +224,7 @@ func TestRESTMapperResourceSingularizer(t *testing.T) {
t.Errorf("%d: unexpected error: %v", i, err) t.Errorf("%d: unexpected error: %v", i, err)
} }
if singular != testCase.Singular { if singular != testCase.Singular {
t.Errorf("%d: mismatched singular: got %v, expected %v", i, singular, testCase.Singular) t.Errorf("%d: mismatched singular: %s, should be %s", i, singular, testCase.Singular)
} }
} }
} }

View File

@ -29,10 +29,6 @@ type GroupResource struct {
Resource string Resource string
} }
func (gr GroupResource) WithVersion(version string) GroupVersionResource {
return GroupVersionResource{Group: gr.Group, Version: version, Resource: gr.Resource}
}
func (gr GroupResource) IsEmpty() bool { func (gr GroupResource) IsEmpty() bool {
return len(gr.Group) == 0 && len(gr.Resource) == 0 return len(gr.Group) == 0 && len(gr.Resource) == 0
} }

View File

@ -57,7 +57,7 @@ func TestRESTMapper(t *testing.T) {
gv := unversioned.GroupVersion{Group: componentconfig.GroupName, Version: "v1alpha1"} gv := unversioned.GroupVersion{Group: componentconfig.GroupName, Version: "v1alpha1"}
proxyGVK := gv.WithKind("KubeProxyConfiguration") proxyGVK := gv.WithKind("KubeProxyConfiguration")
if gvk, err := latest.GroupOrDie(componentconfig.GroupName).RESTMapper.KindFor(gv.WithResource("kubeproxyconfiguration")); err != nil || gvk != proxyGVK { if gvk, err := latest.GroupOrDie(componentconfig.GroupName).RESTMapper.KindFor("kubeproxyconfiguration"); err != nil || gvk != proxyGVK {
t.Errorf("unexpected version mapping: %v %v", gvk, err) t.Errorf("unexpected version mapping: %v %v", gvk, err)
} }

View File

@ -80,7 +80,7 @@ func TestRESTMapper(t *testing.T) {
hpaGVK := gv.WithKind("HorizontalPodAutoscaler") hpaGVK := gv.WithKind("HorizontalPodAutoscaler")
daemonSetGVK := gv.WithKind("DaemonSet") daemonSetGVK := gv.WithKind("DaemonSet")
if gvk, err := latest.GroupOrDie(extensions.GroupName).RESTMapper.KindFor(gv.WithResource("horizontalpodautoscalers")); err != nil || gvk != hpaGVK { if gvk, err := latest.GroupOrDie(extensions.GroupName).RESTMapper.KindFor("horizontalpodautoscalers"); err != nil || gvk != hpaGVK {
t.Errorf("unexpected version mapping: %v %v", gvk, err) t.Errorf("unexpected version mapping: %v %v", gvk, err)
} }

View File

@ -18,7 +18,6 @@ package unversioned
import ( import (
"k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
) )
@ -49,25 +48,17 @@ func newScales(c *ExtensionsClient, namespace string) *scales {
// Get takes the reference to scale subresource and returns the subresource or error, if one occurs. // Get takes the reference to scale subresource and returns the subresource or error, if one occurs.
func (c *scales) Get(kind string, name string) (result *extensions.Scale, err error) { func (c *scales) Get(kind string, name string) (result *extensions.Scale, err error) {
result = &extensions.Scale{} result = &extensions.Scale{}
resource, _ := meta.KindToResource(kind, false)
// TODO this method needs to take a proper unambiguous kind err = c.client.Get().Namespace(c.ns).Resource(resource).Name(name).SubResource("scale").Do().Into(result)
fullyQualifiedKind := unversioned.GroupVersionKind{Kind: kind}
resource, _ := meta.KindToResource(fullyQualifiedKind, false)
err = c.client.Get().Namespace(c.ns).Resource(resource.Resource).Name(name).SubResource("scale").Do().Into(result)
return return
} }
func (c *scales) Update(kind string, scale *extensions.Scale) (result *extensions.Scale, err error) { func (c *scales) Update(kind string, scale *extensions.Scale) (result *extensions.Scale, err error) {
result = &extensions.Scale{} result = &extensions.Scale{}
resource, _ := meta.KindToResource(kind, false)
// TODO this method needs to take a proper unambiguous kind
fullyQualifiedKind := unversioned.GroupVersionKind{Kind: kind}
resource, _ := meta.KindToResource(fullyQualifiedKind, false)
err = c.client.Put(). err = c.client.Put().
Namespace(scale.Namespace). Namespace(scale.Namespace).
Resource(resource.Resource). Resource(resource).
Name(scale.Name). Name(scale.Name).
SubResource("scale"). SubResource("scale").
Body(scale). Body(scale).

View File

@ -59,7 +59,7 @@ type ObjectScheme interface {
func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc { func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc {
return func(action Action) (bool, runtime.Object, error) { return func(action Action) (bool, runtime.Object, error) {
kind, err := mapper.KindFor(unversioned.GroupVersionResource{Resource: action.GetResource()}) gvk, err := mapper.KindFor(action.GetResource())
if err != nil { if err != nil {
return false, nil, fmt.Errorf("unrecognized action %s: %v", action.GetResource(), err) return false, nil, fmt.Errorf("unrecognized action %s: %v", action.GetResource(), err)
} }
@ -67,16 +67,16 @@ func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc {
// TODO: have mapper return a Kind for a subresource? // TODO: have mapper return a Kind for a subresource?
switch castAction := action.(type) { switch castAction := action.(type) {
case ListAction: case ListAction:
kind.Kind += "List" gvk.Kind += "List"
resource, err := o.Kind(kind, "") resource, err := o.Kind(gvk, "")
return true, resource, err return true, resource, err
case GetAction: case GetAction:
resource, err := o.Kind(kind, castAction.GetName()) resource, err := o.Kind(gvk, castAction.GetName())
return true, resource, err return true, resource, err
case DeleteAction: case DeleteAction:
resource, err := o.Kind(kind, castAction.GetName()) resource, err := o.Kind(gvk, castAction.GetName())
return true, resource, err return true, resource, err
case CreateAction: case CreateAction:
@ -84,7 +84,7 @@ func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc {
if err != nil { if err != nil {
return true, nil, err return true, nil, err
} }
resource, err := o.Kind(kind, meta.Name) resource, err := o.Kind(gvk, meta.Name)
return true, resource, err return true, resource, err
case UpdateAction: case UpdateAction:
@ -92,7 +92,7 @@ func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc {
if err != nil { if err != nil {
return true, nil, err return true, nil, err
} }
resource, err := o.Kind(kind, meta.Name) resource, err := o.Kind(gvk, meta.Name)
return true, resource, err return true, resource, err
default: default:

View File

@ -84,7 +84,7 @@ func RunExplain(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []st
} }
// TODO: We should deduce the group for a resource by discovering the supported resources at server. // TODO: We should deduce the group for a resource by discovering the supported resources at server.
gvk, err := mapper.KindFor(unversioned.GroupVersionResource{Resource: inModel}) gvk, err := mapper.KindFor(inModel)
if err != nil { if err != nil {
return err return err
} }

View File

@ -360,12 +360,12 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg
if outputFormat != "" { if outputFormat != "" {
return f.PrintObject(cmd, newRc, out) return f.PrintObject(cmd, newRc, out)
} }
kind, err := api.Scheme.ObjectKind(newRc) gvk, err := api.Scheme.ObjectKind(newRc)
if err != nil { if err != nil {
return err return err
} }
_, res := meta.KindToResource(kind, false) _, res := meta.KindToResource(gvk.Kind, false)
cmdutil.PrintSuccess(mapper, false, out, res.Resource, oldName, message) cmdutil.PrintSuccess(mapper, false, out, res, oldName, message)
return nil return nil
} }

View File

@ -175,12 +175,16 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
return clients.ClientConfigForVersion(nil) return clients.ClientConfigForVersion(nil)
}, },
RESTClient: func(mapping *meta.RESTMapping) (resource.RESTClient, error) { RESTClient: func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
gvk, err := api.RESTMapper.KindFor(mapping.Resource)
if err != nil {
return nil, err
}
mappingVersion := mapping.GroupVersionKind.GroupVersion() mappingVersion := mapping.GroupVersionKind.GroupVersion()
client, err := clients.ClientForVersion(&mappingVersion) client, err := clients.ClientForVersion(&mappingVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
switch mapping.GroupVersionKind.Group { switch gvk.Group {
case api.GroupName: case api.GroupName:
return client.RESTClient, nil return client.RESTClient, nil
case extensions.GroupName: case extensions.GroupName:

View File

@ -44,7 +44,7 @@ func GetSwaggerSchema(version unversioned.GroupVersion, kubeClient client.Interf
// 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) (string, []string, error) {
inResource, fieldsPath := splitDotNotation(inResource) inResource, fieldsPath := splitDotNotation(inResource)
inResource, _ = mapper.ResourceSingularizer(expandResourceShortcut(unversioned.GroupVersionResource{Resource: inResource}).Resource) inResource, _ = mapper.ResourceSingularizer(expandResourceShortcut(inResource))
return inResource, fieldsPath, nil return inResource, fieldsPath, nil
} }

View File

@ -23,7 +23,6 @@ import (
"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" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
) )
const kubectlAnnotationPrefix = "kubectl.kubernetes.io/" const kubectlAnnotationPrefix = "kubectl.kubernetes.io/"
@ -81,40 +80,40 @@ var _ meta.RESTMapper = &ShortcutExpander{}
// KindFor implements meta.RESTMapper. It expands the resource first, then invokes the wrapped // KindFor implements meta.RESTMapper. It expands the resource first, then invokes the wrapped
// mapper. // mapper.
func (e ShortcutExpander) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) { func (e ShortcutExpander) KindFor(resource string) (unversioned.GroupVersionKind, error) {
resource = expandResourceShortcut(resource) resource = expandResourceShortcut(resource)
return e.RESTMapper.KindFor(resource) return e.RESTMapper.KindFor(resource)
} }
// ResourceIsValid takes a string (kind) and checks if it's a valid resource. // ResourceIsValid takes a string (kind) and checks if it's a valid resource.
// It expands the resource first, then invokes the wrapped mapper. // It expands the resource first, then invokes the wrapped mapper.
func (e ShortcutExpander) ResourceIsValid(resource unversioned.GroupVersionResource) bool { func (e ShortcutExpander) ResourceIsValid(resource string) bool {
return e.RESTMapper.ResourceIsValid(expandResourceShortcut(resource)) return e.RESTMapper.ResourceIsValid(expandResourceShortcut(resource))
} }
// expandResourceShortcut will return the expanded version of resource // expandResourceShortcut will return the expanded version of resource
// (something that a pkg/api/meta.RESTMapper can understand), if it is // (something that a pkg/api/meta.RESTMapper can understand), if it is
// indeed a shortcut. Otherwise, will return resource unmodified. // indeed a shortcut. Otherwise, will return resource unmodified.
func expandResourceShortcut(resource unversioned.GroupVersionResource) unversioned.GroupVersionResource { func expandResourceShortcut(resource string) string {
shortForms := map[string]unversioned.GroupVersionResource{ shortForms := map[string]string{
// Please keep this alphabetized // Please keep this alphabetized
"cs": api.SchemeGroupVersion.WithResource("componentstatuses"), "cs": "componentstatuses",
"ds": extensions.SchemeGroupVersion.WithResource("daemonsets"), "ds": "daemonsets",
"ep": api.SchemeGroupVersion.WithResource("endpoints"), "ep": "endpoints",
"ev": api.SchemeGroupVersion.WithResource("events"), "ev": "events",
"hpa": extensions.SchemeGroupVersion.WithResource("horizontalpodautoscalers"), "hpa": "horizontalpodautoscalers",
"ing": extensions.SchemeGroupVersion.WithResource("ingresses"), "ing": "ingresses",
"limits": api.SchemeGroupVersion.WithResource("limitranges"), "limits": "limitranges",
"no": api.SchemeGroupVersion.WithResource("nodes"), "no": "nodes",
"ns": api.SchemeGroupVersion.WithResource("namespaces"), "ns": "namespaces",
"po": api.SchemeGroupVersion.WithResource("pods"), "po": "pods",
"pvc": api.SchemeGroupVersion.WithResource("persistentvolumeclaims"), "pvc": "persistentvolumeclaims",
"pv": api.SchemeGroupVersion.WithResource("persistentvolumes"), "pv": "persistentvolumes",
"quota": api.SchemeGroupVersion.WithResource("resourcequotas"), "quota": "resourcequotas",
"rc": api.SchemeGroupVersion.WithResource("replicationcontrollers"), "rc": "replicationcontrollers",
"svc": api.SchemeGroupVersion.WithResource("services"), "svc": "services",
} }
if expanded, ok := shortForms[resource.Resource]; ok { if expanded, ok := shortForms[resource]; ok {
return expanded return expanded
} }
return resource return resource

View File

@ -25,7 +25,6 @@ import (
"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"
"k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
@ -427,7 +426,7 @@ func (b *Builder) resourceMappings() ([]*meta.RESTMapping, error) {
} }
mappings := []*meta.RESTMapping{} mappings := []*meta.RESTMapping{}
for _, r := range b.resources { for _, r := range b.resources {
gvk, err := b.mapper.KindFor(unversioned.GroupVersionResource{Resource: r}) gvk, err := b.mapper.KindFor(r)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -447,7 +446,7 @@ func (b *Builder) resourceTupleMappings() (map[string]*meta.RESTMapping, error)
if _, ok := mappings[r.Resource]; ok { if _, ok := mappings[r.Resource]; ok {
continue continue
} }
gvk, err := b.mapper.KindFor(unversioned.GroupVersionResource{Resource: r.Resource}) gvk, err := b.mapper.KindFor(r.Resource)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -203,24 +203,11 @@ type NamePrinter struct {
// and print "resource/name" pair. If the object is a List, print all items in it. // and print "resource/name" pair. If the object is a List, print all items in it.
func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error { func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
objvalue := reflect.ValueOf(obj).Elem() objvalue := reflect.ValueOf(obj).Elem()
kindString := objvalue.FieldByName("Kind") kind := objvalue.FieldByName("Kind")
groupVersionString := objvalue.FieldByName("APIVersion") if !kind.IsValid() {
kind := unversioned.GroupVersionKind{} kind = reflect.ValueOf("<unknown>")
if !kindString.IsValid() {
kindString = reflect.ValueOf("<unknown>")
} }
kind.Kind = kindString.String() if kind.String() == "List" {
if !groupVersionString.IsValid() {
groupVersionString = reflect.ValueOf("<unknown>/<unknown>")
}
gv, err := unversioned.ParseGroupVersion(groupVersionString.String())
if err != nil {
kind.Group = gv.Group
kind.Version = gv.Version
}
if kind.Kind == "List" {
items := objvalue.FieldByName("Items") items := objvalue.FieldByName("Items")
if items.Type().String() == "[]runtime.RawExtension" { if items.Type().String() == "[]runtime.RawExtension" {
for i := 0; i < items.Len(); i++ { for i := 0; i < items.Len(); i++ {
@ -250,9 +237,9 @@ func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
if !name.IsValid() { if !name.IsValid() {
name = reflect.ValueOf("<unknown>") name = reflect.ValueOf("<unknown>")
} }
_, resource := meta.KindToResource(kind, false) _, resource := meta.KindToResource(kind.String(), false)
fmt.Fprintf(w, "%s/%s\n", resource.Resource, name) fmt.Fprintf(w, "%s/%s\n", resource, name)
} }
return nil return nil

View File

@ -41,55 +41,14 @@ type thirdPartyResourceDataMapper struct {
var _ meta.RESTMapper = &thirdPartyResourceDataMapper{} var _ meta.RESTMapper = &thirdPartyResourceDataMapper{}
func (t *thirdPartyResourceDataMapper) getResource() unversioned.GroupVersionResource { func (t *thirdPartyResourceDataMapper) isThirdPartyResource(resource string) bool {
plural, _ := meta.KindToResource(t.getKind(), false) plural, _ := meta.KindToResource(t.kind, false)
return resource == plural
return plural
} }
func (t *thirdPartyResourceDataMapper) getKind() unversioned.GroupVersionKind { func (t *thirdPartyResourceDataMapper) KindFor(resource string) (unversioned.GroupVersionKind, error) {
return unversioned.GroupVersionKind{Group: t.group, Version: t.version, Kind: t.kind}
}
func (t *thirdPartyResourceDataMapper) isThirdPartyResource(partialResource unversioned.GroupVersionResource) bool {
actualResource := t.getResource()
if strings.ToLower(partialResource.Resource) != strings.ToLower(actualResource.Resource) {
return false
}
if len(partialResource.Group) != 0 && partialResource.Group != actualResource.Group {
return false
}
if len(partialResource.Version) != 0 && partialResource.Version != actualResource.Version {
return false
}
return true
}
func (t *thirdPartyResourceDataMapper) ResourcesFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) {
if t.isThirdPartyResource(resource) { if t.isThirdPartyResource(resource) {
return []unversioned.GroupVersionResource{t.getResource()}, nil return unversioned.GroupVersionKind{Group: t.group, Version: t.version, Kind: t.kind}, nil
}
return t.mapper.ResourcesFor(resource)
}
func (t *thirdPartyResourceDataMapper) KindsFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionKind, error) {
if t.isThirdPartyResource(resource) {
return []unversioned.GroupVersionKind{t.getKind()}, nil
}
return t.mapper.KindsFor(resource)
}
func (t *thirdPartyResourceDataMapper) ResourceFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) {
if t.isThirdPartyResource(resource) {
return t.getResource(), nil
}
return t.mapper.ResourceFor(resource)
}
func (t *thirdPartyResourceDataMapper) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) {
if t.isThirdPartyResource(resource) {
return t.getKind(), nil
} }
return t.mapper.KindFor(resource) return t.mapper.KindFor(resource)
} }
@ -127,7 +86,8 @@ func (t *thirdPartyResourceDataMapper) ResourceSingularizer(resource string) (si
return t.mapper.ResourceSingularizer(resource) return t.mapper.ResourceSingularizer(resource)
} }
func (t *thirdPartyResourceDataMapper) ResourceIsValid(resource unversioned.GroupVersionResource) bool { // ResourceIsValid takes a string (kind) and checks if it's a valid resource
func (t *thirdPartyResourceDataMapper) ResourceIsValid(resource string) bool {
return t.isThirdPartyResource(resource) || t.mapper.ResourceIsValid(resource) return t.isThirdPartyResource(resource) || t.mapper.ResourceIsValid(resource)
} }

View File

@ -212,9 +212,9 @@ func TestResourceIsValid(t *testing.T) {
for _, test := range tests { for _, test := range tests {
mapper := &thirdPartyResourceDataMapper{kind: test.kind} mapper := &thirdPartyResourceDataMapper{kind: test.kind}
mapper.mapper = api.RESTMapper mapper.mapper = api.RESTMapper
valid := mapper.ResourceIsValid(unversioned.GroupVersionResource{Resource: test.resource}) valid := mapper.ResourceIsValid(test.resource)
if valid != test.valid { if valid != test.valid {
t.Errorf("%s: expected: %v, actual: %v", test.name, test.valid, valid) t.Errorf("expected: %v, saw: %v for %s", test.valid, valid, test.name)
} }
} }
} }

View File

@ -45,11 +45,11 @@ type provision struct {
} }
func (p *provision) Admit(a admission.Attributes) (err error) { func (p *provision) Admit(a admission.Attributes) (err error) {
kind, err := api.RESTMapper.KindFor(a.GetResource().WithVersion("")) gvk, err := api.RESTMapper.KindFor(a.GetResource().Resource)
if err != nil { if err != nil {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }
mapping, err := api.RESTMapper.RESTMapping(kind.GroupKind(), kind.Version) 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

@ -46,11 +46,11 @@ type exists struct {
} }
func (e *exists) Admit(a admission.Attributes) (err error) { func (e *exists) Admit(a admission.Attributes) (err error) {
kind, err := api.RESTMapper.KindFor(a.GetResource().WithVersion("")) gvk, err := api.RESTMapper.KindFor(a.GetResource().Resource)
if err != nil { if err != nil {
return errors.NewInternalError(err) return errors.NewInternalError(err)
} }
mapping, err := api.RESTMapper.RESTMapping(kind.GroupKind(), kind.Version) 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

@ -48,16 +48,17 @@ type lifecycle struct {
} }
func (l *lifecycle) Admit(a admission.Attributes) (err error) { func (l *lifecycle) Admit(a admission.Attributes) (err error) {
// prevent deletion of immortal namespaces // prevent deletion of immortal namespaces
if a.GetOperation() == admission.Delete && a.GetKind() == api.Kind("Namespace") && l.immortalNamespaces.Has(a.GetName()) { if a.GetOperation() == admission.Delete && a.GetKind() == api.Kind("Namespace") && l.immortalNamespaces.Has(a.GetName()) {
return errors.NewForbidden(a.GetResource(), a.GetName(), fmt.Errorf("this namespace may not be deleted")) return errors.NewForbidden(a.GetResource(), a.GetName(), fmt.Errorf("this namespace may not be deleted"))
} }
kind, err := api.RESTMapper.KindFor(a.GetResource().WithVersion("")) gvk, err := api.RESTMapper.KindFor(a.GetResource().Resource)
if err != nil { if err != nil {
return errors.NewInternalError(err) return errors.NewInternalError(err)
} }
mapping, err := api.RESTMapper.RESTMapping(kind.GroupKind(), kind.Version) mapping, err := api.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil { if err != nil {
return errors.NewInternalError(err) return errors.NewInternalError(err)
} }