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")
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)
}

View File

@ -158,23 +158,12 @@ type RESTMapping struct {
// 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.
type RESTMapper interface {
// KindFor takes a partial resource and returns back the single match. Returns an error if there are multiple matches
KindFor(resource unversioned.GroupVersionResource) (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)
// KindFor takes a resource and returns back the unambiguous Kind (GroupVersionKind)
KindFor(resource string) (unversioned.GroupVersionKind, error)
RESTMapping(gk unversioned.GroupKind, versions ...string) (*RESTMapping, error)
AliasesForResource(resource string) ([]string, bool)
ResourceSingularizer(resource string) (singular string, err error)
// ResourceIsValid takes a partial resource and returns back whether or not the resource matches at least one kind
ResourceIsValid(resource unversioned.GroupVersionResource) bool
ResourceIsValid(resource string) bool
}

View File

@ -19,11 +19,9 @@ package meta
import (
"fmt"
"sort"
"strings"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/util/sets"
)
// Implements RESTScope interface
@ -73,11 +71,11 @@ var RESTScopeRoot = &restScope{
type DefaultRESTMapper struct {
defaultGroupVersions []unversioned.GroupVersion
resourceToKind map[unversioned.GroupVersionResource]unversioned.GroupVersionKind
kindToPluralResource map[unversioned.GroupVersionKind]unversioned.GroupVersionResource
resourceToKind map[string]unversioned.GroupVersionKind
kindToPluralResource map[unversioned.GroupVersionKind]string
kindToScope map[unversioned.GroupVersionKind]RESTScope
singularToPlural map[unversioned.GroupVersionResource]unversioned.GroupVersionResource
pluralToSingular map[unversioned.GroupVersionResource]unversioned.GroupVersionResource
singularToPlural map[string]string
pluralToSingular map[string]string
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),
// and a function that retrieves the correct codec and metadata for a given version.
func NewDefaultRESTMapper(defaultGroupVersions []unversioned.GroupVersion, f VersionInterfacesFunc) *DefaultRESTMapper {
resourceToKind := make(map[unversioned.GroupVersionResource]unversioned.GroupVersionKind)
kindToPluralResource := make(map[unversioned.GroupVersionKind]unversioned.GroupVersionResource)
resourceToKind := make(map[string]unversioned.GroupVersionKind)
kindToPluralResource := make(map[unversioned.GroupVersionKind]string)
kindToScope := make(map[unversioned.GroupVersionKind]RESTScope)
singularToPlural := make(map[unversioned.GroupVersionResource]unversioned.GroupVersionResource)
pluralToSingular := make(map[unversioned.GroupVersionResource]unversioned.GroupVersionResource)
singularToPlural := make(map[string]string)
pluralToSingular := make(map[string]string)
// TODO: verify name mappings work correctly when versions differ
return &DefaultRESTMapper{
@ -112,54 +110,45 @@ func NewDefaultRESTMapper(defaultGroupVersions []unversioned.GroupVersion, f Ver
}
}
func (m *DefaultRESTMapper) Add(kind unversioned.GroupVersionKind, scope RESTScope, mixedCase bool) {
plural, singular := KindToResource(kind, mixedCase)
lowerPlural := plural.GroupVersion().WithResource(strings.ToLower(plural.Resource))
lowerSingular := singular.GroupVersion().WithResource(strings.ToLower(singular.Resource))
func (m *DefaultRESTMapper) Add(gvk unversioned.GroupVersionKind, scope RESTScope, mixedCase bool) {
plural, singular := KindToResource(gvk.Kind, mixedCase)
m.singularToPlural[singular] = plural
m.pluralToSingular[plural] = singular
m.singularToPlural[lowerSingular] = lowerPlural
m.pluralToSingular[lowerPlural] = lowerSingular
if _, mixedCaseExists := m.resourceToKind[plural]; !mixedCaseExists {
m.resourceToKind[plural] = kind
m.resourceToKind[singular] = kind
_, ok1 := m.resourceToKind[plural]
_, ok2 := m.resourceToKind[strings.ToLower(plural)]
if !ok1 && !ok2 {
m.resourceToKind[plural] = gvk
m.resourceToKind[singular] = gvk
if strings.ToLower(plural) != plural {
m.resourceToKind[strings.ToLower(plural)] = gvk
m.resourceToKind[strings.ToLower(singular)] = gvk
}
}
if _, lowerCaseExists := m.resourceToKind[lowerPlural]; !lowerCaseExists && (lowerPlural != plural) {
m.resourceToKind[lowerPlural] = kind
m.resourceToKind[lowerSingular] = kind
}
m.kindToPluralResource[kind] = plural
m.kindToScope[kind] = scope
m.kindToPluralResource[gvk] = plural
m.kindToScope[gvk] = scope
}
// KindToResource converts Kind to a resource name.
func KindToResource(kind unversioned.GroupVersionKind, mixedCase bool) (plural, singular unversioned.GroupVersionResource) {
kindName := kind.Kind
if len(kindName) == 0 {
func KindToResource(kind string, mixedCase bool) (plural, singular string) {
if len(kind) == 0 {
return
}
if mixedCase {
// Legacy support for mixed case names
singular = kind.GroupVersion().WithResource(strings.ToLower(kindName[:1]) + kindName[1:])
singular = strings.ToLower(kind[:1]) + kind[1:]
} else {
singular = kind.GroupVersion().WithResource(strings.ToLower(kindName))
singular = strings.ToLower(kind)
}
singularName := singular.Resource
if strings.HasSuffix(singularName, "endpoints") {
if strings.HasSuffix(singular, "endpoints") {
plural = singular
} else {
switch string(singularName[len(singularName)-1]) {
switch string(singular[len(singular)-1]) {
case "s":
plural = kind.GroupVersion().WithResource(singularName + "es")
plural = singular + "es"
case "y":
plural = kind.GroupVersion().WithResource(strings.TrimSuffix(singularName, "y") + "ies")
plural = strings.TrimSuffix(singular, "y") + "ies"
default:
plural = kind.GroupVersion().WithResource(singularName + "s")
plural = singular + "s"
}
}
return
@ -167,240 +156,21 @@ func KindToResource(kind unversioned.GroupVersionKind, mixedCase bool) (plural,
// ResourceSingularizer implements RESTMapper
// 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(resourceType string) (string, error) {
partialResource := unversioned.GroupVersionResource{Resource: resourceType}
resource, err := m.ResourceFor(partialResource)
if err != nil {
return resourceType, err
}
func (m *DefaultRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
singular, ok := m.pluralToSingular[resource]
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) {
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)
// VersionAndKindForResource implements RESTMapper
func (m *DefaultRESTMapper) KindFor(resource string) (unversioned.GroupVersionKind, error) {
gvk, ok := m.resourceToKind[strings.ToLower(resource)]
if !ok {
return gvk, fmt.Errorf("in version and kind for resource, no resource %q has been defined", resource)
}
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
return gvk, nil
}
// 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{
Resource: resource.Resource,
Resource: resource,
GroupVersionKind: *gvk,
Scope: scope,
@ -499,8 +269,8 @@ func (m *DefaultRESTMapper) AliasesForResource(alias string) ([]string, bool) {
return nil, false
}
// ResourceIsValid takes a partial resource and checks if it's valid
func (m *DefaultRESTMapper) ResourceIsValid(resource unversioned.GroupVersionResource) bool {
// ResourceIsValid takes a string (kind) and checks if it's a valid resource
func (m *DefaultRESTMapper) ResourceIsValid(resource string) bool {
_, err := m.KindFor(resource)
return err == nil
}
@ -520,41 +290,10 @@ func (m MultiRESTMapper) ResourceSingularizer(resource string) (singular string,
return
}
func (m MultiRESTMapper) ResourcesFor(resource unversioned.GroupVersionResource) (gvk []unversioned.GroupVersionResource, err error) {
for _, t := range m {
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
// VersionAndKindForResource provides the Version and Kind mappings for the
// REST resources. This implementation supports multiple REST schemas and return
// the first match.
func (m MultiRESTMapper) KindsFor(resource unversioned.GroupVersionResource) (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) {
func (m MultiRESTMapper) KindFor(resource string) (gvk unversioned.GroupVersionKind, err error) {
for _, t := range m {
gvk, err = t.KindFor(resource)
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
func (m MultiRESTMapper) ResourceIsValid(resource unversioned.GroupVersionResource) bool {
func (m MultiRESTMapper) ResourceIsValid(resource string) bool {
for _, t := range m {
if t.ResourceIsValid(resource) {
return true

View File

@ -20,8 +20,6 @@ import (
"errors"
"io"
"net/url"
"reflect"
"strings"
"testing"
"k8s.io/kubernetes/pkg/api/unversioned"
@ -94,23 +92,23 @@ func TestRESTMapperVersionAndKindForResource(t *testing.T) {
testGroupVersion := unversioned.GroupVersion{Group: testGroup, Version: testVersion}
testCases := []struct {
Resource unversioned.GroupVersionResource
Resource string
GroupVersionToRegister unversioned.GroupVersion
ExpectedGVK unversioned.GroupVersionKind
MixedCase bool
Err bool
}{
{Resource: unversioned.GroupVersionResource{Resource: "internalobjec"}, Err: true},
{Resource: unversioned.GroupVersionResource{Resource: "internalObjec"}, Err: true},
{Resource: "internalobjec", Err: true},
{Resource: "internalObjec", Err: true},
{Resource: unversioned.GroupVersionResource{Resource: "internalobject"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: unversioned.GroupVersionResource{Resource: "internalobjects"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: "internalobject", ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: "internalobjects", ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: unversioned.GroupVersionResource{Resource: "internalobject"}, MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: unversioned.GroupVersionResource{Resource: "internalobjects"}, MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: "internalobject", 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: unversioned.GroupVersionResource{Resource: "internalObjects"}, MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: "internalObject", MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: "internalObjects", MixedCase: true, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{testGroupVersion}, fakeInterfaces)
@ -136,19 +134,18 @@ func TestRESTMapperVersionAndKindForResource(t *testing.T) {
func TestRESTMapperGroupForResource(t *testing.T) {
testCases := []struct {
Resource unversioned.GroupVersionResource
Resource string
GroupVersionKind unversioned.GroupVersionKind
Err bool
}{
{Resource: unversioned.GroupVersionResource{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: unversioned.GroupVersionResource{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: "myObject", GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
{Resource: "myobject", GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi2", Version: "test", Kind: "MyObject"}},
{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 {
mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{testCase.GroupVersionKind.GroupVersion()}, fakeInterfaces)
mapper.Add(testCase.GroupVersionKind, RESTScopeNamespace, false)
actualGVK, err := mapper.KindFor(testCase.Resource)
if testCase.Err {
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) {
testCases := []struct {
Kind string
@ -408,11 +181,9 @@ func TestKindToResource(t *testing.T) {
{Kind: "lowercase", MixedCase: false, Plural: "lowercases", Singular: "lowercase"},
}
for i, testCase := range testCases {
version := unversioned.GroupVersion{}
plural, singular := KindToResource(version.WithKind(testCase.Kind), testCase.MixedCase)
if singular != version.WithResource(testCase.Singular) || plural != version.WithResource(testCase.Plural) {
t.Errorf("%d: unexpected plural and singular: %v %v", i, plural, singular)
plural, singular := KindToResource(testCase.Kind, testCase.MixedCase)
if singular != testCase.Singular || plural != testCase.Plural {
t.Errorf("%d: unexpected plural and singular: %s %s", i, plural, singular)
}
}
}
@ -453,7 +224,7 @@ func TestRESTMapperResourceSingularizer(t *testing.T) {
t.Errorf("%d: unexpected error: %v", i, err)
}
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
}
func (gr GroupResource) WithVersion(version string) GroupVersionResource {
return GroupVersionResource{Group: gr.Group, Version: version, Resource: gr.Resource}
}
func (gr GroupResource) IsEmpty() bool {
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"}
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)
}

View File

@ -80,7 +80,7 @@ func TestRESTMapper(t *testing.T) {
hpaGVK := gv.WithKind("HorizontalPodAutoscaler")
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)
}

View File

@ -18,7 +18,6 @@ package unversioned
import (
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"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.
func (c *scales) Get(kind string, name string) (result *extensions.Scale, err error) {
result = &extensions.Scale{}
// TODO this method needs to take a proper unambiguous kind
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)
resource, _ := meta.KindToResource(kind, false)
err = c.client.Get().Namespace(c.ns).Resource(resource).Name(name).SubResource("scale").Do().Into(result)
return
}
func (c *scales) Update(kind string, scale *extensions.Scale) (result *extensions.Scale, err error) {
result = &extensions.Scale{}
// TODO this method needs to take a proper unambiguous kind
fullyQualifiedKind := unversioned.GroupVersionKind{Kind: kind}
resource, _ := meta.KindToResource(fullyQualifiedKind, false)
resource, _ := meta.KindToResource(kind, false)
err = c.client.Put().
Namespace(scale.Namespace).
Resource(resource.Resource).
Resource(resource).
Name(scale.Name).
SubResource("scale").
Body(scale).

View File

@ -59,7 +59,7 @@ type ObjectScheme interface {
func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc {
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 {
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?
switch castAction := action.(type) {
case ListAction:
kind.Kind += "List"
resource, err := o.Kind(kind, "")
gvk.Kind += "List"
resource, err := o.Kind(gvk, "")
return true, resource, err
case GetAction:
resource, err := o.Kind(kind, castAction.GetName())
resource, err := o.Kind(gvk, castAction.GetName())
return true, resource, err
case DeleteAction:
resource, err := o.Kind(kind, castAction.GetName())
resource, err := o.Kind(gvk, castAction.GetName())
return true, resource, err
case CreateAction:
@ -84,7 +84,7 @@ func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc {
if err != nil {
return true, nil, err
}
resource, err := o.Kind(kind, meta.Name)
resource, err := o.Kind(gvk, meta.Name)
return true, resource, err
case UpdateAction:
@ -92,7 +92,7 @@ func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc {
if err != nil {
return true, nil, err
}
resource, err := o.Kind(kind, meta.Name)
resource, err := o.Kind(gvk, meta.Name)
return true, resource, err
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.
gvk, err := mapper.KindFor(unversioned.GroupVersionResource{Resource: inModel})
gvk, err := mapper.KindFor(inModel)
if err != nil {
return err
}

View File

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

View File

@ -175,12 +175,16 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
return clients.ClientConfigForVersion(nil)
},
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()
client, err := clients.ClientForVersion(&mappingVersion)
if err != nil {
return nil, err
}
switch mapping.GroupVersionKind.Group {
switch gvk.Group {
case api.GroupName:
return client.RESTClient, nil
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
func SplitAndParseResourceRequest(inResource string, mapper meta.RESTMapper) (string, []string, error) {
inResource, fieldsPath := splitDotNotation(inResource)
inResource, _ = mapper.ResourceSingularizer(expandResourceShortcut(unversioned.GroupVersionResource{Resource: inResource}).Resource)
inResource, _ = mapper.ResourceSingularizer(expandResourceShortcut(inResource))
return inResource, fieldsPath, nil
}

View File

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

View File

@ -25,7 +25,6 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
@ -427,7 +426,7 @@ func (b *Builder) resourceMappings() ([]*meta.RESTMapping, error) {
}
mappings := []*meta.RESTMapping{}
for _, r := range b.resources {
gvk, err := b.mapper.KindFor(unversioned.GroupVersionResource{Resource: r})
gvk, err := b.mapper.KindFor(r)
if err != nil {
return nil, err
}
@ -447,7 +446,7 @@ func (b *Builder) resourceTupleMappings() (map[string]*meta.RESTMapping, error)
if _, ok := mappings[r.Resource]; ok {
continue
}
gvk, err := b.mapper.KindFor(unversioned.GroupVersionResource{Resource: r.Resource})
gvk, err := b.mapper.KindFor(r.Resource)
if err != nil {
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.
func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
objvalue := reflect.ValueOf(obj).Elem()
kindString := objvalue.FieldByName("Kind")
groupVersionString := objvalue.FieldByName("APIVersion")
kind := unversioned.GroupVersionKind{}
if !kindString.IsValid() {
kindString = reflect.ValueOf("<unknown>")
kind := objvalue.FieldByName("Kind")
if !kind.IsValid() {
kind = reflect.ValueOf("<unknown>")
}
kind.Kind = kindString.String()
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" {
if kind.String() == "List" {
items := objvalue.FieldByName("Items")
if items.Type().String() == "[]runtime.RawExtension" {
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() {
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

View File

@ -41,55 +41,14 @@ type thirdPartyResourceDataMapper struct {
var _ meta.RESTMapper = &thirdPartyResourceDataMapper{}
func (t *thirdPartyResourceDataMapper) getResource() unversioned.GroupVersionResource {
plural, _ := meta.KindToResource(t.getKind(), false)
return plural
func (t *thirdPartyResourceDataMapper) isThirdPartyResource(resource string) bool {
plural, _ := meta.KindToResource(t.kind, false)
return resource == plural
}
func (t *thirdPartyResourceDataMapper) getKind() unversioned.GroupVersionKind {
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) {
func (t *thirdPartyResourceDataMapper) KindFor(resource string) (unversioned.GroupVersionKind, error) {
if t.isThirdPartyResource(resource) {
return []unversioned.GroupVersionResource{t.getResource()}, 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 unversioned.GroupVersionKind{Group: t.group, Version: t.version, Kind: t.kind}, nil
}
return t.mapper.KindFor(resource)
}
@ -127,7 +86,8 @@ func (t *thirdPartyResourceDataMapper) ResourceSingularizer(resource string) (si
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)
}

View File

@ -212,9 +212,9 @@ func TestResourceIsValid(t *testing.T) {
for _, test := range tests {
mapper := &thirdPartyResourceDataMapper{kind: test.kind}
mapper.mapper = api.RESTMapper
valid := mapper.ResourceIsValid(unversioned.GroupVersionResource{Resource: test.resource})
valid := mapper.ResourceIsValid(test.resource)
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) {
kind, err := api.RESTMapper.KindFor(a.GetResource().WithVersion(""))
gvk, err := api.RESTMapper.KindFor(a.GetResource().Resource)
if err != nil {
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 {
return admission.NewForbidden(a, err)
}

View File

@ -46,11 +46,11 @@ type exists struct {
}
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 {
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 {
return errors.NewInternalError(err)
}

View File

@ -48,16 +48,17 @@ type lifecycle struct {
}
func (l *lifecycle) Admit(a admission.Attributes) (err error) {
// prevent deletion of immortal namespaces
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"))
}
kind, err := api.RESTMapper.KindFor(a.GetResource().WithVersion(""))
gvk, err := api.RESTMapper.KindFor(a.GetResource().Resource)
if err != nil {
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 {
return errors.NewInternalError(err)
}