Merge pull request #12405 from uluyol/kubectlexp

Add experimental api support to kubectl
This commit is contained in:
CJ Cullen
2015-08-12 14:24:56 -07:00
17 changed files with 210 additions and 70 deletions

View File

@@ -97,7 +97,7 @@ func init() {
"PodProxyOptions",
"Daemon")
mapper := api.NewDefaultRESTMapper(versions, InterfacesFor, importPrefix, ignoredKinds, rootScoped)
mapper := api.NewDefaultRESTMapper("api", versions, InterfacesFor, importPrefix, ignoredKinds, rootScoped)
// setup aliases for groups of resources
mapper.AddResourceAlias("all", userResources...)
RESTMapper = mapper

View File

@@ -33,11 +33,12 @@ func RegisterRESTMapper(m meta.RESTMapper) {
RESTMapper = append(RESTMapper.(meta.MultiRESTMapper), m)
}
func NewDefaultRESTMapper(versions []string, interfacesFunc meta.VersionInterfacesFunc, importPathPrefix string,
ignoredKinds, rootScoped util.StringSet) *meta.DefaultRESTMapper {
func NewDefaultRESTMapper(group string, versions []string, interfacesFunc meta.VersionInterfacesFunc,
importPathPrefix string, ignoredKinds, rootScoped util.StringSet) *meta.DefaultRESTMapper {
mapper := meta.NewDefaultRESTMapper(versions, interfacesFunc)
// enumerate all supported versions, get the kinds, and register with the mapper how to address our resources.
mapper := meta.NewDefaultRESTMapper(group, versions, 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) {
// TODO: Remove import path prefix check.

View File

@@ -142,8 +142,18 @@ type RESTMapping struct {
// RESTMapper allows clients to map resources to kind, and map kind and version
// to interfaces for manipulating those objects. It is primarily intended for
// consumers of Kubernetes compatible REST APIs as defined in docs/api-conventions.md.
//
// The Kubernetes API provides versioned resources and object kinds which are scoped
// to API groups. In other words, kinds and resources should not be assumed to be
// unique across groups.
//
// 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 {
VersionAndKindForResource(resource string) (defaultVersion, kind string, err error)
// TODO(caesarxuchao): Remove GroupForResource when multi-group support is in (since
// group will be part of the version).
GroupForResource(resource string) (string, error)
RESTMapping(kind string, versions ...string) (*RESTMapping, error)
AliasesForResource(resource string) ([]string, bool)
ResourceSingularizer(resource string) (singular string, err error)

View File

@@ -76,6 +76,7 @@ type DefaultRESTMapper struct {
mapping map[string]typeMeta
reverse map[typeMeta]string
scopes map[typeMeta]RESTScope
group string
versions []string
plurals map[string]string
singulars map[string]string
@@ -88,10 +89,10 @@ type VersionInterfacesFunc func(apiVersion string) (*VersionInterfaces, error)
// NewDefaultRESTMapper initializes a mapping between Kind and APIVersion
// to a resource name and back based on the objects in a runtime.Scheme
// and the Kubernetes API conventions. Takes a priority list of the versions to
// search when an object has no default version (set empty to return an 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(versions []string, f VersionInterfacesFunc) *DefaultRESTMapper {
func NewDefaultRESTMapper(group string, versions []string, f VersionInterfacesFunc) *DefaultRESTMapper {
mapping := make(map[string]typeMeta)
reverse := make(map[typeMeta]string)
scopes := make(map[typeMeta]RESTScope)
@@ -103,6 +104,7 @@ func NewDefaultRESTMapper(versions []string, f VersionInterfacesFunc) *DefaultRE
mapping: mapping,
reverse: reverse,
scopes: scopes,
group: group,
versions: versions,
plurals: plurals,
singulars: singulars,
@@ -174,6 +176,13 @@ func (m *DefaultRESTMapper) VersionAndKindForResource(resource string) (defaultV
return meta.APIVersion, meta.Kind, nil
}
func (m *DefaultRESTMapper) GroupForResource(resource string) (string, error) {
if _, ok := m.mapping[strings.ToLower(resource)]; !ok {
return "", fmt.Errorf("no resource %q has been defined", resource)
}
return m.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
@@ -292,6 +301,18 @@ func (m MultiRESTMapper) VersionAndKindForResource(resource string) (defaultVers
return
}
// GroupForResource provides the Group mappings for the REST resources. This
// implementation supports multiple REST schemas and returns the first match.
func (m MultiRESTMapper) GroupForResource(resource string) (group string, err error) {
for _, t := range m {
group, err = t.GroupForResource(resource)
if err == nil {
return
}
}
return
}
// RESTMapping provides the REST mapping for the resource based on the resource
// kind and version. This implementation supports multiple REST schemas and
// return the first match.

View File

@@ -93,7 +93,7 @@ func TestRESTMapperVersionAndKindForResource(t *testing.T) {
{Resource: "internalObjects", MixedCase: true, Kind: "InternalObject", APIVersion: "test"},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]string{"test"}, fakeInterfaces)
mapper := NewDefaultRESTMapper("tgroup", []string{"test"}, fakeInterfaces)
mapper.Add(RESTScopeNamespace, testCase.Kind, testCase.APIVersion, testCase.MixedCase)
v, k, err := mapper.VersionAndKindForResource(testCase.Resource)
hasErr := err != nil
@@ -107,6 +107,33 @@ func TestRESTMapperVersionAndKindForResource(t *testing.T) {
}
}
func TestRESTMapperGroupForResource(t *testing.T) {
testCases := []struct {
Resource string
Kind, APIVersion, Group string
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"},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper(testCase.Group, []string{"test"}, fakeInterfaces)
mapper.Add(RESTScopeNamespace, testCase.Kind, testCase.APIVersion, false)
g, err := mapper.GroupForResource(testCase.Resource)
if testCase.Err {
if err == nil {
t.Errorf("%d: expected error", i)
}
} 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)
}
}
}
func TestKindToResource(t *testing.T) {
testCases := []struct {
Kind string
@@ -159,7 +186,7 @@ func TestRESTMapperResourceSingularizer(t *testing.T) {
{Kind: "lowercases", APIVersion: "test", MixedCase: false, Plural: "lowercases", Singular: "lowercases"},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]string{"test"}, fakeInterfaces)
mapper := NewDefaultRESTMapper("tgroup", []string{"test"}, fakeInterfaces)
// create singular/plural mapping
mapper.Add(RESTScopeNamespace, testCase.Kind, testCase.APIVersion, testCase.MixedCase)
singular, _ := mapper.ResourceSingularizer(testCase.Plural)
@@ -198,7 +225,7 @@ func TestRESTMapperRESTMapping(t *testing.T) {
// TODO: add test for a resource that exists in one version but not another
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper(testCase.DefaultVersions, fakeInterfaces)
mapper := NewDefaultRESTMapper("tgroup", testCase.DefaultVersions, fakeInterfaces)
mapper.Add(RESTScopeNamespace, "InternalObject", "test", testCase.MixedCase)
mapping, err := mapper.RESTMapping(testCase.Kind, testCase.APIVersions...)
hasErr := err != nil
@@ -225,7 +252,7 @@ func TestRESTMapperRESTMapping(t *testing.T) {
}
func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
mapper := NewDefaultRESTMapper([]string{"test1", "test2"}, fakeInterfaces)
mapper := NewDefaultRESTMapper("tgroup", []string{"test1", "test2"}, fakeInterfaces)
mapper.Add(RESTScopeNamespace, "InternalObject", "test1", false)
mapper.Add(RESTScopeNamespace, "OtherObject", "test2", false)
@@ -278,7 +305,7 @@ func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
}
func TestRESTMapperReportsErrorOnBadVersion(t *testing.T) {
mapper := NewDefaultRESTMapper([]string{"test1", "test2"}, unmatchedVersionInterfaces)
mapper := NewDefaultRESTMapper("tgroup", []string{"test1", "test2"}, unmatchedVersionInterfaces)
mapper.Add(RESTScopeNamespace, "InternalObject", "test1", false)
_, err := mapper.RESTMapping("InternalObject", "test1")
if err == nil {