diff --git a/pkg/api/install/install_test.go b/pkg/api/install/install_test.go index cc634366b19..d65071e0c6b 100644 --- a/pkg/api/install/install_test.go +++ b/pkg/api/install/install_test.go @@ -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) } diff --git a/pkg/api/meta/interfaces.go b/pkg/api/meta/interfaces.go index 8f14a3fab50..c8b8d0ce394 100644 --- a/pkg/api/meta/interfaces.go +++ b/pkg/api/meta/interfaces.go @@ -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 } diff --git a/pkg/api/meta/restmapper.go b/pkg/api/meta/restmapper.go index 449f519afca..ed3e38cc7c1 100644 --- a/pkg/api/meta/restmapper.go +++ b/pkg/api/meta/restmapper.go @@ -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 diff --git a/pkg/api/meta/restmapper_test.go b/pkg/api/meta/restmapper_test.go index 603848d5c87..134705a6514 100644 --- a/pkg/api/meta/restmapper_test.go +++ b/pkg/api/meta/restmapper_test.go @@ -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) } } } diff --git a/pkg/api/unversioned/group_version.go b/pkg/api/unversioned/group_version.go index e1bae179d8d..14af802f5b2 100644 --- a/pkg/api/unversioned/group_version.go +++ b/pkg/api/unversioned/group_version.go @@ -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 } diff --git a/pkg/apis/componentconfig/install/install_test.go b/pkg/apis/componentconfig/install/install_test.go index 047b77e32f6..3a751b52039 100644 --- a/pkg/apis/componentconfig/install/install_test.go +++ b/pkg/apis/componentconfig/install/install_test.go @@ -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) } diff --git a/pkg/apis/extensions/install/install_test.go b/pkg/apis/extensions/install/install_test.go index 98435e044f6..83504f43fc7 100644 --- a/pkg/apis/extensions/install/install_test.go +++ b/pkg/apis/extensions/install/install_test.go @@ -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) } diff --git a/pkg/client/unversioned/scale.go b/pkg/client/unversioned/scale.go index 4064ce4dd49..7663325b487 100644 --- a/pkg/client/unversioned/scale.go +++ b/pkg/client/unversioned/scale.go @@ -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). diff --git a/pkg/client/unversioned/testclient/fixture.go b/pkg/client/unversioned/testclient/fixture.go index fad088e99de..73a80fab294 100644 --- a/pkg/client/unversioned/testclient/fixture.go +++ b/pkg/client/unversioned/testclient/fixture.go @@ -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: diff --git a/pkg/kubectl/cmd/explain.go b/pkg/kubectl/cmd/explain.go index 3c4a555bb27..170275a9ff1 100644 --- a/pkg/kubectl/cmd/explain.go +++ b/pkg/kubectl/cmd/explain.go @@ -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 } diff --git a/pkg/kubectl/cmd/rollingupdate.go b/pkg/kubectl/cmd/rollingupdate.go index fb11b9a3cf7..43900e9fc23 100644 --- a/pkg/kubectl/cmd/rollingupdate.go +++ b/pkg/kubectl/cmd/rollingupdate.go @@ -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 } diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go index 41559304ccd..61b5d69febf 100644 --- a/pkg/kubectl/cmd/util/factory.go +++ b/pkg/kubectl/cmd/util/factory.go @@ -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: diff --git a/pkg/kubectl/explain.go b/pkg/kubectl/explain.go index 1670fd3a89f..57b072c9889 100644 --- a/pkg/kubectl/explain.go +++ b/pkg/kubectl/explain.go @@ -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 } diff --git a/pkg/kubectl/kubectl.go b/pkg/kubectl/kubectl.go index a528fab96eb..6ecb4d278f6 100644 --- a/pkg/kubectl/kubectl.go +++ b/pkg/kubectl/kubectl.go @@ -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 diff --git a/pkg/kubectl/resource/builder.go b/pkg/kubectl/resource/builder.go index a2ca5dcd53f..7c8b20b8694 100644 --- a/pkg/kubectl/resource/builder.go +++ b/pkg/kubectl/resource/builder.go @@ -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 } diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index 55c8b345827..4b2d8199cf1 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -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("") + kind := objvalue.FieldByName("Kind") + if !kind.IsValid() { + kind = reflect.ValueOf("") } - kind.Kind = kindString.String() - - if !groupVersionString.IsValid() { - groupVersionString = reflect.ValueOf("/") - } - 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("") } - _, 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 diff --git a/pkg/registry/thirdpartyresourcedata/codec.go b/pkg/registry/thirdpartyresourcedata/codec.go index 1c3aea830d4..33002775eb8 100644 --- a/pkg/registry/thirdpartyresourcedata/codec.go +++ b/pkg/registry/thirdpartyresourcedata/codec.go @@ -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) } diff --git a/pkg/registry/thirdpartyresourcedata/codec_test.go b/pkg/registry/thirdpartyresourcedata/codec_test.go index 5af08ce82e3..093990f44fd 100644 --- a/pkg/registry/thirdpartyresourcedata/codec_test.go +++ b/pkg/registry/thirdpartyresourcedata/codec_test.go @@ -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) } } } diff --git a/plugin/pkg/admission/namespace/autoprovision/admission.go b/plugin/pkg/admission/namespace/autoprovision/admission.go index 23fdfea48a2..f4886d6a9c4 100644 --- a/plugin/pkg/admission/namespace/autoprovision/admission.go +++ b/plugin/pkg/admission/namespace/autoprovision/admission.go @@ -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) } diff --git a/plugin/pkg/admission/namespace/exists/admission.go b/plugin/pkg/admission/namespace/exists/admission.go index 5411bc2bb0c..22de7828b3c 100644 --- a/plugin/pkg/admission/namespace/exists/admission.go +++ b/plugin/pkg/admission/namespace/exists/admission.go @@ -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) } diff --git a/plugin/pkg/admission/namespace/lifecycle/admission.go b/plugin/pkg/admission/namespace/lifecycle/admission.go index 8344f6e0a58..19a77c1609d 100644 --- a/plugin/pkg/admission/namespace/lifecycle/admission.go +++ b/plugin/pkg/admission/namespace/lifecycle/admission.go @@ -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) }