mirror of https://github.com/k3s-io/k3s
use groupversion in RESTMapping
parent
b675a77213
commit
303bcad398
|
@ -78,12 +78,16 @@ func TestRESTMapper(t *testing.T) {
|
|||
t.Errorf("unexpected version mapping: %s %s %v", v, k, err)
|
||||
}
|
||||
|
||||
if m, err := latest.GroupOrDie("").RESTMapper.RESTMapping("PodTemplate", ""); err != nil || m.APIVersion != "v1" || m.Resource != "podtemplates" {
|
||||
expectedGroupVersion := unversioned.GroupVersion{Version: "v1"}
|
||||
|
||||
if m, err := latest.GroupOrDie("").RESTMapper.RESTMapping("PodTemplate", ""); err != nil || m.GroupVersionKind.GroupVersion() != expectedGroupVersion || m.Resource != "podtemplates" {
|
||||
t.Errorf("unexpected version mapping: %#v %v", m, err)
|
||||
}
|
||||
|
||||
for _, version := range latest.GroupOrDie("").Versions {
|
||||
mapping, err := latest.GroupOrDie("").RESTMapper.RESTMapping("ReplicationController", version)
|
||||
currGroupVersion := unversioned.GroupVersion{Version: version}
|
||||
|
||||
mapping, err := latest.GroupOrDie("").RESTMapper.RESTMapping("ReplicationController", currGroupVersion.String())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
@ -91,11 +95,11 @@ func TestRESTMapper(t *testing.T) {
|
|||
if mapping.Resource != "replicationControllers" && mapping.Resource != "replicationcontrollers" {
|
||||
t.Errorf("incorrect resource name: %#v", mapping)
|
||||
}
|
||||
if mapping.APIVersion != version {
|
||||
if mapping.GroupVersionKind.GroupVersion() != currGroupVersion {
|
||||
t.Errorf("incorrect version: %v", mapping)
|
||||
}
|
||||
|
||||
interfaces, _ := latest.GroupOrDie("").InterfacesFor(version)
|
||||
interfaces, _ := latest.GroupOrDie("").InterfacesFor(currGroupVersion.String())
|
||||
if mapping.Codec != interfaces.Codec {
|
||||
t.Errorf("unexpected codec: %#v, expected: %#v", mapping, interfaces)
|
||||
}
|
||||
|
|
|
@ -17,9 +17,11 @@ limitations under the License.
|
|||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
|
@ -33,14 +35,23 @@ func RegisterRESTMapper(m meta.RESTMapper) {
|
|||
RESTMapper = append(RESTMapper.(meta.MultiRESTMapper), m)
|
||||
}
|
||||
|
||||
func NewDefaultRESTMapper(group string, versions []string, interfacesFunc meta.VersionInterfacesFunc,
|
||||
func NewDefaultRESTMapper(group string, groupVersionStrings []string, interfacesFunc meta.VersionInterfacesFunc,
|
||||
importPathPrefix string, ignoredKinds, rootScoped sets.String) *meta.DefaultRESTMapper {
|
||||
|
||||
mapper := meta.NewDefaultRESTMapper(group, versions, interfacesFunc)
|
||||
mapper := meta.NewDefaultRESTMapper(group, groupVersionStrings, interfacesFunc)
|
||||
// enumerate all supported versions, get the kinds, and register with the mapper how to address
|
||||
// our resources.
|
||||
for _, version := range versions {
|
||||
for kind, oType := range Scheme.KnownTypes(version) {
|
||||
for _, gvString := range groupVersionStrings {
|
||||
gv, err := unversioned.ParseGroupVersion(gvString)
|
||||
// TODO stop panicing when the types are fixed
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if gv.Group != group {
|
||||
panic(fmt.Sprintf("%q does not match the expect %q", gv.Group, group))
|
||||
}
|
||||
|
||||
for kind, oType := range Scheme.KnownTypes(gv.String()) {
|
||||
// TODO: Remove import path prefix check.
|
||||
// We check the import path prefix because we currently stuff both "api" and "extensions" objects
|
||||
// into the same group within Scheme since Scheme has no notion of groups yet.
|
||||
|
@ -51,7 +62,7 @@ func NewDefaultRESTMapper(group string, versions []string, interfacesFunc meta.V
|
|||
if rootScoped.Has(kind) {
|
||||
scope = meta.RESTScopeRoot
|
||||
}
|
||||
mapper.Add(scope, kind, version, false)
|
||||
mapper.Add(scope, kind, gv.String(), false)
|
||||
}
|
||||
}
|
||||
return mapper
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package meta
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
)
|
||||
|
@ -124,10 +125,8 @@ type RESTScope interface {
|
|||
type RESTMapping struct {
|
||||
// Resource is a string representing the name of this resource as a REST client would see it
|
||||
Resource string
|
||||
// APIVersion represents the APIVersion that represents the resource as presented. It is provided
|
||||
// for convenience for passing around a consistent mapping.
|
||||
APIVersion string
|
||||
Kind string
|
||||
|
||||
GroupVersionKind unversioned.GroupVersionKind
|
||||
|
||||
// Scope contains the information needed to deal with REST Resources that are in a resource hierarchy
|
||||
Scope RESTScope
|
||||
|
|
|
@ -20,6 +20,8 @@ package meta
|
|||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
)
|
||||
|
||||
// Implements RESTScope interface
|
||||
|
@ -72,12 +74,12 @@ type typeMeta struct {
|
|||
//
|
||||
// TODO: Only accept plural for some operations for increased control?
|
||||
// (`get pod bar` vs `get pods bar`)
|
||||
// TODO these maps should be keyed based on GroupVersionKinds
|
||||
type DefaultRESTMapper struct {
|
||||
mapping map[string]typeMeta
|
||||
reverse map[typeMeta]string
|
||||
scopes map[typeMeta]RESTScope
|
||||
group string
|
||||
versions []string
|
||||
groupVersions []unversioned.GroupVersion
|
||||
plurals map[string]string
|
||||
singulars map[string]string
|
||||
interfacesFunc VersionInterfacesFunc
|
||||
|
@ -92,7 +94,12 @@ type VersionInterfacesFunc func(apiVersion string) (*VersionInterfaces, error)
|
|||
// and the Kubernetes API conventions. Takes a group name, a priority list of the versions
|
||||
// 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(group string, versions []string, f VersionInterfacesFunc) *DefaultRESTMapper {
|
||||
// TODO remove group when this API is fixed. It is no longer used.
|
||||
// The external API for a RESTMapper is cross-version and this is currently called using
|
||||
// group/version tuples. In the end, the structure may be easier to understand with
|
||||
// a GroupRESTMapper and CrossGroupRESTMapper, but for now, this one is constructed and
|
||||
// used a CrossGroupRESTMapper.
|
||||
func NewDefaultRESTMapper(group string, gvStrings []string, f VersionInterfacesFunc) *DefaultRESTMapper {
|
||||
mapping := make(map[string]typeMeta)
|
||||
reverse := make(map[typeMeta]string)
|
||||
scopes := make(map[typeMeta]RESTScope)
|
||||
|
@ -100,23 +107,29 @@ func NewDefaultRESTMapper(group string, versions []string, f VersionInterfacesFu
|
|||
singulars := make(map[string]string)
|
||||
// TODO: verify name mappings work correctly when versions differ
|
||||
|
||||
gvs := []unversioned.GroupVersion{}
|
||||
for _, gvString := range gvStrings {
|
||||
gvs = append(gvs, unversioned.ParseGroupVersionOrDie(gvString))
|
||||
}
|
||||
|
||||
return &DefaultRESTMapper{
|
||||
mapping: mapping,
|
||||
reverse: reverse,
|
||||
scopes: scopes,
|
||||
group: group,
|
||||
versions: versions,
|
||||
groupVersions: gvs,
|
||||
plurals: plurals,
|
||||
singulars: singulars,
|
||||
interfacesFunc: f,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DefaultRESTMapper) Add(scope RESTScope, kind string, version string, mixedCase bool) {
|
||||
func (m *DefaultRESTMapper) Add(scope RESTScope, kind string, gvString string, mixedCase bool) {
|
||||
gv := unversioned.ParseGroupVersionOrDie(gvString)
|
||||
|
||||
plural, singular := KindToResource(kind, mixedCase)
|
||||
m.plurals[singular] = plural
|
||||
m.singulars[plural] = singular
|
||||
meta := typeMeta{APIVersion: version, Kind: kind}
|
||||
meta := typeMeta{APIVersion: gv.String(), Kind: kind}
|
||||
_, ok1 := m.mapping[plural]
|
||||
_, ok2 := m.mapping[strings.ToLower(plural)]
|
||||
if !ok1 && !ok2 {
|
||||
|
@ -177,74 +190,90 @@ func (m *DefaultRESTMapper) VersionAndKindForResource(resource string) (defaultV
|
|||
}
|
||||
|
||||
func (m *DefaultRESTMapper) GroupForResource(resource string) (string, error) {
|
||||
if _, ok := m.mapping[strings.ToLower(resource)]; !ok {
|
||||
typemeta, exists := m.mapping[strings.ToLower(resource)]
|
||||
if !exists {
|
||||
return "", fmt.Errorf("in group for resource, no resource %q has been defined", resource)
|
||||
}
|
||||
return m.group, nil
|
||||
|
||||
gv, err := unversioned.ParseGroupVersion(typemeta.APIVersion)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return gv.Group, nil
|
||||
}
|
||||
|
||||
// RESTMapping returns a struct representing the resource path and conversion interfaces a
|
||||
// RESTClient should use to operate on the provided kind in order of versions. If a version search
|
||||
// order is not provided, the search order provided to DefaultRESTMapper will be used to resolve which
|
||||
// APIVersion should be used to access the named kind.
|
||||
// TODO version here in this RESTMapper means just APIVersion, but the RESTMapper API is intended to handle multiple groups
|
||||
// So this API is broken. The RESTMapper test made it clear that versions here were API versions, but the code tries to use
|
||||
// them with group/version tuples.
|
||||
// TODO this should probably become RESTMapping(GroupKind, versions ...string)
|
||||
func (m *DefaultRESTMapper) RESTMapping(kind string, versions ...string) (*RESTMapping, error) {
|
||||
// Pick an appropriate version
|
||||
var version string
|
||||
var groupVersion *unversioned.GroupVersion
|
||||
hadVersion := false
|
||||
for _, v := range versions {
|
||||
if len(v) == 0 {
|
||||
continue
|
||||
}
|
||||
currGroupVersion, err := unversioned.ParseGroupVersion(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hadVersion = true
|
||||
if _, ok := m.reverse[typeMeta{APIVersion: v, Kind: kind}]; ok {
|
||||
version = v
|
||||
if _, ok := m.reverse[typeMeta{APIVersion: currGroupVersion.String(), Kind: kind}]; ok {
|
||||
groupVersion = &currGroupVersion
|
||||
break
|
||||
}
|
||||
}
|
||||
// Use the default preferred versions
|
||||
if !hadVersion && len(version) == 0 {
|
||||
for _, v := range m.versions {
|
||||
if _, ok := m.reverse[typeMeta{APIVersion: v, Kind: kind}]; ok {
|
||||
version = v
|
||||
if !hadVersion && (groupVersion == nil) {
|
||||
for _, currGroupVersion := range m.groupVersions {
|
||||
if _, ok := m.reverse[typeMeta{APIVersion: currGroupVersion.String(), Kind: kind}]; ok {
|
||||
groupVersion = &currGroupVersion
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(version) == 0 {
|
||||
if groupVersion == nil {
|
||||
return nil, fmt.Errorf("no kind named %q is registered in versions %q", kind, versions)
|
||||
}
|
||||
|
||||
gvk := unversioned.NewGroupVersionKind(*groupVersion, kind)
|
||||
|
||||
// Ensure we have a REST mapping
|
||||
resource, ok := m.reverse[typeMeta{APIVersion: version, Kind: kind}]
|
||||
resource, ok := m.reverse[typeMeta{APIVersion: gvk.GroupVersion().String(), Kind: gvk.Kind}]
|
||||
if !ok {
|
||||
found := []string{}
|
||||
for _, v := range m.versions {
|
||||
if _, ok := m.reverse[typeMeta{APIVersion: v, Kind: kind}]; ok {
|
||||
found = append(found, v)
|
||||
found := []unversioned.GroupVersion{}
|
||||
for _, gv := range m.groupVersions {
|
||||
if _, ok := m.reverse[typeMeta{APIVersion: gv.String(), Kind: kind}]; ok {
|
||||
found = append(found, gv)
|
||||
}
|
||||
}
|
||||
if len(found) > 0 {
|
||||
return nil, fmt.Errorf("object with kind %q exists in versions %q, not %q", kind, strings.Join(found, ", "), version)
|
||||
return nil, fmt.Errorf("object with kind %q exists in versions %v, not %v", kind, found, *groupVersion)
|
||||
}
|
||||
return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported object", version, kind)
|
||||
return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported object", groupVersion, kind)
|
||||
}
|
||||
|
||||
// Ensure we have a REST scope
|
||||
scope, ok := m.scopes[typeMeta{APIVersion: version, Kind: kind}]
|
||||
scope, ok := m.scopes[typeMeta{APIVersion: gvk.GroupVersion().String(), Kind: gvk.Kind}]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", version, kind)
|
||||
return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", gvk.GroupVersion().String(), gvk.Kind)
|
||||
}
|
||||
|
||||
interfaces, err := m.interfacesFunc(version)
|
||||
interfaces, err := m.interfacesFunc(gvk.GroupVersion().String())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the provided version %q has no relevant versions", version)
|
||||
return nil, fmt.Errorf("the provided version %q has no relevant versions", gvk.GroupVersion().String())
|
||||
}
|
||||
|
||||
retVal := &RESTMapping{
|
||||
Resource: resource,
|
||||
APIVersion: version,
|
||||
Kind: kind,
|
||||
Scope: scope,
|
||||
Resource: resource,
|
||||
GroupVersionKind: gvk,
|
||||
Scope: scope,
|
||||
|
||||
Codec: interfaces.Codec,
|
||||
ObjectConvertor: interfaces.ObjectConvertor,
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"io"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
|
@ -79,53 +80,71 @@ func unmatchedVersionInterfaces(version string) (*VersionInterfaces, error) {
|
|||
}
|
||||
|
||||
func TestRESTMapperVersionAndKindForResource(t *testing.T) {
|
||||
testGroup := "test.group"
|
||||
testVersion := "test"
|
||||
testGroupVersion := unversioned.GroupVersion{Group: testGroup, Version: testVersion}
|
||||
|
||||
testCases := []struct {
|
||||
Resource string
|
||||
Kind, APIVersion string
|
||||
MixedCase bool
|
||||
Err bool
|
||||
Resource string
|
||||
GroupVersionToRegister unversioned.GroupVersion
|
||||
ExpectedGVK unversioned.GroupVersionKind
|
||||
MixedCase bool
|
||||
Err bool
|
||||
}{
|
||||
{Resource: "internalobjec", Err: true},
|
||||
{Resource: "internalObjec", Err: true},
|
||||
{Resource: "internalobjec", Err: true, GroupVersionToRegister: testGroupVersion},
|
||||
{Resource: "internalObjec", Err: true, GroupVersionToRegister: testGroupVersion},
|
||||
|
||||
{Resource: "internalobject", Kind: "InternalObject", APIVersion: "test"},
|
||||
{Resource: "internalobjects", Kind: "InternalObject", APIVersion: "test"},
|
||||
{Resource: "internalobject", GroupVersionToRegister: testGroupVersion, ExpectedGVK: unversioned.NewGroupVersionKind(testGroupVersion, "InternalObject")},
|
||||
{Resource: "internalobjects", GroupVersionToRegister: testGroupVersion, ExpectedGVK: unversioned.NewGroupVersionKind(testGroupVersion, "InternalObject")},
|
||||
|
||||
{Resource: "internalobject", MixedCase: true, Kind: "InternalObject", APIVersion: "test"},
|
||||
{Resource: "internalobjects", MixedCase: true, Kind: "InternalObject", APIVersion: "test"},
|
||||
{Resource: "internalobject", GroupVersionToRegister: testGroupVersion, MixedCase: true, ExpectedGVK: unversioned.NewGroupVersionKind(testGroupVersion, "InternalObject")},
|
||||
{Resource: "internalobjects", GroupVersionToRegister: testGroupVersion, MixedCase: true, ExpectedGVK: unversioned.NewGroupVersionKind(testGroupVersion, "InternalObject")},
|
||||
|
||||
{Resource: "internalObject", MixedCase: true, Kind: "InternalObject", APIVersion: "test"},
|
||||
{Resource: "internalObjects", MixedCase: true, Kind: "InternalObject", APIVersion: "test"},
|
||||
{Resource: "internalObject", GroupVersionToRegister: testGroupVersion, MixedCase: true, ExpectedGVK: unversioned.NewGroupVersionKind(testGroupVersion, "InternalObject")},
|
||||
{Resource: "internalObjects", GroupVersionToRegister: testGroupVersion, MixedCase: true, ExpectedGVK: unversioned.NewGroupVersionKind(testGroupVersion, "InternalObject")},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper("tgroup", []string{"test"}, fakeInterfaces)
|
||||
mapper.Add(RESTScopeNamespace, testCase.Kind, testCase.APIVersion, testCase.MixedCase)
|
||||
mapper := NewDefaultRESTMapper(testGroup, []string{testGroupVersion.String()}, fakeInterfaces)
|
||||
mapper.Add(RESTScopeNamespace, testCase.ExpectedGVK.Kind, testCase.GroupVersionToRegister.String(), testCase.MixedCase)
|
||||
v, k, err := mapper.VersionAndKindForResource(testCase.Resource)
|
||||
|
||||
hasErr := err != nil
|
||||
if hasErr != testCase.Err {
|
||||
t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err)
|
||||
continue
|
||||
}
|
||||
if v != testCase.APIVersion || k != testCase.Kind {
|
||||
t.Errorf("%d: unexpected version and kind: %s %s", i, v, k)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
actualGV, err := unversioned.ParseGroupVersion(v)
|
||||
if err != nil {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
actualGVK := unversioned.NewGroupVersionKind(actualGV, k)
|
||||
|
||||
if actualGVK != testCase.ExpectedGVK {
|
||||
t.Errorf("%d: unexpected version and kind: e=%s a=%s", i, testCase.ExpectedGVK, actualGVK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperGroupForResource(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Resource string
|
||||
Kind, APIVersion, Group string
|
||||
Err bool
|
||||
Resource string
|
||||
Kind string
|
||||
GroupVersion unversioned.GroupVersion
|
||||
Err bool
|
||||
}{
|
||||
{Resource: "myObject", Kind: "MyObject", APIVersion: "test", Group: "testapi"},
|
||||
{Resource: "myobject", Kind: "MyObject", APIVersion: "test", Group: "testapi2"},
|
||||
{Resource: "myObje", Err: true, Kind: "MyObject", APIVersion: "test", Group: "testapi"},
|
||||
{Resource: "myobje", Err: true, Kind: "MyObject", APIVersion: "test", Group: "testapi"},
|
||||
{Resource: "myObject", Kind: "MyObject", GroupVersion: unversioned.GroupVersion{Group: "testapi", Version: "test"}},
|
||||
{Resource: "myobject", Kind: "MyObject", GroupVersion: unversioned.GroupVersion{Group: "testapi2", Version: "test"}},
|
||||
{Resource: "myObje", Err: true, Kind: "MyObject", GroupVersion: unversioned.GroupVersion{Group: "testapi", Version: "test"}},
|
||||
{Resource: "myobje", Err: true, Kind: "MyObject", GroupVersion: unversioned.GroupVersion{Group: "testapi", Version: "test"}},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper(testCase.Group, []string{"test"}, fakeInterfaces)
|
||||
mapper.Add(RESTScopeNamespace, testCase.Kind, testCase.APIVersion, false)
|
||||
mapper := NewDefaultRESTMapper(testCase.GroupVersion.Group, []string{testCase.GroupVersion.String()}, fakeInterfaces)
|
||||
mapper.Add(RESTScopeNamespace, testCase.Kind, testCase.GroupVersion.String(), false)
|
||||
g, err := mapper.GroupForResource(testCase.Resource)
|
||||
if testCase.Err {
|
||||
if err == nil {
|
||||
|
@ -133,8 +152,8 @@ func TestRESTMapperGroupForResource(t *testing.T) {
|
|||
}
|
||||
} else if err != nil {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
} else if g != testCase.Group {
|
||||
t.Errorf("%d: expected group %q, got %q", i, testCase.Group, g)
|
||||
} else if g != testCase.GroupVersion.Group {
|
||||
t.Errorf("%d: expected group %q, got %q", i, testCase.GroupVersion.Group, g)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,31 +189,34 @@ func TestKindToResource(t *testing.T) {
|
|||
|
||||
func TestRESTMapperResourceSingularizer(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Kind, APIVersion string
|
||||
MixedCase bool
|
||||
Plural string
|
||||
Singular string
|
||||
Kind string
|
||||
MixedCase bool
|
||||
Plural string
|
||||
Singular string
|
||||
}{
|
||||
{Kind: "Pod", APIVersion: "test", MixedCase: true, Plural: "pods", Singular: "pod"},
|
||||
{Kind: "Pod", APIVersion: "test", MixedCase: false, Plural: "pods", Singular: "pod"},
|
||||
{Kind: "Pod", MixedCase: true, Plural: "pods", Singular: "pod"},
|
||||
{Kind: "Pod", MixedCase: false, Plural: "pods", Singular: "pod"},
|
||||
|
||||
{Kind: "ReplicationController", APIVersion: "test", MixedCase: true, Plural: "replicationControllers", Singular: "replicationController"},
|
||||
{Kind: "ReplicationController", APIVersion: "test", MixedCase: false, Plural: "replicationcontrollers", Singular: "replicationcontroller"},
|
||||
{Kind: "ReplicationController", MixedCase: true, Plural: "replicationControllers", Singular: "replicationController"},
|
||||
{Kind: "ReplicationController", MixedCase: false, Plural: "replicationcontrollers", Singular: "replicationcontroller"},
|
||||
|
||||
{Kind: "ImageRepository", APIVersion: "test", MixedCase: true, Plural: "imageRepositories", Singular: "imageRepository"},
|
||||
{Kind: "ImageRepository", APIVersion: "test", MixedCase: false, Plural: "imagerepositories", Singular: "imagerepository"},
|
||||
{Kind: "ImageRepository", MixedCase: true, Plural: "imageRepositories", Singular: "imageRepository"},
|
||||
{Kind: "ImageRepository", MixedCase: false, Plural: "imagerepositories", Singular: "imagerepository"},
|
||||
|
||||
{Kind: "Status", APIVersion: "test", MixedCase: true, Plural: "statuses", Singular: "status"},
|
||||
{Kind: "Status", APIVersion: "test", MixedCase: false, Plural: "statuses", Singular: "status"},
|
||||
{Kind: "Status", MixedCase: true, Plural: "statuses", Singular: "status"},
|
||||
{Kind: "Status", MixedCase: false, Plural: "statuses", Singular: "status"},
|
||||
|
||||
{Kind: "lowercase", APIVersion: "test", MixedCase: false, Plural: "lowercases", Singular: "lowercase"},
|
||||
{Kind: "lowercase", MixedCase: false, Plural: "lowercases", Singular: "lowercase"},
|
||||
// Don't add extra s if the original object is already plural
|
||||
{Kind: "lowercases", APIVersion: "test", MixedCase: false, Plural: "lowercases", Singular: "lowercases"},
|
||||
{Kind: "lowercases", MixedCase: false, Plural: "lowercases", Singular: "lowercases"},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper("tgroup", []string{"test"}, fakeInterfaces)
|
||||
testGroupVersion := unversioned.GroupVersion{Group: "tgroup", Version: "test"}
|
||||
|
||||
mapper := NewDefaultRESTMapper(testGroupVersion.Group, []string{testGroupVersion.String()}, fakeInterfaces)
|
||||
// create singular/plural mapping
|
||||
mapper.Add(RESTScopeNamespace, testCase.Kind, testCase.APIVersion, testCase.MixedCase)
|
||||
mapper.Add(RESTScopeNamespace, testCase.Kind, testGroupVersion.String(), testCase.MixedCase)
|
||||
|
||||
singular, _ := mapper.ResourceSingularizer(testCase.Plural)
|
||||
if singular != testCase.Singular {
|
||||
t.Errorf("%d: mismatched singular: %s, should be %s", i, singular, testCase.Singular)
|
||||
|
@ -203,37 +225,48 @@ func TestRESTMapperResourceSingularizer(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRESTMapperRESTMapping(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Kind string
|
||||
APIVersions []string
|
||||
MixedCase bool
|
||||
DefaultVersions []string
|
||||
testGroup := "tgroup"
|
||||
testGroupVersion := unversioned.GroupVersion{Group: testGroup, Version: "test"}
|
||||
|
||||
Resource string
|
||||
Version string
|
||||
Err bool
|
||||
testCases := []struct {
|
||||
Kind string
|
||||
APIGroupVersions []unversioned.GroupVersion
|
||||
MixedCase bool
|
||||
DefaultVersions []string
|
||||
|
||||
Resource string
|
||||
ExpectedGroupVersion *unversioned.GroupVersion
|
||||
Err bool
|
||||
}{
|
||||
{Kind: "Unknown", Err: true},
|
||||
{Kind: "InternalObject", Err: true},
|
||||
|
||||
{DefaultVersions: []string{"test"}, Kind: "Unknown", Err: true},
|
||||
{DefaultVersions: []string{testGroupVersion.String()}, Kind: "Unknown", Err: true},
|
||||
|
||||
{DefaultVersions: []string{"test"}, Kind: "InternalObject", APIVersions: []string{"test"}, Resource: "internalobjects"},
|
||||
{DefaultVersions: []string{"test"}, Kind: "InternalObject", APIVersions: []string{"test"}, Resource: "internalobjects"},
|
||||
{DefaultVersions: []string{testGroupVersion.String()}, Kind: "InternalObject", APIGroupVersions: []unversioned.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
{DefaultVersions: []string{testGroupVersion.String()}, Kind: "InternalObject", APIGroupVersions: []unversioned.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
|
||||
{DefaultVersions: []string{"test"}, Kind: "InternalObject", APIVersions: []string{"test"}, Resource: "internalobjects"},
|
||||
{DefaultVersions: []string{testGroupVersion.String()}, Kind: "InternalObject", APIGroupVersions: []unversioned.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
|
||||
{DefaultVersions: []string{"test"}, Kind: "InternalObject", APIVersions: []string{}, Resource: "internalobjects", Version: "test"},
|
||||
{DefaultVersions: []string{testGroupVersion.String()}, Kind: "InternalObject", APIGroupVersions: []unversioned.GroupVersion{}, Resource: "internalobjects", ExpectedGroupVersion: &unversioned.GroupVersion{Group: testGroup, Version: "test"}},
|
||||
|
||||
{DefaultVersions: []string{"test"}, Kind: "InternalObject", APIVersions: []string{"test"}, Resource: "internalobjects"},
|
||||
{DefaultVersions: []string{"test"}, Kind: "InternalObject", APIVersions: []string{"test"}, MixedCase: true, Resource: "internalObjects"},
|
||||
{DefaultVersions: []string{testGroupVersion.String()}, Kind: "InternalObject", APIGroupVersions: []unversioned.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
{DefaultVersions: []string{testGroupVersion.String()}, Kind: "InternalObject", APIGroupVersions: []unversioned.GroupVersion{{Group: testGroup, Version: "test"}}, MixedCase: true, Resource: "internalObjects"},
|
||||
|
||||
// TODO: add test for a resource that exists in one version but not another
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper("tgroup", testCase.DefaultVersions, fakeInterfaces)
|
||||
mapper.Add(RESTScopeNamespace, "InternalObject", "test", testCase.MixedCase)
|
||||
mapping, err := mapper.RESTMapping(testCase.Kind, testCase.APIVersions...)
|
||||
internalGroupVersion := unversioned.GroupVersion{Group: testGroup, Version: "test"}
|
||||
|
||||
mapper := NewDefaultRESTMapper(testGroup, testCase.DefaultVersions, fakeInterfaces)
|
||||
mapper.Add(RESTScopeNamespace, "InternalObject", internalGroupVersion.String(), testCase.MixedCase)
|
||||
|
||||
deprecatedGroupVersionStrings := []string{}
|
||||
for _, gv := range testCase.APIGroupVersions {
|
||||
deprecatedGroupVersionStrings = append(deprecatedGroupVersionStrings, gv.String())
|
||||
}
|
||||
|
||||
mapping, err := mapper.RESTMapping(testCase.Kind, deprecatedGroupVersionStrings...)
|
||||
hasErr := err != nil
|
||||
if hasErr != testCase.Err {
|
||||
t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err)
|
||||
|
@ -244,30 +277,37 @@ func TestRESTMapperRESTMapping(t *testing.T) {
|
|||
if mapping.Resource != testCase.Resource {
|
||||
t.Errorf("%d: unexpected resource: %#v", i, mapping)
|
||||
}
|
||||
version := testCase.Version
|
||||
if version == "" {
|
||||
version = testCase.APIVersions[0]
|
||||
}
|
||||
if mapping.APIVersion != version {
|
||||
t.Errorf("%d: unexpected version: %#v", i, mapping)
|
||||
}
|
||||
|
||||
if mapping.Codec == nil || mapping.MetadataAccessor == nil || mapping.ObjectConvertor == nil {
|
||||
t.Errorf("%d: missing codec and accessor: %#v", i, mapping)
|
||||
}
|
||||
|
||||
groupVersion := testCase.ExpectedGroupVersion
|
||||
if groupVersion == nil {
|
||||
groupVersion = &testCase.APIGroupVersions[0]
|
||||
}
|
||||
if mapping.GroupVersionKind.GroupVersion() != *groupVersion {
|
||||
t.Errorf("%d: unexpected version: %#v", i, mapping)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
|
||||
mapper := NewDefaultRESTMapper("tgroup", []string{"test1", "test2"}, fakeInterfaces)
|
||||
mapper.Add(RESTScopeNamespace, "InternalObject", "test1", false)
|
||||
mapper.Add(RESTScopeNamespace, "OtherObject", "test2", false)
|
||||
expectedGroupVersion1 := unversioned.GroupVersion{Group: "tgroup", Version: "test1"}
|
||||
expectedGroupVersion2 := unversioned.GroupVersion{Group: "tgroup", Version: "test2"}
|
||||
expectedGroupVersion3 := unversioned.GroupVersion{Group: "tgroup", Version: "test3"}
|
||||
|
||||
mapper := NewDefaultRESTMapper("tgroup", []string{expectedGroupVersion1.String(), expectedGroupVersion2.String()}, fakeInterfaces)
|
||||
mapper.Add(RESTScopeNamespace, "InternalObject", expectedGroupVersion1.String(), false)
|
||||
mapper.Add(RESTScopeNamespace, "OtherObject", expectedGroupVersion2.String(), false)
|
||||
|
||||
// pick default matching object kind based on search order
|
||||
mapping, err := mapper.RESTMapping("OtherObject")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if mapping.Resource != "otherobjects" || mapping.APIVersion != "test2" {
|
||||
if mapping.Resource != "otherobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
|
||||
t.Errorf("unexpected mapping: %#v", mapping)
|
||||
}
|
||||
|
||||
|
@ -275,45 +315,48 @@ func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if mapping.Resource != "internalobjects" || mapping.APIVersion != "test1" {
|
||||
if mapping.Resource != "internalobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion1 {
|
||||
t.Errorf("unexpected mapping: %#v", mapping)
|
||||
}
|
||||
|
||||
// mismatch of version
|
||||
mapping, err = mapper.RESTMapping("InternalObject", "test2")
|
||||
mapping, err = mapper.RESTMapping("InternalObject", expectedGroupVersion2.String())
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
mapping, err = mapper.RESTMapping("OtherObject", "test1")
|
||||
mapping, err = mapper.RESTMapping("OtherObject", expectedGroupVersion1.String())
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
|
||||
// not in the search versions
|
||||
mapping, err = mapper.RESTMapping("OtherObject", "test3")
|
||||
mapping, err = mapper.RESTMapping("OtherObject", expectedGroupVersion3.String())
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
|
||||
// explicit search order
|
||||
mapping, err = mapper.RESTMapping("OtherObject", "test3", "test1")
|
||||
mapping, err = mapper.RESTMapping("OtherObject", expectedGroupVersion3.String(), expectedGroupVersion1.String())
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
|
||||
mapping, err = mapper.RESTMapping("OtherObject", "test3", "test2")
|
||||
mapping, err = mapper.RESTMapping("OtherObject", expectedGroupVersion3.String(), expectedGroupVersion2.String())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected non-error")
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if mapping.Resource != "otherobjects" || mapping.APIVersion != "test2" {
|
||||
if mapping.Resource != "otherobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
|
||||
t.Errorf("unexpected mapping: %#v", mapping)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperReportsErrorOnBadVersion(t *testing.T) {
|
||||
mapper := NewDefaultRESTMapper("tgroup", []string{"test1", "test2"}, unmatchedVersionInterfaces)
|
||||
mapper.Add(RESTScopeNamespace, "InternalObject", "test1", false)
|
||||
_, err := mapper.RESTMapping("InternalObject", "test1")
|
||||
expectedGroupVersion1 := unversioned.GroupVersion{Group: "tgroup", Version: "test1"}
|
||||
expectedGroupVersion2 := unversioned.GroupVersion{Group: "tgroup", Version: "test2"}
|
||||
|
||||
mapper := NewDefaultRESTMapper("tgroup", []string{expectedGroupVersion1.String(), expectedGroupVersion2.String()}, unmatchedVersionInterfaces)
|
||||
mapper.Add(RESTScopeNamespace, "InternalObject", expectedGroupVersion1.String(), false)
|
||||
_, err := mapper.RESTMapping("InternalObject", expectedGroupVersion1.String())
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
|
|
|
@ -22,7 +22,26 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// TODO: We need to remove the GroupVersion in types.go. We use the name GroupVersion here temporarily.
|
||||
// GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion
|
||||
// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling
|
||||
type GroupVersionKind struct {
|
||||
Group string
|
||||
Version string
|
||||
Kind string
|
||||
}
|
||||
|
||||
func NewGroupVersionKind(gv GroupVersion, kind string) GroupVersionKind {
|
||||
return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind}
|
||||
}
|
||||
|
||||
func (gvk GroupVersionKind) GroupVersion() GroupVersion {
|
||||
return GroupVersion{Group: gvk.Group, Version: gvk.Version}
|
||||
}
|
||||
|
||||
func (gvk *GroupVersionKind) String() string {
|
||||
return gvk.Group + "/" + gvk.Version + ", Kind=" + gvk.Kind
|
||||
}
|
||||
|
||||
// GroupVersion contains the "group" and the "version", which uniquely identifies the API.
|
||||
type GroupVersion struct {
|
||||
Group string
|
||||
|
@ -31,7 +50,7 @@ type GroupVersion struct {
|
|||
|
||||
// String puts "group" and "version" into a single "group/version" string. For the legacy v1
|
||||
// it returns "v1".
|
||||
func (gv *GroupVersion) String() string {
|
||||
func (gv GroupVersion) String() string {
|
||||
// special case of "v1" for backward compatibility
|
||||
if gv.Group == "" && gv.Version == "v1" {
|
||||
return gv.Version
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/latest"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
)
|
||||
|
||||
|
@ -53,28 +54,36 @@ func TestInterfacesFor(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRESTMapper(t *testing.T) {
|
||||
if v, k, err := latest.GroupOrDie("componentconfig").RESTMapper.VersionAndKindForResource("kubeproxyconfiguration"); err != nil || v != "componentconfig/v1alpha1" || k != "KubeProxyConfiguration" {
|
||||
t.Errorf("unexpected version mapping: %s %s %v", v, k, err)
|
||||
expectedGroupVersion := unversioned.GroupVersion{Group: "componentconfig", Version: "v1alpha1"}
|
||||
|
||||
if v, k, err := latest.GroupOrDie("componentconfig").RESTMapper.VersionAndKindForResource("kubeproxyconfiguration"); err != nil || v != expectedGroupVersion.String() || k != "KubeProxyConfiguration" {
|
||||
t.Errorf("unexpected version mapping: %q %q %v", v, k, err)
|
||||
}
|
||||
|
||||
if m, err := latest.GroupOrDie("componentconfig").RESTMapper.RESTMapping("KubeProxyConfiguration", ""); err != nil || m.APIVersion != "componentconfig/v1alpha1" || m.Resource != "kubeproxyconfigurations" {
|
||||
if m, err := latest.GroupOrDie("componentconfig").RESTMapper.RESTMapping("KubeProxyConfiguration", ""); err != nil || m.GroupVersionKind.GroupVersion() != expectedGroupVersion || m.Resource != "kubeproxyconfigurations" {
|
||||
t.Errorf("unexpected version mapping: %#v %v", m, err)
|
||||
}
|
||||
|
||||
for _, groupVersion := range latest.GroupOrDie("componentconfig").GroupVersions {
|
||||
mapping, err := latest.GroupOrDie("componentconfig").RESTMapper.RESTMapping("KubeProxyConfiguration", groupVersion)
|
||||
for _, groupVersionString := range latest.GroupOrDie("componentconfig").GroupVersions {
|
||||
gv, err := unversioned.ParseGroupVersion(groupVersionString)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
mapping, err := latest.GroupOrDie("componentconfig").RESTMapper.RESTMapping("KubeProxyConfiguration", gv.String())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if mapping.Resource != "kubeproxyconfigurations" {
|
||||
t.Errorf("incorrect resource name: %#v", mapping)
|
||||
}
|
||||
if mapping.APIVersion != groupVersion {
|
||||
if mapping.GroupVersionKind.GroupVersion() != gv {
|
||||
t.Errorf("incorrect groupVersion: %v", mapping)
|
||||
}
|
||||
|
||||
interfaces, _ := latest.GroupOrDie("componentconfig").InterfacesFor(groupVersion)
|
||||
interfaces, _ := latest.GroupOrDie("componentconfig").InterfacesFor(gv.String())
|
||||
if mapping.Codec != interfaces.Codec {
|
||||
t.Errorf("unexpected codec: %#v, expected: %#v", mapping, interfaces)
|
||||
}
|
||||
|
|
|
@ -75,16 +75,20 @@ func TestInterfacesFor(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRESTMapper(t *testing.T) {
|
||||
if v, k, err := latest.GroupOrDie("extensions").RESTMapper.VersionAndKindForResource("horizontalpodautoscalers"); err != nil || v != "extensions/v1beta1" || k != "HorizontalPodAutoscaler" {
|
||||
expectedGroupVersion := unversioned.GroupVersion{Group: "extensions", Version: "v1beta1"}
|
||||
|
||||
if v, k, err := latest.GroupOrDie("extensions").RESTMapper.VersionAndKindForResource("horizontalpodautoscalers"); err != nil || v != expectedGroupVersion.String() || k != "HorizontalPodAutoscaler" {
|
||||
t.Errorf("unexpected version mapping: %s %s %v", v, k, err)
|
||||
}
|
||||
|
||||
if m, err := latest.GroupOrDie("extensions").RESTMapper.RESTMapping("DaemonSet", ""); err != nil || m.APIVersion != "extensions/v1beta1" || m.Resource != "daemonsets" {
|
||||
if m, err := latest.GroupOrDie("extensions").RESTMapper.RESTMapping("DaemonSet", ""); err != nil || m.GroupVersionKind.GroupVersion() != expectedGroupVersion || m.Resource != "daemonsets" {
|
||||
t.Errorf("unexpected version mapping: %#v %v", m, err)
|
||||
}
|
||||
|
||||
for _, groupVersion := range latest.GroupOrDie("extensions").GroupVersions {
|
||||
mapping, err := latest.GroupOrDie("extensions").RESTMapper.RESTMapping("HorizontalPodAutoscaler", groupVersion)
|
||||
for _, groupVersionString := range latest.GroupOrDie("extensions").GroupVersions {
|
||||
gv, err := unversioned.ParseGroupVersion(groupVersionString)
|
||||
|
||||
mapping, err := latest.GroupOrDie("extensions").RESTMapper.RESTMapping("HorizontalPodAutoscaler", gv.String())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
@ -92,11 +96,11 @@ func TestRESTMapper(t *testing.T) {
|
|||
if mapping.Resource != "horizontalpodautoscalers" {
|
||||
t.Errorf("incorrect resource name: %#v", mapping)
|
||||
}
|
||||
if mapping.APIVersion != groupVersion {
|
||||
if mapping.GroupVersionKind.GroupVersion() != gv {
|
||||
t.Errorf("incorrect groupVersion: %v", mapping)
|
||||
}
|
||||
|
||||
interfaces, _ := latest.GroupOrDie("extensions").InterfacesFor(groupVersion)
|
||||
interfaces, _ := latest.GroupOrDie("extensions").InterfacesFor(gv.String())
|
||||
if mapping.Codec != interfaces.Codec {
|
||||
t.Errorf("unexpected codec: %#v, expected: %#v", mapping, interfaces)
|
||||
}
|
||||
|
|
|
@ -59,19 +59,16 @@ func convert(obj runtime.Object) (runtime.Object, error) {
|
|||
// This creates fake API versions, similar to api/latest.go.
|
||||
var testAPIGroup = "test.group"
|
||||
var testGroupVersion = unversioned.GroupVersion{Group: testAPIGroup, Version: "version"}
|
||||
var testVersion = testGroupVersion.String()
|
||||
var newGroupVersion = unversioned.GroupVersion{Group: testAPIGroup, Version: "version2"}
|
||||
var newVersion = newGroupVersion.String()
|
||||
var prefix = "apis"
|
||||
|
||||
var grouplessGroupVersion = unversioned.GroupVersion{Group: "", Version: "v1"}
|
||||
var grouplessVersion = grouplessGroupVersion.String()
|
||||
var grouplessPrefix = "api"
|
||||
var grouplessCodec = runtime.CodecFor(api.Scheme, grouplessVersion)
|
||||
var grouplessCodec = runtime.CodecFor(api.Scheme, grouplessGroupVersion.String())
|
||||
|
||||
var versions = []string{grouplessVersion, testVersion, newVersion}
|
||||
var codec = runtime.CodecFor(api.Scheme, testVersion)
|
||||
var newCodec = runtime.CodecFor(api.Scheme, newVersion)
|
||||
var groupVersions = []unversioned.GroupVersion{grouplessGroupVersion, testGroupVersion, newGroupVersion}
|
||||
var codec = runtime.CodecFor(api.Scheme, testGroupVersion.String())
|
||||
var newCodec = runtime.CodecFor(api.Scheme, newGroupVersion.String())
|
||||
|
||||
var accessor = meta.NewAccessor()
|
||||
var versioner runtime.ResourceVersioner = accessor
|
||||
|
@ -81,32 +78,37 @@ var admissionControl admission.Interface
|
|||
var requestContextMapper api.RequestContextMapper
|
||||
|
||||
func interfacesFor(version string) (*meta.VersionInterfaces, error) {
|
||||
switch version {
|
||||
case testVersion:
|
||||
gv, err := unversioned.ParseGroupVersion(version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch gv {
|
||||
case testGroupVersion:
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: codec,
|
||||
ObjectConvertor: api.Scheme,
|
||||
MetadataAccessor: accessor,
|
||||
}, nil
|
||||
case newVersion:
|
||||
case newGroupVersion:
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: newCodec,
|
||||
ObjectConvertor: api.Scheme,
|
||||
MetadataAccessor: accessor,
|
||||
}, nil
|
||||
case grouplessVersion:
|
||||
case grouplessGroupVersion:
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: grouplessCodec,
|
||||
ObjectConvertor: api.Scheme,
|
||||
MetadataAccessor: accessor,
|
||||
}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported storage version: %s (valid: %s)", version, strings.Join(versions, ", "))
|
||||
return nil, fmt.Errorf("unsupported storage version: %s (valid: %v)", version, groupVersions)
|
||||
}
|
||||
}
|
||||
|
||||
func newMapper() *meta.DefaultRESTMapper {
|
||||
return meta.NewDefaultRESTMapper("testgroup", versions, interfacesFor)
|
||||
gvStrings := []string{testGroupVersion.String(), newGroupVersion.String()}
|
||||
return meta.NewDefaultRESTMapper(testAPIGroup, gvStrings, interfacesFor)
|
||||
}
|
||||
|
||||
func addGrouplessTypes() {
|
||||
|
@ -120,9 +122,9 @@ func addGrouplessTypes() {
|
|||
TimeoutSeconds *int64 `json:"timeoutSeconds,omitempty"`
|
||||
}
|
||||
api.Scheme.AddKnownTypes(
|
||||
grouplessVersion, &apiservertesting.Simple{}, &apiservertesting.SimpleList{}, &unversioned.Status{},
|
||||
grouplessGroupVersion.String(), &apiservertesting.Simple{}, &apiservertesting.SimpleList{}, &unversioned.Status{},
|
||||
&ListOptions{}, &api.DeleteOptions{}, &apiservertesting.SimpleGetOptions{}, &apiservertesting.SimpleRoot{})
|
||||
api.Scheme.AddKnownTypes(grouplessVersion, &api.Pod{})
|
||||
api.Scheme.AddKnownTypes(grouplessGroupVersion.String(), &api.Pod{})
|
||||
}
|
||||
|
||||
func addTestTypes() {
|
||||
|
@ -136,9 +138,9 @@ func addTestTypes() {
|
|||
TimeoutSeconds *int64 `json:"timeoutSeconds,omitempty"`
|
||||
}
|
||||
api.Scheme.AddKnownTypes(
|
||||
testVersion, &apiservertesting.Simple{}, &apiservertesting.SimpleList{}, &unversioned.Status{},
|
||||
testGroupVersion.String(), &apiservertesting.Simple{}, &apiservertesting.SimpleList{}, &unversioned.Status{},
|
||||
&ListOptions{}, &api.DeleteOptions{}, &apiservertesting.SimpleGetOptions{}, &apiservertesting.SimpleRoot{})
|
||||
api.Scheme.AddKnownTypes(testVersion, &api.Pod{})
|
||||
api.Scheme.AddKnownTypes(testGroupVersion.String(), &api.Pod{})
|
||||
}
|
||||
|
||||
func addNewTestTypes() {
|
||||
|
@ -152,7 +154,7 @@ func addNewTestTypes() {
|
|||
TimeoutSeconds *int64 `json:"timeoutSeconds,omitempty"`
|
||||
}
|
||||
api.Scheme.AddKnownTypes(
|
||||
newVersion, &apiservertesting.Simple{}, &apiservertesting.SimpleList{}, &unversioned.Status{},
|
||||
newGroupVersion.String(), &apiservertesting.Simple{}, &apiservertesting.SimpleList{}, &unversioned.Status{},
|
||||
&ListOptions{}, &api.DeleteOptions{}, &apiservertesting.SimpleGetOptions{}, &apiservertesting.SimpleRoot{})
|
||||
}
|
||||
|
||||
|
@ -172,13 +174,13 @@ func init() {
|
|||
|
||||
// enumerate all supported versions, get the kinds, and register with
|
||||
// the mapper how to address our resources
|
||||
for _, version := range versions {
|
||||
for kind := range api.Scheme.KnownTypes(version) {
|
||||
for _, gv := range groupVersions {
|
||||
for kind := range api.Scheme.KnownTypes(gv.String()) {
|
||||
root := bool(kind == "SimpleRoot")
|
||||
if root {
|
||||
nsMapper.Add(meta.RESTScopeRoot, kind, version, false)
|
||||
nsMapper.Add(meta.RESTScopeRoot, kind, gv.String(), false)
|
||||
} else {
|
||||
nsMapper.Add(meta.RESTScopeNamespace, kind, version, false)
|
||||
nsMapper.Add(meta.RESTScopeNamespace, kind, gv.String(), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,17 +190,17 @@ func init() {
|
|||
admissionControl = admit.NewAlwaysAdmit()
|
||||
requestContextMapper = api.NewRequestContextMapper()
|
||||
|
||||
api.Scheme.AddFieldLabelConversionFunc(grouplessVersion, "Simple",
|
||||
api.Scheme.AddFieldLabelConversionFunc(grouplessGroupVersion.String(), "Simple",
|
||||
func(label, value string) (string, string, error) {
|
||||
return label, value, nil
|
||||
},
|
||||
)
|
||||
api.Scheme.AddFieldLabelConversionFunc(testVersion, "Simple",
|
||||
api.Scheme.AddFieldLabelConversionFunc(testGroupVersion.String(), "Simple",
|
||||
func(label, value string) (string, string, error) {
|
||||
return label, value, nil
|
||||
},
|
||||
)
|
||||
api.Scheme.AddFieldLabelConversionFunc(newVersion, "Simple",
|
||||
api.Scheme.AddFieldLabelConversionFunc(newGroupVersion.String(), "Simple",
|
||||
func(label, value string) (string, string, error) {
|
||||
return label, value, nil
|
||||
},
|
||||
|
@ -653,31 +655,31 @@ func TestNotFound(t *testing.T) {
|
|||
}
|
||||
cases := map[string]T{
|
||||
// Positive checks to make sure everything is wired correctly
|
||||
"groupless GET root": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/simpleroots", http.StatusOK},
|
||||
"groupless GET namespaced": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/ns/simples", http.StatusOK},
|
||||
"groupless GET root": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simpleroots", http.StatusOK},
|
||||
"groupless GET namespaced": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/ns/simples", http.StatusOK},
|
||||
|
||||
"groupless GET long prefix": {"GET", "/" + grouplessPrefix + "/", http.StatusNotFound},
|
||||
|
||||
"groupless root PATCH method": {"PATCH", "/" + grouplessPrefix + "/" + grouplessVersion + "/simpleroots", http.StatusMethodNotAllowed},
|
||||
"groupless root GET missing storage": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/blah", http.StatusNotFound},
|
||||
"groupless root GET with extra segment": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/simpleroots/bar/baz", http.StatusNotFound},
|
||||
"groupless root DELETE without extra segment": {"DELETE", "/" + grouplessPrefix + "/" + grouplessVersion + "/simpleroots", http.StatusMethodNotAllowed},
|
||||
"groupless root DELETE with extra segment": {"DELETE", "/" + grouplessPrefix + "/" + grouplessVersion + "/simpleroots/bar/baz", http.StatusNotFound},
|
||||
"groupless root PUT without extra segment": {"PUT", "/" + grouplessPrefix + "/" + grouplessVersion + "/simpleroots", http.StatusMethodNotAllowed},
|
||||
"groupless root PUT with extra segment": {"PUT", "/" + grouplessPrefix + "/" + grouplessVersion + "/simpleroots/bar/baz", http.StatusNotFound},
|
||||
"groupless root watch missing storage": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/watch/", http.StatusNotFound},
|
||||
"groupless root PATCH method": {"PATCH", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simpleroots", http.StatusMethodNotAllowed},
|
||||
"groupless root GET missing storage": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/blah", http.StatusNotFound},
|
||||
"groupless root GET with extra segment": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simpleroots/bar/baz", http.StatusNotFound},
|
||||
"groupless root DELETE without extra segment": {"DELETE", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simpleroots", http.StatusMethodNotAllowed},
|
||||
"groupless root DELETE with extra segment": {"DELETE", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simpleroots/bar/baz", http.StatusNotFound},
|
||||
"groupless root PUT without extra segment": {"PUT", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simpleroots", http.StatusMethodNotAllowed},
|
||||
"groupless root PUT with extra segment": {"PUT", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simpleroots/bar/baz", http.StatusNotFound},
|
||||
"groupless root watch missing storage": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/watch/", http.StatusNotFound},
|
||||
|
||||
"groupless namespaced PATCH method": {"PATCH", "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/ns/simples", http.StatusMethodNotAllowed},
|
||||
"groupless namespaced PATCH method": {"PATCH", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/ns/simples", http.StatusMethodNotAllowed},
|
||||
"groupless namespaced GET long prefix": {"GET", "/" + grouplessPrefix + "/", http.StatusNotFound},
|
||||
"groupless namespaced GET missing storage": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/blah", http.StatusNotFound},
|
||||
"groupless namespaced GET with extra segment": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/ns/simples/bar/baz", http.StatusNotFound},
|
||||
"groupless namespaced POST with extra segment": {"POST", "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/ns/simples/bar", http.StatusMethodNotAllowed},
|
||||
"groupless namespaced DELETE without extra segment": {"DELETE", "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/ns/simples", http.StatusMethodNotAllowed},
|
||||
"groupless namespaced DELETE with extra segment": {"DELETE", "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/ns/simples/bar/baz", http.StatusNotFound},
|
||||
"groupless namespaced PUT without extra segment": {"PUT", "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/ns/simples", http.StatusMethodNotAllowed},
|
||||
"groupless namespaced PUT with extra segment": {"PUT", "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/ns/simples/bar/baz", http.StatusNotFound},
|
||||
"groupless namespaced watch missing storage": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/watch/", http.StatusNotFound},
|
||||
"groupless namespaced watch with bad method": {"POST", "/" + grouplessPrefix + "/" + grouplessVersion + "/watch/namespaces/ns/simples/bar", http.StatusMethodNotAllowed},
|
||||
"groupless namespaced GET missing storage": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/blah", http.StatusNotFound},
|
||||
"groupless namespaced GET with extra segment": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/ns/simples/bar/baz", http.StatusNotFound},
|
||||
"groupless namespaced POST with extra segment": {"POST", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/ns/simples/bar", http.StatusMethodNotAllowed},
|
||||
"groupless namespaced DELETE without extra segment": {"DELETE", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/ns/simples", http.StatusMethodNotAllowed},
|
||||
"groupless namespaced DELETE with extra segment": {"DELETE", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/ns/simples/bar/baz", http.StatusNotFound},
|
||||
"groupless namespaced PUT without extra segment": {"PUT", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/ns/simples", http.StatusMethodNotAllowed},
|
||||
"groupless namespaced PUT with extra segment": {"PUT", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/ns/simples/bar/baz", http.StatusNotFound},
|
||||
"groupless namespaced watch missing storage": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/watch/", http.StatusNotFound},
|
||||
"groupless namespaced watch with bad method": {"POST", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/watch/namespaces/ns/simples/bar", http.StatusMethodNotAllowed},
|
||||
|
||||
// Positive checks to make sure everything is wired correctly
|
||||
"GET root": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simpleroots", http.StatusOK},
|
||||
|
@ -753,15 +755,15 @@ func TestUnimplementedRESTStorage(t *testing.T) {
|
|||
ErrCode int
|
||||
}
|
||||
cases := map[string]T{
|
||||
"groupless GET object": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/foo/bar", http.StatusNotFound},
|
||||
"groupless GET list": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/foo", http.StatusNotFound},
|
||||
"groupless POST list": {"POST", "/" + grouplessPrefix + "/" + grouplessVersion + "/foo", http.StatusNotFound},
|
||||
"groupless PUT object": {"PUT", "/" + grouplessPrefix + "/" + grouplessVersion + "/foo/bar", http.StatusNotFound},
|
||||
"groupless DELETE object": {"DELETE", "/" + grouplessPrefix + "/" + grouplessVersion + "/foo/bar", http.StatusNotFound},
|
||||
"groupless watch list": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/watch/foo", http.StatusNotFound},
|
||||
"groupless watch object": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/watch/foo/bar", http.StatusNotFound},
|
||||
"groupless proxy object": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/proxy/foo/bar", http.StatusNotFound},
|
||||
"groupless redirect object": {"GET", "/" + grouplessPrefix + "/" + grouplessVersion + "/redirect/foo/bar", http.StatusNotFound},
|
||||
"groupless GET object": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/foo/bar", http.StatusNotFound},
|
||||
"groupless GET list": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/foo", http.StatusNotFound},
|
||||
"groupless POST list": {"POST", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/foo", http.StatusNotFound},
|
||||
"groupless PUT object": {"PUT", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/foo/bar", http.StatusNotFound},
|
||||
"groupless DELETE object": {"DELETE", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/foo/bar", http.StatusNotFound},
|
||||
"groupless watch list": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/watch/foo", http.StatusNotFound},
|
||||
"groupless watch object": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/watch/foo/bar", http.StatusNotFound},
|
||||
"groupless proxy object": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/proxy/foo/bar", http.StatusNotFound},
|
||||
"groupless redirect object": {"GET", "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/redirect/foo/bar", http.StatusNotFound},
|
||||
|
||||
"GET object": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/foo/bar", http.StatusNotFound},
|
||||
"GET list": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/foo", http.StatusNotFound},
|
||||
|
@ -841,76 +843,76 @@ func TestList(t *testing.T) {
|
|||
|
||||
// legacy namespace param is ignored
|
||||
{
|
||||
url: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple?namespace=",
|
||||
url: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple?namespace=",
|
||||
namespace: "",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple",
|
||||
legacy: true,
|
||||
},
|
||||
{
|
||||
url: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple?namespace=other",
|
||||
url: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple?namespace=other",
|
||||
namespace: "",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple",
|
||||
legacy: true,
|
||||
},
|
||||
{
|
||||
url: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple?namespace=other&labelSelector=a%3Db&fieldSelector=c%3Dd",
|
||||
url: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple?namespace=other&labelSelector=a%3Db&fieldSelector=c%3Dd",
|
||||
namespace: "",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple",
|
||||
legacy: true,
|
||||
label: "a=b",
|
||||
field: "c=d",
|
||||
},
|
||||
// legacy api version is honored
|
||||
{
|
||||
url: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple",
|
||||
url: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple",
|
||||
namespace: "",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple",
|
||||
legacy: true,
|
||||
},
|
||||
{
|
||||
url: "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/other/simple",
|
||||
url: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/other/simple",
|
||||
namespace: "other",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/other/simple",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/other/simple",
|
||||
legacy: true,
|
||||
},
|
||||
{
|
||||
url: "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/other/simple?labelSelector=a%3Db&fieldSelector=c%3Dd",
|
||||
url: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/other/simple?labelSelector=a%3Db&fieldSelector=c%3Dd",
|
||||
namespace: "other",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/other/simple",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/other/simple",
|
||||
legacy: true,
|
||||
label: "a=b",
|
||||
field: "c=d",
|
||||
},
|
||||
// list items across all namespaces
|
||||
{
|
||||
url: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple",
|
||||
url: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple",
|
||||
namespace: "",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple",
|
||||
legacy: true,
|
||||
},
|
||||
// list items in a namespace in the path
|
||||
{
|
||||
url: "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/default/simple",
|
||||
url: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/default/simple",
|
||||
namespace: "default",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/default/simple",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/default/simple",
|
||||
},
|
||||
{
|
||||
url: "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/other/simple",
|
||||
url: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/other/simple",
|
||||
namespace: "other",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/other/simple",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/other/simple",
|
||||
},
|
||||
{
|
||||
url: "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/other/simple?labelSelector=a%3Db&fieldSelector=c%3Dd",
|
||||
url: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/other/simple?labelSelector=a%3Db&fieldSelector=c%3Dd",
|
||||
namespace: "other",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessVersion + "/namespaces/other/simple",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/other/simple",
|
||||
label: "a=b",
|
||||
field: "c=d",
|
||||
},
|
||||
// list items across all namespaces
|
||||
{
|
||||
url: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple",
|
||||
url: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple",
|
||||
namespace: "",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessVersion + "/simple",
|
||||
selfLink: "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/simple",
|
||||
},
|
||||
|
||||
// Group API
|
||||
|
@ -2862,7 +2864,7 @@ func TestCreateChecksAPIVersion(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testVersion+"/namespaces/default/simple", bytes.NewBuffer(data))
|
||||
request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple", bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
@ -2903,7 +2905,7 @@ func TestCreateDefaultsAPIVersion(t *testing.T) {
|
|||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testVersion+"/namespaces/default/simple", bytes.NewBuffer(data))
|
||||
request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple", bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
@ -2927,7 +2929,7 @@ func TestUpdateChecksAPIVersion(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testVersion+"/namespaces/default/simple/bar", bytes.NewBuffer(data))
|
||||
request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/bar", bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
|
@ -178,8 +178,8 @@ func TestWatchParamParsing(t *testing.T) {
|
|||
|
||||
dest, _ := url.Parse(server.URL)
|
||||
|
||||
rootPath := "/" + prefix + "/" + testVersion + "/watch/simples"
|
||||
namespacedPath := "/" + prefix + "/" + testVersion + "/watch/namespaces/other/simpleroots"
|
||||
rootPath := "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/simples"
|
||||
namespacedPath := "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/namespaces/other/simpleroots"
|
||||
|
||||
table := []struct {
|
||||
path string
|
||||
|
@ -358,13 +358,13 @@ func TestWatchHTTPTimeout(t *testing.T) {
|
|||
|
||||
// Setup a client
|
||||
dest, _ := url.Parse(s.URL)
|
||||
dest.Path = "/" + prefix + "/" + newVersion + "/simple"
|
||||
dest.Path = "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/simple"
|
||||
dest.RawQuery = "watch=true"
|
||||
|
||||
req, _ := http.NewRequest("GET", dest.String(), nil)
|
||||
client := http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
watcher.Add(&apiservertesting.Simple{TypeMeta: unversioned.TypeMeta{APIVersion: newVersion}})
|
||||
watcher.Add(&apiservertesting.Simple{TypeMeta: unversioned.TypeMeta{APIVersion: newGroupVersion.String()}})
|
||||
|
||||
// Make sure we can actually watch an endpoint
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
|
|
|
@ -96,7 +96,7 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
|
|||
}
|
||||
info := infos[0]
|
||||
mapping := info.ResourceMapping()
|
||||
if err := f.CanBeAutoscaled(mapping.Kind); err != nil {
|
||||
if err := f.CanBeAutoscaled(mapping.GroupVersionKind.Kind); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -111,9 +111,9 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
|
|||
name := info.Name
|
||||
params["default-name"] = name
|
||||
|
||||
params["scaleRef-kind"] = mapping.Kind
|
||||
params["scaleRef-kind"] = mapping.GroupVersionKind.Kind
|
||||
params["scaleRef-name"] = name
|
||||
params["scaleRef-apiVersion"] = mapping.APIVersion
|
||||
params["scaleRef-apiVersion"] = mapping.GroupVersionKind.GroupVersion().String()
|
||||
|
||||
if err = kubectl.ValidateParams(names, params); err != nil {
|
||||
return err
|
||||
|
|
|
@ -76,23 +76,27 @@ func versionErrIfFalse(b bool) error {
|
|||
return versionErr
|
||||
}
|
||||
|
||||
var validVersion = testapi.Default.Version()
|
||||
var internalGV = unversioned.GroupVersion{Group: "apitest", Version: ""}
|
||||
var unlikelyGV = unversioned.GroupVersion{Group: "apitest", Version: "unlikelyversion"}
|
||||
var validVersionGV = unversioned.GroupVersion{Group: "apitest", Version: validVersion}
|
||||
|
||||
func newExternalScheme() (*runtime.Scheme, meta.RESTMapper, runtime.Codec) {
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypeWithName("", "Type", &internalType{})
|
||||
scheme.AddKnownTypeWithName("unlikelyversion", "Type", &externalType{})
|
||||
scheme.AddKnownTypeWithName(internalGV.Version, "Type", &internalType{})
|
||||
scheme.AddKnownTypeWithName(unlikelyGV.String(), "Type", &externalType{})
|
||||
//This tests that kubectl will not confuse the external scheme with the internal scheme, even when they accidentally have versions of the same name.
|
||||
scheme.AddKnownTypeWithName(testapi.Default.Version(), "Type", &ExternalType2{})
|
||||
scheme.AddKnownTypeWithName(validVersionGV.String(), "Type", &ExternalType2{})
|
||||
|
||||
codec := runtime.CodecFor(scheme, "unlikelyversion")
|
||||
validVersion := testapi.Default.Version()
|
||||
mapper := meta.NewDefaultRESTMapper("apitest", []string{"unlikelyversion", validVersion}, func(version string) (*meta.VersionInterfaces, error) {
|
||||
codec := runtime.CodecFor(scheme, unlikelyGV.String())
|
||||
mapper := meta.NewDefaultRESTMapper("apitest", []string{unlikelyGV.String(), validVersionGV.String()}, func(version string) (*meta.VersionInterfaces, error) {
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: runtime.CodecFor(scheme, version),
|
||||
ObjectConvertor: scheme,
|
||||
MetadataAccessor: meta.NewAccessor(),
|
||||
}, versionErrIfFalse(version == validVersion || version == "unlikelyversion")
|
||||
}, versionErrIfFalse(version == validVersionGV.String() || version == unlikelyGV.String())
|
||||
})
|
||||
for _, version := range []string{"unlikelyversion", validVersion} {
|
||||
for _, version := range []string{unlikelyGV.String(), validVersionGV.String()} {
|
||||
for kind := range scheme.KnownTypes(version) {
|
||||
mixedCase := false
|
||||
scope := meta.RESTScopeNamespace
|
||||
|
|
|
@ -120,7 +120,7 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
|
|||
}
|
||||
info := infos[0]
|
||||
mapping := info.ResourceMapping()
|
||||
if err := f.CanBeExposed(mapping.Kind); err != nil {
|
||||
if err := f.CanBeExposed(mapping.GroupVersionKind.Kind); err != nil {
|
||||
return err
|
||||
}
|
||||
// Get the input object
|
||||
|
@ -187,7 +187,7 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
|
|||
}
|
||||
|
||||
if inline := cmdutil.GetFlagString(cmd, "overrides"); len(inline) > 0 {
|
||||
object, err = cmdutil.Merge(object, inline, mapping.Kind)
|
||||
object, err = cmdutil.Merge(object, inline, mapping.GroupVersionKind.Kind)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -159,19 +159,19 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
|
|||
"handles specific version": {
|
||||
outputVersion: testapi.Default.Version(),
|
||||
listVersion: testapi.Default.Version(),
|
||||
testtypeVersion: "unlikelyversion",
|
||||
testtypeVersion: unlikelyGV.String(),
|
||||
rcVersion: testapi.Default.Version(),
|
||||
},
|
||||
"handles second specific version": {
|
||||
outputVersion: "unlikelyversion",
|
||||
listVersion: testapi.Default.Version(),
|
||||
testtypeVersion: "unlikelyversion",
|
||||
testtypeVersion: unlikelyGV.String(),
|
||||
rcVersion: testapi.Default.Version(), // see expected behavior 3b
|
||||
},
|
||||
"handles common version": {
|
||||
outputVersion: testapi.Default.Version(),
|
||||
listVersion: testapi.Default.Version(),
|
||||
testtypeVersion: "unlikelyversion",
|
||||
testtypeVersion: unlikelyGV.String(),
|
||||
rcVersion: testapi.Default.Version(),
|
||||
},
|
||||
}
|
||||
|
@ -198,6 +198,7 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
|
|||
cmd := NewCmdGet(f, buf)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Set("output", "json")
|
||||
|
||||
cmd.Flags().Set("output-version", test.outputVersion)
|
||||
err := RunGet(f, buf, cmd, []string{"type/foo", "replicationcontrollers/foo"}, &GetOptions{})
|
||||
if err != nil {
|
||||
|
|
|
@ -29,6 +29,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
|
@ -382,8 +383,9 @@ func isReplicasDefaulted(info *resource.Info) bool {
|
|||
// was unable to recover versioned info
|
||||
return false
|
||||
}
|
||||
switch info.Mapping.APIVersion {
|
||||
case "v1":
|
||||
|
||||
switch info.Mapping.GroupVersionKind.GroupVersion() {
|
||||
case unversioned.GroupVersion{Version: "v1"}:
|
||||
if rc, ok := info.VersionedObject.(*v1.ReplicationController); ok {
|
||||
return rc.Spec.Replicas == nil
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := clients.ClientForVersion(mapping.APIVersion)
|
||||
client, err := clients.ClientForVersion(mapping.GroupVersionKind.GroupVersion().String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -165,11 +165,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := clients.ClientForVersion(mapping.APIVersion)
|
||||
client, err := clients.ClientForVersion(mapping.GroupVersionKind.GroupVersion().String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if describer, ok := kubectl.DescriberFor(group, mapping.Kind, client); ok {
|
||||
if describer, ok := kubectl.DescriberFor(group, mapping.GroupVersionKind.Kind, client); ok {
|
||||
return describer, nil
|
||||
}
|
||||
return nil, fmt.Errorf("no description has been implemented for %q", mapping.Kind)
|
||||
|
@ -242,18 +242,18 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||
}
|
||||
},
|
||||
Scaler: func(mapping *meta.RESTMapping) (kubectl.Scaler, error) {
|
||||
client, err := clients.ClientForVersion(mapping.APIVersion)
|
||||
client, err := clients.ClientForVersion(mapping.GroupVersionKind.GroupVersion().String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kubectl.ScalerFor(mapping.Kind, client)
|
||||
return kubectl.ScalerFor(mapping.GroupVersionKind.Kind, client)
|
||||
},
|
||||
Reaper: func(mapping *meta.RESTMapping) (kubectl.Reaper, error) {
|
||||
client, err := clients.ClientForVersion(mapping.APIVersion)
|
||||
client, err := clients.ClientForVersion(mapping.GroupVersionKind.GroupVersion().String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kubectl.ReaperFor(mapping.Kind, client)
|
||||
return kubectl.ReaperFor(mapping.GroupVersionKind.Kind, client)
|
||||
},
|
||||
Validator: func(validate bool, cacheDir string) (validation.Schema, error) {
|
||||
if validate {
|
||||
|
@ -581,12 +581,12 @@ func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMappin
|
|||
|
||||
version := OutputVersion(cmd, defaultVersion)
|
||||
if len(version) == 0 {
|
||||
version = mapping.APIVersion
|
||||
version = mapping.GroupVersionKind.GroupVersion().String()
|
||||
}
|
||||
if len(version) == 0 {
|
||||
return nil, fmt.Errorf("you must specify an output-version when using this output format")
|
||||
}
|
||||
printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.APIVersion)
|
||||
printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion().String())
|
||||
} else {
|
||||
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
|
||||
columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
|
||||
|
|
|
@ -470,7 +470,7 @@ func TestResourceByNameWithoutRequireObject(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if mapping.Kind != "Pod" || mapping.Resource != "pods" {
|
||||
if mapping.GroupVersionKind.Kind != "Pod" || mapping.Resource != "pods" {
|
||||
t.Errorf("unexpected resource mapping: %#v", mapping)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -254,7 +254,7 @@ func AsVersionedObjects(infos []*Info, version string) ([]runtime.Object, error)
|
|||
}
|
||||
}
|
||||
|
||||
converted, err := tryConvert(info.Mapping.ObjectConvertor, info.Object, version, info.Mapping.APIVersion)
|
||||
converted, err := tryConvert(info.Mapping.ObjectConvertor, info.Object, version, info.Mapping.GroupVersionKind.GroupVersion().String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ func NewSelector(client RESTClient, mapping *meta.RESTMapping, namespace string,
|
|||
|
||||
// Visit implements Visitor
|
||||
func (r *Selector) Visit(fn VisitorFunc) error {
|
||||
list, err := NewHelper(r.Client, r.Mapping).List(r.Namespace, r.ResourceMapping().APIVersion, r.Selector)
|
||||
list, err := NewHelper(r.Client, r.Mapping).List(r.Namespace, r.ResourceMapping().GroupVersionKind.GroupVersion().String(), r.Selector)
|
||||
if err != nil {
|
||||
if errors.IsBadRequest(err) || errors.IsNotFound(err) {
|
||||
if r.Selector.Empty() {
|
||||
|
@ -70,7 +70,7 @@ func (r *Selector) Visit(fn VisitorFunc) error {
|
|||
}
|
||||
|
||||
func (r *Selector) Watch(resourceVersion string) (watch.Interface, error) {
|
||||
return NewHelper(r.Client, r.Mapping).Watch(r.Namespace, resourceVersion, r.ResourceMapping().APIVersion, r.Selector)
|
||||
return NewHelper(r.Client, r.Mapping).Watch(r.Namespace, resourceVersion, r.ResourceMapping().GroupVersionKind.GroupVersion().String(), r.Selector)
|
||||
}
|
||||
|
||||
// ResourceMapping returns the mapping for this resource and implements ResourceMapping
|
||||
|
|
Loading…
Reference in New Issue