diff --git a/cmd/kube-apiserver/app/BUILD b/cmd/kube-apiserver/app/BUILD index 3388c4fb6ec..b671a78ee65 100644 --- a/cmd/kube-apiserver/app/BUILD +++ b/cmd/kube-apiserver/app/BUILD @@ -82,7 +82,6 @@ go_library( "//vendor/k8s.io/apiserver/pkg/server:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/filters:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library", - "//vendor/k8s.io/apiserver/pkg/server/mux:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/options:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/storage:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", diff --git a/cmd/kube-apiserver/app/aggregator.go b/cmd/kube-apiserver/app/aggregator.go index 66f262c1c80..0107d12b8a6 100644 --- a/cmd/kube-apiserver/app/aggregator.go +++ b/cmd/kube-apiserver/app/aggregator.go @@ -30,7 +30,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/healthz" - "k8s.io/apiserver/pkg/server/mux" genericoptions "k8s.io/apiserver/pkg/server/options" kubeclientset "k8s.io/client-go/kubernetes" "k8s.io/kube-aggregator/pkg/apis/apiregistration" @@ -46,7 +45,6 @@ func createAggregatorConfig(kubeAPIServerConfig genericapiserver.Config, command // make a shallow copy to let us twiddle a few things // most of the config actually remains the same. We only need to mess with a couple items related to the particulars of the aggregator genericConfig := kubeAPIServerConfig - genericConfig.FallThroughHandler = mux.NewPathRecorderMux() // the aggregator doesn't wire these up. It just delegates them to the kubeapiserver genericConfig.EnableSwaggerUI = false diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 35915073c80..4b4c9768fe5 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -110,7 +110,7 @@ func Run(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) error { // run the insecure server now, don't block. It doesn't have any aggregator goodies since authentication wouldn't work if insecureServingOptions != nil { - insecureHandlerChain := kubeserver.BuildInsecureHandlerChain(kubeAPIServer.GenericAPIServer.HandlerContainer.ServeMux, kubeAPIServerConfig.GenericConfig) + insecureHandlerChain := kubeserver.BuildInsecureHandlerChain(kubeAPIServer.GenericAPIServer.UnprotectedHandler(), kubeAPIServerConfig.GenericConfig) if err := kubeserver.NonBlockingRun(insecureServingOptions, insecureHandlerChain, stopCh); err != nil { return err } @@ -139,7 +139,7 @@ func Run(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) error { // CreateKubeAPIServer creates and wires a workable kube-apiserver func CreateKubeAPIServer(kubeAPIServerConfig *master.Config, sharedInformers informers.SharedInformerFactory, stopCh <-chan struct{}) (*master.Master, error) { - kubeAPIServer, err := kubeAPIServerConfig.Complete().New() + kubeAPIServer, err := kubeAPIServerConfig.Complete().New(genericapiserver.EmptyDelegate) if err != nil { return nil, err } diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index 8cea7ece4fb..05a8d3e2fea 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -224,13 +224,13 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error { cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes) } - m, err := genericConfig.Complete().New() + m, err := genericConfig.Complete().New(genericapiserver.EmptyDelegate) if err != nil { return err } - routes.UIRedirect{}.Install(m.FallThroughHandler) - routes.Logs{}.Install(m.HandlerContainer) + routes.UIRedirect{}.Install(m.Handler.PostGoRestfulMux) + routes.Logs{}.Install(m.Handler.GoRestfulContainer) apiResourceConfigSource := storageFactory.APIResourceConfigSource installFederationAPIs(m, genericConfig.RESTOptionsGetter, apiResourceConfigSource) @@ -241,7 +241,7 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error { // run the insecure server now if insecureServingOptions != nil { - insecureHandlerChain := kubeserver.BuildInsecureHandlerChain(m.HandlerContainer.ServeMux, genericConfig) + insecureHandlerChain := kubeserver.BuildInsecureHandlerChain(m.UnprotectedHandler(), genericConfig) if err := kubeserver.NonBlockingRun(insecureServingOptions, insecureHandlerChain, stopCh); err != nil { return err } diff --git a/pkg/master/master.go b/pkg/master/master.go index fe5a810b55a..26d114ca29f 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -206,21 +206,21 @@ func (c *Config) SkipComplete() completedConfig { // Certain config fields will be set to a default value if unset. // Certain config fields must be specified, including: // KubeletClientConfig -func (c completedConfig) New() (*Master, error) { +func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget) (*Master, error) { if reflect.DeepEqual(c.KubeletClientConfig, kubeletclient.KubeletClientConfig{}) { return nil, fmt.Errorf("Master.New() called with empty config.KubeletClientConfig") } - s, err := c.Config.GenericConfig.SkipComplete().New() // completion is done in Complete, no need for a second time + s, err := c.Config.GenericConfig.SkipComplete().New(delegationTarget) // completion is done in Complete, no need for a second time if err != nil { return nil, err } if c.EnableUISupport { - routes.UIRedirect{}.Install(s.FallThroughHandler) + routes.UIRedirect{}.Install(s.Handler.PostGoRestfulMux) } if c.EnableLogsSupport { - routes.Logs{}.Install(s.HandlerContainer) + routes.Logs{}.Install(s.Handler.GoRestfulContainer) } m := &Master{ diff --git a/pkg/master/master_openapi_test.go b/pkg/master/master_openapi_test.go index 6f855a47d39..68ca925559e 100644 --- a/pkg/master/master_openapi_test.go +++ b/pkg/master/master_openapi_test.go @@ -53,13 +53,13 @@ func TestValidOpenAPISpec(t *testing.T) { } config.GenericConfig.SwaggerConfig = genericapiserver.DefaultSwaggerConfig() - master, err := config.Complete().New() + master, err := config.Complete().New(genericapiserver.EmptyDelegate) if err != nil { t.Fatalf("Error in bringing up the master: %v", err) } // make sure swagger.json is not registered before calling PrepareRun. - server := httptest.NewServer(master.GenericAPIServer.HandlerContainer.ServeMux) + server := httptest.NewServer(master.GenericAPIServer.Handler.GoRestfulContainer.ServeMux) defer server.Close() resp, err := http.Get(server.URL + "/swagger.json") if !assert.NoError(err) { diff --git a/pkg/master/master_test.go b/pkg/master/master_test.go index ca84297dbcb..57f46dd1fc0 100644 --- a/pkg/master/master_test.go +++ b/pkg/master/master_test.go @@ -107,7 +107,7 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion func newMaster(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) { etcdserver, config, assert := setUp(t) - master, err := config.Complete().New() + master, err := config.Complete().New(genericapiserver.EmptyDelegate) if err != nil { t.Fatalf("Error in bringing up the master: %v", err) } @@ -133,7 +133,7 @@ func limitedAPIResourceConfigSource() *serverstorage.ResourceConfig { func newLimitedMaster(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) { etcdserver, config, assert := setUp(t) config.APIResourceConfigSource = limitedAPIResourceConfigSource() - master, err := config.Complete().New() + master, err := config.Complete().New(genericapiserver.EmptyDelegate) if err != nil { t.Fatalf("Error in bringing up the master: %v", err) } @@ -226,7 +226,7 @@ func TestAPIVersionOfDiscoveryEndpoints(t *testing.T) { master, etcdserver, _, assert := newMaster(t) defer etcdserver.Terminate(t) - server := httptest.NewServer(master.GenericAPIServer.HandlerContainer.ServeMux) + server := httptest.NewServer(master.GenericAPIServer.Handler.GoRestfulContainer.ServeMux) // /api exists in release-1.1 resp, err := http.Get(server.URL + "/api") diff --git a/pkg/master/thirdparty/thirdparty.go b/pkg/master/thirdparty/thirdparty.go index 6542a00020c..d5228b89ccc 100644 --- a/pkg/master/thirdparty/thirdparty.go +++ b/pkg/master/thirdparty/thirdparty.go @@ -156,11 +156,11 @@ func (m *ThirdPartyResourceServer) RemoveThirdPartyResource(path string) error { return err } - services := m.genericAPIServer.HandlerContainer.RegisteredWebServices() + services := m.genericAPIServer.Handler.GoRestfulContainer.RegisteredWebServices() for ix := range services { root := services[ix].RootPath() if root == path || strings.HasPrefix(root, path+"/") { - m.genericAPIServer.HandlerContainer.Remove(services[ix]) + m.genericAPIServer.Handler.GoRestfulContainer.Remove(services[ix]) } } return nil @@ -281,13 +281,13 @@ func (m *ThirdPartyResourceServer) InstallThirdPartyResource(rsrc *extensions.Th // the group with the new API if m.hasThirdPartyGroupStorage(path) { m.addThirdPartyResourceStorage(path, plural.Resource, thirdparty.Storage[plural.Resource].(*thirdpartyresourcedatastore.REST), apiGroup) - return thirdparty.UpdateREST(m.genericAPIServer.HandlerContainer.Container) + return thirdparty.UpdateREST(m.genericAPIServer.Handler.GoRestfulContainer) } - if err := thirdparty.InstallREST(m.genericAPIServer.HandlerContainer.Container); err != nil { + if err := thirdparty.InstallREST(m.genericAPIServer.Handler.GoRestfulContainer); err != nil { glog.Errorf("Unable to setup thirdparty api: %v", err) } - m.genericAPIServer.HandlerContainer.Add(discovery.NewAPIGroupHandler(api.Codecs, apiGroup).WebService()) + m.genericAPIServer.Handler.GoRestfulContainer.Add(discovery.NewAPIGroupHandler(api.Codecs, apiGroup).WebService()) m.addThirdPartyResourceStorage(path, plural.Resource, thirdparty.Storage[plural.Resource].(*thirdpartyresourcedatastore.REST), apiGroup) api.Registry.AddThirdPartyAPIGroupVersions(schema.GroupVersion{Group: group, Version: rsrc.Versions[0].Name}) diff --git a/pkg/routes/logs.go b/pkg/routes/logs.go index 317d412cecc..cfe9b27de8b 100644 --- a/pkg/routes/logs.go +++ b/pkg/routes/logs.go @@ -21,14 +21,12 @@ import ( "path" "github.com/emicklei/go-restful" - - "k8s.io/apiserver/pkg/server/mux" ) // Logs adds handlers for the /logs path serving log files from /var/log. type Logs struct{} -func (l Logs) Install(c *mux.APIContainer) { +func (l Logs) Install(c *restful.Container) { // use restful: ws.Route(ws.GET("/logs/{logpath:*}").To(fileHandler)) // See github.com/emicklei/go-restful/blob/master/examples/restful-serve-static.go ws := new(restful.WebService) diff --git a/staging/src/k8s.io/apiserver/pkg/server/BUILD b/staging/src/k8s.io/apiserver/pkg/server/BUILD index 474f68999f1..69402d05bfe 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/server/BUILD @@ -35,7 +35,6 @@ go_test( "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library", - "//vendor/k8s.io/apiserver/pkg/server/mux:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library", ], @@ -48,6 +47,7 @@ go_library( "config_selfclient.go", "doc.go", "genericapiserver.go", + "handler.go", "healthz.go", "hooks.go", "serve.go", @@ -55,11 +55,13 @@ go_library( tags = ["automanaged"], deps = [ "//vendor/github.com/coreos/go-systemd/daemon:go_default_library", + "//vendor/github.com/emicklei/go-restful:go_default_library", "//vendor/github.com/emicklei/go-restful-swagger12:go_default_library", "//vendor/github.com/go-openapi/spec:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/pborman/uuid:go_default_library", "//vendor/github.com/pkg/errors:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", @@ -83,6 +85,7 @@ go_library( "//vendor/k8s.io/apiserver/pkg/endpoints:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/discovery:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/filters:go_default_library", + "//vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/openapi:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", diff --git a/staging/src/k8s.io/apiserver/pkg/server/config.go b/staging/src/k8s.io/apiserver/pkg/server/config.go index 26d56145559..a1e2db3b1fc 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/config.go @@ -53,7 +53,6 @@ import ( genericregistry "k8s.io/apiserver/pkg/registry/generic" genericfilters "k8s.io/apiserver/pkg/server/filters" "k8s.io/apiserver/pkg/server/healthz" - "k8s.io/apiserver/pkg/server/mux" "k8s.io/apiserver/pkg/server/routes" restclient "k8s.io/client-go/rest" certutil "k8s.io/client-go/util/cert" @@ -110,10 +109,6 @@ type Config struct { // Will default to a value based on secure serving info and available ipv4 IPs. ExternalAddress string - // FallThroughHandler is the final HTTP handler in the chain. If it is nil, one will be created for you. - // It comes after all filters and the API handling - FallThroughHandler *mux.PathRecorderMux - //=========================================================================== // Fields you probably don't care about changing //=========================================================================== @@ -312,6 +307,17 @@ func (c *Config) Complete() completedConfig { }, } } + + if c.OpenAPIConfig.Info == nil { + c.OpenAPIConfig.Info = &spec.Info{} + } + if c.OpenAPIConfig.Info.Version == "" { + if c.Version != nil { + c.OpenAPIConfig.Info.Version = strings.Split(c.Version.String(), "-")[0] + } else { + c.OpenAPIConfig.Info.Version = "unversioned" + } + } } if c.SwaggerConfig != nil && len(c.SwaggerConfig.WebServicesUrl) == 0 { if c.SecureServingInfo != nil { @@ -342,9 +348,6 @@ func (c *Config) Complete() completedConfig { tokenAuthorizer := authorizerfactory.NewPrivilegedGroups(user.SystemPrivilegedGroup) c.Authorizer = authorizerunion.New(tokenAuthorizer, c.Authorizer) } - if c.FallThroughHandler == nil { - c.FallThroughHandler = mux.NewPathRecorderMux() - } return completedConfig{c} } @@ -354,38 +357,10 @@ func (c *Config) SkipComplete() completedConfig { return completedConfig{c} } -// New returns a new instance of GenericAPIServer from the given config. -// Certain config fields will be set to a default value if unset, -// including: -// ServiceClusterIPRange -// ServiceNodePortRange -// MasterCount -// ReadWritePort -// PublicAddress -// Public fields: -// Handler -- The returned GenericAPIServer has a field TopHandler which is an -// http.Handler which handles all the endpoints provided by the GenericAPIServer, -// including the API, the UI, and miscellaneous debugging endpoints. All -// these are subject to authorization and authentication. -// InsecureHandler -- an http.Handler which handles all the same -// endpoints as Handler, but no authorization and authentication is done. -// Public methods: -// HandleWithAuth -- Allows caller to add an http.Handler for an endpoint -// that uses the same authentication and authorization (if any is configured) -// as the GenericAPIServer's built-in endpoints. -// If the caller wants to add additional endpoints not using the GenericAPIServer's -// auth, then the caller should create a handler for those endpoints, which delegates the -// any unhandled paths to "Handler". -func (c completedConfig) New() (*GenericAPIServer, error) { - s, err := c.constructServer() - if err != nil { - return nil, err - } +// New creates a new server which logically combines the handling chain with the passed server. +func (c completedConfig) New(delegationTarget DelegationTarget) (*GenericAPIServer, error) { + // The delegationTarget and the config must agree on the RequestContextMapper - return c.buildHandlers(s, nil) -} - -func (c completedConfig) constructServer() (*GenericAPIServer, error) { if c.Serializer == nil { return nil, fmt.Errorf("Genericapiserver.New() called with config.Serializer == nil") } @@ -393,7 +368,10 @@ func (c completedConfig) constructServer() (*GenericAPIServer, error) { return nil, fmt.Errorf("Genericapiserver.New() called with config.LoopbackClientConfig == nil") } - handlerContainer := mux.NewAPIContainer(http.NewServeMux(), c.Serializer, c.FallThroughHandler) + handlerChainBuilder := func(handler http.Handler) http.Handler { + return c.BuildHandlerChainFunc(handler, c.Config) + } + apiServerHandler := NewAPIServerHandler(c.Serializer, handlerChainBuilder, delegationTarget.UnprotectedHandler()) s := &GenericAPIServer{ discoveryAddresses: c.DiscoveryAddresses, @@ -408,10 +386,9 @@ func (c completedConfig) constructServer() (*GenericAPIServer, error) { SecureServingInfo: c.SecureServingInfo, ExternalAddress: c.ExternalAddress, - HandlerContainer: handlerContainer, - FallThroughHandler: c.FallThroughHandler, + Handler: apiServerHandler, - listedPathProvider: routes.ListedPathProviders{handlerContainer, c.FallThroughHandler}, + listedPathProvider: apiServerHandler, swaggerConfig: c.SwaggerConfig, openAPIConfig: c.OpenAPIConfig, @@ -424,20 +401,6 @@ func (c completedConfig) constructServer() (*GenericAPIServer, error) { DiscoveryGroupManager: discovery.NewRootAPIsHandler(c.DiscoveryAddresses, c.Serializer), } - return s, nil -} - -// NewWithDelegate creates a new server which logically combines the handling chain with the passed server. -func (c completedConfig) NewWithDelegate(delegationTarget DelegationTarget) (*GenericAPIServer, error) { - // some pieces of the delegationTarget take precendence. Callers should already have ensured that these - // were wired correctly. Documenting them here. - // c.RequestContextMapper = delegationTarget.RequestContextMapper() - - s, err := c.constructServer() - if err != nil { - return nil, err - } - for k, v := range delegationTarget.PostStartHooks() { s.postStartHooks[k] = v } @@ -459,38 +422,17 @@ func (c completedConfig) NewWithDelegate(delegationTarget DelegationTarget) (*Ge s.listedPathProvider = routes.ListedPathProviders{s.listedPathProvider, delegationTarget} + installAPI(s, c.Config) + // use the UnprotectedHandler from the delegation target to ensure that we don't attempt to double authenticator, authorize, // or some other part of the filter chain in delegation cases. - return c.buildHandlers(s, delegationTarget.UnprotectedHandler()) -} - -// buildHandlers builds our handling chain -func (c completedConfig) buildHandlers(s *GenericAPIServer, delegate http.Handler) (*GenericAPIServer, error) { - if s.openAPIConfig != nil { - if s.openAPIConfig.Info == nil { - s.openAPIConfig.Info = &spec.Info{} - } - if s.openAPIConfig.Info.Version == "" { - if c.Version != nil { - s.openAPIConfig.Info.Version = strings.Split(c.Version.String(), "-")[0] - } else { - s.openAPIConfig.Info.Version = "unversioned" - } - } - } - - installAPI(s, c.Config) - if delegate != nil { - s.FallThroughHandler.NotFoundHandler(delegate) - } else if c.EnableIndex { - s.FallThroughHandler.NotFoundHandler(routes.IndexLister{ + if delegationTarget.UnprotectedHandler() == nil && c.EnableIndex { + s.Handler.PostGoRestfulMux.NotFoundHandler(routes.IndexLister{ StatusCode: http.StatusNotFound, PathProvider: s.listedPathProvider, }) } - s.Handler = c.BuildHandlerChainFunc(s.HandlerContainer.ServeMux, c.Config) - return s, nil } @@ -510,28 +452,28 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler { func installAPI(s *GenericAPIServer, c *Config) { if c.EnableIndex { - routes.Index{}.Install(s.listedPathProvider, c.FallThroughHandler) + routes.Index{}.Install(s.listedPathProvider, s.Handler.PostGoRestfulMux) } if c.SwaggerConfig != nil && c.EnableSwaggerUI { - routes.SwaggerUI{}.Install(s.FallThroughHandler) + routes.SwaggerUI{}.Install(s.Handler.PostGoRestfulMux) } if c.EnableProfiling { - routes.Profiling{}.Install(s.FallThroughHandler) + routes.Profiling{}.Install(s.Handler.PostGoRestfulMux) if c.EnableContentionProfiling { goruntime.SetBlockProfileRate(1) } } if c.EnableMetrics { if c.EnableProfiling { - routes.MetricsWithReset{}.Install(s.FallThroughHandler) + routes.MetricsWithReset{}.Install(s.Handler.PostGoRestfulMux) } else { - routes.DefaultMetrics{}.Install(s.FallThroughHandler) + routes.DefaultMetrics{}.Install(s.Handler.PostGoRestfulMux) } } - routes.Version{Version: c.Version}.Install(s.HandlerContainer) + routes.Version{Version: c.Version}.Install(s.Handler.GoRestfulContainer) if c.EnableDiscovery { - s.HandlerContainer.Add(s.DiscoveryGroupManager.WebService()) + s.Handler.GoRestfulContainer.Add(s.DiscoveryGroupManager.WebService()) } } diff --git a/staging/src/k8s.io/apiserver/pkg/server/config_test.go b/staging/src/k8s.io/apiserver/pkg/server/config_test.go index 04a824d4b6e..acaab781c8d 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/config_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/config_test.go @@ -28,7 +28,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/server/healthz" - "k8s.io/apiserver/pkg/server/mux" "k8s.io/client-go/rest" ) @@ -38,7 +37,6 @@ func TestNewWithDelegate(t *testing.T) { delegateConfig.RequestContextMapper = genericapirequest.NewRequestContextMapper() delegateConfig.LegacyAPIGroupPrefixes = sets.NewString("/api") delegateConfig.LoopbackClientConfig = &rest.Config{} - delegateConfig.FallThroughHandler = mux.NewPathRecorderMux() delegateConfig.SwaggerConfig = DefaultSwaggerConfig() delegateHealthzCalled := false @@ -47,14 +45,13 @@ func TestNewWithDelegate(t *testing.T) { return fmt.Errorf("delegate failed healthcheck") })) - delegateConfig.FallThroughHandler.HandleFunc("/foo", func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusForbidden) - }) - - delegateServer, err := delegateConfig.SkipComplete().New() + delegateServer, err := delegateConfig.SkipComplete().New(EmptyDelegate) if err != nil { t.Fatal(err) } + delegateServer.Handler.PostGoRestfulMux.HandleFunc("/foo", func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusForbidden) + }) delegateServer.AddPostStartHook("delegate-post-start-hook", func(context PostStartHookContext) error { return nil @@ -68,7 +65,6 @@ func TestNewWithDelegate(t *testing.T) { wrappingConfig.RequestContextMapper = genericapirequest.NewRequestContextMapper() wrappingConfig.LegacyAPIGroupPrefixes = sets.NewString("/api") wrappingConfig.LoopbackClientConfig = &rest.Config{} - wrappingConfig.FallThroughHandler = mux.NewPathRecorderMux() wrappingConfig.SwaggerConfig = DefaultSwaggerConfig() wrappingHealthzCalled := false @@ -77,14 +73,13 @@ func TestNewWithDelegate(t *testing.T) { return fmt.Errorf("wrapping failed healthcheck") })) - wrappingConfig.FallThroughHandler.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusUnauthorized) - }) - - wrappingServer, err := wrappingConfig.Complete().NewWithDelegate(delegateServer) + wrappingServer, err := wrappingConfig.Complete().New(delegateServer) if err != nil { t.Fatal(err) } + wrappingServer.Handler.PostGoRestfulMux.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusUnauthorized) + }) wrappingServer.AddPostStartHook("wrapping-post-start-hook", func(context PostStartHookContext) error { return nil diff --git a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go index 52d5368d63f..4197209e827 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go +++ b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go @@ -42,8 +42,6 @@ import ( apirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/server/healthz" - "k8s.io/apiserver/pkg/server/mux" - genericmux "k8s.io/apiserver/pkg/server/mux" "k8s.io/apiserver/pkg/server/routes" restclient "k8s.io/client-go/rest" ) @@ -101,9 +99,6 @@ type GenericAPIServer struct { // requestContextMapper provides a way to get the context for a request. It may be nil. requestContextMapper apirequest.RequestContextMapper - // The registered APIs - HandlerContainer *genericmux.APIContainer - SecureServingInfo *SecureServingInfo // numerical ports, set after listening @@ -121,10 +116,8 @@ type GenericAPIServer struct { Serializer runtime.NegotiatedSerializer // "Outputs" - Handler http.Handler - // FallThroughHandler is the final HTTP handler in the chain. - // It comes after all filters and the API handling - FallThroughHandler *mux.PathRecorderMux + // Handler holdes the handlers being used by this API server + Handler *APIServerHandler // listedPathProvider is a lister which provides the set of paths to show at / listedPathProvider routes.ListedPathProvider @@ -171,7 +164,7 @@ type DelegationTarget interface { } func (s *GenericAPIServer) UnprotectedHandler() http.Handler { - return s.HandlerContainer.ServeMux + return s.Handler.GoRestfulContainer.ServeMux } func (s *GenericAPIServer) PostStartHooks() map[string]postStartHookEntry { return s.postStartHooks @@ -233,12 +226,12 @@ type preparedGenericAPIServer struct { // PrepareRun does post API installation setup steps. func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer { if s.swaggerConfig != nil { - routes.Swagger{Config: s.swaggerConfig}.Install(s.HandlerContainer) + routes.Swagger{Config: s.swaggerConfig}.Install(s.Handler.GoRestfulContainer) } if s.openAPIConfig != nil { routes.OpenAPI{ Config: s.openAPIConfig, - }.Install(s.HandlerContainer, s.FallThroughHandler) + }.Install(s.Handler.GoRestfulContainer, s.Handler.PostGoRestfulMux) } s.installHealthz() @@ -306,7 +299,7 @@ func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *A apiGroupVersion.OptionsExternalVersion = apiGroupInfo.OptionsExternalVersion } - if err := apiGroupVersion.InstallREST(s.HandlerContainer.Container); err != nil { + if err := apiGroupVersion.InstallREST(s.Handler.GoRestfulContainer); err != nil { return fmt.Errorf("Unable to setup API %v: %v", apiGroupInfo, err) } } @@ -329,7 +322,7 @@ func (s *GenericAPIServer) InstallLegacyAPIGroup(apiPrefix string, apiGroupInfo } // Install the version handler. // Add a handler at / to enumerate the supported api versions. - s.HandlerContainer.Add(discovery.NewLegacyRootAPIHandler(s.discoveryAddresses, s.Serializer, apiPrefix, apiVersions).WebService()) + s.Handler.GoRestfulContainer.Add(discovery.NewLegacyRootAPIHandler(s.discoveryAddresses, s.Serializer, apiPrefix, apiVersions).WebService()) return nil } @@ -373,7 +366,7 @@ func (s *GenericAPIServer) InstallAPIGroup(apiGroupInfo *APIGroupInfo) error { } s.DiscoveryGroupManager.AddGroup(apiGroup) - s.HandlerContainer.Add(discovery.NewAPIGroupHandler(s.Serializer, apiGroup).WebService()) + s.Handler.GoRestfulContainer.Add(discovery.NewAPIGroupHandler(s.Serializer, apiGroup).WebService()) return nil } diff --git a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver_test.go b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver_test.go index b32124e407a..6dfb340861f 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver_test.go @@ -47,7 +47,6 @@ import ( "k8s.io/apiserver/pkg/endpoints/discovery" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/apiserver/pkg/server/mux" etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing" restclient "k8s.io/client-go/rest" ) @@ -90,7 +89,6 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion config.RequestContextMapper = genericapirequest.NewRequestContextMapper() config.LegacyAPIGroupPrefixes = sets.NewString("/api") config.LoopbackClientConfig = &restclient.Config{} - config.FallThroughHandler = mux.NewPathRecorderMux() // TODO restore this test, but right now, eliminate our cycle // config.OpenAPIConfig = DefaultOpenAPIConfig(testGetOpenAPIDefinitions, runtime.NewScheme()) @@ -108,7 +106,7 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion func newMaster(t *testing.T) (*GenericAPIServer, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) { etcdserver, config, assert := setUp(t) - s, err := config.Complete().New() + s, err := config.Complete().New(EmptyDelegate) if err != nil { t.Fatalf("Error in bringing up the server: %v", err) } @@ -140,7 +138,7 @@ func TestInstallAPIGroups(t *testing.T) { config.LegacyAPIGroupPrefixes = sets.NewString("/apiPrefix") config.DiscoveryAddresses = discovery.DefaultAddresses{DefaultAddress: "ExternalAddress"} - s, err := config.SkipComplete().New() + s, err := config.SkipComplete().New(EmptyDelegate) if err != nil { t.Fatalf("Error in bringing up the server: %v", err) } @@ -304,7 +302,7 @@ func TestPrepareRun(t *testing.T) { assert.NotNil(config.SwaggerConfig) // assert.NotNil(config.OpenAPIConfig) - server := httptest.NewServer(s.HandlerContainer.ServeMux) + server := httptest.NewServer(s.Handler.GoRestfulContainer.ServeMux) defer server.Close() s.PrepareRun() @@ -345,13 +343,13 @@ func TestCustomHandlerChain(t *testing.T) { called = true }) - s, err := config.SkipComplete().New() + s, err := config.SkipComplete().New(EmptyDelegate) if err != nil { t.Fatalf("Error in bringing up the server: %v", err) } - s.FallThroughHandler.Handle("/nonswagger", handler) - s.FallThroughHandler.Handle("/secret", handler) + s.Handler.PostGoRestfulMux.Handle("/nonswagger", handler) + s.Handler.PostGoRestfulMux.Handle("/secret", handler) type Test struct { handler http.Handler @@ -400,7 +398,7 @@ func TestNotRestRoutesHaveAuth(t *testing.T) { kubeVersion := fakeVersion() config.Version = &kubeVersion - s, err := config.SkipComplete().New() + s, err := config.SkipComplete().New(EmptyDelegate) if err != nil { t.Fatalf("Error in bringing up the server: %v", err) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/handler.go b/staging/src/k8s.io/apiserver/pkg/server/handler.go new file mode 100644 index 00000000000..7c205f005c5 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/server/handler.go @@ -0,0 +1,128 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package server + +import ( + "bytes" + "fmt" + "net/http" + rt "runtime" + "sort" + + "github.com/emicklei/go-restful" + "github.com/golang/glog" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" + "k8s.io/apiserver/pkg/server/mux" + genericmux "k8s.io/apiserver/pkg/server/mux" +) + +// APIServerHandlers holds the different http.Handlers used by the API server. +// This includes the full handler chain, the gorestful handler (used for the API) which falls through to the postGoRestful handler +// and the postGoRestful handler (which can contain a fallthrough of its own) +type APIServerHandler struct { + // FullHandlerChain is the one that is eventually served with. It should include the full filter + // chain and then call the GoRestfulContainer. + FullHandlerChain http.Handler + // The registered APIs + GoRestfulContainer *restful.Container + // PostGoRestfulMux is the final HTTP handler in the chain. + // It comes after all filters and the API handling + PostGoRestfulMux *mux.PathRecorderMux +} + +// HandlerChainBuilderFn is used to wrap the GoRestfulContainer handler using the provided handler chain. +// It is normally used to apply filtering like authentication and authorization +type HandlerChainBuilderFn func(apiHandler http.Handler) http.Handler + +func NewAPIServerHandler(s runtime.NegotiatedSerializer, handlerChainBuilder HandlerChainBuilderFn, notFoundHandler http.Handler) *APIServerHandler { + postGoRestfulMux := genericmux.NewPathRecorderMux() + if notFoundHandler != nil { + postGoRestfulMux.NotFoundHandler(notFoundHandler) + } + + gorestfulContainer := restful.NewContainer() + gorestfulContainer.ServeMux = http.NewServeMux() + gorestfulContainer.Router(restful.CurlyRouter{}) // e.g. for proxy/{kind}/{name}/{*} + gorestfulContainer.RecoverHandler(func(panicReason interface{}, httpWriter http.ResponseWriter) { + logStackOnRecover(s, panicReason, httpWriter) + }) + gorestfulContainer.ServiceErrorHandler(func(serviceErr restful.ServiceError, request *restful.Request, response *restful.Response) { + serviceErrorHandler(s, serviceErr, request, response) + }) + + // register the defaultHandler for everything. This will allow an unhandled request to fall through to another handler instead of + // ending up with a forced 404 + gorestfulContainer.Handle("/", postGoRestfulMux) + + return &APIServerHandler{ + FullHandlerChain: handlerChainBuilder(gorestfulContainer.ServeMux), + GoRestfulContainer: gorestfulContainer, + PostGoRestfulMux: postGoRestfulMux, + } +} + +// ListedPaths returns the paths that should be shown under / +func (a *APIServerHandler) ListedPaths() []string { + var handledPaths []string + // Extract the paths handled using restful.WebService + for _, ws := range a.GoRestfulContainer.RegisteredWebServices() { + handledPaths = append(handledPaths, ws.RootPath()) + } + handledPaths = append(handledPaths, a.PostGoRestfulMux.ListedPaths()...) + sort.Strings(handledPaths) + + return handledPaths +} + +//TODO: Unify with RecoverPanics? +func logStackOnRecover(s runtime.NegotiatedSerializer, panicReason interface{}, w http.ResponseWriter) { + var buffer bytes.Buffer + buffer.WriteString(fmt.Sprintf("recover from panic situation: - %v\r\n", panicReason)) + for i := 2; ; i++ { + _, file, line, ok := rt.Caller(i) + if !ok { + break + } + buffer.WriteString(fmt.Sprintf(" %s:%d\r\n", file, line)) + } + glog.Errorln(buffer.String()) + + headers := http.Header{} + if ct := w.Header().Get("Content-Type"); len(ct) > 0 { + headers.Set("Accept", ct) + } + responsewriters.ErrorNegotiated(apierrors.NewGenericServerResponse(http.StatusInternalServerError, "", schema.GroupResource{}, "", "", 0, false), s, schema.GroupVersion{}, w, &http.Request{Header: headers}) +} + +func serviceErrorHandler(s runtime.NegotiatedSerializer, serviceErr restful.ServiceError, request *restful.Request, resp *restful.Response) { + responsewriters.ErrorNegotiated( + apierrors.NewGenericServerResponse(serviceErr.Code, "", schema.GroupResource{}, "", serviceErr.Message, 0, false), + s, + schema.GroupVersion{}, + resp, + request.Request, + ) +} + +// ServeHTTP makes it an http.Handler +func (a *APIServerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + a.FullHandlerChain.ServeHTTP(w, r) +} diff --git a/staging/src/k8s.io/apiserver/pkg/server/healthz.go b/staging/src/k8s.io/apiserver/pkg/server/healthz.go index 2d9116cab9e..527917478d3 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/healthz.go +++ b/staging/src/k8s.io/apiserver/pkg/server/healthz.go @@ -41,5 +41,5 @@ func (s *GenericAPIServer) installHealthz() { defer s.healthzLock.Unlock() s.healthzCreated = true - healthz.InstallHandler(s.FallThroughHandler, s.healthzChecks...) + healthz.InstallHandler(s.Handler.PostGoRestfulMux, s.healthzChecks...) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/mux/BUILD b/staging/src/k8s.io/apiserver/pkg/server/mux/BUILD index 992a4b6934c..16b6684df21 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/mux/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/server/mux/BUILD @@ -19,19 +19,12 @@ go_test( go_library( name = "go_default_library", srcs = [ - "container.go", "doc.go", "pathrecorder.go", ], tags = ["automanaged"], deps = [ - "//vendor/github.com/emicklei/go-restful:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", - "//vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters:go_default_library", ], ) diff --git a/staging/src/k8s.io/apiserver/pkg/server/mux/container.go b/staging/src/k8s.io/apiserver/pkg/server/mux/container.go deleted file mode 100644 index f2598e1a269..00000000000 --- a/staging/src/k8s.io/apiserver/pkg/server/mux/container.go +++ /dev/null @@ -1,102 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package mux - -import ( - "bytes" - "fmt" - "net/http" - rt "runtime" - "sort" - - "github.com/emicklei/go-restful" - "github.com/golang/glog" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" -) - -// APIContainer is a restful container which in addition support registering -// handlers that do not show up in swagger or in / -type APIContainer struct { - *restful.Container -} - -// NewAPIContainer constructs a new container for APIs -func NewAPIContainer(mux *http.ServeMux, s runtime.NegotiatedSerializer, defaultMux http.Handler) *APIContainer { - c := APIContainer{ - Container: restful.NewContainer(), - } - c.Container.ServeMux = mux - c.Container.Router(restful.CurlyRouter{}) // e.g. for proxy/{kind}/{name}/{*} - c.Container.RecoverHandler(func(panicReason interface{}, httpWriter http.ResponseWriter) { - logStackOnRecover(s, panicReason, httpWriter) - }) - c.Container.ServiceErrorHandler(func(serviceErr restful.ServiceError, request *restful.Request, response *restful.Response) { - serviceErrorHandler(s, serviceErr, request, response) - }) - - // register the defaultHandler for everything. This will allow an unhandled request to fall through to another handler instead of - // ending up with a forced 404 - c.Container.Handle("/", defaultMux) - - return &c -} - -// ListedPaths returns the paths of the webservices for listing on /. -func (c *APIContainer) ListedPaths() []string { - var handledPaths []string - // Extract the paths handled using restful.WebService - for _, ws := range c.RegisteredWebServices() { - handledPaths = append(handledPaths, ws.RootPath()) - } - sort.Strings(handledPaths) - - return handledPaths -} - -//TODO: Unify with RecoverPanics? -func logStackOnRecover(s runtime.NegotiatedSerializer, panicReason interface{}, w http.ResponseWriter) { - var buffer bytes.Buffer - buffer.WriteString(fmt.Sprintf("recover from panic situation: - %v\r\n", panicReason)) - for i := 2; ; i++ { - _, file, line, ok := rt.Caller(i) - if !ok { - break - } - buffer.WriteString(fmt.Sprintf(" %s:%d\r\n", file, line)) - } - glog.Errorln(buffer.String()) - - headers := http.Header{} - if ct := w.Header().Get("Content-Type"); len(ct) > 0 { - headers.Set("Accept", ct) - } - responsewriters.ErrorNegotiated(apierrors.NewGenericServerResponse(http.StatusInternalServerError, "", schema.GroupResource{}, "", "", 0, false), s, schema.GroupVersion{}, w, &http.Request{Header: headers}) -} - -func serviceErrorHandler(s runtime.NegotiatedSerializer, serviceErr restful.ServiceError, request *restful.Request, resp *restful.Response) { - responsewriters.ErrorNegotiated( - apierrors.NewGenericServerResponse(serviceErr.Code, "", schema.GroupResource{}, "", serviceErr.Message, 0, false), - s, - schema.GroupVersion{}, - resp, - request.Request, - ) -} diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go b/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go index 4d974d22f4a..ec4d8e8edca 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go @@ -475,7 +475,7 @@ NextTest: return } - s, err := config.Complete().New() + s, err := config.Complete().New(server.EmptyDelegate) if err != nil { t.Errorf("%q - failed creating the server: %v", title, err) return diff --git a/staging/src/k8s.io/apiserver/pkg/server/routes/openapi.go b/staging/src/k8s.io/apiserver/pkg/server/routes/openapi.go index a547e00e3f9..9ced93008f7 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/openapi.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/openapi.go @@ -17,6 +17,8 @@ limitations under the License. package routes import ( + "github.com/emicklei/go-restful" + "k8s.io/apimachinery/pkg/openapi" "k8s.io/apiserver/pkg/server/mux" apiserveropenapi "k8s.io/apiserver/pkg/server/openapi" @@ -30,7 +32,7 @@ type OpenAPI struct { } // Install adds the SwaggerUI webservice to the given mux. -func (oa OpenAPI) Install(c *mux.APIContainer, mux *mux.PathRecorderMux) { +func (oa OpenAPI) Install(c *restful.Container, mux *mux.PathRecorderMux) { err := apiserveropenapi.RegisterOpenAPIService("/swagger.json", c.RegisteredWebServices(), oa.Config, mux) if err != nil { glog.Fatalf("Failed to register open api spec for root: %v", err) diff --git a/staging/src/k8s.io/apiserver/pkg/server/routes/swagger.go b/staging/src/k8s.io/apiserver/pkg/server/routes/swagger.go index 90f0abf7646..08e342ef568 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/swagger.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/swagger.go @@ -17,8 +17,7 @@ limitations under the License. package routes import ( - "k8s.io/apiserver/pkg/server/mux" - + "github.com/emicklei/go-restful" "github.com/emicklei/go-restful-swagger12" ) @@ -31,7 +30,7 @@ type Swagger struct { } // Install adds the SwaggerUI webservice to the given mux. -func (s Swagger) Install(c *mux.APIContainer) { +func (s Swagger) Install(c *restful.Container) { s.Config.WebServices = c.RegisteredWebServices() - swagger.RegisterSwaggerService(*s.Config, c.Container) + swagger.RegisterSwaggerService(*s.Config, c) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/routes/version.go b/staging/src/k8s.io/apiserver/pkg/server/routes/version.go index a1c3c6ad73f..dd9ab0dcfe5 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/version.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/version.go @@ -23,7 +23,6 @@ import ( "k8s.io/apimachinery/pkg/version" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" - "k8s.io/apiserver/pkg/server/mux" ) // Version provides a webservice with version information. @@ -32,7 +31,7 @@ type Version struct { } // Install registers the APIServer's `/version` handler. -func (v Version) Install(c *mux.APIContainer) { +func (v Version) Install(c *restful.Container) { if v.Version == nil { return } diff --git a/staging/src/k8s.io/kube-aggregator/pkg/apiserver/apiserver.go b/staging/src/k8s.io/kube-aggregator/pkg/apiserver/apiserver.go index 76f52d9cbff..6de74e316d1 100644 --- a/staging/src/k8s.io/kube-aggregator/pkg/apiserver/apiserver.go +++ b/staging/src/k8s.io/kube-aggregator/pkg/apiserver/apiserver.go @@ -135,7 +135,7 @@ func (c *Config) SkipComplete() completedConfig { // New returns a new instance of APIAggregator from the given config. func (c completedConfig) NewWithDelegate(delegationTarget genericapiserver.DelegationTarget, stopCh <-chan struct{}) (*APIAggregator, error) { - genericServer, err := c.Config.GenericConfig.SkipComplete().NewWithDelegate(delegationTarget) // completion is done in Complete, no need for a second time + genericServer, err := c.Config.GenericConfig.SkipComplete().New(delegationTarget) // completion is done in Complete, no need for a second time if err != nil { return nil, err } @@ -176,8 +176,8 @@ func (c completedConfig) NewWithDelegate(delegationTarget genericapiserver.Deleg serviceLister: s.serviceLister, endpointsLister: s.endpointsLister, } - s.GenericAPIServer.FallThroughHandler.Handle("/apis", apisHandler) - s.GenericAPIServer.FallThroughHandler.UnlistedHandle("/apis/", apisHandler) + s.GenericAPIServer.Handler.PostGoRestfulMux.Handle("/apis", apisHandler) + s.GenericAPIServer.Handler.PostGoRestfulMux.UnlistedHandle("/apis/", apisHandler) apiserviceRegistrationController := NewAPIServiceRegistrationController(informerFactory.Apiregistration().InternalVersion().APIServices(), kubeInformers.Core().V1().Services(), s) @@ -219,8 +219,8 @@ func (s *APIAggregator) AddAPIService(apiService *apiregistration.APIService, de } proxyHandler.updateAPIService(apiService, destinationHost) s.proxyHandlers[apiService.Name] = proxyHandler - s.GenericAPIServer.FallThroughHandler.Handle(proxyPath, proxyHandler) - s.GenericAPIServer.FallThroughHandler.UnlistedHandle(proxyPath+"/", proxyHandler) + s.GenericAPIServer.Handler.PostGoRestfulMux.Handle(proxyPath, proxyHandler) + s.GenericAPIServer.Handler.PostGoRestfulMux.UnlistedHandlePrefix(proxyPath+"/", proxyHandler) // if we're dealing with the legacy group, we're done here if apiService.Name == legacyAPIServiceName { @@ -243,8 +243,8 @@ func (s *APIAggregator) AddAPIService(apiService *apiregistration.APIService, de delegate: s.delegateHandler, } // aggregation is protected - s.GenericAPIServer.FallThroughHandler.Handle(groupPath, groupDiscoveryHandler) - s.GenericAPIServer.FallThroughHandler.UnlistedHandle(groupPath+"/", groupDiscoveryHandler) + s.GenericAPIServer.Handler.PostGoRestfulMux.Handle(groupPath, groupDiscoveryHandler) + s.GenericAPIServer.Handler.PostGoRestfulMux.UnlistedHandle(groupPath+"/", groupDiscoveryHandler) s.handledGroups.Insert(apiService.Spec.Group) } @@ -258,8 +258,8 @@ func (s *APIAggregator) RemoveAPIService(apiServiceName string) { if apiServiceName == legacyAPIServiceName { proxyPath = "/api" } - s.GenericAPIServer.FallThroughHandler.Unregister(proxyPath) - s.GenericAPIServer.FallThroughHandler.Unregister(proxyPath + "/") + s.GenericAPIServer.Handler.PostGoRestfulMux.Unregister(proxyPath) + s.GenericAPIServer.Handler.PostGoRestfulMux.Unregister(proxyPath + "/") delete(s.proxyHandlers, apiServiceName) // TODO unregister group level discovery when there are no more versions for the group diff --git a/staging/src/k8s.io/kube-apiextensions-server/pkg/apiserver/apiserver.go b/staging/src/k8s.io/kube-apiextensions-server/pkg/apiserver/apiserver.go index abb05d970d6..9322d33a63f 100644 --- a/staging/src/k8s.io/kube-apiextensions-server/pkg/apiserver/apiserver.go +++ b/staging/src/k8s.io/kube-apiextensions-server/pkg/apiserver/apiserver.go @@ -102,7 +102,7 @@ func (c *Config) SkipComplete() completedConfig { // New returns a new instance of CustomResources from the given config. func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget, stopCh <-chan struct{}) (*CustomResources, error) { - genericServer, err := c.Config.GenericConfig.SkipComplete().New() // completion is done in Complete, no need for a second time + genericServer, err := c.Config.GenericConfig.SkipComplete().New(genericapiserver.EmptyDelegate) // completion is done in Complete, no need for a second time if err != nil { return nil, err } @@ -149,8 +149,8 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget, c.CustomResourceRESTOptionsGetter, c.GenericConfig.AdmissionControl, ) - s.GenericAPIServer.FallThroughHandler.Handle("/apis", customResourceHandler) - s.GenericAPIServer.FallThroughHandler.HandlePrefix("/apis/", customResourceHandler) + s.GenericAPIServer.Handler.PostGoRestfulMux.Handle("/apis", customResourceHandler) + s.GenericAPIServer.Handler.PostGoRestfulMux.HandlePrefix("/apis/", customResourceHandler) customResourceController := NewDiscoveryController(customResourceInformers.Apiextensions().InternalVersion().CustomResources(), versionDiscoveryHandler, groupDiscoveryHandler) diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apiserver/apiserver.go b/staging/src/k8s.io/sample-apiserver/pkg/apiserver/apiserver.go index 95ed82fb251..f014e7f92b9 100644 --- a/staging/src/k8s.io/sample-apiserver/pkg/apiserver/apiserver.go +++ b/staging/src/k8s.io/sample-apiserver/pkg/apiserver/apiserver.go @@ -90,7 +90,7 @@ func (c *Config) SkipComplete() completedConfig { // New returns a new instance of WardleServer from the given config. func (c completedConfig) New() (*WardleServer, error) { - genericServer, err := c.Config.GenericConfig.SkipComplete().New() // completion is done in Complete, no need for a second time + genericServer, err := c.Config.GenericConfig.SkipComplete().New(genericapiserver.EmptyDelegate) // completion is done in Complete, no need for a second time if err != nil { return nil, err } diff --git a/test/integration/framework/master_utils.go b/test/integration/framework/master_utils.go index d702003b7d9..8f6c7471444 100644 --- a/test/integration/framework/master_utils.go +++ b/test/integration/framework/master_utils.go @@ -236,7 +236,7 @@ func startMasterOrDie(masterConfig *master.Config, incomingServer *httptest.Serv masterConfig.GenericConfig.LoopbackClientConfig.BearerToken = privilegedLoopbackToken - m, err := masterConfig.Complete().New() + m, err := masterConfig.Complete().New(genericapiserver.EmptyDelegate) if err != nil { glog.Fatalf("error in bringing up the master: %v", err) }