diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index 95d1948b6d1..212e0e4f1a8 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -223,7 +223,7 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error { return err } - routes.UIRedirect{}.Install(m.HandlerContainer) + routes.UIRedirect{}.Install(m.FallThroughHandler) routes.Logs{}.Install(m.HandlerContainer) installFederationAPIs(m, genericConfig.RESTOptionsGetter) diff --git a/pkg/master/master.go b/pkg/master/master.go index ea0f87232b3..ce73d414f72 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -216,7 +216,7 @@ func (c completedConfig) New() (*Master, error) { } if c.EnableUISupport { - routes.UIRedirect{}.Install(s.HandlerContainer) + routes.UIRedirect{}.Install(s.FallThroughHandler) } if c.EnableLogsSupport { routes.Logs{}.Install(s.HandlerContainer) diff --git a/pkg/master/master_openapi_test.go b/pkg/master/master_openapi_test.go index d4f96bdf490..6f855a47d39 100644 --- a/pkg/master/master_openapi_test.go +++ b/pkg/master/master_openapi_test.go @@ -40,7 +40,7 @@ import ( // TestValidOpenAPISpec verifies that the open api is added // at the proper endpoint and the spec is valid. func TestValidOpenAPISpec(t *testing.T) { - _, etcdserver, config, assert := setUp(t) + etcdserver, config, assert := setUp(t) defer etcdserver.Terminate(t) config.GenericConfig.EnableIndex = true diff --git a/pkg/master/master_test.go b/pkg/master/master_test.go index 3f640e0df40..44114f4077a 100644 --- a/pkg/master/master_test.go +++ b/pkg/master/master_test.go @@ -60,7 +60,7 @@ import ( ) // setUp is a convience function for setting up for (most) tests. -func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) { +func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertions) { server, storageConfig := etcdtesting.NewUnsecuredEtcd3TestClientServer(t, api.Scheme) config := &Config{ @@ -101,16 +101,11 @@ func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert. TLSClientConfig: &tls.Config{}, }) - master, err := config.Complete().New() - if err != nil { - t.Fatal(err) - } - - return master, server, *config, assert.New(t) + return server, *config, assert.New(t) } func newMaster(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) { - _, etcdserver, config, assert := setUp(t) + etcdserver, config, assert := setUp(t) master, err := config.Complete().New() if err != nil { @@ -136,7 +131,7 @@ func limitedAPIResourceConfigSource() *serverstorage.ResourceConfig { // newLimitedMaster only enables the core group, the extensions group, the batch group, and the autoscaling group. func newLimitedMaster(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) { - _, etcdserver, config, assert := setUp(t) + etcdserver, config, assert := setUp(t) config.APIResourceConfigSource = limitedAPIResourceConfigSource() master, err := config.Complete().New() if err != nil { diff --git a/pkg/routes/ui.go b/pkg/routes/ui.go index 0d4b85e06c6..fd7baf1f394 100644 --- a/pkg/routes/ui.go +++ b/pkg/routes/ui.go @@ -27,8 +27,8 @@ const dashboardPath = "/api/v1/namespaces/kube-system/services/kubernetes-dashbo // UIRediect redirects /ui to the kube-ui proxy path. type UIRedirect struct{} -func (r UIRedirect) Install(c *mux.APIContainer) { - c.NonSwaggerRoutes.HandleFunc("/ui/", func(w http.ResponseWriter, r *http.Request) { +func (r UIRedirect) Install(c *mux.PathRecorderMux) { + c.HandleFunc("/ui/", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, dashboardPath, http.StatusTemporaryRedirect) }) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/config.go b/staging/src/k8s.io/apiserver/pkg/server/config.go index 01fc5adc958..059ef95635b 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/config.go @@ -107,6 +107,10 @@ 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 //=========================================================================== @@ -337,6 +341,9 @@ 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} } @@ -392,6 +399,8 @@ func (c completedConfig) New() (*GenericAPIServer, error) { apiGroupsForDiscovery: map[string]metav1.APIGroup{}, + FallThroughHandler: c.FallThroughHandler, + swaggerConfig: c.SwaggerConfig, openAPIConfig: c.OpenAPIConfig, @@ -399,7 +408,7 @@ func (c completedConfig) New() (*GenericAPIServer, error) { healthzChecks: c.HealthzChecks, } - s.HandlerContainer = mux.NewAPIContainer(http.NewServeMux(), c.Serializer) + s.HandlerContainer = mux.NewAPIContainer(http.NewServeMux(), c.Serializer, s.FallThroughHandler) if s.openAPIConfig != nil { if s.openAPIConfig.Info == nil { @@ -447,22 +456,22 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) (secure, insec func (s *GenericAPIServer) installAPI(c *Config) { if c.EnableIndex { - routes.Index{}.Install(s.HandlerContainer) + routes.Index{}.Install(s.HandlerContainer, s.FallThroughHandler) } if c.SwaggerConfig != nil && c.EnableSwaggerUI { - routes.SwaggerUI{}.Install(s.HandlerContainer) + routes.SwaggerUI{}.Install(s.FallThroughHandler) } if c.EnableProfiling { - routes.Profiling{}.Install(s.HandlerContainer) + routes.Profiling{}.Install(s.FallThroughHandler) if c.EnableContentionProfiling { goruntime.SetBlockProfileRate(1) } } if c.EnableMetrics { if c.EnableProfiling { - routes.MetricsWithReset{}.Install(s.HandlerContainer) + routes.MetricsWithReset{}.Install(s.FallThroughHandler) } else { - routes.DefaultMetrics{}.Install(s.HandlerContainer) + routes.DefaultMetrics{}.Install(s.FallThroughHandler) } } routes.Version{Version: c.Version}.Install(s.HandlerContainer) diff --git a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go index e129120bcf1..68e15287295 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go +++ b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go @@ -44,6 +44,7 @@ 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" @@ -125,6 +126,9 @@ type GenericAPIServer struct { // "Outputs" Handler http.Handler InsecureHandler http.Handler + // FallThroughHandler is the final HTTP handler in the chain. + // It comes after all filters and the API handling + FallThroughHandler *mux.PathRecorderMux // Map storing information about all groups to be exposed in discovery response. // The map is from name to the group. @@ -179,7 +183,7 @@ func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer { if s.openAPIConfig != nil { routes.OpenAPI{ Config: s.openAPIConfig, - }.Install(s.HandlerContainer) + }.Install(s.HandlerContainer, s.FallThroughHandler) } s.installHealthz() 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 d2895b1d5cd..77527fa2a83 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver_test.go @@ -48,6 +48,7 @@ import ( "k8s.io/apiserver/pkg/authorization/authorizer" 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,6 +91,7 @@ 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()) @@ -352,8 +354,8 @@ func TestCustomHandlerChain(t *testing.T) { t.Fatalf("Error in bringing up the server: %v", err) } - s.HandlerContainer.NonSwaggerRoutes.Handle("/nonswagger", handler) - s.HandlerContainer.UnlistedRoutes.Handle("/secret", handler) + s.FallThroughHandler.Handle("/nonswagger", handler) + s.FallThroughHandler.Handle("/secret", handler) type Test struct { handler http.Handler diff --git a/staging/src/k8s.io/apiserver/pkg/server/healthz.go b/staging/src/k8s.io/apiserver/pkg/server/healthz.go index db8a132c4ee..2d9116cab9e 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.HandlerContainer.NonSwaggerRoutes, s.healthzChecks...) + healthz.InstallHandler(s.FallThroughHandler, s.healthzChecks...) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/mux/container.go b/staging/src/k8s.io/apiserver/pkg/server/mux/container.go index 8c0f4d154c8..4cd7614f227 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/mux/container.go +++ b/staging/src/k8s.io/apiserver/pkg/server/mux/container.go @@ -35,22 +35,12 @@ import ( // handlers that do not show up in swagger or in / type APIContainer struct { *restful.Container - - // NonSwaggerRoutes are recorded and are visible at /, but do not show up in Swagger. - NonSwaggerRoutes PathRecorderMux - - // UnlistedRoutes are not recorded, therefore not visible at / and do not show up in Swagger. - UnlistedRoutes *http.ServeMux } // NewAPIContainer constructs a new container for APIs -func NewAPIContainer(mux *http.ServeMux, s runtime.NegotiatedSerializer) *APIContainer { +func NewAPIContainer(mux *http.ServeMux, s runtime.NegotiatedSerializer, defaultMux http.Handler) *APIContainer { c := APIContainer{ Container: restful.NewContainer(), - NonSwaggerRoutes: PathRecorderMux{ - mux: mux, - }, - UnlistedRoutes: mux, } c.Container.ServeMux = mux c.Container.Router(restful.CurlyRouter{}) // e.g. for proxy/{kind}/{name}/{*} @@ -61,6 +51,10 @@ func NewAPIContainer(mux *http.ServeMux, s runtime.NegotiatedSerializer) *APICon 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 } diff --git a/staging/src/k8s.io/apiserver/pkg/server/mux/pathrecorder.go b/staging/src/k8s.io/apiserver/pkg/server/mux/pathrecorder.go index 4de891a7333..7c1ed2a7d10 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/mux/pathrecorder.go +++ b/staging/src/k8s.io/apiserver/pkg/server/mux/pathrecorder.go @@ -17,47 +17,83 @@ limitations under the License. package mux import ( + "fmt" "net/http" + "runtime/debug" + + utilruntime "k8s.io/apimachinery/pkg/util/runtime" ) -// Mux is an object that can register http handlers. -type Mux interface { - Handle(pattern string, handler http.Handler) - HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) -} - -// PathRecorderMux wraps a mux object and records the registered paths. It is _not_ go routine safe. +// PathRecorderMux wraps a mux object and records the registered exposedPaths. It is _not_ go routine safe. type PathRecorderMux struct { - mux Mux - paths []string + mux *http.ServeMux + exposedPaths []string + + // pathStacks holds the stacks of all registered paths. This allows us to show a more helpful message + // before the "http: multiple registrations for %s" panic. + pathStacks map[string]string } // NewPathRecorderMux creates a new PathRecorderMux with the given mux as the base mux. -func NewPathRecorderMux(mux Mux) *PathRecorderMux { +func NewPathRecorderMux() *PathRecorderMux { return &PathRecorderMux{ - mux: mux, + mux: http.NewServeMux(), + pathStacks: map[string]string{}, } } -// BaseMux returns the underlying mux. -func (m *PathRecorderMux) BaseMux() Mux { - return m.mux -} - -// HandledPaths returns the registered handler paths. +// HandledPaths returns the registered handler exposedPaths. func (m *PathRecorderMux) HandledPaths() []string { - return append([]string{}, m.paths...) + return append([]string{}, m.exposedPaths...) } // Handle registers the handler for the given pattern. // If a handler already exists for pattern, Handle panics. func (m *PathRecorderMux) Handle(path string, handler http.Handler) { - m.paths = append(m.paths, path) + if existingStack, ok := m.pathStacks[path]; ok { + utilruntime.HandleError(fmt.Errorf("registered %q from %v", path, existingStack)) + } + m.pathStacks[path] = string(debug.Stack()) + + m.exposedPaths = append(m.exposedPaths, path) m.mux.Handle(path, handler) } // HandleFunc registers the handler function for the given pattern. +// If a handler already exists for pattern, Handle panics. func (m *PathRecorderMux) HandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) { - m.paths = append(m.paths, path) + if existingStack, ok := m.pathStacks[path]; ok { + utilruntime.HandleError(fmt.Errorf("registered %q from %v", path, existingStack)) + } + m.pathStacks[path] = string(debug.Stack()) + + m.exposedPaths = append(m.exposedPaths, path) m.mux.HandleFunc(path, handler) } + +// UnlistedHandle registers the handler for the given pattern, but doesn't list it. +// If a handler already exists for pattern, Handle panics. +func (m *PathRecorderMux) UnlistedHandle(path string, handler http.Handler) { + if existingStack, ok := m.pathStacks[path]; ok { + utilruntime.HandleError(fmt.Errorf("registered %q from %v", path, existingStack)) + } + m.pathStacks[path] = string(debug.Stack()) + m.mux.Handle(path, handler) + +} + +// UnlistedHandleFunc registers the handler function for the given pattern, but doesn't list it. +// If a handler already exists for pattern, Handle panics. +func (m *PathRecorderMux) UnlistedHandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) { + if existingStack, ok := m.pathStacks[path]; ok { + utilruntime.HandleError(fmt.Errorf("registered %q from %v", path, existingStack)) + } + m.pathStacks[path] = string(debug.Stack()) + + m.mux.HandleFunc(path, handler) +} + +// ServeHTTP makes it an http.Handler +func (m *PathRecorderMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { + m.mux.ServeHTTP(w, r) +} diff --git a/staging/src/k8s.io/apiserver/pkg/server/mux/container_test.go b/staging/src/k8s.io/apiserver/pkg/server/mux/pathrecorder_test.go similarity index 52% rename from staging/src/k8s.io/apiserver/pkg/server/mux/container_test.go rename to staging/src/k8s.io/apiserver/pkg/server/mux/pathrecorder_test.go index 6602e97ca10..c6865c88600 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/mux/container_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/mux/pathrecorder_test.go @@ -23,18 +23,10 @@ import ( "github.com/stretchr/testify/assert" ) -func TestNewAPIContainer(t *testing.T) { - mux := http.NewServeMux() - c := NewAPIContainer(mux, nil) - assert.Equal(t, mux, c.UnlistedRoutes, "UnlistedRoutes ServeMux's do not match") - assert.Equal(t, mux, c.Container.ServeMux, "Container ServeMux's do not match") -} - func TestSecretHandlers(t *testing.T) { - mux := http.NewServeMux() - c := NewAPIContainer(mux, nil) - c.UnlistedRoutes.HandleFunc("/secret", func(http.ResponseWriter, *http.Request) {}) - c.NonSwaggerRoutes.HandleFunc("/nonswagger", func(http.ResponseWriter, *http.Request) {}) - assert.NotContains(t, c.NonSwaggerRoutes.HandledPaths(), "/secret") - assert.Contains(t, c.NonSwaggerRoutes.HandledPaths(), "/nonswagger") + c := NewPathRecorderMux() + c.UnlistedHandleFunc("/secret", func(http.ResponseWriter, *http.Request) {}) + c.HandleFunc("/nonswagger", func(http.ResponseWriter, *http.Request) {}) + assert.NotContains(t, c.HandledPaths(), "/secret") + assert.Contains(t, c.HandledPaths(), "/nonswagger") } diff --git a/staging/src/k8s.io/apiserver/pkg/server/openapi/openapi.go b/staging/src/k8s.io/apiserver/pkg/server/openapi/openapi.go index 258347f3ae2..10f3872c1a1 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/openapi/openapi.go +++ b/staging/src/k8s.io/apiserver/pkg/server/openapi/openapi.go @@ -44,7 +44,7 @@ type openAPI struct { } // RegisterOpenAPIService registers a handler to provides standard OpenAPI specification. -func RegisterOpenAPIService(servePath string, webServices []*restful.WebService, config *openapi.Config, container *genericmux.APIContainer) (err error) { +func RegisterOpenAPIService(servePath string, webServices []*restful.WebService, config *openapi.Config, mux *genericmux.PathRecorderMux) (err error) { o := openAPI{ config: config, servePath: servePath, @@ -63,7 +63,7 @@ func RegisterOpenAPIService(servePath string, webServices []*restful.WebService, return err } - container.UnlistedRoutes.HandleFunc(servePath, func(w http.ResponseWriter, r *http.Request) { + mux.UnlistedHandleFunc(servePath, func(w http.ResponseWriter, r *http.Request) { resp := restful.NewResponse(w) if r.URL.Path != servePath { resp.WriteErrorString(http.StatusNotFound, "Path not found!") diff --git a/staging/src/k8s.io/apiserver/pkg/server/routes/index.go b/staging/src/k8s.io/apiserver/pkg/server/routes/index.go index d2da396ec7b..b535ff0ac73 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/index.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/index.go @@ -29,8 +29,8 @@ import ( type Index struct{} // Install adds the Index webservice to the given mux. -func (i Index) Install(c *mux.APIContainer) { - c.UnlistedRoutes.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { +func (i Index) Install(c *mux.APIContainer, mux *mux.PathRecorderMux) { + mux.UnlistedHandleFunc("/", func(w http.ResponseWriter, r *http.Request) { status := http.StatusOK if r.URL.Path != "/" && r.URL.Path != "/index.html" { // Since "/" matches all paths, handleIndex is called for all paths for which there is no handler api.Registry. @@ -43,7 +43,7 @@ func (i Index) Install(c *mux.APIContainer) { handledPaths = append(handledPaths, ws.RootPath()) } // Extract the paths handled using mux handler. - handledPaths = append(handledPaths, c.NonSwaggerRoutes.HandledPaths()...) + handledPaths = append(handledPaths, mux.HandledPaths()...) sort.Strings(handledPaths) responsewriters.WriteRawJSON(status, metav1.RootPaths{Paths: handledPaths}, w) }) diff --git a/staging/src/k8s.io/apiserver/pkg/server/routes/metrics.go b/staging/src/k8s.io/apiserver/pkg/server/routes/metrics.go index 541362cdc04..6d4e56edcbf 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/metrics.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/metrics.go @@ -31,8 +31,8 @@ import ( type DefaultMetrics struct{} // Install adds the DefaultMetrics handler -func (m DefaultMetrics) Install(c *mux.APIContainer) { - c.NonSwaggerRoutes.Handle("/metrics", prometheus.Handler()) +func (m DefaultMetrics) Install(c *mux.PathRecorderMux) { + c.Handle("/metrics", prometheus.Handler()) } // MetricsWithReset install the prometheus metrics handler extended with support for the DELETE method @@ -40,9 +40,9 @@ func (m DefaultMetrics) Install(c *mux.APIContainer) { type MetricsWithReset struct{} // Install adds the MetricsWithReset handler -func (m MetricsWithReset) Install(c *mux.APIContainer) { +func (m MetricsWithReset) Install(c *mux.PathRecorderMux) { defaultMetricsHandler := prometheus.Handler().ServeHTTP - c.NonSwaggerRoutes.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) { + c.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) { if req.Method == "DELETE" { apimetrics.Reset() etcdmetrics.Reset() 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 073866fde2d..a547e00e3f9 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/openapi.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/openapi.go @@ -30,8 +30,8 @@ type OpenAPI struct { } // Install adds the SwaggerUI webservice to the given mux. -func (oa OpenAPI) Install(c *mux.APIContainer) { - err := apiserveropenapi.RegisterOpenAPIService("/swagger.json", c.RegisteredWebServices(), oa.Config, c) +func (oa OpenAPI) Install(c *mux.APIContainer, 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/profiling.go b/staging/src/k8s.io/apiserver/pkg/server/routes/profiling.go index 071b784f766..fce6b631f95 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/profiling.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/profiling.go @@ -26,9 +26,9 @@ import ( type Profiling struct{} // Install adds the Profiling webservice to the given mux. -func (d Profiling) Install(c *mux.APIContainer) { - c.UnlistedRoutes.HandleFunc("/debug/pprof/", pprof.Index) - c.UnlistedRoutes.HandleFunc("/debug/pprof/profile", pprof.Profile) - c.UnlistedRoutes.HandleFunc("/debug/pprof/symbol", pprof.Symbol) - c.UnlistedRoutes.HandleFunc("/debug/pprof/trace", pprof.Trace) +func (d Profiling) Install(c *mux.PathRecorderMux) { + c.UnlistedHandleFunc("/debug/pprof/", pprof.Index) + c.UnlistedHandleFunc("/debug/pprof/profile", pprof.Profile) + c.UnlistedHandleFunc("/debug/pprof/symbol", pprof.Symbol) + c.UnlistedHandleFunc("/debug/pprof/trace", pprof.Trace) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/routes/swaggerui.go b/staging/src/k8s.io/apiserver/pkg/server/routes/swaggerui.go index c59f68242cd..712210eff8c 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/swaggerui.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/swaggerui.go @@ -29,12 +29,12 @@ import ( type SwaggerUI struct{} // Install adds the SwaggerUI webservice to the given mux. -func (l SwaggerUI) Install(c *mux.APIContainer) { +func (l SwaggerUI) Install(c *mux.PathRecorderMux) { fileServer := http.FileServer(&assetfs.AssetFS{ Asset: swagger.Asset, AssetDir: swagger.AssetDir, Prefix: "third_party/swagger-ui", }) prefix := "/swagger-ui/" - c.NonSwaggerRoutes.Handle(prefix, http.StripPrefix(prefix, fileServer)) + c.Handle(prefix, http.StripPrefix(prefix, fileServer)) } 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 142882a89e8..19916a63ef2 100644 --- a/staging/src/k8s.io/kube-aggregator/pkg/apiserver/apiserver.go +++ b/staging/src/k8s.io/kube-aggregator/pkg/apiserver/apiserver.go @@ -250,8 +250,8 @@ func (s *APIAggregator) AddAPIService(apiService *apiregistration.APIService) { endpointsLister: s.endpointsLister, } // aggregation is protected - s.GenericAPIServer.HandlerContainer.UnlistedRoutes.Handle(groupPath, groupDiscoveryHandler) - s.GenericAPIServer.HandlerContainer.UnlistedRoutes.Handle(groupPath+"/", groupDiscoveryHandler) + s.GenericAPIServer.FallThroughHandler.UnlistedHandle(groupPath, groupDiscoveryHandler) + s.GenericAPIServer.FallThroughHandler.UnlistedHandle(groupPath+"/", groupDiscoveryHandler) s.handledGroups.Insert(apiService.Spec.Group) } diff --git a/vendor/BUILD b/vendor/BUILD index 811973ee8ff..bde45731420 100644 --- a/vendor/BUILD +++ b/vendor/BUILD @@ -10488,6 +10488,7 @@ go_test( "//vendor:k8s.io/apiserver/pkg/authorization/authorizer", "//vendor:k8s.io/apiserver/pkg/endpoints/request", "//vendor:k8s.io/apiserver/pkg/registry/rest", + "//vendor:k8s.io/apiserver/pkg/server/mux", "//vendor:k8s.io/apiserver/pkg/storage/etcd/testing", "//vendor:k8s.io/client-go/rest", ], @@ -10627,7 +10628,7 @@ go_library( go_test( name = "k8s.io/apiserver/pkg/server/mux_test", - srcs = ["k8s.io/apiserver/pkg/server/mux/container_test.go"], + srcs = ["k8s.io/apiserver/pkg/server/mux/pathrecorder_test.go"], library = ":k8s.io/apiserver/pkg/server/mux", tags = ["automanaged"], deps = ["//vendor:github.com/stretchr/testify/assert"], @@ -10647,6 +10648,7 @@ go_library( "//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime/schema", + "//vendor:k8s.io/apimachinery/pkg/util/runtime", "//vendor:k8s.io/apiserver/pkg/endpoints/handlers/responsewriters", ], )