diff --git a/pkg/api/unversioned/group_version.go b/pkg/api/unversioned/group_version.go index 2cd68baa3f..8d294582ff 100644 --- a/pkg/api/unversioned/group_version.go +++ b/pkg/api/unversioned/group_version.go @@ -56,6 +56,15 @@ func ParseGroupVersion(gv string) (GroupVersion, error) { } } +func ParseGroupVersionOrDie(gv string) GroupVersion { + ret, err := ParseGroupVersion(gv) + if err != nil { + panic(err) + } + + return ret +} + // MarshalJSON implements the json.Marshaller interface. func (gv GroupVersion) MarshalJSON() ([]byte, error) { s := gv.String() diff --git a/pkg/apiserver/api_installer.go b/pkg/apiserver/api_installer.go index ffcf696830..208c687799 100644 --- a/pkg/apiserver/api_installer.go +++ b/pkg/apiserver/api_installer.go @@ -95,7 +95,7 @@ func (a *APIInstaller) NewWebService() *restful.WebService { // TODO: change to restful.MIME_JSON when we set content type in client ws.Consumes("*/*") ws.Produces(restful.MIME_JSON) - ws.ApiVersion(a.group.Version) + ws.ApiVersion(a.group.GroupVersion.String()) return ws } @@ -104,9 +104,9 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag admit := a.group.Admit context := a.group.Context - serverVersion := a.group.ServerVersion - if len(serverVersion) == 0 { - serverVersion = a.group.Version + serverGroupVersion := a.group.GroupVersion + if a.group.ServerGroupVersion != nil { + serverGroupVersion = *a.group.ServerGroupVersion } var resource, subresource string @@ -126,13 +126,13 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if err != nil { return nil, err } - versionedPtr, err := a.group.Creater.New(a.group.Version, kind) + versionedPtr, err := a.group.Creater.New(a.group.GroupVersion.String(), kind) if err != nil { return nil, err } versionedObject := indirectArbitraryPointer(versionedPtr) - mapping, err := a.group.Mapper.RESTMapping(kind, a.group.Version) + mapping, err := a.group.Mapper.RESTMapping(kind, a.group.GroupVersion.String()) if err != nil { return nil, err } @@ -148,7 +148,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if err != nil { return nil, err } - parentMapping, err := a.group.Mapper.RESTMapping(parentKind, a.group.Version) + parentMapping, err := a.group.Mapper.RESTMapping(parentKind, a.group.GroupVersion.String()) if err != nil { return nil, err } @@ -181,14 +181,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if isLister { list := lister.NewList() _, listKind, err := a.group.Typer.ObjectVersionAndKind(list) - versionedListPtr, err := a.group.Creater.New(a.group.Version, listKind) + versionedListPtr, err := a.group.Creater.New(a.group.GroupVersion.String(), listKind) if err != nil { return nil, err } versionedList = indirectArbitraryPointer(versionedListPtr) } - versionedListOptions, err := a.group.Creater.New(serverVersion, "ListOptions") + versionedListOptions, err := a.group.Creater.New(serverGroupVersion.String(), "ListOptions") if err != nil { return nil, err } @@ -196,7 +196,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag var versionedDeleterObject interface{} switch { case isGracefulDeleter: - objectPtr, err := a.group.Creater.New(serverVersion, "DeleteOptions") + objectPtr, err := a.group.Creater.New(serverGroupVersion.String(), "DeleteOptions") if err != nil { return nil, err } @@ -206,7 +206,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag gracefulDeleter = rest.GracefulDeleteAdapter{Deleter: deleter} } - versionedStatusPtr, err := a.group.Creater.New(serverVersion, "Status") + versionedStatusPtr, err := a.group.Creater.New(serverGroupVersion.String(), "Status") if err != nil { return nil, err } @@ -224,7 +224,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if err != nil { return nil, err } - versionedGetOptions, err = a.group.Creater.New(serverVersion, getOptionsKind) + versionedGetOptions, err = a.group.Creater.New(serverGroupVersion.String(), getOptionsKind) if err != nil { return nil, err } @@ -245,7 +245,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if err != nil { return nil, err } - versionedConnectOptions, err = a.group.Creater.New(serverVersion, connectOptionsKind) + versionedConnectOptions, err = a.group.Creater.New(serverGroupVersion.String(), connectOptionsKind) } } @@ -379,8 +379,8 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag Creater: a.group.Creater, Convertor: a.group.Convertor, Codec: mapping.Codec, - APIVersion: a.group.Version, - ServerAPIVersion: serverVersion, + APIVersion: a.group.GroupVersion.String(), + ServerAPIVersion: serverGroupVersion.String(), Resource: resource, Subresource: subresource, Kind: kind, diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 4ccc573878..7254a004f0 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -79,9 +79,8 @@ type Mux interface { type APIGroupVersion struct { Storage map[string]rest.Storage - Root string - // TODO: caesarxuchao: Version actually contains "group/version", refactor it to avoid confusion. - Version string + Root string + GroupVersion unversioned.GroupVersion // RequestInfoResolver is used to parse URLs for the legacy proxy handler. Don't use this for anything else // TODO: refactor proxy handler to use sub resources @@ -91,9 +90,8 @@ type APIGroupVersion struct { // schema like api.Status, api.DeleteOptions, and api.ListOptions. Other implementors may // define a version "v1beta1" but want to use the Kubernetes "v1" internal objects. If // empty, defaults to Version. - // TODO: caesarxuchao: ServerVersion actually contains "group/version", - // refactor it to avoid confusion. - ServerVersion string + // TODO this seems suspicious. Is this actually just "unversioned" now? + ServerGroupVersion *unversioned.GroupVersion Mapper meta.RESTMapper @@ -126,8 +124,7 @@ func (g *APIGroupVersion) InstallREST(container *restful.Container) error { installer := g.newInstaller() ws := installer.NewWebService() apiResources, registrationErrors := installer.Install(ws) - // TODO: g.Version only contains "version" now, it will contain "group/version" in the near future. - AddSupportedResourcesWebService(ws, g.Version, apiResources) + AddSupportedResourcesWebService(ws, g.GroupVersion, apiResources) container.Add(ws) return utilerrors.NewAggregate(registrationErrors) } @@ -151,14 +148,13 @@ func (g *APIGroupVersion) UpdateREST(container *restful.Container) error { return apierrors.NewInternalError(fmt.Errorf("unable to find an existing webservice for prefix %s", installer.prefix)) } apiResources, registrationErrors := installer.Install(ws) - // TODO: g.Version only contains "version" now, it will contain "group/version" in the near future. - AddSupportedResourcesWebService(ws, g.Version, apiResources) + AddSupportedResourcesWebService(ws, g.GroupVersion, apiResources) return utilerrors.NewAggregate(registrationErrors) } // newInstaller is a helper to create the installer. Used by InstallREST and UpdateREST. func (g *APIGroupVersion) newInstaller() *APIInstaller { - prefix := path.Join(g.Root, g.Version) + prefix := path.Join(g.Root, g.GroupVersion.Group, g.GroupVersion.Version) installer := &APIInstaller{ group: g, info: g.RequestInfoResolver, @@ -287,7 +283,7 @@ func AddGroupWebService(container *restful.Container, path string, group unversi // Adds a service to return the supported resources, E.g., a such web service // will be registered at /apis/extensions/v1. -func AddSupportedResourcesWebService(ws *restful.WebService, groupVersion string, apiResources []unversioned.APIResource) { +func AddSupportedResourcesWebService(ws *restful.WebService, groupVersion unversioned.GroupVersion, apiResources []unversioned.APIResource) { resourceHandler := SupportedResourcesHandler(groupVersion, apiResources) ws.Route(ws.GET("/").To(resourceHandler). Doc("get available resources"). @@ -328,10 +324,10 @@ func GroupHandler(group unversioned.APIGroup) restful.RouteFunction { } // SupportedResourcesHandler returns a handler which will list the provided resources as available. -func SupportedResourcesHandler(groupVersion string, apiResources []unversioned.APIResource) restful.RouteFunction { +func SupportedResourcesHandler(groupVersion unversioned.GroupVersion, apiResources []unversioned.APIResource) restful.RouteFunction { return func(req *restful.Request, resp *restful.Response) { // TODO: use restful's Response methods - writeJSON(http.StatusOK, api.Codec, &unversioned.APIResourceList{GroupVersion: groupVersion, APIResources: apiResources}, resp.ResponseWriter, true) + writeJSON(http.StatusOK, api.Codec, &unversioned.APIResourceList{GroupVersion: groupVersion.String(), APIResources: apiResources}, resp.ResponseWriter, true) } } diff --git a/pkg/apiserver/apiserver_test.go b/pkg/apiserver/apiserver_test.go index a0a990a5ef..7aef5f8577 100644 --- a/pkg/apiserver/apiserver_test.go +++ b/pkg/apiserver/apiserver_test.go @@ -57,8 +57,12 @@ func convert(obj runtime.Object) (runtime.Object, error) { } // This creates fake API versions, similar to api/latest.go. -const testVersion = "version" -const newVersion = "version2" +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 versions = []string{testVersion, newVersion} var codec = runtime.CodecFor(api.Scheme, testVersion) @@ -208,7 +212,7 @@ func handleInternal(legacy bool, storage map[string]rest.Storage, admissionContr group := &APIGroupVersion{ Storage: storage, - Root: "/api", + Root: "/" + prefix, RequestInfoResolver: newTestRequestInfoResolver(), Creater: api.Scheme, @@ -220,13 +224,13 @@ func handleInternal(legacy bool, storage map[string]rest.Storage, admissionContr Context: requestContextMapper, } if legacy { - group.Version = testVersion - group.ServerVersion = testVersion + group.GroupVersion = testGroupVersion + group.ServerGroupVersion = &testGroupVersion group.Codec = codec group.Mapper = namespaceMapper } else { - group.Version = newVersion - group.ServerVersion = newVersion + group.GroupVersion = newGroupVersion + group.ServerGroupVersion = &newGroupVersion group.Codec = newCodec group.Mapper = namespaceMapper } @@ -235,7 +239,7 @@ func handleInternal(legacy bool, storage map[string]rest.Storage, admissionContr container.Router(restful.CurlyRouter{}) mux := container.ServeMux if err := group.InstallREST(container); err != nil { - panic(fmt.Sprintf("unable to install container %s: %v", group.Version, err)) + panic(fmt.Sprintf("unable to install container %s: %v", group.GroupVersion, err)) } ws := new(restful.WebService) InstallSupport(mux, ws, false) @@ -599,35 +603,35 @@ func TestNotFound(t *testing.T) { } cases := map[string]T{ // Positive checks to make sure everything is wired correctly - "GET root": {"GET", "/api/version/simpleroots", http.StatusOK}, - // TODO: JTL: "GET root item": {"GET", "/api/version/simpleroots/bar", http.StatusOK}, - "GET namespaced": {"GET", "/api/version/namespaces/ns/simples", http.StatusOK}, - // TODO: JTL: "GET namespaced item": {"GET", "/api/version/namespaces/ns/simples/bar", http.StatusOK}, + "GET root": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simpleroots", http.StatusOK}, + // TODO: JTL: "GET root item": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simpleroots/bar", http.StatusOK}, + "GET namespaced": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/ns/simples", http.StatusOK}, + // TODO: JTL: "GET namespaced item": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/ns/simples/bar", http.StatusOK}, - "GET long prefix": {"GET", "/api/", http.StatusNotFound}, + "GET long prefix": {"GET", "/" + prefix + "/", http.StatusNotFound}, - "root PATCH method": {"PATCH", "/api/version/simpleroots", http.StatusMethodNotAllowed}, - "root GET missing storage": {"GET", "/api/version/blah", http.StatusNotFound}, - "root GET with extra segment": {"GET", "/api/version/simpleroots/bar/baz", http.StatusNotFound}, - // TODO: JTL: "root POST with extra segment": {"POST", "/api/version/simpleroots/bar", http.StatusMethodNotAllowed}, - "root DELETE without extra segment": {"DELETE", "/api/version/simpleroots", http.StatusMethodNotAllowed}, - "root DELETE with extra segment": {"DELETE", "/api/version/simpleroots/bar/baz", http.StatusNotFound}, - "root PUT without extra segment": {"PUT", "/api/version/simpleroots", http.StatusMethodNotAllowed}, - "root PUT with extra segment": {"PUT", "/api/version/simpleroots/bar/baz", http.StatusNotFound}, - "root watch missing storage": {"GET", "/api/version/watch/", http.StatusNotFound}, - // TODO: JTL: "root watch with bad method": {"POST", "/api/version/watch/simpleroot/bar", http.StatusMethodNotAllowed}, + "root PATCH method": {"PATCH", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simpleroots", http.StatusMethodNotAllowed}, + "root GET missing storage": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/blah", http.StatusNotFound}, + "root GET with extra segment": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simpleroots/bar/baz", http.StatusNotFound}, + // TODO: JTL: "root POST with extra segment": {"POST", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simpleroots/bar", http.StatusMethodNotAllowed}, + "root DELETE without extra segment": {"DELETE", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simpleroots", http.StatusMethodNotAllowed}, + "root DELETE with extra segment": {"DELETE", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simpleroots/bar/baz", http.StatusNotFound}, + "root PUT without extra segment": {"PUT", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simpleroots", http.StatusMethodNotAllowed}, + "root PUT with extra segment": {"PUT", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simpleroots/bar/baz", http.StatusNotFound}, + "root watch missing storage": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/", http.StatusNotFound}, + // TODO: JTL: "root watch with bad method": {"POST", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/simpleroot/bar", http.StatusMethodNotAllowed}, - "namespaced PATCH method": {"PATCH", "/api/version/namespaces/ns/simples", http.StatusMethodNotAllowed}, - "namespaced GET long prefix": {"GET", "/api/", http.StatusNotFound}, - "namespaced GET missing storage": {"GET", "/api/version/blah", http.StatusNotFound}, - "namespaced GET with extra segment": {"GET", "/api/version/namespaces/ns/simples/bar/baz", http.StatusNotFound}, - "namespaced POST with extra segment": {"POST", "/api/version/namespaces/ns/simples/bar", http.StatusMethodNotAllowed}, - "namespaced DELETE without extra segment": {"DELETE", "/api/version/namespaces/ns/simples", http.StatusMethodNotAllowed}, - "namespaced DELETE with extra segment": {"DELETE", "/api/version/namespaces/ns/simples/bar/baz", http.StatusNotFound}, - "namespaced PUT without extra segment": {"PUT", "/api/version/namespaces/ns/simples", http.StatusMethodNotAllowed}, - "namespaced PUT with extra segment": {"PUT", "/api/version/namespaces/ns/simples/bar/baz", http.StatusNotFound}, - "namespaced watch missing storage": {"GET", "/api/version/watch/", http.StatusNotFound}, - "namespaced watch with bad method": {"POST", "/api/version/watch/namespaces/ns/simples/bar", http.StatusMethodNotAllowed}, + "namespaced PATCH method": {"PATCH", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/ns/simples", http.StatusMethodNotAllowed}, + "namespaced GET long prefix": {"GET", "/" + prefix + "/", http.StatusNotFound}, + "namespaced GET missing storage": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/blah", http.StatusNotFound}, + "namespaced GET with extra segment": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/ns/simples/bar/baz", http.StatusNotFound}, + "namespaced POST with extra segment": {"POST", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/ns/simples/bar", http.StatusMethodNotAllowed}, + "namespaced DELETE without extra segment": {"DELETE", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/ns/simples", http.StatusMethodNotAllowed}, + "namespaced DELETE with extra segment": {"DELETE", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/ns/simples/bar/baz", http.StatusNotFound}, + "namespaced PUT without extra segment": {"PUT", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/ns/simples", http.StatusMethodNotAllowed}, + "namespaced PUT with extra segment": {"PUT", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/ns/simples/bar/baz", http.StatusNotFound}, + "namespaced watch missing storage": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/", http.StatusNotFound}, + "namespaced watch with bad method": {"POST", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/namespaces/ns/simples/bar", http.StatusMethodNotAllowed}, } handler := handle(map[string]rest.Storage{ "simples": &SimpleRESTStorage{}, @@ -672,15 +676,15 @@ func TestUnimplementedRESTStorage(t *testing.T) { ErrCode int } cases := map[string]T{ - "GET object": {"GET", "/api/version/foo/bar", http.StatusNotFound}, - "GET list": {"GET", "/api/version/foo", http.StatusNotFound}, - "POST list": {"POST", "/api/version/foo", http.StatusNotFound}, - "PUT object": {"PUT", "/api/version/foo/bar", http.StatusNotFound}, - "DELETE object": {"DELETE", "/api/version/foo/bar", http.StatusNotFound}, - "watch list": {"GET", "/api/version/watch/foo", http.StatusNotFound}, - "watch object": {"GET", "/api/version/watch/foo/bar", http.StatusNotFound}, - "proxy object": {"GET", "/api/version/proxy/foo/bar", http.StatusNotFound}, - "redirect object": {"GET", "/api/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}, + "POST list": {"POST", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/foo", http.StatusNotFound}, + "PUT object": {"PUT", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/foo/bar", http.StatusNotFound}, + "DELETE object": {"DELETE", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/foo/bar", http.StatusNotFound}, + "watch list": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/foo", http.StatusNotFound}, + "watch object": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/foo/bar", http.StatusNotFound}, + "proxy object": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/proxy/foo/bar", http.StatusNotFound}, + "redirect object": {"GET", "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/redirect/foo/bar", http.StatusNotFound}, } handler := handle(map[string]rest.Storage{ "foo": UnimplementedRESTStorage{}, @@ -748,76 +752,76 @@ func TestList(t *testing.T) { }{ // legacy namespace param is ignored { - url: "/api/version/simple?namespace=", + url: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple?namespace=", namespace: "", - selfLink: "/api/version/simple", + selfLink: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple", legacy: true, }, { - url: "/api/version/simple?namespace=other", + url: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple?namespace=other", namespace: "", - selfLink: "/api/version/simple", + selfLink: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple", legacy: true, }, { - url: "/api/version/simple?namespace=other&labels=a%3Db&fields=c%3Dd", + url: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple?namespace=other&labels=a%3Db&fields=c%3Dd", namespace: "", - selfLink: "/api/version/simple", + selfLink: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple", legacy: true, label: "a=b", field: "c=d", }, // legacy api version is honored { - url: "/api/version/simple", + url: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple", namespace: "", - selfLink: "/api/version/simple", + selfLink: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple", legacy: true, }, { - url: "/api/version/namespaces/other/simple", + url: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/other/simple", namespace: "other", - selfLink: "/api/version/namespaces/other/simple", + selfLink: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/other/simple", legacy: true, }, { - url: "/api/version/namespaces/other/simple?labels=a%3Db&fields=c%3Dd", + url: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/other/simple?labels=a%3Db&fields=c%3Dd", namespace: "other", - selfLink: "/api/version/namespaces/other/simple", + selfLink: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/other/simple", legacy: true, label: "a=b", field: "c=d", }, // list items across all namespaces { - url: "/api/version/simple", + url: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple", namespace: "", - selfLink: "/api/version/simple", + selfLink: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple", legacy: true, }, // list items in a namespace in the path { - url: "/api/version2/namespaces/default/simple", + url: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/namespaces/default/simple", namespace: "default", - selfLink: "/api/version2/namespaces/default/simple", + selfLink: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/namespaces/default/simple", }, { - url: "/api/version2/namespaces/other/simple", + url: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/namespaces/other/simple", namespace: "other", - selfLink: "/api/version2/namespaces/other/simple", + selfLink: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/namespaces/other/simple", }, { - url: "/api/version2/namespaces/other/simple?labelSelector=a%3Db&fieldSelector=c%3Dd", + url: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/namespaces/other/simple?labelSelector=a%3Db&fieldSelector=c%3Dd", namespace: "other", - selfLink: "/api/version2/namespaces/other/simple", + selfLink: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/namespaces/other/simple", label: "a=b", field: "c=d", }, // list items across all namespaces { - url: "/api/version2/simple", + url: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/simple", namespace: "", - selfLink: "/api/version2/simple", + selfLink: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/simple", }, } for i, testCase := range testCases { @@ -881,7 +885,7 @@ func TestErrorList(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/simple") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple") if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -906,7 +910,7 @@ func TestNonEmptyList(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/simple") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple") if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -933,10 +937,10 @@ func TestNonEmptyList(t *testing.T) { if listOut.Items[0].Other != simpleStorage.list[0].Other { t.Errorf("Unexpected data: %#v, %s", listOut.Items[0], string(body)) } - if listOut.SelfLink != "/api/version/simple" { + if listOut.SelfLink != "/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/simple" { t.Errorf("unexpected list self link: %#v", listOut) } - expectedSelfLink := "/api/version/namespaces/other/simple/something" + expectedSelfLink := "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/other/simple/something" if listOut.Items[0].ObjectMeta.SelfLink != expectedSelfLink { t.Errorf("Unexpected data: %#v, %s", listOut.Items[0].ObjectMeta.SelfLink, expectedSelfLink) } @@ -957,7 +961,7 @@ func TestSelfLinkSkipsEmptyName(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/simple") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple") if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -983,7 +987,7 @@ func TestSelfLinkSkipsEmptyName(t *testing.T) { if listOut.Items[0].Other != simpleStorage.list[0].Other { t.Errorf("Unexpected data: %#v, %s", listOut.Items[0], string(body)) } - if listOut.SelfLink != "/api/version/simple" { + if listOut.SelfLink != "/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/simple" { t.Errorf("unexpected list self link: %#v", listOut) } expectedSelfLink := "" @@ -1021,7 +1025,7 @@ func TestGet(t *testing.T) { } selfLinker := &setTestSelfLinker{ t: t, - expectedSet: "/api/version/namespaces/default/simple/id", + expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id", name: "id", namespace: "default", } @@ -1030,7 +1034,7 @@ func TestGet(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/namespaces/default/simple/id") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id") if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -1062,7 +1066,7 @@ func TestGetBinary(t *testing.T) { server := httptest.NewServer(handle(map[string]rest.Storage{"simple": &simpleStorage})) defer server.Close() - req, err := http.NewRequest("GET", server.URL+"/api/version/namespaces/default/simple/binary", nil) + req, err := http.NewRequest("GET", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/binary", nil) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -1078,7 +1082,7 @@ func TestGetBinary(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - if !stream.closed || stream.version != "version" || stream.accept != "text/other, */*" || + if !stream.closed || stream.version != testGroupVersion.String() || stream.accept != "text/other, */*" || resp.Header.Get("Content-Type") != stream.contentType || string(body) != "response data" { t.Errorf("unexpected stream: %#v", stream) } @@ -1139,7 +1143,7 @@ func TestGetWithOptions(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/namespaces/default/simple/id?param1=test1¶m2=test2") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id?param1=test1¶m2=test2") if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -1181,7 +1185,7 @@ func TestGetWithOptionsAndPath(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/namespaces/default/simple/id/a/different/path?param1=test1¶m2=test2&atAPath=not") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id/a/different/path?param1=test1¶m2=test2&atAPath=not") if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -1216,7 +1220,7 @@ func TestGetAlternateSelfLink(t *testing.T) { } selfLinker := &setTestSelfLinker{ t: t, - expectedSet: "/api/version/namespaces/test/simple/id", + expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/test/simple/id", name: "id", namespace: "test", } @@ -1225,7 +1229,7 @@ func TestGetAlternateSelfLink(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/namespaces/test/simple/id") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/test/simple/id") if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -1254,7 +1258,7 @@ func TestGetNamespaceSelfLink(t *testing.T) { } selfLinker := &setTestSelfLinker{ t: t, - expectedSet: "/api/version2/namespaces/foo/simple/id", + expectedSet: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/namespaces/foo/simple/id", name: "id", namespace: "foo", } @@ -1263,7 +1267,7 @@ func TestGetNamespaceSelfLink(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version2/namespaces/foo/simple/id") + resp, err := http.Get(server.URL + "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/namespaces/foo/simple/id") if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -1292,7 +1296,7 @@ func TestGetMissing(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/simple/id") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simple/id") if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1318,7 +1322,7 @@ func TestConnect(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/namespaces/default/simple/" + itemID + "/connect") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/" + itemID + "/connect") if err != nil { t.Errorf("unexpected error: %v", err) @@ -1356,7 +1360,7 @@ func TestConnectResponderObject(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/namespaces/default/simple/" + itemID + "/connect") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/" + itemID + "/connect") if err != nil { t.Errorf("unexpected error: %v", err) @@ -1397,7 +1401,7 @@ func TestConnectResponderError(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/namespaces/default/simple/" + itemID + "/connect") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/" + itemID + "/connect") if err != nil { t.Errorf("unexpected error: %v", err) @@ -1466,7 +1470,7 @@ func TestConnectWithOptions(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/namespaces/default/simple/" + itemID + "/connect?param1=value1¶m2=value2") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/" + itemID + "/connect?param1=value1¶m2=value2") if err != nil { t.Errorf("unexpected error: %v", err) @@ -1516,7 +1520,7 @@ func TestConnectWithOptionsAndPath(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - resp, err := http.Get(server.URL + "/api/version/namespaces/default/simple/" + itemID + "/connect/" + testPath + "?param1=value1¶m2=value2") + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/" + itemID + "/connect/" + testPath + "?param1=value1¶m2=value2") if err != nil { t.Errorf("unexpected error: %v", err) @@ -1557,7 +1561,7 @@ func TestDelete(t *testing.T) { defer server.Close() client := http.Client{} - request, err := http.NewRequest("DELETE", server.URL+"/api/version/namespaces/default/simple/"+ID, nil) + request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, nil) res, err := client.Do(request) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -1589,7 +1593,7 @@ func TestDeleteWithOptions(t *testing.T) { } client := http.Client{} - request, err := http.NewRequest("DELETE", server.URL+"/api/version/namespaces/default/simple/"+ID, bytes.NewReader(body)) + request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) res, err := client.Do(request) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -1621,7 +1625,7 @@ func TestLegacyDelete(t *testing.T) { defer server.Close() client := http.Client{} - request, err := http.NewRequest("DELETE", server.URL+"/api/version/namespaces/default/simple/"+ID, nil) + request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, nil) res, err := client.Do(request) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -1653,7 +1657,7 @@ func TestLegacyDeleteIgnoresOptions(t *testing.T) { } client := http.Client{} - request, err := http.NewRequest("DELETE", server.URL+"/api/version/namespaces/default/simple/"+ID, bytes.NewReader(body)) + request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) res, err := client.Do(request) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -1679,7 +1683,7 @@ func TestDeleteInvokesAdmissionControl(t *testing.T) { defer server.Close() client := http.Client{} - request, err := http.NewRequest("DELETE", server.URL+"/api/version/namespaces/default/simple/"+ID, nil) + request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, nil) response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -1701,7 +1705,7 @@ func TestDeleteMissing(t *testing.T) { defer server.Close() client := http.Client{} - request, err := http.NewRequest("DELETE", server.URL+"/api/version/namespaces/default/simple/"+ID, nil) + request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, nil) response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -1726,7 +1730,7 @@ func TestPatch(t *testing.T) { storage["simple"] = &simpleStorage selfLinker := &setTestSelfLinker{ t: t, - expectedSet: "/api/version/namespaces/default/simple/" + ID, + expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/" + ID, name: ID, namespace: api.NamespaceDefault, } @@ -1735,7 +1739,7 @@ func TestPatch(t *testing.T) { defer server.Close() client := http.Client{} - request, err := http.NewRequest("PATCH", server.URL+"/api/version/namespaces/default/simple/"+ID, bytes.NewReader([]byte(`{"labels":{"foo":"bar"}}`))) + request, err := http.NewRequest("PATCH", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader([]byte(`{"labels":{"foo":"bar"}}`))) request.Header.Set("Content-Type", "application/merge-patch+json; charset=UTF-8") _, err = client.Do(request) if err != nil { @@ -1767,7 +1771,7 @@ func TestPatchRequiresMatchingName(t *testing.T) { defer server.Close() client := http.Client{} - request, err := http.NewRequest("PATCH", server.URL+"/api/version/namespaces/default/simple/"+ID, bytes.NewReader([]byte(`{"metadata":{"name":"idbar"}}`))) + request, err := http.NewRequest("PATCH", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader([]byte(`{"metadata":{"name":"idbar"}}`))) request.Header.Set("Content-Type", "application/merge-patch+json") response, err := client.Do(request) if err != nil { @@ -1785,7 +1789,7 @@ func TestUpdate(t *testing.T) { storage["simple"] = &simpleStorage selfLinker := &setTestSelfLinker{ t: t, - expectedSet: "/api/version/namespaces/default/simple/" + ID, + expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/" + ID, name: ID, namespace: api.NamespaceDefault, } @@ -1807,7 +1811,7 @@ func TestUpdate(t *testing.T) { } client := http.Client{} - request, err := http.NewRequest("PUT", server.URL+"/api/version/namespaces/default/simple/"+ID, bytes.NewReader(body)) + request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) _, err = client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -1844,7 +1848,7 @@ func TestUpdateInvokesAdmissionControl(t *testing.T) { } client := http.Client{} - request, err := http.NewRequest("PUT", server.URL+"/api/version/namespaces/default/simple/"+ID, bytes.NewReader(body)) + request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -1873,7 +1877,7 @@ func TestUpdateRequiresMatchingName(t *testing.T) { } client := http.Client{} - request, err := http.NewRequest("PUT", server.URL+"/api/version/namespaces/default/simple/"+ID, bytes.NewReader(body)) + request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -1905,7 +1909,7 @@ func TestUpdateAllowsMissingNamespace(t *testing.T) { } client := http.Client{} - request, err := http.NewRequest("PUT", server.URL+"/api/version/namespaces/default/simple/"+ID, bytes.NewReader(body)) + request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -1943,7 +1947,7 @@ func TestUpdateAllowsMismatchedNamespaceOnError(t *testing.T) { } client := http.Client{} - request, err := http.NewRequest("PUT", server.URL+"/api/version/namespaces/default/simple/"+ID, bytes.NewReader(body)) + request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) _, err = client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -1980,7 +1984,7 @@ func TestUpdatePreventsMismatchedNamespace(t *testing.T) { } client := http.Client{} - request, err := http.NewRequest("PUT", server.URL+"/api/version/namespaces/default/simple/"+ID, bytes.NewReader(body)) + request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -2014,7 +2018,7 @@ func TestUpdateMissing(t *testing.T) { } client := http.Client{} - request, err := http.NewRequest("PUT", server.URL+"/api/version/namespaces/default/simple/"+ID, bytes.NewReader(body)) + request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -2041,7 +2045,7 @@ func TestCreateNotFound(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - request, err := http.NewRequest("POST", server.URL+"/api/version/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) } @@ -2067,7 +2071,7 @@ func TestCreateChecksDecode(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - request, err := http.NewRequest("POST", server.URL+"/api/version/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) } @@ -2092,7 +2096,7 @@ func TestUpdateREST(t *testing.T) { makeGroup := func(storage map[string]rest.Storage) *APIGroupVersion { return &APIGroupVersion{ Storage: storage, - Root: "/api", + Root: "/" + prefix, RequestInfoResolver: newTestRequestInfoResolver(), Creater: api.Scheme, Convertor: api.Scheme, @@ -2103,9 +2107,9 @@ func TestUpdateREST(t *testing.T) { Context: requestContextMapper, Mapper: namespaceMapper, - Version: newVersion, - ServerVersion: newVersion, - Codec: newCodec, + GroupVersion: newGroupVersion, + ServerGroupVersion: &newGroupVersion, + Codec: newCodec, } } @@ -2119,13 +2123,13 @@ func TestUpdateREST(t *testing.T) { testREST := func(t *testing.T, container *restful.Container, barCode int) { w := httptest.NewRecorder() - container.ServeHTTP(w, &http.Request{Method: "GET", URL: &url.URL{Path: "/api/version2/namespaces/test/foo/test"}}) + container.ServeHTTP(w, &http.Request{Method: "GET", URL: &url.URL{Path: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/namespaces/test/foo/test"}}) if w.Code != http.StatusOK { t.Fatalf("expected OK: %#v", w) } w = httptest.NewRecorder() - container.ServeHTTP(w, &http.Request{Method: "GET", URL: &url.URL{Path: "/api/version2/namespaces/test/bar/test"}}) + container.ServeHTTP(w, &http.Request{Method: "GET", URL: &url.URL{Path: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/namespaces/test/bar/test"}}) if w.Code != barCode { t.Errorf("expected response code %d for GET to bar but received %d", barCode, w.Code) } @@ -2174,7 +2178,7 @@ func TestParentResourceIsRequired(t *testing.T) { Storage: map[string]rest.Storage{ "simple/sub": storage, }, - Root: "/api", + Root: "/" + prefix, RequestInfoResolver: newTestRequestInfoResolver(), Creater: api.Scheme, Convertor: api.Scheme, @@ -2185,9 +2189,9 @@ func TestParentResourceIsRequired(t *testing.T) { Context: requestContextMapper, Mapper: namespaceMapper, - Version: newVersion, - ServerVersion: newVersion, - Codec: newCodec, + GroupVersion: newGroupVersion, + ServerGroupVersion: &newGroupVersion, + Codec: newCodec, } container := restful.NewContainer() if err := group.InstallREST(container); err == nil { @@ -2203,7 +2207,7 @@ func TestParentResourceIsRequired(t *testing.T) { "simple": &SimpleRESTStorage{}, "simple/sub": storage, }, - Root: "/api", + Root: "/" + prefix, RequestInfoResolver: newTestRequestInfoResolver(), Creater: api.Scheme, Convertor: api.Scheme, @@ -2214,9 +2218,9 @@ func TestParentResourceIsRequired(t *testing.T) { Context: requestContextMapper, Mapper: namespaceMapper, - Version: newVersion, - ServerVersion: newVersion, - Codec: newCodec, + GroupVersion: newGroupVersion, + ServerGroupVersion: &newGroupVersion, + Codec: newCodec, } container = restful.NewContainer() if err := group.InstallREST(container); err != nil { @@ -2225,14 +2229,14 @@ func TestParentResourceIsRequired(t *testing.T) { // resource is NOT registered in the root scope w := httptest.NewRecorder() - container.ServeHTTP(w, &http.Request{Method: "GET", URL: &url.URL{Path: "/api/simple/test/sub"}}) + container.ServeHTTP(w, &http.Request{Method: "GET", URL: &url.URL{Path: "/" + prefix + "/simple/test/sub"}}) if w.Code != http.StatusNotFound { t.Errorf("expected not found: %#v", w) } // resource is registered in the namespace scope w = httptest.NewRecorder() - container.ServeHTTP(w, &http.Request{Method: "GET", URL: &url.URL{Path: "/api/version2/namespaces/test/simple/test/sub"}}) + container.ServeHTTP(w, &http.Request{Method: "GET", URL: &url.URL{Path: "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/namespaces/test/simple/test/sub"}}) if w.Code != http.StatusOK { t.Fatalf("expected OK: %#v", w) } @@ -2257,7 +2261,7 @@ func TestCreateWithName(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - request, err := http.NewRequest("POST", server.URL+"/api/version/namespaces/default/simple/"+pathName+"/sub", bytes.NewBuffer(data)) + request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+pathName+"/sub", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -2284,7 +2288,7 @@ func TestUpdateChecksDecode(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - request, err := http.NewRequest("PUT", server.URL+"/api/version/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) } @@ -2346,7 +2350,7 @@ func TestCreate(t *testing.T) { t: t, name: "bar", namespace: "default", - expectedSet: "/api/version/namespaces/default/foo/bar", + expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/foo/bar", } handler := handleLinker(map[string]rest.Storage{"foo": &storage}, selfLinker) server := httptest.NewServer(handler) @@ -2360,7 +2364,7 @@ func TestCreate(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - request, err := http.NewRequest("POST", server.URL+"/api/version/namespaces/default/foo", bytes.NewBuffer(data)) + request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/foo", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -2405,7 +2409,7 @@ func TestCreateInNamespace(t *testing.T) { t: t, name: "bar", namespace: "other", - expectedSet: "/api/version/namespaces/other/foo/bar", + expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/other/foo/bar", } handler := handleLinker(map[string]rest.Storage{"foo": &storage}, selfLinker) server := httptest.NewServer(handler) @@ -2419,7 +2423,7 @@ func TestCreateInNamespace(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - request, err := http.NewRequest("POST", server.URL+"/api/version/namespaces/other/foo", bytes.NewBuffer(data)) + request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/other/foo", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -2464,7 +2468,7 @@ func TestCreateInvokesAdmissionControl(t *testing.T) { t: t, name: "bar", namespace: "other", - expectedSet: "/api/version/namespaces/other/foo/bar", + expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/other/foo/bar", } handler := handleInternal(true, map[string]rest.Storage{"foo": &storage}, deny.NewAlwaysDeny(), selfLinker) server := httptest.NewServer(handler) @@ -2478,7 +2482,7 @@ func TestCreateInvokesAdmissionControl(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - request, err := http.NewRequest("POST", server.URL+"/api/version/namespaces/other/foo", bytes.NewBuffer(data)) + request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/other/foo", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -2532,7 +2536,7 @@ func TestDelayReturnsError(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - status := expectApiStatus(t, "DELETE", fmt.Sprintf("%s/api/version/namespaces/default/foo/bar", server.URL), nil, http.StatusConflict) + status := expectApiStatus(t, "DELETE", fmt.Sprintf("%s/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/foo/bar", server.URL), nil, http.StatusConflict) if status.Status != unversioned.StatusFailure || status.Message == "" || status.Details == nil || status.Reason != unversioned.StatusReasonAlreadyExists { t.Errorf("Unexpected status %#v", status) } @@ -2606,7 +2610,7 @@ func TestCreateTimeout(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - itemOut := expectApiStatus(t, "POST", server.URL+"/api/version/namespaces/default/foo?timeout=4ms", data, apierrs.StatusServerTimeout) + itemOut := expectApiStatus(t, "POST", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/foo?timeout=4ms", data, apierrs.StatusServerTimeout) if itemOut.Status != unversioned.StatusFailure || itemOut.Reason != unversioned.StatusReasonTimeout { t.Errorf("Unexpected status %#v", itemOut) } @@ -2698,7 +2702,7 @@ func TestCreateChecksAPIVersion(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - request, err := http.NewRequest("POST", server.URL+"/api/"+testVersion+"/namespaces/default/simple", bytes.NewBuffer(data)) + request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testVersion+"/namespaces/default/simple", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -2739,7 +2743,7 @@ func TestCreateDefaultsAPIVersion(t *testing.T) { t.Errorf("unexpected error: %v", err) } - request, err := http.NewRequest("POST", server.URL+"/api/"+testVersion+"/namespaces/default/simple", bytes.NewBuffer(data)) + request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testVersion+"/namespaces/default/simple", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -2763,7 +2767,7 @@ func TestUpdateChecksAPIVersion(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - request, err := http.NewRequest("PUT", server.URL+"/api/"+testVersion+"/namespaces/default/simple/bar", bytes.NewBuffer(data)) + request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testVersion+"/namespaces/default/simple/bar", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } diff --git a/pkg/apiserver/proxy_test.go b/pkg/apiserver/proxy_test.go index 3980181e2b..75f7a9f396 100644 --- a/pkg/apiserver/proxy_test.go +++ b/pkg/apiserver/proxy_test.go @@ -95,7 +95,7 @@ func TestProxy(t *testing.T) { server *httptest.Server proxyTestPattern string }{ - {namespaceServer, "/api/version2/proxy/namespaces/" + item.reqNamespace + "/foo/id" + item.path}, + {namespaceServer, "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/proxy/namespaces/" + item.reqNamespace + "/foo/id" + item.path}, } for _, serverPattern := range serverPatterns { @@ -212,7 +212,7 @@ func TestProxyUpgrade(t *testing.T) { server := httptest.NewServer(namespaceHandler) defer server.Close() - ws, err := websocket.Dial("ws://"+server.Listener.Addr().String()+"/api/version2/proxy/namespaces/myns/foo/123", "", "http://127.0.0.1/") + ws, err := websocket.Dial("ws://"+server.Listener.Addr().String()+"/"+prefix+"/"+newGroupVersion.Group+"/"+newGroupVersion.Version+"/proxy/namespaces/myns/foo/123", "", "http://127.0.0.1/") if err != nil { t.Errorf("%s: websocket dial err: %s", k, err) continue @@ -276,7 +276,7 @@ func TestRedirectOnMissingTrailingSlash(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - proxyTestPattern := "/api/version2/proxy/namespaces/ns/foo/id" + item.path + proxyTestPattern := "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/proxy/namespaces/ns/foo/id" + item.path req, err := http.NewRequest( "GET", server.URL+proxyTestPattern+"?"+item.query, diff --git a/pkg/apiserver/watch_test.go b/pkg/apiserver/watch_test.go index 6553424bf4..b82c031c39 100644 --- a/pkg/apiserver/watch_test.go +++ b/pkg/apiserver/watch_test.go @@ -62,7 +62,7 @@ func TestWatchWebsocket(t *testing.T) { dest, _ := url.Parse(server.URL) dest.Scheme = "ws" // Required by websocket, though the server never sees it. - dest.Path = "/api/version/watch/simples" + dest.Path = "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/simples" dest.RawQuery = "" ws, err := websocket.Dial(dest.String(), "", "http://localhost") @@ -114,7 +114,7 @@ func TestWatchHTTP(t *testing.T) { client := http.Client{} dest, _ := url.Parse(server.URL) - dest.Path = "/api/version/watch/simples" + dest.Path = "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/simples" dest.RawQuery = "" request, err := http.NewRequest("GET", dest.String(), nil) @@ -178,8 +178,8 @@ func TestWatchParamParsing(t *testing.T) { dest, _ := url.Parse(server.URL) - rootPath := "/api/" + testVersion + "/watch/simples" - namespacedPath := "/api/" + testVersion + "/watch/namespaces/other/simpleroots" + rootPath := "/" + prefix + "/" + testVersion + "/watch/simples" + namespacedPath := "/" + prefix + "/" + testVersion + "/watch/namespaces/other/simpleroots" table := []struct { path string @@ -286,7 +286,7 @@ func TestWatchProtocolSelection(t *testing.T) { client := http.Client{} dest, _ := url.Parse(server.URL) - dest.Path = "/api/version/watch/simples" + dest.Path = "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/simples" dest.RawQuery = "" table := []struct { @@ -358,7 +358,7 @@ func TestWatchHTTPTimeout(t *testing.T) { // Setup a client dest, _ := url.Parse(s.URL) - dest.Path = "/api/" + newVersion + "/simple" + dest.Path = "/" + prefix + "/" + newVersion + "/simple" dest.RawQuery = "watch=true" req, _ := http.NewRequest("GET", dest.String(), nil) diff --git a/pkg/master/master.go b/pkg/master/master.go index d64f0e7e16..715cf567d6 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -670,8 +670,8 @@ func (m *Master) init(c *Config) { } expAPIVersions := []unversioned.GroupVersionForDiscovery{ { - GroupVersion: expVersion.Version, - Version: apiutil.GetVersion(expVersion.Version), + GroupVersion: expVersion.GroupVersion.String(), + Version: expVersion.GroupVersion.Version, }, } storageVersion, found := c.StorageVersions[g.Group] @@ -685,7 +685,7 @@ func (m *Master) init(c *Config) { } apiserver.AddGroupWebService(m.handlerContainer, c.APIGroupPrefix+"/"+latest.GroupOrDie("extensions").Group, group) allGroups = append(allGroups, group) - apiserver.InstallServiceErrorHandler(m.handlerContainer, m.newRequestInfoResolver(), []string{expVersion.Version}) + apiserver.InstallServiceErrorHandler(m.handlerContainer, m.newRequestInfoResolver(), []string{expVersion.GroupVersion.String()}) } // This should be done after all groups are registered @@ -892,7 +892,7 @@ func (m *Master) api_v1() *apiserver.APIGroupVersion { } version := m.defaultAPIGroupVersion() version.Storage = storage - version.Version = "v1" + version.GroupVersion = unversioned.GroupVersion{Version: "v1"} version.Codec = v1.Codec return version } @@ -1005,7 +1005,7 @@ func (m *Master) InstallThirdPartyResource(rsrc *expapi.ThirdPartyResource) erro } apiserver.AddGroupWebService(m.handlerContainer, path, apiGroup) m.addThirdPartyResourceStorage(path, thirdparty.Storage[strings.ToLower(kind)+"s"].(*thirdpartyresourcedataetcd.REST)) - apiserver.InstallServiceErrorHandler(m.handlerContainer, m.newRequestInfoResolver(), []string{thirdparty.Version}) + apiserver.InstallServiceErrorHandler(m.handlerContainer, m.newRequestInfoResolver(), []string{thirdparty.GroupVersion.String()}) return nil } @@ -1018,20 +1018,22 @@ func (m *Master) thirdpartyapi(group, kind, version string) *apiserver.APIGroupV strings.ToLower(kind) + "s": resourceStorage, } + serverGroupVersion := unversioned.ParseGroupVersionOrDie(latest.GroupOrDie("").GroupVersion) + return &apiserver.APIGroupVersion{ Root: apiRoot, - Version: apiutil.GetGroupVersion(group, version), + GroupVersion: unversioned.GroupVersion{Group: group, Version: version}, RequestInfoResolver: m.newRequestInfoResolver(), Creater: thirdpartyresourcedata.NewObjectCreator(group, version, api.Scheme), Convertor: api.Scheme, Typer: api.Scheme, - Mapper: thirdpartyresourcedata.NewMapper(latest.GroupOrDie("extensions").RESTMapper, kind, version, group), - Codec: thirdpartyresourcedata.NewCodec(latest.GroupOrDie("extensions").Codec, kind), - Linker: latest.GroupOrDie("extensions").SelfLinker, - Storage: storage, - ServerVersion: latest.GroupOrDie("").GroupVersion, + Mapper: thirdpartyresourcedata.NewMapper(latest.GroupOrDie("extensions").RESTMapper, kind, version, group), + Codec: thirdpartyresourcedata.NewCodec(latest.GroupOrDie("extensions").Codec, kind), + Linker: latest.GroupOrDie("extensions").SelfLinker, + Storage: storage, + ServerGroupVersion: &serverGroupVersion, Context: m.requestContextMapper, @@ -1106,6 +1108,7 @@ func (m *Master) experimental(c *Config) *apiserver.APIGroupVersion { } extensionsGroup := latest.GroupOrDie("extensions") + serverGroupVersion := unversioned.ParseGroupVersionOrDie(latest.GroupOrDie("").GroupVersion) return &apiserver.APIGroupVersion{ Root: m.apiGroupPrefix, @@ -1115,12 +1118,12 @@ func (m *Master) experimental(c *Config) *apiserver.APIGroupVersion { Convertor: api.Scheme, Typer: api.Scheme, - Mapper: extensionsGroup.RESTMapper, - Codec: extensionsGroup.Codec, - Linker: extensionsGroup.SelfLinker, - Storage: storage, - Version: extensionsGroup.GroupVersion, - ServerVersion: latest.GroupOrDie("").GroupVersion, + Mapper: extensionsGroup.RESTMapper, + Codec: extensionsGroup.Codec, + Linker: extensionsGroup.SelfLinker, + Storage: storage, + GroupVersion: unversioned.ParseGroupVersionOrDie(extensionsGroup.GroupVersion), + ServerGroupVersion: &serverGroupVersion, Admit: m.admissionControl, Context: m.requestContextMapper, diff --git a/pkg/master/master_test.go b/pkg/master/master_test.go index f5819b616e..65fb2feedc 100644 --- a/pkg/master/master_test.go +++ b/pkg/master/master_test.go @@ -175,7 +175,7 @@ func TestFindExternalAddress(t *testing.T) { func TestApi_v1(t *testing.T) { master, _, assert := setUp(t) version := master.api_v1() - assert.Equal("v1", version.Version, "Version was not v1: %s", version.Version) + assert.Equal(unversioned.GroupVersion{Version: "v1"}, version.GroupVersion, "Version was not v1: %s", version.GroupVersion) assert.Equal(v1.Codec, version.Codec, "version.Codec was not for v1: %s", version.Codec) for k, v := range master.storage { assert.Contains(version.Storage, v, "Value %s not found (key: %s)", k, v) @@ -322,12 +322,14 @@ func TestDefaultAPIGroupVersion(t *testing.T) { func TestExpapi(t *testing.T) { master, config, assert := setUp(t) + extensionsGroupMeta := latest.GroupOrDie("extensions") + expAPIGroup := master.experimental(&config) assert.Equal(expAPIGroup.Root, master.apiGroupPrefix) - assert.Equal(expAPIGroup.Mapper, latest.GroupOrDie("extensions").RESTMapper) - assert.Equal(expAPIGroup.Codec, latest.GroupOrDie("extensions").Codec) - assert.Equal(expAPIGroup.Linker, latest.GroupOrDie("extensions").SelfLinker) - assert.Equal(expAPIGroup.Version, latest.GroupOrDie("extensions").GroupVersion) + assert.Equal(expAPIGroup.Mapper, extensionsGroupMeta.RESTMapper) + assert.Equal(expAPIGroup.Codec, extensionsGroupMeta.Codec) + assert.Equal(expAPIGroup.Linker, extensionsGroupMeta.SelfLinker) + assert.Equal(expAPIGroup.GroupVersion, unversioned.GroupVersion{Group: extensionsGroupMeta.Group, Version: extensionsGroupMeta.Version}) } // TestGetNodeAddresses verifies that proper results are returned