From 4c33e36a885a7062fbe4f5e20cefd51bd7019536 Mon Sep 17 00:00:00 2001 From: derekwaynecarr Date: Thu, 29 Jan 2015 17:46:54 -0500 Subject: [PATCH] Plumb restmapper properly through apiserver and tests --- pkg/api/latest/latest.go | 27 ++----------- pkg/api/meta/interfaces.go | 21 ++++++---- pkg/api/meta/restmapper.go | 42 ++++++++++++++++++++ pkg/api/meta/restmapper_test.go | 22 +++-------- pkg/apiserver/apiserver.go | 39 +++++++++--------- pkg/apiserver/apiserver_test.go | 59 ++++++++++++++++------------ pkg/apiserver/proxy_test.go | 2 +- pkg/apiserver/redirect_test.go | 4 +- pkg/apiserver/watch_test.go | 8 ++-- pkg/kubectl/cmd/cmd_test.go | 8 +++- pkg/kubectl/resource/builder_test.go | 1 + pkg/kubectl/resource/mapper.go | 3 -- pkg/master/master.go | 13 +++--- 13 files changed, 142 insertions(+), 107 deletions(-) diff --git a/pkg/api/latest/latest.go b/pkg/api/latest/latest.go index 24a1600aba8..519c270e340 100644 --- a/pkg/api/latest/latest.go +++ b/pkg/api/latest/latest.go @@ -103,25 +103,6 @@ func init() { return interfaces, true }, ) - // scopes that are used to qualify resources in the API - namespaceAsQueryParam := meta.RESTScope{ - Name: "namespace", - ParamName: "namespace", - ParamPath: false, - ParamDescription: "object name and auth scope, such as for teams and projects", - } - namespaceAsPathParam := meta.RESTScope{ - Name: "namespace", - ParamName: "ns", - ParamPath: true, - ParamDescription: "object name and auth scope, such as for teams and projects", - } - rootScope := meta.RESTScope{ - Name: "root", - ParamName: "", - ParamPath: true, - } - // list of versions we support on the server versions := []string{"v1beta1", "v1beta2", "v1beta3"} @@ -133,9 +114,9 @@ func init() { // backwards compatibility, prior to v1beta3, we identified the namespace as a query parameter versionToNamespaceScope := map[string]meta.RESTScope{ - "v1beta1": namespaceAsQueryParam, - "v1beta2": namespaceAsQueryParam, - "v1beta3": namespaceAsPathParam, + "v1beta1": meta.RESTScopeNamespaceLegacy, + "v1beta2": meta.RESTScopeNamespaceLegacy, + "v1beta3": meta.RESTScopeNamespace, } // the list of kinds that are scoped at the root of the api hierarchy @@ -155,7 +136,7 @@ func init() { scope := versionToNamespaceScope[version] _, found = kindToRootScope[kind] if found { - scope = rootScope + scope = meta.RESTScopeRoot } mapper.Add(scope, kind, version, mixedCase) } diff --git a/pkg/api/meta/interfaces.go b/pkg/api/meta/interfaces.go index b56dcf802a8..2d039cb66f5 100644 --- a/pkg/api/meta/interfaces.go +++ b/pkg/api/meta/interfaces.go @@ -94,19 +94,26 @@ type MetadataAccessor interface { runtime.ResourceVersioner } -// RESTScope contains the information needed to deal with REST Resources that are in a resource hierarchy -type RESTScope struct { - // Name of the scope (e.g. "cluster", "namespace", etc.) - Name string +type RESTScopeName string + +const ( + RESTScopeNameNamespace RESTScopeName = "namespace" + RESTScopeNameRoot RESTScopeName = "root" +) + +// RESTScope contains the information needed to deal with REST resources that are in a resource hierarchy +type RESTScope interface { + // Name of the scope + Name() RESTScopeName // ParamName is the optional name of the parameter that should be inserted in the resource url // If empty, no param will be inserted - ParamName string + ParamName() string // ParamPath is a boolean that controls how the parameter is manifested in resource paths // If true, this parameter is encoded in path (i.e. /{paramName}/{paramValue}) // If false, this parameter is encoded in query (i.e. ?{paramName}={paramValue}) - ParamPath bool + ParamPath() bool // ParamDescription is the optional description to use to document the parameter in api documentation - ParamDescription string + ParamDescription() string } // RESTMapping contains the information needed to deal with objects of a specific diff --git a/pkg/api/meta/restmapper.go b/pkg/api/meta/restmapper.go index e4c751cb168..2790b76139d 100644 --- a/pkg/api/meta/restmapper.go +++ b/pkg/api/meta/restmapper.go @@ -21,6 +21,45 @@ import ( "strings" ) +// Implements RESTScope interface +type restScope struct { + name RESTScopeName + paramName string + paramPath bool + paramDescription string +} + +func (r *restScope) Name() RESTScopeName { + return r.name +} +func (r *restScope) ParamName() string { + return r.paramName +} +func (r *restScope) ParamPath() bool { + return r.paramPath +} +func (r *restScope) ParamDescription() string { + return r.paramDescription +} + +var RESTScopeNamespaceLegacy = &restScope{ + name: RESTScopeNameNamespace, + paramName: "namespace", + paramPath: false, + paramDescription: "object name and auth scope, such as for teams and projects", +} + +var RESTScopeNamespace = &restScope{ + name: RESTScopeNameNamespace, + paramName: "namespace", + paramPath: true, + paramDescription: "object name and auth scope, such as for teams and projects", +} + +var RESTScopeRoot = &restScope{ + name: RESTScopeNameRoot, +} + // typeMeta is used as a key for lookup in the mapping between REST path and // API object. type typeMeta struct { @@ -89,6 +128,9 @@ func (m *DefaultRESTMapper) Add(scope RESTScope, kind string, version string, mi // kindToResource converts Kind to a resource name. func kindToResource(kind string, mixedCase bool) (plural, singular string) { + if len(kind) == 0 { + return + } if mixedCase { // Legacy support for mixed case names singular = strings.ToLower(kind[:1]) + kind[1:] diff --git a/pkg/api/meta/restmapper_test.go b/pkg/api/meta/restmapper_test.go index 62b25111182..d849fdd1535 100644 --- a/pkg/api/meta/restmapper_test.go +++ b/pkg/api/meta/restmapper_test.go @@ -75,10 +75,7 @@ func TestRESTMapperVersionAndKindForResource(t *testing.T) { } for i, testCase := range testCases { mapper := NewDefaultRESTMapper([]string{"test"}, fakeInterfaces) - scheme := runtime.NewScheme() - scheme.AddKnownTypes("test", &InternalObject{}) - mapper.Add(scheme, testCase.MixedCase, "test") - + mapper.Add(RESTScopeNamespace, testCase.Kind, testCase.APIVersion, testCase.MixedCase) v, k, err := mapper.VersionAndKindForResource(testCase.Resource) hasErr := err != nil if hasErr != testCase.Err { @@ -150,10 +147,7 @@ func TestRESTMapperRESTMapping(t *testing.T) { } for i, testCase := range testCases { mapper := NewDefaultRESTMapper(testCase.DefaultVersions, fakeInterfaces) - scheme := runtime.NewScheme() - scheme.AddKnownTypes("test", &InternalObject{}) - mapper.Add(scheme, testCase.MixedCase, "test") - + mapper.Add(RESTScopeNamespace, "InternalObject", "test", testCase.MixedCase) mapping, err := mapper.RESTMapping(testCase.Kind, testCase.APIVersions...) hasErr := err != nil if hasErr != testCase.Err { @@ -180,11 +174,8 @@ func TestRESTMapperRESTMapping(t *testing.T) { func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) { mapper := NewDefaultRESTMapper([]string{"test1", "test2"}, fakeInterfaces) - scheme := runtime.NewScheme() - scheme.AddKnownTypes("test1", &InternalObject{}) - scheme.AddKnownTypeWithName("test2", "OtherObject", &InternalObject{}) - scheme.AddKnownTypeWithName("test3", "OtherObject", &InternalObject{}) - mapper.Add(scheme, false, "test1", "test2") + mapper.Add(RESTScopeNamespace, "InternalObject", "test1", false) + mapper.Add(RESTScopeNamespace, "OtherObject", "test2", false) // pick default matching object kind based on search order mapping, err := mapper.RESTMapping("OtherObject") @@ -236,10 +227,7 @@ func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) { func TestRESTMapperReportsErrorOnBadVersion(t *testing.T) { mapper := NewDefaultRESTMapper([]string{"test1", "test2"}, unmatchedVersionInterfaces) - scheme := runtime.NewScheme() - scheme.AddKnownTypes("test1", &InternalObject{}) - mapper.Add(scheme, false, "test1") - + mapper.Add(RESTScopeNamespace, "InternalObject", "test1", false) _, err := mapper.RESTMapping("InternalObject", "test1") if err == nil { t.Errorf("unexpected non-error") diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 1b15dadfb71..e73e0f13907 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -29,7 +29,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -56,9 +56,9 @@ type defaultAPIServer struct { // as RESTful resources at prefix, serialized by codec, and also includes the support // http resources. // Note: This method is used only in tests. -func Handle(storage map[string]RESTStorage, codec runtime.Codec, root string, version string, selfLinker runtime.SelfLinker, admissionControl admission.Interface) http.Handler { +func Handle(storage map[string]RESTStorage, codec runtime.Codec, root string, version string, selfLinker runtime.SelfLinker, admissionControl admission.Interface, mapper meta.RESTMapper) http.Handler { prefix := root + "/" + version - group := NewAPIGroupVersion(storage, codec, prefix, selfLinker, admissionControl) + group := NewAPIGroupVersion(storage, codec, prefix, selfLinker, admissionControl, mapper) container := restful.NewContainer() mux := container.ServeMux group.InstallREST(container, mux, root, version) @@ -77,6 +77,7 @@ func Handle(storage map[string]RESTStorage, codec runtime.Codec, root string, ve // TODO: consider migrating this to go-restful which is a more full-featured version of the same thing. type APIGroupVersion struct { handler RESTHandler + mapper meta.RESTMapper } // NewAPIGroupVersion returns an object that will serve a set of REST resources and their @@ -84,15 +85,18 @@ type APIGroupVersion struct { // This is a helper method for registering multiple sets of REST handlers under different // prefixes onto a server. // TODO: add multitype codec serialization -func NewAPIGroupVersion(storage map[string]RESTStorage, codec runtime.Codec, canonicalPrefix string, selfLinker runtime.SelfLinker, admissionControl admission.Interface) *APIGroupVersion { - return &APIGroupVersion{RESTHandler{ - storage: storage, - codec: codec, - canonicalPrefix: canonicalPrefix, - selfLinker: selfLinker, - ops: NewOperations(), - admissionControl: admissionControl, - }} +func NewAPIGroupVersion(storage map[string]RESTStorage, codec runtime.Codec, canonicalPrefix string, selfLinker runtime.SelfLinker, admissionControl admission.Interface, mapper meta.RESTMapper) *APIGroupVersion { + return &APIGroupVersion{ + handler: RESTHandler{ + storage: storage, + codec: codec, + canonicalPrefix: canonicalPrefix, + selfLinker: selfLinker, + ops: NewOperations(), + admissionControl: admissionControl, + }, + mapper: mapper, + } } // This magic incantation returns *ptrToObject for an arbitrary pointer @@ -100,7 +104,7 @@ func indirectArbitraryPointer(ptrToObject interface{}) interface{} { return reflect.Indirect(reflect.ValueOf(ptrToObject)).Interface() } -func registerResourceHandlers(ws *restful.WebService, version string, path string, storage RESTStorage, h restful.RouteFunction) error { +func registerResourceHandlers(ws *restful.WebService, version string, path string, storage RESTStorage, h restful.RouteFunction, mapper meta.RESTMapper) error { object := storage.New() _, kind, err := api.Scheme.ObjectVersionAndKind(object) if err != nil { @@ -112,7 +116,6 @@ func registerResourceHandlers(ws *restful.WebService, version string, path strin } versionedObject := indirectArbitraryPointer(versionedPtr) - mapper := latest.RESTMapper mapping, err := mapper.RESTMapping(kind, version) if err != nil { glog.V(1).Infof("OH NOES kind %s version %s err: %v", kind, version, err) @@ -124,9 +127,9 @@ func registerResourceHandlers(ws *restful.WebService, version string, path strin // check if this scope := mapping.Scope var scopeParam *restful.Parameter - if len(scope.ParamName) > 0 && scope.ParamPath { - path = scope.ParamName + "/{" + scope.ParamName + "}/" + path - scopeParam = ws.PathParameter(scope.ParamName, scope.ParamDescription).DataType("string") + if len(scope.ParamName()) > 0 && scope.ParamPath() { + path = scope.ParamName() + "/{" + scope.ParamName() + "}/" + path + scopeParam = ws.PathParameter(scope.ParamName(), scope.ParamDescription()).DataType("string") } glog.V(5).Infof("Installing version=/%s, kind=/%s, path=/%s", version, kind, path) @@ -263,7 +266,7 @@ func (g *APIGroupVersion) InstallREST(container *restful.Container, mux Mux, roo registrationErrors := make([]error, 0) for path, storage := range g.handler.storage { - if err := registerResourceHandlers(ws, version, path, storage, h); err != nil { + if err := registerResourceHandlers(ws, version, path, storage, h, g.mapper); err != nil { registrationErrors = append(registrationErrors, err) } } diff --git a/pkg/apiserver/apiserver_test.go b/pkg/apiserver/apiserver_test.go index 50840d1aba4..d0f1aa673da 100644 --- a/pkg/apiserver/apiserver_test.go +++ b/pkg/apiserver/apiserver_test.go @@ -93,7 +93,15 @@ func init() { return interfaces, true }, ) - defMapper.Add(api.Scheme, true, versions...) + // 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) { + mixedCase := true + scope := meta.RESTScopeNamespaceLegacy + defMapper.Add(scope, kind, version, mixedCase) + } + } + mapper = defMapper admissionControl = admit.NewAlwaysAdmit() } @@ -270,7 +278,7 @@ func TestNotFound(t *testing.T) { } handler := Handle(map[string]RESTStorage{ "foo": &SimpleRESTStorage{}, - }, codec, "/prefix", testVersion, selfLinker, admissionControl) + }, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() client := http.Client{} @@ -287,6 +295,7 @@ func TestNotFound(t *testing.T) { if response.StatusCode != v.Status { t.Errorf("Expected %d for %s (%s), Got %#v", v.Status, v.Method, k, response) + t.Errorf("MAPPER: %v", mapper) } } } @@ -315,7 +324,7 @@ func TestMethodNotAllowed(t *testing.T) { } handler := Handle(map[string]RESTStorage{ "foo": UnimplementedRESTStorage{}, - }, codec, "/prefix", testVersion, selfLinker, admissionControl) + }, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() client := http.Client{} @@ -354,7 +363,7 @@ func TestMethodNotAllowed(t *testing.T) { } func TestVersion(t *testing.T) { - handler := Handle(map[string]RESTStorage{}, codec, "/prefix", testVersion, selfLinker, admissionControl) + handler := Handle(map[string]RESTStorage{}, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() client := http.Client{} @@ -389,7 +398,7 @@ func TestSimpleList(t *testing.T) { namespace: "other", expectedSet: "/prefix/version/simple?namespace=other", } - handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl) + handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -412,7 +421,7 @@ func TestErrorList(t *testing.T) { errors: map[string]error{"list": fmt.Errorf("test Error")}, } storage["simple"] = &simpleStorage - handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl) + handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -438,7 +447,7 @@ func TestNonEmptyList(t *testing.T) { }, } storage["simple"] = &simpleStorage - handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl) + handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -484,7 +493,7 @@ func TestGet(t *testing.T) { expectedSet: "/prefix/version/simple/id", } storage["simple"] = &simpleStorage - handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl) + handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -509,7 +518,7 @@ func TestGetMissing(t *testing.T) { errors: map[string]error{"get": apierrs.NewNotFound("simple", "id")}, } storage["simple"] = &simpleStorage - handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl) + handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -528,7 +537,7 @@ func TestDelete(t *testing.T) { simpleStorage := SimpleRESTStorage{} ID := "id" storage["simple"] = &simpleStorage - handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl) + handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -549,7 +558,7 @@ func TestDeleteInvokesAdmissionControl(t *testing.T) { simpleStorage := SimpleRESTStorage{} ID := "id" storage["simple"] = &simpleStorage - handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny()) + handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny(), mapper) server := httptest.NewServer(handler) defer server.Close() @@ -571,7 +580,7 @@ func TestDeleteMissing(t *testing.T) { errors: map[string]error{"delete": apierrs.NewNotFound("simple", ID)}, } storage["simple"] = &simpleStorage - handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl) + handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -596,7 +605,7 @@ func TestUpdate(t *testing.T) { t: t, expectedSet: "/prefix/version/simple/" + ID, } - handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl) + handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -633,7 +642,7 @@ func TestUpdateInvokesAdmissionControl(t *testing.T) { t: t, expectedSet: "/prefix/version/simple/" + ID, } - handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny()) + handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny(), mapper) server := httptest.NewServer(handler) defer server.Close() @@ -664,7 +673,7 @@ func TestUpdateMissing(t *testing.T) { errors: map[string]error{"update": apierrs.NewNotFound("simple", ID)}, } storage["simple"] = &simpleStorage - handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl) + handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -695,7 +704,7 @@ func TestCreateNotFound(t *testing.T) { // See https://github.com/GoogleCloudPlatform/kubernetes/pull/486#discussion_r15037092. errors: map[string]error{"create": apierrs.NewNotFound("simple", "id")}, }, - }, codec, "/prefix", testVersion, selfLinker, admissionControl) + }, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() client := http.Client{} @@ -759,11 +768,11 @@ func TestCreate(t *testing.T) { t: t, name: "bar", namespace: "other", - expectedSet: "/prefix/version/ns/other/foo/bar", + expectedSet: "/prefix/version/foo/bar?namespace=other", } handler := Handle(map[string]RESTStorage{ "foo": &storage, - }, codec, "/prefix", testVersion, selfLinker, admissionControl) + }, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() client := http.Client{} @@ -772,7 +781,7 @@ func TestCreate(t *testing.T) { Other: "bar", } data, _ := codec.Encode(simple) - request, err := http.NewRequest("POST", server.URL+"/prefix/version/ns/other/foo", bytes.NewBuffer(data)) + request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo?namespace=other", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -817,11 +826,11 @@ func TestCreateInvokesAdmissionControl(t *testing.T) { t: t, name: "bar", namespace: "other", - expectedSet: "/prefix/version/ns/other/foo/bar", + expectedSet: "/prefix/version/foo/bar?namespace=other", } handler := Handle(map[string]RESTStorage{ "foo": &storage, - }, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny()) + }, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny(), mapper) server := httptest.NewServer(handler) defer server.Close() client := http.Client{} @@ -830,7 +839,7 @@ func TestCreateInvokesAdmissionControl(t *testing.T) { Other: "bar", } data, _ := codec.Encode(simple) - request, err := http.NewRequest("POST", server.URL+"/prefix/version/ns/other/foo", bytes.NewBuffer(data)) + request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo?namespace=other", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -881,7 +890,7 @@ func TestDelayReturnsError(t *testing.T) { return nil, apierrs.NewAlreadyExists("foo", "bar") }, } - handler := Handle(map[string]RESTStorage{"foo": &storage}, codec, "/prefix", testVersion, selfLinker, admissionControl) + handler := Handle(map[string]RESTStorage{"foo": &storage}, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -947,7 +956,7 @@ func TestCreateTimeout(t *testing.T) { } handler := Handle(map[string]RESTStorage{ "foo": &storage, - }, codec, "/prefix", testVersion, selfLinker, admissionControl) + }, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -979,7 +988,7 @@ func TestCORSAllowedOrigins(t *testing.T) { } handler := CORS( - Handle(map[string]RESTStorage{}, codec, "/prefix", testVersion, selfLinker, admissionControl), + Handle(map[string]RESTStorage{}, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper), allowedOriginRegexps, nil, nil, "true", ) server := httptest.NewServer(handler) diff --git a/pkg/apiserver/proxy_test.go b/pkg/apiserver/proxy_test.go index 99f3ce66f8d..8eb51e4d09a 100644 --- a/pkg/apiserver/proxy_test.go +++ b/pkg/apiserver/proxy_test.go @@ -230,7 +230,7 @@ func TestProxy(t *testing.T) { } handler := Handle(map[string]RESTStorage{ "foo": simpleStorage, - }, codec, "/prefix", "version", selfLinker, admissionControl) + }, codec, "/prefix", "version", selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() diff --git a/pkg/apiserver/redirect_test.go b/pkg/apiserver/redirect_test.go index c4ae26923b1..2ec95f2a587 100644 --- a/pkg/apiserver/redirect_test.go +++ b/pkg/apiserver/redirect_test.go @@ -31,7 +31,7 @@ func TestRedirect(t *testing.T) { } handler := Handle(map[string]RESTStorage{ "foo": simpleStorage, - }, codec, "/prefix", "version", selfLinker, admissionControl) + }, codec, "/prefix", "version", selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -84,7 +84,7 @@ func TestRedirectWithNamespaces(t *testing.T) { } handler := Handle(map[string]RESTStorage{ "foo": simpleStorage, - }, codec, "/prefix", "version", selfLinker, admissionControl) + }, codec, "/prefix", "version", selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() diff --git a/pkg/apiserver/watch_test.go b/pkg/apiserver/watch_test.go index 276a4d3f5d0..ef33a2c32e0 100644 --- a/pkg/apiserver/watch_test.go +++ b/pkg/apiserver/watch_test.go @@ -50,7 +50,7 @@ func TestWatchWebsocket(t *testing.T) { _ = ResourceWatcher(simpleStorage) // Give compile error if this doesn't work. handler := Handle(map[string]RESTStorage{ "foo": simpleStorage, - }, codec, "/api", "version", selfLinker, admissionControl) + }, codec, "/api", "version", selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -104,7 +104,7 @@ func TestWatchHTTP(t *testing.T) { simpleStorage := &SimpleRESTStorage{} handler := Handle(map[string]RESTStorage{ "foo": simpleStorage, - }, codec, "/api", "version", selfLinker, admissionControl) + }, codec, "/api", "version", selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() client := http.Client{} @@ -167,7 +167,7 @@ func TestWatchParamParsing(t *testing.T) { simpleStorage := &SimpleRESTStorage{} handler := Handle(map[string]RESTStorage{ "foo": simpleStorage, - }, codec, "/api", "version", selfLinker, admissionControl) + }, codec, "/api", "version", selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() @@ -239,7 +239,7 @@ func TestWatchProtocolSelection(t *testing.T) { simpleStorage := &SimpleRESTStorage{} handler := Handle(map[string]RESTStorage{ "foo": simpleStorage, - }, codec, "/api", "version", selfLinker, admissionControl) + }, codec, "/api", "version", selfLinker, admissionControl, mapper) server := httptest.NewServer(handler) defer server.Close() defer server.CloseClientConnections() diff --git a/pkg/kubectl/cmd/cmd_test.go b/pkg/kubectl/cmd/cmd_test.go index b007a3a30e8..ef5dc0bc674 100644 --- a/pkg/kubectl/cmd/cmd_test.go +++ b/pkg/kubectl/cmd/cmd_test.go @@ -66,7 +66,13 @@ func newExternalScheme() (*runtime.Scheme, meta.RESTMapper, runtime.Codec) { MetadataAccessor: meta.NewAccessor(), }, (version == "unlikelyversion") }) - mapper.Add(scheme, false, "unlikelyversion") + for _, version := range []string{"unlikelyversion"} { + for kind := range scheme.KnownTypes(version) { + mixedCase := false + scope := meta.RESTScopeNamespace + mapper.Add(scope, kind, version, mixedCase) + } + } return scheme, mapper, codec } diff --git a/pkg/kubectl/resource/builder_test.go b/pkg/kubectl/resource/builder_test.go index 397a003a102..99a2094d2ab 100644 --- a/pkg/kubectl/resource/builder_test.go +++ b/pkg/kubectl/resource/builder_test.go @@ -30,6 +30,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors" diff --git a/pkg/kubectl/resource/mapper.go b/pkg/kubectl/resource/mapper.go index 0d58572b627..874eddbe87b 100644 --- a/pkg/kubectl/resource/mapper.go +++ b/pkg/kubectl/resource/mapper.go @@ -54,9 +54,6 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) { } name, _ := mapping.MetadataAccessor.Name(obj) namespace, _ := mapping.MetadataAccessor.Namespace(obj) - if mapping.Scope.Name != "namespace" { - namespace = "" - } resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj) return &Info{ Mapping: mapping, diff --git a/pkg/master/master.go b/pkg/master/master.go index cc81000fa52..4687a03e2a2 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -31,6 +31,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" @@ -491,25 +492,25 @@ func (m *Master) getServersToValidate(c *Config) map[string]apiserver.Server { } // api_v1beta1 returns the resources and codec for API version v1beta1. -func (m *Master) api_v1beta1() (map[string]apiserver.RESTStorage, runtime.Codec, string, runtime.SelfLinker, admission.Interface) { +func (m *Master) api_v1beta1() (map[string]apiserver.RESTStorage, runtime.Codec, string, runtime.SelfLinker, admission.Interface, meta.RESTMapper) { storage := make(map[string]apiserver.RESTStorage) for k, v := range m.storage { storage[k] = v } - return storage, v1beta1.Codec, "/api/v1beta1", latest.SelfLinker, m.admissionControl + return storage, v1beta1.Codec, "/api/v1beta1", latest.SelfLinker, m.admissionControl, latest.RESTMapper } // api_v1beta2 returns the resources and codec for API version v1beta2. -func (m *Master) api_v1beta2() (map[string]apiserver.RESTStorage, runtime.Codec, string, runtime.SelfLinker, admission.Interface) { +func (m *Master) api_v1beta2() (map[string]apiserver.RESTStorage, runtime.Codec, string, runtime.SelfLinker, admission.Interface, meta.RESTMapper) { storage := make(map[string]apiserver.RESTStorage) for k, v := range m.storage { storage[k] = v } - return storage, v1beta2.Codec, "/api/v1beta2", latest.SelfLinker, m.admissionControl + return storage, v1beta2.Codec, "/api/v1beta2", latest.SelfLinker, m.admissionControl, latest.RESTMapper } // api_v1beta3 returns the resources and codec for API version v1beta3. -func (m *Master) api_v1beta3() (map[string]apiserver.RESTStorage, runtime.Codec, string, runtime.SelfLinker, admission.Interface) { +func (m *Master) api_v1beta3() (map[string]apiserver.RESTStorage, runtime.Codec, string, runtime.SelfLinker, admission.Interface, meta.RESTMapper) { storage := make(map[string]apiserver.RESTStorage) for k, v := range m.storage { if k == "minions" { @@ -517,5 +518,5 @@ func (m *Master) api_v1beta3() (map[string]apiserver.RESTStorage, runtime.Codec, } storage[strings.ToLower(k)] = v } - return storage, v1beta3.Codec, "/api/v1beta3", latest.SelfLinker, m.admissionControl + return storage, v1beta3.Codec, "/api/v1beta3", latest.SelfLinker, m.admissionControl, latest.RESTMapper }