mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 06:54:01 +00:00
Simplify api_installer and setup methods
This commit is contained in:
parent
42ff28c1a2
commit
4b16a87096
@ -26,16 +26,15 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
)
|
)
|
||||||
|
|
||||||
type APIInstaller struct {
|
type APIInstaller struct {
|
||||||
group *APIGroupVersion
|
group *APIGroupVersion
|
||||||
prefix string // Path prefix where API resources are to be registered.
|
info *APIRequestInfoResolver
|
||||||
version string // The API version being installed.
|
prefix string // Path prefix where API resources are to be registered.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Struct capturing information about an action ("GET", "POST", "WATCH", PROXY", etc).
|
// Struct capturing information about an action ("GET", "POST", "WATCH", PROXY", etc).
|
||||||
@ -58,15 +57,15 @@ func (a *APIInstaller) Install() (ws *restful.WebService, errors []error) {
|
|||||||
|
|
||||||
// Initialize the custom handlers.
|
// Initialize the custom handlers.
|
||||||
watchHandler := (&WatchHandler{
|
watchHandler := (&WatchHandler{
|
||||||
storage: a.group.storage,
|
storage: a.group.Storage,
|
||||||
codec: a.group.codec,
|
codec: a.group.Codec,
|
||||||
linker: a.group.linker,
|
linker: a.group.Linker,
|
||||||
info: a.group.info,
|
info: a.info,
|
||||||
})
|
})
|
||||||
redirectHandler := (&RedirectHandler{a.group.storage, a.group.codec, a.group.context, a.group.info})
|
redirectHandler := (&RedirectHandler{a.group.Storage, a.group.Codec, a.group.Context, a.info})
|
||||||
proxyHandler := (&ProxyHandler{a.prefix + "/proxy/", a.group.storage, a.group.codec, a.group.context, a.group.info})
|
proxyHandler := (&ProxyHandler{a.prefix + "/proxy/", a.group.Storage, a.group.Codec, a.group.Context, a.info})
|
||||||
|
|
||||||
for path, storage := range a.group.storage {
|
for path, storage := range a.group.Storage {
|
||||||
if err := a.registerResourceHandlers(path, storage, ws, watchHandler, redirectHandler, proxyHandler); err != nil {
|
if err := a.registerResourceHandlers(path, storage, ws, watchHandler, redirectHandler, proxyHandler); err != nil {
|
||||||
errors = append(errors, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
@ -77,18 +76,17 @@ func (a *APIInstaller) Install() (ws *restful.WebService, errors []error) {
|
|||||||
func (a *APIInstaller) newWebService() *restful.WebService {
|
func (a *APIInstaller) newWebService() *restful.WebService {
|
||||||
ws := new(restful.WebService)
|
ws := new(restful.WebService)
|
||||||
ws.Path(a.prefix)
|
ws.Path(a.prefix)
|
||||||
ws.Doc("API at " + a.prefix + " version " + a.version)
|
ws.Doc("API at " + a.prefix + " version " + a.group.Version)
|
||||||
// TODO: change to restful.MIME_JSON when we set content type in client
|
// TODO: change to restful.MIME_JSON when we set content type in client
|
||||||
ws.Consumes("*/*")
|
ws.Consumes("*/*")
|
||||||
ws.Produces(restful.MIME_JSON)
|
ws.Produces(restful.MIME_JSON)
|
||||||
ws.ApiVersion(a.version)
|
ws.ApiVersion(a.group.Version)
|
||||||
return ws
|
return ws
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage, ws *restful.WebService, watchHandler, redirectHandler, proxyHandler http.Handler) error {
|
func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage, ws *restful.WebService, watchHandler, redirectHandler, proxyHandler http.Handler) error {
|
||||||
codec := a.group.codec
|
admit := a.group.Admit
|
||||||
admit := a.group.admit
|
context := a.group.Context
|
||||||
context := a.group.context
|
|
||||||
|
|
||||||
var resource, subresource string
|
var resource, subresource string
|
||||||
switch parts := strings.Split(path, "/"); len(parts) {
|
switch parts := strings.Split(path, "/"); len(parts) {
|
||||||
@ -97,19 +95,16 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
|
|||||||
case 1:
|
case 1:
|
||||||
resource = parts[0]
|
resource = parts[0]
|
||||||
default:
|
default:
|
||||||
|
// TODO: support deeper paths
|
||||||
return fmt.Errorf("api_installer allows only one or two segment paths (resource or resource/subresource)")
|
return fmt.Errorf("api_installer allows only one or two segment paths (resource or resource/subresource)")
|
||||||
}
|
}
|
||||||
|
|
||||||
object := storage.New()
|
object := storage.New()
|
||||||
// TODO: add scheme to APIInstaller rather than using api.Scheme
|
_, kind, err := a.group.Typer.ObjectVersionAndKind(object)
|
||||||
_, kind, err := api.Scheme.ObjectVersionAndKind(object)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
versionedPtr, err := api.Scheme.New(a.version, kind)
|
versionedPtr, err := a.group.Creater.New(a.group.Version, kind)
|
||||||
if conversion.IsNotRegisteredError(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -118,15 +113,15 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
|
|||||||
var versionedList interface{}
|
var versionedList interface{}
|
||||||
if lister, ok := storage.(RESTLister); ok {
|
if lister, ok := storage.(RESTLister); ok {
|
||||||
list := lister.NewList()
|
list := lister.NewList()
|
||||||
_, listKind, err := api.Scheme.ObjectVersionAndKind(list)
|
_, listKind, err := a.group.Typer.ObjectVersionAndKind(list)
|
||||||
versionedListPtr, err := api.Scheme.New(a.version, listKind)
|
versionedListPtr, err := a.group.Creater.New(a.group.Version, listKind)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
versionedList = indirectArbitraryPointer(versionedListPtr)
|
versionedList = indirectArbitraryPointer(versionedListPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapping, err := a.group.mapper.RESTMapping(kind, a.version)
|
mapping, err := a.group.Mapper.RESTMapping(kind, a.group.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -156,25 +151,27 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
|
|||||||
|
|
||||||
// Get the list of actions for the given scope.
|
// Get the list of actions for the given scope.
|
||||||
if scope.Name() != meta.RESTScopeNameNamespace {
|
if scope.Name() != meta.RESTScopeNameNamespace {
|
||||||
itemPath := resource + "/{name}"
|
resourcePath := resource
|
||||||
|
itemPath := resourcePath + "/{name}"
|
||||||
if len(subresource) > 0 {
|
if len(subresource) > 0 {
|
||||||
itemPath = itemPath + "/" + subresource
|
itemPath = itemPath + "/" + subresource
|
||||||
|
resourcePath = itemPath
|
||||||
}
|
}
|
||||||
nameParams := append(params, nameParam)
|
nameParams := append(params, nameParam)
|
||||||
namer := rootScopeNaming{scope, a.group.linker, gpath.Join(a.prefix, itemPath)}
|
namer := rootScopeNaming{scope, a.group.Linker, gpath.Join(a.prefix, itemPath)}
|
||||||
|
|
||||||
// Handler for standard REST verbs (GET, PUT, POST and DELETE).
|
// Handler for standard REST verbs (GET, PUT, POST and DELETE).
|
||||||
actions = appendIf(actions, action{"LIST", resource, params, namer}, isLister)
|
actions = appendIf(actions, action{"LIST", resourcePath, params, namer}, isLister)
|
||||||
actions = appendIf(actions, action{"POST", resource, params, namer}, isCreater)
|
actions = appendIf(actions, action{"POST", resourcePath, params, namer}, isCreater)
|
||||||
actions = appendIf(actions, action{"WATCHLIST", "/watch/" + resource, params, namer}, allowWatchList)
|
actions = appendIf(actions, action{"WATCHLIST", "watch/" + resourcePath, params, namer}, allowWatchList)
|
||||||
|
|
||||||
actions = appendIf(actions, action{"GET", itemPath, nameParams, namer}, isGetter)
|
actions = appendIf(actions, action{"GET", itemPath, nameParams, namer}, isGetter)
|
||||||
actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer}, isUpdater)
|
actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer}, isUpdater)
|
||||||
actions = appendIf(actions, action{"DELETE", itemPath, nameParams, namer}, isDeleter)
|
actions = appendIf(actions, action{"DELETE", itemPath, nameParams, namer}, isDeleter)
|
||||||
actions = appendIf(actions, action{"WATCH", "/watch/" + itemPath, nameParams, namer}, isWatcher)
|
actions = appendIf(actions, action{"WATCH", "watch/" + itemPath, nameParams, namer}, isWatcher)
|
||||||
actions = appendIf(actions, action{"REDIRECT", "/redirect/" + itemPath, nameParams, namer}, isRedirector)
|
actions = appendIf(actions, action{"REDIRECT", "redirect/" + itemPath, nameParams, namer}, isRedirector)
|
||||||
actions = appendIf(actions, action{"PROXY", "/proxy/" + itemPath + "/{path:*}", nameParams, namer}, isRedirector)
|
actions = appendIf(actions, action{"PROXY", "proxy/" + itemPath + "/{path:*}", nameParams, namer}, isRedirector)
|
||||||
actions = appendIf(actions, action{"PROXY", "/proxy/" + itemPath, nameParams, namer}, isRedirector)
|
actions = appendIf(actions, action{"PROXY", "proxy/" + itemPath, nameParams, namer}, isRedirector)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// v1beta3 format with namespace in path
|
// v1beta3 format with namespace in path
|
||||||
@ -184,29 +181,31 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
|
|||||||
namespacedPath := scope.ParamName() + "/{" + scope.ParamName() + "}/" + resource
|
namespacedPath := scope.ParamName() + "/{" + scope.ParamName() + "}/" + resource
|
||||||
namespaceParams := []*restful.Parameter{namespaceParam}
|
namespaceParams := []*restful.Parameter{namespaceParam}
|
||||||
|
|
||||||
|
resourcePath := namespacedPath
|
||||||
itemPath := namespacedPath + "/{name}"
|
itemPath := namespacedPath + "/{name}"
|
||||||
if len(subresource) > 0 {
|
if len(subresource) > 0 {
|
||||||
itemPath = itemPath + "/" + subresource
|
itemPath = itemPath + "/" + subresource
|
||||||
|
resourcePath = itemPath
|
||||||
}
|
}
|
||||||
nameParams := append(namespaceParams, nameParam)
|
nameParams := append(namespaceParams, nameParam)
|
||||||
namer := scopeNaming{scope, a.group.linker, gpath.Join(a.prefix, itemPath), false}
|
namer := scopeNaming{scope, a.group.Linker, gpath.Join(a.prefix, itemPath), false}
|
||||||
|
|
||||||
actions = appendIf(actions, action{"LIST", namespacedPath, namespaceParams, namer}, isLister)
|
actions = appendIf(actions, action{"LIST", resourcePath, namespaceParams, namer}, isLister)
|
||||||
actions = appendIf(actions, action{"POST", namespacedPath, namespaceParams, namer}, isCreater)
|
actions = appendIf(actions, action{"POST", resourcePath, namespaceParams, namer}, isCreater)
|
||||||
actions = appendIf(actions, action{"WATCHLIST", "/watch/" + namespacedPath, namespaceParams, namer}, allowWatchList)
|
actions = appendIf(actions, action{"WATCHLIST", "watch/" + resourcePath, namespaceParams, namer}, allowWatchList)
|
||||||
|
|
||||||
actions = appendIf(actions, action{"GET", itemPath, nameParams, namer}, isGetter)
|
actions = appendIf(actions, action{"GET", itemPath, nameParams, namer}, isGetter)
|
||||||
actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer}, isUpdater)
|
actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer}, isUpdater)
|
||||||
actions = appendIf(actions, action{"DELETE", itemPath, nameParams, namer}, isDeleter)
|
actions = appendIf(actions, action{"DELETE", itemPath, nameParams, namer}, isDeleter)
|
||||||
actions = appendIf(actions, action{"WATCH", "/watch/" + itemPath, nameParams, namer}, isWatcher)
|
actions = appendIf(actions, action{"WATCH", "watch/" + itemPath, nameParams, namer}, isWatcher)
|
||||||
actions = appendIf(actions, action{"REDIRECT", "/redirect/" + itemPath, nameParams, namer}, isRedirector)
|
actions = appendIf(actions, action{"REDIRECT", "redirect/" + itemPath, nameParams, namer}, isRedirector)
|
||||||
actions = appendIf(actions, action{"PROXY", "/proxy/" + itemPath + "/{path:*}", nameParams, namer}, isRedirector)
|
actions = appendIf(actions, action{"PROXY", "proxy/" + itemPath + "/{path:*}", nameParams, namer}, isRedirector)
|
||||||
actions = appendIf(actions, action{"PROXY", "/proxy/" + itemPath, nameParams, namer}, isRedirector)
|
actions = appendIf(actions, action{"PROXY", "proxy/" + itemPath, nameParams, namer}, isRedirector)
|
||||||
|
|
||||||
// list across namespace.
|
// list across namespace.
|
||||||
namer = scopeNaming{scope, a.group.linker, gpath.Join(a.prefix, itemPath), true}
|
namer = scopeNaming{scope, a.group.Linker, gpath.Join(a.prefix, itemPath), true}
|
||||||
actions = appendIf(actions, action{"LIST", resource, params, namer}, isLister)
|
actions = appendIf(actions, action{"LIST", resource, params, namer}, isLister)
|
||||||
actions = appendIf(actions, action{"WATCHLIST", "/watch/" + resource, params, namer}, allowWatchList)
|
actions = appendIf(actions, action{"WATCHLIST", "watch/" + resource, params, namer}, allowWatchList)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Handler for standard REST verbs (GET, PUT, POST and DELETE).
|
// Handler for standard REST verbs (GET, PUT, POST and DELETE).
|
||||||
@ -214,24 +213,27 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
|
|||||||
namespaceParam := ws.QueryParameter(scope.ParamName(), scope.ParamDescription()).DataType("string")
|
namespaceParam := ws.QueryParameter(scope.ParamName(), scope.ParamDescription()).DataType("string")
|
||||||
namespaceParams := []*restful.Parameter{namespaceParam}
|
namespaceParams := []*restful.Parameter{namespaceParam}
|
||||||
|
|
||||||
itemPath := resource + "/{name}"
|
basePath := resource
|
||||||
|
resourcePath := basePath
|
||||||
|
itemPath := resourcePath + "/{name}"
|
||||||
if len(subresource) > 0 {
|
if len(subresource) > 0 {
|
||||||
itemPath = itemPath + "/" + subresource
|
itemPath = itemPath + "/" + subresource
|
||||||
|
resourcePath = itemPath
|
||||||
}
|
}
|
||||||
nameParams := append(namespaceParams, nameParam)
|
nameParams := append(namespaceParams, nameParam)
|
||||||
namer := legacyScopeNaming{scope, a.group.linker, gpath.Join(a.prefix, itemPath)}
|
namer := legacyScopeNaming{scope, a.group.Linker, gpath.Join(a.prefix, itemPath)}
|
||||||
|
|
||||||
actions = appendIf(actions, action{"LIST", resource, namespaceParams, namer}, isLister)
|
actions = appendIf(actions, action{"LIST", resourcePath, namespaceParams, namer}, isLister)
|
||||||
actions = appendIf(actions, action{"POST", resource, namespaceParams, namer}, isCreater)
|
actions = appendIf(actions, action{"POST", resourcePath, namespaceParams, namer}, isCreater)
|
||||||
actions = appendIf(actions, action{"WATCHLIST", "/watch/" + resource, namespaceParams, namer}, allowWatchList)
|
actions = appendIf(actions, action{"WATCHLIST", "watch/" + resourcePath, namespaceParams, namer}, allowWatchList)
|
||||||
|
|
||||||
actions = appendIf(actions, action{"GET", itemPath, nameParams, namer}, isGetter)
|
actions = appendIf(actions, action{"GET", itemPath, nameParams, namer}, isGetter)
|
||||||
actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer}, isUpdater)
|
actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer}, isUpdater)
|
||||||
actions = appendIf(actions, action{"DELETE", itemPath, nameParams, namer}, isDeleter)
|
actions = appendIf(actions, action{"DELETE", itemPath, nameParams, namer}, isDeleter)
|
||||||
actions = appendIf(actions, action{"WATCH", "/watch/" + itemPath, nameParams, namer}, isWatcher)
|
actions = appendIf(actions, action{"WATCH", "watch/" + itemPath, nameParams, namer}, isWatcher)
|
||||||
actions = appendIf(actions, action{"REDIRECT", "/redirect/" + itemPath, nameParams, namer}, isRedirector)
|
actions = appendIf(actions, action{"REDIRECT", "redirect/" + itemPath, nameParams, namer}, isRedirector)
|
||||||
actions = appendIf(actions, action{"PROXY", "/proxy/" + itemPath + "/{path:*}", nameParams, namer}, isRedirector)
|
actions = appendIf(actions, action{"PROXY", "proxy/" + itemPath + "/{path:*}", nameParams, namer}, isRedirector)
|
||||||
actions = appendIf(actions, action{"PROXY", "/proxy/" + itemPath, nameParams, namer}, isRedirector)
|
actions = appendIf(actions, action{"PROXY", "proxy/" + itemPath, nameParams, namer}, isRedirector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +258,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
|
|||||||
m := monitorFilter(action.Verb, resource)
|
m := monitorFilter(action.Verb, resource)
|
||||||
switch action.Verb {
|
switch action.Verb {
|
||||||
case "GET": // Get a resource.
|
case "GET": // Get a resource.
|
||||||
route := ws.GET(action.Path).To(GetResource(getter, ctxFn, action.Namer, codec)).
|
route := ws.GET(action.Path).To(GetResource(getter, ctxFn, action.Namer, mapping.Codec)).
|
||||||
Filter(m).
|
Filter(m).
|
||||||
Doc("read the specified " + kind).
|
Doc("read the specified " + kind).
|
||||||
Operation("read" + kind).
|
Operation("read" + kind).
|
||||||
@ -264,7 +266,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
|
|||||||
addParams(route, action.Params)
|
addParams(route, action.Params)
|
||||||
ws.Route(route)
|
ws.Route(route)
|
||||||
case "LIST": // List all resources of a kind.
|
case "LIST": // List all resources of a kind.
|
||||||
route := ws.GET(action.Path).To(ListResource(lister, ctxFn, action.Namer, codec, a.group.info)).
|
route := ws.GET(action.Path).To(ListResource(lister, ctxFn, action.Namer, mapping.Codec, a.group.Version, resource)).
|
||||||
Filter(m).
|
Filter(m).
|
||||||
Doc("list objects of kind " + kind).
|
Doc("list objects of kind " + kind).
|
||||||
Operation("list" + kind).
|
Operation("list" + kind).
|
||||||
@ -272,7 +274,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
|
|||||||
addParams(route, action.Params)
|
addParams(route, action.Params)
|
||||||
ws.Route(route)
|
ws.Route(route)
|
||||||
case "PUT": // Update a resource.
|
case "PUT": // Update a resource.
|
||||||
route := ws.PUT(action.Path).To(UpdateResource(updater, ctxFn, action.Namer, codec, resource, admit)).
|
route := ws.PUT(action.Path).To(UpdateResource(updater, ctxFn, action.Namer, mapping.Codec, a.group.Typer, resource, admit)).
|
||||||
Filter(m).
|
Filter(m).
|
||||||
Doc("replace the specified " + kind).
|
Doc("replace the specified " + kind).
|
||||||
Operation("replace" + kind).
|
Operation("replace" + kind).
|
||||||
@ -280,7 +282,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
|
|||||||
addParams(route, action.Params)
|
addParams(route, action.Params)
|
||||||
ws.Route(route)
|
ws.Route(route)
|
||||||
case "POST": // Create a resource.
|
case "POST": // Create a resource.
|
||||||
route := ws.POST(action.Path).To(CreateResource(creater, ctxFn, action.Namer, codec, resource, admit)).
|
route := ws.POST(action.Path).To(CreateResource(creater, ctxFn, action.Namer, mapping.Codec, a.group.Typer, resource, admit)).
|
||||||
Filter(m).
|
Filter(m).
|
||||||
Doc("create a " + kind).
|
Doc("create a " + kind).
|
||||||
Operation("create" + kind).
|
Operation("create" + kind).
|
||||||
@ -288,7 +290,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
|
|||||||
addParams(route, action.Params)
|
addParams(route, action.Params)
|
||||||
ws.Route(route)
|
ws.Route(route)
|
||||||
case "DELETE": // Delete a resource.
|
case "DELETE": // Delete a resource.
|
||||||
route := ws.DELETE(action.Path).To(DeleteResource(deleter, ctxFn, action.Namer, codec, resource, kind, admit)).
|
route := ws.DELETE(action.Path).To(DeleteResource(deleter, ctxFn, action.Namer, mapping.Codec, resource, kind, admit)).
|
||||||
Filter(m).
|
Filter(m).
|
||||||
Doc("delete a " + kind).
|
Doc("delete a " + kind).
|
||||||
Operation("delete" + kind)
|
Operation("delete" + kind)
|
||||||
|
@ -29,7 +29,6 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"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/meta"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
@ -91,72 +90,38 @@ type Mux interface {
|
|||||||
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
|
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultAPIServer exposes nested objects for testability.
|
|
||||||
type defaultAPIServer struct {
|
|
||||||
http.Handler
|
|
||||||
group *APIGroupVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle returns a Handler function that exposes the provided storage interfaces
|
|
||||||
// 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, linker runtime.SelfLinker, admissionControl admission.Interface, contextMapper api.RequestContextMapper, mapper meta.RESTMapper) http.Handler {
|
|
||||||
prefix := path.Join(root, version)
|
|
||||||
group := NewAPIGroupVersion(storage, codec, root, prefix, linker, admissionControl, contextMapper, mapper)
|
|
||||||
container := restful.NewContainer()
|
|
||||||
container.Router(restful.CurlyRouter{})
|
|
||||||
mux := container.ServeMux
|
|
||||||
group.InstallREST(container, root, version)
|
|
||||||
ws := new(restful.WebService)
|
|
||||||
InstallSupport(mux, ws)
|
|
||||||
container.Add(ws)
|
|
||||||
return &defaultAPIServer{mux, group}
|
|
||||||
}
|
|
||||||
|
|
||||||
// APIGroupVersion is a helper for exposing RESTStorage objects as http.Handlers via go-restful
|
// APIGroupVersion is a helper for exposing RESTStorage objects as http.Handlers via go-restful
|
||||||
// It handles URLs of the form:
|
// It handles URLs of the form:
|
||||||
// /${storage_key}[/${object_name}]
|
// /${storage_key}[/${object_name}]
|
||||||
// Where 'storage_key' points to a RESTStorage object stored in storage.
|
// Where 'storage_key' points to a RESTStorage object stored in storage.
|
||||||
type APIGroupVersion struct {
|
type APIGroupVersion struct {
|
||||||
storage map[string]RESTStorage
|
Storage map[string]RESTStorage
|
||||||
codec runtime.Codec
|
|
||||||
prefix string
|
|
||||||
linker runtime.SelfLinker
|
|
||||||
admit admission.Interface
|
|
||||||
context api.RequestContextMapper
|
|
||||||
mapper meta.RESTMapper
|
|
||||||
// TODO: put me into a cleaner interface
|
|
||||||
info *APIRequestInfoResolver
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAPIGroupVersion returns an object that will serve a set of REST resources and their
|
Root string
|
||||||
// associated operations. The provided codec controls serialization and deserialization.
|
Version string
|
||||||
// This is a helper method for registering multiple sets of REST handlers under different
|
|
||||||
// prefixes onto a server.
|
Mapper meta.RESTMapper
|
||||||
// TODO: add multitype codec serialization
|
|
||||||
func NewAPIGroupVersion(storage map[string]RESTStorage, codec runtime.Codec, root, prefix string, linker runtime.SelfLinker, admissionControl admission.Interface, contextMapper api.RequestContextMapper, mapper meta.RESTMapper) *APIGroupVersion {
|
Codec runtime.Codec
|
||||||
return &APIGroupVersion{
|
Typer runtime.ObjectTyper
|
||||||
storage: storage,
|
Creater runtime.ObjectCreater
|
||||||
codec: codec,
|
Linker runtime.SelfLinker
|
||||||
prefix: prefix,
|
|
||||||
linker: linker,
|
Admit admission.Interface
|
||||||
admit: admissionControl,
|
Context api.RequestContextMapper
|
||||||
context: contextMapper,
|
|
||||||
mapper: mapper,
|
|
||||||
info: &APIRequestInfoResolver{util.NewStringSet(strings.TrimPrefix(root, "/")), latest.RESTMapper},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallREST registers the REST handlers (storage, watch, proxy and redirect) into a restful Container.
|
// InstallREST registers the REST handlers (storage, watch, proxy and redirect) into a restful Container.
|
||||||
// It is expected that the provided path root prefix will serve all operations. Root MUST NOT end
|
// It is expected that the provided path root prefix will serve all operations. Root MUST NOT end
|
||||||
// in a slash. A restful WebService is created for the group and version.
|
// in a slash. A restful WebService is created for the group and version.
|
||||||
func (g *APIGroupVersion) InstallREST(container *restful.Container, root string, version string) error {
|
func (g *APIGroupVersion) InstallREST(container *restful.Container) error {
|
||||||
prefix := path.Join(root, version)
|
info := &APIRequestInfoResolver{util.NewStringSet(strings.TrimPrefix(g.Root, "/")), g.Mapper}
|
||||||
|
|
||||||
|
prefix := path.Join(g.Root, g.Version)
|
||||||
installer := &APIInstaller{
|
installer := &APIInstaller{
|
||||||
group: g,
|
group: g,
|
||||||
prefix: prefix,
|
info: info,
|
||||||
version: version,
|
prefix: prefix,
|
||||||
}
|
}
|
||||||
ws, registrationErrors := installer.Install()
|
ws, registrationErrors := installer.Install()
|
||||||
container.Add(ws)
|
container.Add(ws)
|
||||||
|
@ -41,6 +41,8 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/admit"
|
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/admit"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/deny"
|
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/deny"
|
||||||
|
|
||||||
|
"github.com/emicklei/go-restful"
|
||||||
)
|
)
|
||||||
|
|
||||||
func convert(obj runtime.Object) (runtime.Object, error) {
|
func convert(obj runtime.Object) (runtime.Object, error) {
|
||||||
@ -115,6 +117,59 @@ func init() {
|
|||||||
requestContextMapper = api.NewRequestContextMapper()
|
requestContextMapper = api.NewRequestContextMapper()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// defaultAPIServer exposes nested objects for testability.
|
||||||
|
type defaultAPIServer struct {
|
||||||
|
http.Handler
|
||||||
|
group *APIGroupVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// uses the default settings
|
||||||
|
func handle(storage map[string]RESTStorage) http.Handler {
|
||||||
|
return handleInternal(storage, admissionControl, mapper, selfLinker)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tests with a deny admission controller
|
||||||
|
func handleDeny(storage map[string]RESTStorage) http.Handler {
|
||||||
|
return handleInternal(storage, deny.NewAlwaysDeny(), mapper, selfLinker)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tests using the new namespace scope mechanism
|
||||||
|
func handleNamespaced(storage map[string]RESTStorage) http.Handler {
|
||||||
|
return handleInternal(storage, admissionControl, namespaceMapper, selfLinker)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tests using a custom self linker
|
||||||
|
func handleLinker(storage map[string]RESTStorage, selfLinker runtime.SelfLinker) http.Handler {
|
||||||
|
return handleInternal(storage, admissionControl, mapper, selfLinker)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleInternal(storage map[string]RESTStorage, admissionControl admission.Interface, mapper meta.RESTMapper, selfLinker runtime.SelfLinker) http.Handler {
|
||||||
|
group := &APIGroupVersion{
|
||||||
|
Storage: storage,
|
||||||
|
|
||||||
|
Mapper: mapper,
|
||||||
|
|
||||||
|
Root: "/api",
|
||||||
|
Version: testVersion,
|
||||||
|
|
||||||
|
Creater: api.Scheme,
|
||||||
|
Typer: api.Scheme,
|
||||||
|
Codec: codec,
|
||||||
|
Linker: selfLinker,
|
||||||
|
|
||||||
|
Admit: admissionControl,
|
||||||
|
Context: requestContextMapper,
|
||||||
|
}
|
||||||
|
container := restful.NewContainer()
|
||||||
|
container.Router(restful.CurlyRouter{})
|
||||||
|
mux := container.ServeMux
|
||||||
|
group.InstallREST(container)
|
||||||
|
ws := new(restful.WebService)
|
||||||
|
InstallSupport(mux, ws)
|
||||||
|
container.Add(ws)
|
||||||
|
return &defaultAPIServer{mux, group}
|
||||||
|
}
|
||||||
|
|
||||||
type Simple struct {
|
type Simple struct {
|
||||||
api.TypeMeta `json:",inline"`
|
api.TypeMeta `json:",inline"`
|
||||||
api.ObjectMeta `json:"metadata"`
|
api.ObjectMeta `json:"metadata"`
|
||||||
@ -285,21 +340,21 @@ func TestNotFound(t *testing.T) {
|
|||||||
Status int
|
Status int
|
||||||
}
|
}
|
||||||
cases := map[string]T{
|
cases := map[string]T{
|
||||||
"PATCH method": {"PATCH", "/prefix/version/foo", http.StatusMethodNotAllowed},
|
"PATCH method": {"PATCH", "/api/version/foo", http.StatusMethodNotAllowed},
|
||||||
"GET long prefix": {"GET", "/prefix/", http.StatusNotFound},
|
"GET long prefix": {"GET", "/api/", http.StatusNotFound},
|
||||||
"GET missing storage": {"GET", "/prefix/version/blah", http.StatusNotFound},
|
"GET missing storage": {"GET", "/api/version/blah", http.StatusNotFound},
|
||||||
"GET with extra segment": {"GET", "/prefix/version/foo/bar/baz", http.StatusNotFound},
|
"GET with extra segment": {"GET", "/api/version/foo/bar/baz", http.StatusNotFound},
|
||||||
"POST with extra segment": {"POST", "/prefix/version/foo/bar", http.StatusMethodNotAllowed},
|
"POST with extra segment": {"POST", "/api/version/foo/bar", http.StatusMethodNotAllowed},
|
||||||
"DELETE without extra segment": {"DELETE", "/prefix/version/foo", http.StatusMethodNotAllowed},
|
"DELETE without extra segment": {"DELETE", "/api/version/foo", http.StatusMethodNotAllowed},
|
||||||
"DELETE with extra segment": {"DELETE", "/prefix/version/foo/bar/baz", http.StatusNotFound},
|
"DELETE with extra segment": {"DELETE", "/api/version/foo/bar/baz", http.StatusNotFound},
|
||||||
"PUT without extra segment": {"PUT", "/prefix/version/foo", http.StatusMethodNotAllowed},
|
"PUT without extra segment": {"PUT", "/api/version/foo", http.StatusMethodNotAllowed},
|
||||||
"PUT with extra segment": {"PUT", "/prefix/version/foo/bar/baz", http.StatusNotFound},
|
"PUT with extra segment": {"PUT", "/api/version/foo/bar/baz", http.StatusNotFound},
|
||||||
"watch missing storage": {"GET", "/prefix/version/watch/", http.StatusNotFound},
|
"watch missing storage": {"GET", "/api/version/watch/", http.StatusNotFound},
|
||||||
"watch with bad method": {"POST", "/prefix/version/watch/foo/bar", http.StatusMethodNotAllowed},
|
"watch with bad method": {"POST", "/api/version/watch/foo/bar", http.StatusMethodNotAllowed},
|
||||||
}
|
}
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handle(map[string]RESTStorage{
|
||||||
"foo": &SimpleRESTStorage{},
|
"foo": &SimpleRESTStorage{},
|
||||||
}, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
})
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
@ -339,19 +394,19 @@ func TestUnimplementedRESTStorage(t *testing.T) {
|
|||||||
ErrCode int
|
ErrCode int
|
||||||
}
|
}
|
||||||
cases := map[string]T{
|
cases := map[string]T{
|
||||||
"GET object": {"GET", "/prefix/version/foo/bar", http.StatusNotFound},
|
"GET object": {"GET", "/api/version/foo/bar", http.StatusNotFound},
|
||||||
"GET list": {"GET", "/prefix/version/foo", http.StatusNotFound},
|
"GET list": {"GET", "/api/version/foo", http.StatusNotFound},
|
||||||
"POST list": {"POST", "/prefix/version/foo", http.StatusNotFound},
|
"POST list": {"POST", "/api/version/foo", http.StatusNotFound},
|
||||||
"PUT object": {"PUT", "/prefix/version/foo/bar", http.StatusNotFound},
|
"PUT object": {"PUT", "/api/version/foo/bar", http.StatusNotFound},
|
||||||
"DELETE object": {"DELETE", "/prefix/version/foo/bar", http.StatusNotFound},
|
"DELETE object": {"DELETE", "/api/version/foo/bar", http.StatusNotFound},
|
||||||
"watch list": {"GET", "/prefix/version/watch/foo", http.StatusNotFound},
|
"watch list": {"GET", "/api/version/watch/foo", http.StatusNotFound},
|
||||||
"watch object": {"GET", "/prefix/version/watch/foo/bar", http.StatusNotFound},
|
"watch object": {"GET", "/api/version/watch/foo/bar", http.StatusNotFound},
|
||||||
"proxy object": {"GET", "/prefix/version/proxy/foo/bar", http.StatusNotFound},
|
"proxy object": {"GET", "/api/version/proxy/foo/bar", http.StatusNotFound},
|
||||||
"redirect object": {"GET", "/prefix/version/redirect/foo/bar", http.StatusNotFound},
|
"redirect object": {"GET", "/api/version/redirect/foo/bar", http.StatusNotFound},
|
||||||
}
|
}
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handle(map[string]RESTStorage{
|
||||||
"foo": UnimplementedRESTStorage{},
|
"foo": UnimplementedRESTStorage{},
|
||||||
}, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
})
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
@ -376,7 +431,7 @@ func TestUnimplementedRESTStorage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestVersion(t *testing.T) {
|
func TestVersion(t *testing.T) {
|
||||||
handler := Handle(map[string]RESTStorage{}, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handle(map[string]RESTStorage{})
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
@ -409,14 +464,14 @@ func TestList(t *testing.T) {
|
|||||||
selfLink string
|
selfLink string
|
||||||
legacy bool
|
legacy bool
|
||||||
}{
|
}{
|
||||||
{"/prefix/version/simple", "", "/prefix/version/simple?namespace=", true},
|
{"/api/version/simple", "", "/api/version/simple?namespace=", true},
|
||||||
{"/prefix/version/simple?namespace=other", "other", "/prefix/version/simple?namespace=other", true},
|
{"/api/version/simple?namespace=other", "other", "/api/version/simple?namespace=other", true},
|
||||||
// list items across all namespaces
|
// list items across all namespaces
|
||||||
{"/prefix/version/simple?namespace=", "", "/prefix/version/simple?namespace=", true},
|
{"/api/version/simple?namespace=", "", "/api/version/simple?namespace=", true},
|
||||||
{"/prefix/version/namespaces/default/simple", "default", "/prefix/version/namespaces/default/simple", false},
|
{"/api/version/namespaces/default/simple", "default", "/api/version/namespaces/default/simple", false},
|
||||||
{"/prefix/version/namespaces/other/simple", "other", "/prefix/version/namespaces/other/simple", false},
|
{"/api/version/namespaces/other/simple", "other", "/api/version/namespaces/other/simple", false},
|
||||||
// list items across all namespaces
|
// list items across all namespaces
|
||||||
{"/prefix/version/simple", "", "/prefix/version/simple", false},
|
{"/api/version/simple", "", "/api/version/simple", false},
|
||||||
}
|
}
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
storage := map[string]RESTStorage{}
|
storage := map[string]RESTStorage{}
|
||||||
@ -429,9 +484,9 @@ func TestList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
var handler http.Handler
|
var handler http.Handler
|
||||||
if testCase.legacy {
|
if testCase.legacy {
|
||||||
handler = Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler = handleLinker(storage, selfLinker)
|
||||||
} else {
|
} else {
|
||||||
handler = Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, namespaceMapper)
|
handler = handleInternal(storage, admissionControl, namespaceMapper, selfLinker)
|
||||||
}
|
}
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
@ -462,11 +517,11 @@ func TestErrorList(t *testing.T) {
|
|||||||
errors: map[string]error{"list": fmt.Errorf("test Error")},
|
errors: map[string]error{"list": fmt.Errorf("test Error")},
|
||||||
}
|
}
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handle(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
resp, err := http.Get(server.URL + "/prefix/version/simple")
|
resp, err := http.Get(server.URL + "/api/version/simple")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -487,11 +542,11 @@ func TestNonEmptyList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handle(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
resp, err := http.Get(server.URL + "/prefix/version/simple")
|
resp, err := http.Get(server.URL + "/api/version/simple")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -515,10 +570,10 @@ func TestNonEmptyList(t *testing.T) {
|
|||||||
if listOut.Items[0].Other != simpleStorage.list[0].Other {
|
if listOut.Items[0].Other != simpleStorage.list[0].Other {
|
||||||
t.Errorf("Unexpected data: %#v, %s", listOut.Items[0], string(body))
|
t.Errorf("Unexpected data: %#v, %s", listOut.Items[0], string(body))
|
||||||
}
|
}
|
||||||
if listOut.SelfLink != "/prefix/version/simple?namespace=" {
|
if listOut.SelfLink != "/api/version/simple?namespace=" {
|
||||||
t.Errorf("unexpected list self link: %#v", listOut)
|
t.Errorf("unexpected list self link: %#v", listOut)
|
||||||
}
|
}
|
||||||
expectedSelfLink := "/prefix/version/simple/something?namespace=other"
|
expectedSelfLink := "/api/version/simple/something?namespace=other"
|
||||||
if listOut.Items[0].ObjectMeta.SelfLink != expectedSelfLink {
|
if listOut.Items[0].ObjectMeta.SelfLink != expectedSelfLink {
|
||||||
t.Errorf("Unexpected data: %#v, %s", listOut.Items[0].ObjectMeta.SelfLink, expectedSelfLink)
|
t.Errorf("Unexpected data: %#v, %s", listOut.Items[0].ObjectMeta.SelfLink, expectedSelfLink)
|
||||||
}
|
}
|
||||||
@ -535,11 +590,11 @@ func TestSelfLinkSkipsEmptyName(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handle(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
resp, err := http.Get(server.URL + "/prefix/version/simple")
|
resp, err := http.Get(server.URL + "/api/version/simple")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -562,7 +617,7 @@ func TestSelfLinkSkipsEmptyName(t *testing.T) {
|
|||||||
if listOut.Items[0].Other != simpleStorage.list[0].Other {
|
if listOut.Items[0].Other != simpleStorage.list[0].Other {
|
||||||
t.Errorf("Unexpected data: %#v, %s", listOut.Items[0], string(body))
|
t.Errorf("Unexpected data: %#v, %s", listOut.Items[0], string(body))
|
||||||
}
|
}
|
||||||
if listOut.SelfLink != "/prefix/version/simple?namespace=" {
|
if listOut.SelfLink != "/api/version/simple?namespace=" {
|
||||||
t.Errorf("unexpected list self link: %#v", listOut)
|
t.Errorf("unexpected list self link: %#v", listOut)
|
||||||
}
|
}
|
||||||
expectedSelfLink := ""
|
expectedSelfLink := ""
|
||||||
@ -580,16 +635,16 @@ func TestGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
selfLinker := &setTestSelfLinker{
|
selfLinker := &setTestSelfLinker{
|
||||||
t: t,
|
t: t,
|
||||||
expectedSet: "/prefix/version/simple/id?namespace=default",
|
expectedSet: "/api/version/simple/id?namespace=default",
|
||||||
name: "id",
|
name: "id",
|
||||||
namespace: "default",
|
namespace: "default",
|
||||||
}
|
}
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handleLinker(storage, selfLinker)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
resp, err := http.Get(server.URL + "/prefix/version/simple/id")
|
resp, err := http.Get(server.URL + "/api/version/simple/id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -619,16 +674,16 @@ func TestGetAlternateSelfLink(t *testing.T) {
|
|||||||
}
|
}
|
||||||
selfLinker := &setTestSelfLinker{
|
selfLinker := &setTestSelfLinker{
|
||||||
t: t,
|
t: t,
|
||||||
expectedSet: "/prefix/version/simple/id?namespace=test",
|
expectedSet: "/api/version/simple/id?namespace=test",
|
||||||
name: "id",
|
name: "id",
|
||||||
namespace: "test",
|
namespace: "test",
|
||||||
}
|
}
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, legacyNamespaceMapper)
|
handler := handleLinker(storage, selfLinker)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
resp, err := http.Get(server.URL + "/prefix/version/simple/id?namespace=test")
|
resp, err := http.Get(server.URL + "/api/version/simple/id?namespace=test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -657,16 +712,16 @@ func TestGetNamespaceSelfLink(t *testing.T) {
|
|||||||
}
|
}
|
||||||
selfLinker := &setTestSelfLinker{
|
selfLinker := &setTestSelfLinker{
|
||||||
t: t,
|
t: t,
|
||||||
expectedSet: "/prefix/version/namespaces/foo/simple/id",
|
expectedSet: "/api/version/namespaces/foo/simple/id",
|
||||||
name: "id",
|
name: "id",
|
||||||
namespace: "foo",
|
namespace: "foo",
|
||||||
}
|
}
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, namespaceMapper)
|
handler := handleInternal(storage, admissionControl, namespaceMapper, selfLinker)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
resp, err := http.Get(server.URL + "/prefix/version/namespaces/foo/simple/id")
|
resp, err := http.Get(server.URL + "/api/version/namespaces/foo/simple/id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -691,11 +746,11 @@ func TestGetMissing(t *testing.T) {
|
|||||||
errors: map[string]error{"get": apierrs.NewNotFound("simple", "id")},
|
errors: map[string]error{"get": apierrs.NewNotFound("simple", "id")},
|
||||||
}
|
}
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handle(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
resp, err := http.Get(server.URL + "/prefix/version/simple/id")
|
resp, err := http.Get(server.URL + "/api/version/simple/id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -710,12 +765,12 @@ func TestDelete(t *testing.T) {
|
|||||||
simpleStorage := SimpleRESTStorage{}
|
simpleStorage := SimpleRESTStorage{}
|
||||||
ID := "id"
|
ID := "id"
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handle(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
request, err := http.NewRequest("DELETE", server.URL+"/prefix/version/simple/"+ID, nil)
|
request, err := http.NewRequest("DELETE", server.URL+"/api/version/simple/"+ID, nil)
|
||||||
res, err := client.Do(request)
|
res, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
@ -733,12 +788,12 @@ func TestDeleteInvokesAdmissionControl(t *testing.T) {
|
|||||||
simpleStorage := SimpleRESTStorage{}
|
simpleStorage := SimpleRESTStorage{}
|
||||||
ID := "id"
|
ID := "id"
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny(), requestContextMapper, mapper)
|
handler := handleDeny(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
request, err := http.NewRequest("DELETE", server.URL+"/prefix/version/simple/"+ID, nil)
|
request, err := http.NewRequest("DELETE", server.URL+"/api/version/simple/"+ID, nil)
|
||||||
response, err := client.Do(request)
|
response, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@ -755,12 +810,12 @@ func TestDeleteMissing(t *testing.T) {
|
|||||||
errors: map[string]error{"delete": apierrs.NewNotFound("simple", ID)},
|
errors: map[string]error{"delete": apierrs.NewNotFound("simple", ID)},
|
||||||
}
|
}
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handle(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
request, err := http.NewRequest("DELETE", server.URL+"/prefix/version/simple/"+ID, nil)
|
request, err := http.NewRequest("DELETE", server.URL+"/api/version/simple/"+ID, nil)
|
||||||
response, err := client.Do(request)
|
response, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@ -778,11 +833,11 @@ func TestUpdate(t *testing.T) {
|
|||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
selfLinker := &setTestSelfLinker{
|
selfLinker := &setTestSelfLinker{
|
||||||
t: t,
|
t: t,
|
||||||
expectedSet: "/prefix/version/simple/" + ID + "?namespace=default",
|
expectedSet: "/api/version/simple/" + ID + "?namespace=default",
|
||||||
name: ID,
|
name: ID,
|
||||||
namespace: api.NamespaceDefault,
|
namespace: api.NamespaceDefault,
|
||||||
}
|
}
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handleLinker(storage, selfLinker)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
@ -800,7 +855,7 @@ func TestUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
request, err := http.NewRequest("PUT", server.URL+"/api/version/simple/"+ID, bytes.NewReader(body))
|
||||||
_, err = client.Do(request)
|
_, err = client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@ -819,7 +874,7 @@ func TestUpdateInvokesAdmissionControl(t *testing.T) {
|
|||||||
simpleStorage := SimpleRESTStorage{}
|
simpleStorage := SimpleRESTStorage{}
|
||||||
ID := "id"
|
ID := "id"
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny(), requestContextMapper, mapper)
|
handler := handleDeny(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
@ -837,7 +892,7 @@ func TestUpdateInvokesAdmissionControl(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
request, err := http.NewRequest("PUT", server.URL+"/api/version/simple/"+ID, bytes.NewReader(body))
|
||||||
response, err := client.Do(request)
|
response, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@ -852,7 +907,7 @@ func TestUpdateRequiresMatchingName(t *testing.T) {
|
|||||||
simpleStorage := SimpleRESTStorage{}
|
simpleStorage := SimpleRESTStorage{}
|
||||||
ID := "id"
|
ID := "id"
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny(), requestContextMapper, mapper)
|
handler := handleDeny(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
@ -866,7 +921,7 @@ func TestUpdateRequiresMatchingName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
request, err := http.NewRequest("PUT", server.URL+"/api/version/simple/"+ID, bytes.NewReader(body))
|
||||||
response, err := client.Do(request)
|
response, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@ -881,7 +936,7 @@ func TestUpdateAllowsMissingNamespace(t *testing.T) {
|
|||||||
simpleStorage := SimpleRESTStorage{}
|
simpleStorage := SimpleRESTStorage{}
|
||||||
ID := "id"
|
ID := "id"
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handle(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
@ -898,7 +953,7 @@ func TestUpdateAllowsMissingNamespace(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
request, err := http.NewRequest("PUT", server.URL+"/api/version/simple/"+ID, bytes.NewReader(body))
|
||||||
response, err := client.Do(request)
|
response, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@ -918,7 +973,7 @@ func TestUpdateAllowsMismatchedNamespaceOnError(t *testing.T) {
|
|||||||
t: t,
|
t: t,
|
||||||
err: fmt.Errorf("test error"),
|
err: fmt.Errorf("test error"),
|
||||||
}
|
}
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handleLinker(storage, selfLinker)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
@ -936,7 +991,7 @@ func TestUpdateAllowsMismatchedNamespaceOnError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
request, err := http.NewRequest("PUT", server.URL+"/api/version/simple/"+ID, bytes.NewReader(body))
|
||||||
_, err = client.Do(request)
|
_, err = client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@ -955,7 +1010,7 @@ func TestUpdatePreventsMismatchedNamespace(t *testing.T) {
|
|||||||
simpleStorage := SimpleRESTStorage{}
|
simpleStorage := SimpleRESTStorage{}
|
||||||
ID := "id"
|
ID := "id"
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handle(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
@ -973,7 +1028,7 @@ func TestUpdatePreventsMismatchedNamespace(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
request, err := http.NewRequest("PUT", server.URL+"/api/version/simple/"+ID, bytes.NewReader(body))
|
||||||
response, err := client.Do(request)
|
response, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@ -990,7 +1045,7 @@ func TestUpdateMissing(t *testing.T) {
|
|||||||
errors: map[string]error{"update": apierrs.NewNotFound("simple", ID)},
|
errors: map[string]error{"update": apierrs.NewNotFound("simple", ID)},
|
||||||
}
|
}
|
||||||
storage["simple"] = &simpleStorage
|
storage["simple"] = &simpleStorage
|
||||||
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handle(storage)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
@ -1007,7 +1062,7 @@ func TestUpdateMissing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
request, err := http.NewRequest("PUT", server.URL+"/api/version/simple/"+ID, bytes.NewReader(body))
|
||||||
response, err := client.Do(request)
|
response, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@ -1018,20 +1073,20 @@ func TestUpdateMissing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateNotFound(t *testing.T) {
|
func TestCreateNotFound(t *testing.T) {
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handle(map[string]RESTStorage{
|
||||||
"simple": &SimpleRESTStorage{
|
"simple": &SimpleRESTStorage{
|
||||||
// storage.Create can fail with not found error in theory.
|
// storage.Create can fail with not found error in theory.
|
||||||
// See https://github.com/GoogleCloudPlatform/kubernetes/pull/486#discussion_r15037092.
|
// See https://github.com/GoogleCloudPlatform/kubernetes/pull/486#discussion_r15037092.
|
||||||
errors: map[string]error{"create": apierrs.NewNotFound("simple", "id")},
|
errors: map[string]error{"create": apierrs.NewNotFound("simple", "id")},
|
||||||
},
|
},
|
||||||
}, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
})
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
|
|
||||||
simple := &Simple{Other: "foo"}
|
simple := &Simple{Other: "foo"}
|
||||||
data, _ := codec.Encode(simple)
|
data, _ := codec.Encode(simple)
|
||||||
request, err := http.NewRequest("POST", server.URL+"/prefix/version/simple", bytes.NewBuffer(data))
|
request, err := http.NewRequest("POST", server.URL+"/api/version/simple", bytes.NewBuffer(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -1046,6 +1101,54 @@ func TestCreateNotFound(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateChecksDecode(t *testing.T) {
|
||||||
|
handler := handle(map[string]RESTStorage{"simple": &SimpleRESTStorage{}})
|
||||||
|
server := httptest.NewServer(handler)
|
||||||
|
defer server.Close()
|
||||||
|
client := http.Client{}
|
||||||
|
|
||||||
|
simple := &api.Pod{}
|
||||||
|
data, _ := codec.Encode(simple)
|
||||||
|
request, err := http.NewRequest("POST", server.URL+"/api/version/simple", bytes.NewBuffer(data))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
response, err := client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if response.StatusCode != http.StatusBadRequest {
|
||||||
|
t.Errorf("Unexpected response %#v", response)
|
||||||
|
}
|
||||||
|
if b, _ := ioutil.ReadAll(response.Body); !strings.Contains(string(b), "must be of type Simple") {
|
||||||
|
t.Errorf("unexpected response: %s", string(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateChecksDecode(t *testing.T) {
|
||||||
|
handler := handle(map[string]RESTStorage{"simple": &SimpleRESTStorage{}})
|
||||||
|
server := httptest.NewServer(handler)
|
||||||
|
defer server.Close()
|
||||||
|
client := http.Client{}
|
||||||
|
|
||||||
|
simple := &api.Pod{}
|
||||||
|
data, _ := codec.Encode(simple)
|
||||||
|
request, err := http.NewRequest("PUT", server.URL+"/api/version/simple/bar", bytes.NewBuffer(data))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
response, err := client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if response.StatusCode != http.StatusBadRequest {
|
||||||
|
t.Errorf("Unexpected response %#v", response)
|
||||||
|
}
|
||||||
|
if b, _ := ioutil.ReadAll(response.Body); !strings.Contains(string(b), "must be of type Simple") {
|
||||||
|
t.Errorf("unexpected response: %s", string(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseTimeout(t *testing.T) {
|
func TestParseTimeout(t *testing.T) {
|
||||||
if d := parseTimeout(""); d != 30*time.Second {
|
if d := parseTimeout(""); d != 30*time.Second {
|
||||||
t.Errorf("blank timeout produces %v", d)
|
t.Errorf("blank timeout produces %v", d)
|
||||||
@ -1089,11 +1192,9 @@ func TestCreate(t *testing.T) {
|
|||||||
t: t,
|
t: t,
|
||||||
name: "bar",
|
name: "bar",
|
||||||
namespace: "default",
|
namespace: "default",
|
||||||
expectedSet: "/prefix/version/foo/bar?namespace=default",
|
expectedSet: "/api/version/foo/bar?namespace=default",
|
||||||
}
|
}
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handleLinker(map[string]RESTStorage{"foo": &storage}, selfLinker)
|
||||||
"foo": &storage,
|
|
||||||
}, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
@ -1102,7 +1203,7 @@ func TestCreate(t *testing.T) {
|
|||||||
Other: "bar",
|
Other: "bar",
|
||||||
}
|
}
|
||||||
data, _ := codec.Encode(simple)
|
data, _ := codec.Encode(simple)
|
||||||
request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo", bytes.NewBuffer(data))
|
request, err := http.NewRequest("POST", server.URL+"/api/version/foo", bytes.NewBuffer(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -1147,11 +1248,9 @@ func TestCreateInNamespace(t *testing.T) {
|
|||||||
t: t,
|
t: t,
|
||||||
name: "bar",
|
name: "bar",
|
||||||
namespace: "other",
|
namespace: "other",
|
||||||
expectedSet: "/prefix/version/foo/bar?namespace=other",
|
expectedSet: "/api/version/foo/bar?namespace=other",
|
||||||
}
|
}
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handleLinker(map[string]RESTStorage{"foo": &storage}, selfLinker)
|
||||||
"foo": &storage,
|
|
||||||
}, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
@ -1160,7 +1259,7 @@ func TestCreateInNamespace(t *testing.T) {
|
|||||||
Other: "bar",
|
Other: "bar",
|
||||||
}
|
}
|
||||||
data, _ := codec.Encode(simple)
|
data, _ := codec.Encode(simple)
|
||||||
request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo?namespace=other", bytes.NewBuffer(data))
|
request, err := http.NewRequest("POST", server.URL+"/api/version/foo?namespace=other", bytes.NewBuffer(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -1205,11 +1304,9 @@ func TestCreateInvokesAdmissionControl(t *testing.T) {
|
|||||||
t: t,
|
t: t,
|
||||||
name: "bar",
|
name: "bar",
|
||||||
namespace: "other",
|
namespace: "other",
|
||||||
expectedSet: "/prefix/version/foo/bar?namespace=other",
|
expectedSet: "/api/version/foo/bar?namespace=other",
|
||||||
}
|
}
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handleInternal(map[string]RESTStorage{"foo": &storage}, deny.NewAlwaysDeny(), mapper, selfLinker)
|
||||||
"foo": &storage,
|
|
||||||
}, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny(), requestContextMapper, mapper)
|
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
@ -1218,7 +1315,7 @@ func TestCreateInvokesAdmissionControl(t *testing.T) {
|
|||||||
Other: "bar",
|
Other: "bar",
|
||||||
}
|
}
|
||||||
data, _ := codec.Encode(simple)
|
data, _ := codec.Encode(simple)
|
||||||
request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo?namespace=other", bytes.NewBuffer(data))
|
request, err := http.NewRequest("POST", server.URL+"/api/version/foo?namespace=other", bytes.NewBuffer(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -1269,11 +1366,11 @@ func TestDelayReturnsError(t *testing.T) {
|
|||||||
return nil, apierrs.NewAlreadyExists("foo", "bar")
|
return nil, apierrs.NewAlreadyExists("foo", "bar")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
handler := Handle(map[string]RESTStorage{"foo": &storage}, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
handler := handle(map[string]RESTStorage{"foo": &storage})
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
status := expectApiStatus(t, "DELETE", fmt.Sprintf("%s/prefix/version/foo/bar", server.URL), nil, http.StatusConflict)
|
status := expectApiStatus(t, "DELETE", fmt.Sprintf("%s/api/version/foo/bar", server.URL), nil, http.StatusConflict)
|
||||||
if status.Status != api.StatusFailure || status.Message == "" || status.Details == nil || status.Reason != api.StatusReasonAlreadyExists {
|
if status.Status != api.StatusFailure || status.Message == "" || status.Details == nil || status.Reason != api.StatusReasonAlreadyExists {
|
||||||
t.Errorf("Unexpected status %#v", status)
|
t.Errorf("Unexpected status %#v", status)
|
||||||
}
|
}
|
||||||
@ -1333,15 +1430,15 @@ func TestCreateTimeout(t *testing.T) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handle(map[string]RESTStorage{
|
||||||
"foo": &storage,
|
"foo": &storage,
|
||||||
}, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
})
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
simple := &Simple{Other: "foo"}
|
simple := &Simple{Other: "foo"}
|
||||||
data, _ := codec.Encode(simple)
|
data, _ := codec.Encode(simple)
|
||||||
itemOut := expectApiStatus(t, "POST", server.URL+"/prefix/version/foo?timeout=4ms", data, apierrs.StatusServerTimeout)
|
itemOut := expectApiStatus(t, "POST", server.URL+"/api/version/foo?timeout=4ms", data, apierrs.StatusServerTimeout)
|
||||||
if itemOut.Status != api.StatusFailure || itemOut.Reason != api.StatusReasonTimeout {
|
if itemOut.Status != api.StatusFailure || itemOut.Reason != api.StatusReasonTimeout {
|
||||||
t.Errorf("Unexpected status %#v", itemOut)
|
t.Errorf("Unexpected status %#v", itemOut)
|
||||||
}
|
}
|
||||||
@ -1367,7 +1464,7 @@ func TestCORSAllowedOrigins(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handler := CORS(
|
handler := CORS(
|
||||||
Handle(map[string]RESTStorage{}, codec, "/prefix", testVersion, selfLinker, admissionControl, requestContextMapper, mapper),
|
handle(map[string]RESTStorage{}),
|
||||||
allowedOriginRegexps, nil, nil, "true",
|
allowedOriginRegexps, nil, nil, "true",
|
||||||
)
|
)
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
|
@ -280,14 +280,10 @@ func TestProxy(t *testing.T) {
|
|||||||
expectedResourceNamespace: item.reqNamespace,
|
expectedResourceNamespace: item.reqNamespace,
|
||||||
}
|
}
|
||||||
|
|
||||||
namespaceHandler := Handle(map[string]RESTStorage{
|
namespaceHandler := handleNamespaced(map[string]RESTStorage{"foo": simpleStorage})
|
||||||
"foo": simpleStorage,
|
|
||||||
}, codec, "/prefix", "version", selfLinker, admissionControl, requestContextMapper, namespaceMapper)
|
|
||||||
namespaceServer := httptest.NewServer(namespaceHandler)
|
namespaceServer := httptest.NewServer(namespaceHandler)
|
||||||
defer namespaceServer.Close()
|
defer namespaceServer.Close()
|
||||||
legacyNamespaceHandler := Handle(map[string]RESTStorage{
|
legacyNamespaceHandler := handle(map[string]RESTStorage{"foo": simpleStorage})
|
||||||
"foo": simpleStorage,
|
|
||||||
}, codec, "/prefix", "version", selfLinker, admissionControl, requestContextMapper, legacyNamespaceMapper)
|
|
||||||
legacyNamespaceServer := httptest.NewServer(legacyNamespaceHandler)
|
legacyNamespaceServer := httptest.NewServer(legacyNamespaceHandler)
|
||||||
defer legacyNamespaceServer.Close()
|
defer legacyNamespaceServer.Close()
|
||||||
|
|
||||||
@ -296,8 +292,8 @@ func TestProxy(t *testing.T) {
|
|||||||
server *httptest.Server
|
server *httptest.Server
|
||||||
proxyTestPattern string
|
proxyTestPattern string
|
||||||
}{
|
}{
|
||||||
{namespaceServer, "/prefix/version/proxy/namespaces/" + item.reqNamespace + "/foo/id" + item.path},
|
{namespaceServer, "/api/version/proxy/namespaces/" + item.reqNamespace + "/foo/id" + item.path},
|
||||||
{legacyNamespaceServer, "/prefix/version/proxy/foo/id" + item.path + "?namespace=" + item.reqNamespace},
|
{legacyNamespaceServer, "/api/version/proxy/foo/id" + item.path + "?namespace=" + item.reqNamespace},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, serverPattern := range serverPatterns {
|
for _, serverPattern := range serverPatterns {
|
||||||
@ -344,14 +340,12 @@ func TestProxyUpgrade(t *testing.T) {
|
|||||||
expectedResourceNamespace: "myns",
|
expectedResourceNamespace: "myns",
|
||||||
}
|
}
|
||||||
|
|
||||||
namespaceHandler := Handle(map[string]RESTStorage{
|
namespaceHandler := handleNamespaced(map[string]RESTStorage{"foo": simpleStorage})
|
||||||
"foo": simpleStorage,
|
|
||||||
}, codec, "/prefix", "version", selfLinker, admissionControl, requestContextMapper, namespaceMapper)
|
|
||||||
|
|
||||||
server := httptest.NewServer(namespaceHandler)
|
server := httptest.NewServer(namespaceHandler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
ws, err := websocket.Dial("ws://"+server.Listener.Addr().String()+"/prefix/version/proxy/namespaces/myns/foo/123", "", "http://127.0.0.1/")
|
ws, err := websocket.Dial("ws://"+server.Listener.Addr().String()+"/api/version/proxy/namespaces/myns/foo/123", "", "http://127.0.0.1/")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("websocket dial err: %s", err)
|
t.Fatalf("websocket dial err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,7 @@ func TestRedirect(t *testing.T) {
|
|||||||
errors: map[string]error{},
|
errors: map[string]error{},
|
||||||
expectedResourceNamespace: "default",
|
expectedResourceNamespace: "default",
|
||||||
}
|
}
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handle(map[string]RESTStorage{"foo": simpleStorage})
|
||||||
"foo": simpleStorage,
|
|
||||||
}, codec, "/prefix", "version", selfLinker, admissionControl, requestContextMapper, mapper)
|
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
@ -54,7 +52,7 @@ func TestRedirect(t *testing.T) {
|
|||||||
for _, item := range table {
|
for _, item := range table {
|
||||||
simpleStorage.errors["resourceLocation"] = item.err
|
simpleStorage.errors["resourceLocation"] = item.err
|
||||||
simpleStorage.resourceLocation = item.id
|
simpleStorage.resourceLocation = item.id
|
||||||
resp, err := client.Get(server.URL + "/prefix/version/redirect/foo/" + item.id)
|
resp, err := client.Get(server.URL + "/api/version/redirect/foo/" + item.id)
|
||||||
if resp == nil {
|
if resp == nil {
|
||||||
t.Fatalf("Unexpected nil resp")
|
t.Fatalf("Unexpected nil resp")
|
||||||
}
|
}
|
||||||
@ -82,9 +80,7 @@ func TestRedirectWithNamespaces(t *testing.T) {
|
|||||||
errors: map[string]error{},
|
errors: map[string]error{},
|
||||||
expectedResourceNamespace: "other",
|
expectedResourceNamespace: "other",
|
||||||
}
|
}
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handleNamespaced(map[string]RESTStorage{"foo": simpleStorage})
|
||||||
"foo": simpleStorage,
|
|
||||||
}, codec, "/prefix", "version", selfLinker, admissionControl, requestContextMapper, namespaceMapper)
|
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
@ -107,7 +103,7 @@ func TestRedirectWithNamespaces(t *testing.T) {
|
|||||||
for _, item := range table {
|
for _, item := range table {
|
||||||
simpleStorage.errors["resourceLocation"] = item.err
|
simpleStorage.errors["resourceLocation"] = item.err
|
||||||
simpleStorage.resourceLocation = item.id
|
simpleStorage.resourceLocation = item.id
|
||||||
resp, err := client.Get(server.URL + "/prefix/version/redirect/namespaces/other/foo/" + item.id)
|
resp, err := client.Get(server.URL + "/api/version/redirect/namespaces/other/foo/" + item.id)
|
||||||
if resp == nil {
|
if resp == nil {
|
||||||
t.Fatalf("Unexpected nil resp")
|
t.Fatalf("Unexpected nil resp")
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package apiserver
|
package apiserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
gpath "path"
|
gpath "path"
|
||||||
@ -97,7 +98,7 @@ func parseSelectorQueryParams(query url.Values, version, apiResource string) (la
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListResource returns a function that handles retrieving a list of resources from a RESTStorage object.
|
// ListResource returns a function that handles retrieving a list of resources from a RESTStorage object.
|
||||||
func ListResource(r RESTLister, ctxFn ContextFunc, namer ScopeNamer, codec runtime.Codec, requestInfoResolver *APIRequestInfoResolver) restful.RouteFunction {
|
func ListResource(r RESTLister, ctxFn ContextFunc, namer ScopeNamer, codec runtime.Codec, version, apiResource string) restful.RouteFunction {
|
||||||
return func(req *restful.Request, res *restful.Response) {
|
return func(req *restful.Request, res *restful.Response) {
|
||||||
w := res.ResponseWriter
|
w := res.ResponseWriter
|
||||||
|
|
||||||
@ -109,13 +110,7 @@ func ListResource(r RESTLister, ctxFn ContextFunc, namer ScopeNamer, codec runti
|
|||||||
ctx := ctxFn(req)
|
ctx := ctxFn(req)
|
||||||
ctx = api.WithNamespace(ctx, namespace)
|
ctx = api.WithNamespace(ctx, namespace)
|
||||||
|
|
||||||
requestInfo, err := requestInfoResolver.GetAPIRequestInfo(req.Request)
|
label, field, err := parseSelectorQueryParams(req.Request.URL.Query(), version, apiResource)
|
||||||
if err != nil {
|
|
||||||
errorJSON(err, codec, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
label, field, err := parseSelectorQueryParams(req.Request.URL.Query(), requestInfo.APIVersion, requestInfo.Resource)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorJSON(err, codec, w)
|
errorJSON(err, codec, w)
|
||||||
return
|
return
|
||||||
@ -135,7 +130,7 @@ func ListResource(r RESTLister, ctxFn ContextFunc, namer ScopeNamer, codec runti
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateResource returns a function that will handle a resource creation.
|
// CreateResource returns a function that will handle a resource creation.
|
||||||
func CreateResource(r RESTCreater, ctxFn ContextFunc, namer ScopeNamer, codec runtime.Codec, resource string, admit admission.Interface) restful.RouteFunction {
|
func CreateResource(r RESTCreater, ctxFn ContextFunc, namer ScopeNamer, codec runtime.Codec, typer runtime.ObjectTyper, resource string, admit admission.Interface) restful.RouteFunction {
|
||||||
return func(req *restful.Request, res *restful.Response) {
|
return func(req *restful.Request, res *restful.Response) {
|
||||||
w := res.ResponseWriter
|
w := res.ResponseWriter
|
||||||
|
|
||||||
@ -158,6 +153,7 @@ func CreateResource(r RESTCreater, ctxFn ContextFunc, namer ScopeNamer, codec ru
|
|||||||
|
|
||||||
obj := r.New()
|
obj := r.New()
|
||||||
if err := codec.DecodeInto(body, obj); err != nil {
|
if err := codec.DecodeInto(body, obj); err != nil {
|
||||||
|
err = transformDecodeError(typer, err, obj, body)
|
||||||
errorJSON(err, codec, w)
|
errorJSON(err, codec, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -190,7 +186,7 @@ func CreateResource(r RESTCreater, ctxFn ContextFunc, namer ScopeNamer, codec ru
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateResource returns a function that will handle a resource update
|
// UpdateResource returns a function that will handle a resource update
|
||||||
func UpdateResource(r RESTUpdater, ctxFn ContextFunc, namer ScopeNamer, codec runtime.Codec, resource string, admit admission.Interface) restful.RouteFunction {
|
func UpdateResource(r RESTUpdater, ctxFn ContextFunc, namer ScopeNamer, codec runtime.Codec, typer runtime.ObjectTyper, resource string, admit admission.Interface) restful.RouteFunction {
|
||||||
return func(req *restful.Request, res *restful.Response) {
|
return func(req *restful.Request, res *restful.Response) {
|
||||||
w := res.ResponseWriter
|
w := res.ResponseWriter
|
||||||
|
|
||||||
@ -213,6 +209,7 @@ func UpdateResource(r RESTUpdater, ctxFn ContextFunc, namer ScopeNamer, codec ru
|
|||||||
|
|
||||||
obj := r.New()
|
obj := r.New()
|
||||||
if err := codec.DecodeInto(body, obj); err != nil {
|
if err := codec.DecodeInto(body, obj); err != nil {
|
||||||
|
err = transformDecodeError(typer, err, obj, body)
|
||||||
errorJSON(err, codec, w)
|
errorJSON(err, codec, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -346,6 +343,18 @@ func finishRequest(timeout time.Duration, fn resultFunc) (result runtime.Object,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// transformDecodeError adds additional information when a decode fails.
|
||||||
|
func transformDecodeError(typer runtime.ObjectTyper, baseErr error, into runtime.Object, body []byte) error {
|
||||||
|
_, kind, err := typer.ObjectVersionAndKind(into)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if version, dataKind, err := typer.DataVersionAndKind(body); err == nil && len(dataKind) > 0 {
|
||||||
|
return errors.NewBadRequest(fmt.Sprintf("%s in version %s cannot be handled as a %s: %v", dataKind, version, kind, baseErr))
|
||||||
|
}
|
||||||
|
return errors.NewBadRequest(fmt.Sprintf("the object provided is unrecognized (must be of type %s): %v", kind, baseErr))
|
||||||
|
}
|
||||||
|
|
||||||
// setSelfLink sets the self link of an object (or the child items in a list) to the base URL of the request
|
// setSelfLink sets the self link of an object (or the child items in a list) to the base URL of the request
|
||||||
// plus the path and query generated by the provided linkFunc
|
// plus the path and query generated by the provided linkFunc
|
||||||
func setSelfLink(obj runtime.Object, req *restful.Request, namer ScopeNamer) error {
|
func setSelfLink(obj runtime.Object, req *restful.Request, namer ScopeNamer) error {
|
||||||
|
@ -49,9 +49,7 @@ var watchTestTable = []struct {
|
|||||||
func TestWatchWebsocket(t *testing.T) {
|
func TestWatchWebsocket(t *testing.T) {
|
||||||
simpleStorage := &SimpleRESTStorage{}
|
simpleStorage := &SimpleRESTStorage{}
|
||||||
_ = ResourceWatcher(simpleStorage) // Give compile error if this doesn't work.
|
_ = ResourceWatcher(simpleStorage) // Give compile error if this doesn't work.
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handle(map[string]RESTStorage{"foo": simpleStorage})
|
||||||
"foo": simpleStorage,
|
|
||||||
}, codec, "/api", "version", selfLinker, admissionControl, requestContextMapper, mapper)
|
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
@ -103,9 +101,7 @@ func TestWatchWebsocket(t *testing.T) {
|
|||||||
|
|
||||||
func TestWatchHTTP(t *testing.T) {
|
func TestWatchHTTP(t *testing.T) {
|
||||||
simpleStorage := &SimpleRESTStorage{}
|
simpleStorage := &SimpleRESTStorage{}
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handle(map[string]RESTStorage{"foo": simpleStorage})
|
||||||
"foo": simpleStorage,
|
|
||||||
}, codec, "/api", "version", selfLinker, admissionControl, requestContextMapper, mapper)
|
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
@ -170,9 +166,7 @@ func TestWatchParamParsing(t *testing.T) {
|
|||||||
return label, value, nil
|
return label, value, nil
|
||||||
})
|
})
|
||||||
simpleStorage := &SimpleRESTStorage{}
|
simpleStorage := &SimpleRESTStorage{}
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handle(map[string]RESTStorage{"foo": simpleStorage})
|
||||||
"foo": simpleStorage,
|
|
||||||
}, codec, "/api", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
@ -242,9 +236,7 @@ func TestWatchParamParsing(t *testing.T) {
|
|||||||
|
|
||||||
func TestWatchProtocolSelection(t *testing.T) {
|
func TestWatchProtocolSelection(t *testing.T) {
|
||||||
simpleStorage := &SimpleRESTStorage{}
|
simpleStorage := &SimpleRESTStorage{}
|
||||||
handler := Handle(map[string]RESTStorage{
|
handler := handle(map[string]RESTStorage{"foo": simpleStorage})
|
||||||
"foo": simpleStorage,
|
|
||||||
}, codec, "/api", "version", selfLinker, admissionControl, requestContextMapper, mapper)
|
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
defer server.CloseClientConnections()
|
defer server.CloseClientConnections()
|
||||||
|
@ -30,7 +30,6 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
"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/v1beta1"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
|
||||||
@ -55,7 +54,6 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/resourcequotausage"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/resourcequotausage"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/secret"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/secret"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/ui"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/ui"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
@ -425,14 +423,14 @@ func (m *Master) init(c *Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apiVersions := []string{"v1beta1", "v1beta2"}
|
apiVersions := []string{"v1beta1", "v1beta2"}
|
||||||
if err := apiserver.NewAPIGroupVersion(m.api_v1beta1()).InstallREST(m.handlerContainer, c.APIPrefix, "v1beta1"); err != nil {
|
if err := m.api_v1beta1().InstallREST(m.handlerContainer); err != nil {
|
||||||
glog.Fatalf("Unable to setup API v1beta1: %v", err)
|
glog.Fatalf("Unable to setup API v1beta1: %v", err)
|
||||||
}
|
}
|
||||||
if err := apiserver.NewAPIGroupVersion(m.api_v1beta2()).InstallREST(m.handlerContainer, c.APIPrefix, "v1beta2"); err != nil {
|
if err := m.api_v1beta2().InstallREST(m.handlerContainer); err != nil {
|
||||||
glog.Fatalf("Unable to setup API v1beta2: %v", err)
|
glog.Fatalf("Unable to setup API v1beta2: %v", err)
|
||||||
}
|
}
|
||||||
if c.EnableV1Beta3 {
|
if c.EnableV1Beta3 {
|
||||||
if err := apiserver.NewAPIGroupVersion(m.api_v1beta3()).InstallREST(m.handlerContainer, c.APIPrefix, "v1beta3"); err != nil {
|
if err := m.api_v1beta3().InstallREST(m.handlerContainer); err != nil {
|
||||||
glog.Fatalf("Unable to setup API v1beta3: %v", err)
|
glog.Fatalf("Unable to setup API v1beta3: %v", err)
|
||||||
}
|
}
|
||||||
apiVersions = []string{"v1beta1", "v1beta2", "v1beta3"}
|
apiVersions = []string{"v1beta1", "v1beta2", "v1beta3"}
|
||||||
@ -569,26 +567,49 @@ func (m *Master) getServersToValidate(c *Config) map[string]apiserver.Server {
|
|||||||
return serversToValidate
|
return serversToValidate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Master) defaultAPIGroupVersion() *apiserver.APIGroupVersion {
|
||||||
|
return &apiserver.APIGroupVersion{
|
||||||
|
Root: m.apiPrefix,
|
||||||
|
|
||||||
|
Mapper: latest.RESTMapper,
|
||||||
|
|
||||||
|
Creater: api.Scheme,
|
||||||
|
Typer: api.Scheme,
|
||||||
|
Linker: latest.SelfLinker,
|
||||||
|
|
||||||
|
Admit: m.admissionControl,
|
||||||
|
Context: m.requestContextMapper,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// api_v1beta1 returns the resources and codec for API version v1beta1.
|
// api_v1beta1 returns the resources and codec for API version v1beta1.
|
||||||
func (m *Master) api_v1beta1() (map[string]apiserver.RESTStorage, runtime.Codec, string, string, runtime.SelfLinker, admission.Interface, api.RequestContextMapper, meta.RESTMapper) {
|
func (m *Master) api_v1beta1() *apiserver.APIGroupVersion {
|
||||||
storage := make(map[string]apiserver.RESTStorage)
|
storage := make(map[string]apiserver.RESTStorage)
|
||||||
for k, v := range m.storage {
|
for k, v := range m.storage {
|
||||||
storage[k] = v
|
storage[k] = v
|
||||||
}
|
}
|
||||||
return storage, v1beta1.Codec, "api", "/api/v1beta1", latest.SelfLinker, m.admissionControl, m.requestContextMapper, latest.RESTMapper
|
version := m.defaultAPIGroupVersion()
|
||||||
|
version.Storage = storage
|
||||||
|
version.Version = "v1beta1"
|
||||||
|
version.Codec = v1beta1.Codec
|
||||||
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
// api_v1beta2 returns the resources and codec for API version v1beta2.
|
// api_v1beta2 returns the resources and codec for API version v1beta2.
|
||||||
func (m *Master) api_v1beta2() (map[string]apiserver.RESTStorage, runtime.Codec, string, string, runtime.SelfLinker, admission.Interface, api.RequestContextMapper, meta.RESTMapper) {
|
func (m *Master) api_v1beta2() *apiserver.APIGroupVersion {
|
||||||
storage := make(map[string]apiserver.RESTStorage)
|
storage := make(map[string]apiserver.RESTStorage)
|
||||||
for k, v := range m.storage {
|
for k, v := range m.storage {
|
||||||
storage[k] = v
|
storage[k] = v
|
||||||
}
|
}
|
||||||
return storage, v1beta2.Codec, "api", "/api/v1beta2", latest.SelfLinker, m.admissionControl, m.requestContextMapper, latest.RESTMapper
|
version := m.defaultAPIGroupVersion()
|
||||||
|
version.Storage = storage
|
||||||
|
version.Version = "v1beta2"
|
||||||
|
version.Codec = v1beta2.Codec
|
||||||
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
// api_v1beta3 returns the resources and codec for API version v1beta3.
|
// api_v1beta3 returns the resources and codec for API version v1beta3.
|
||||||
func (m *Master) api_v1beta3() (map[string]apiserver.RESTStorage, runtime.Codec, string, string, runtime.SelfLinker, admission.Interface, api.RequestContextMapper, meta.RESTMapper) {
|
func (m *Master) api_v1beta3() *apiserver.APIGroupVersion {
|
||||||
storage := make(map[string]apiserver.RESTStorage)
|
storage := make(map[string]apiserver.RESTStorage)
|
||||||
for k, v := range m.storage {
|
for k, v := range m.storage {
|
||||||
if k == "minions" {
|
if k == "minions" {
|
||||||
@ -596,5 +617,9 @@ func (m *Master) api_v1beta3() (map[string]apiserver.RESTStorage, runtime.Codec,
|
|||||||
}
|
}
|
||||||
storage[strings.ToLower(k)] = v
|
storage[strings.ToLower(k)] = v
|
||||||
}
|
}
|
||||||
return storage, v1beta3.Codec, "api", "/api/v1beta3", latest.SelfLinker, m.admissionControl, m.requestContextMapper, latest.RESTMapper
|
version := m.defaultAPIGroupVersion()
|
||||||
|
version.Storage = storage
|
||||||
|
version.Version = "v1beta3"
|
||||||
|
version.Codec = v1beta3.Codec
|
||||||
|
return version
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,11 @@ type ObjectTyper interface {
|
|||||||
ObjectVersionAndKind(Object) (version, kind string, err error)
|
ObjectVersionAndKind(Object) (version, kind string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ObjectCreater contains methods for instantiating an object by kind and version.
|
||||||
|
type ObjectCreater interface {
|
||||||
|
New(version, kind string) (out Object, err error)
|
||||||
|
}
|
||||||
|
|
||||||
// ResourceVersioner provides methods for setting and retrieving
|
// ResourceVersioner provides methods for setting and retrieving
|
||||||
// the resource version from an API object.
|
// the resource version from an API object.
|
||||||
type ResourceVersioner interface {
|
type ResourceVersioner interface {
|
||||||
|
Loading…
Reference in New Issue
Block a user