mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-11-01 18:58:18 +00:00
Merge pull request #42886 from deads2k/server-02-fallthrough
Automatic merge from submit-queue allow fallthrough handling from go-restful routes This sets up the gorestful routes to fall through to a default handler and reorders the API to be ahead of the other endpoints. This makes it possible to cleanly support cases of "match, fail, try this other handler" which we'll need for API server composition. @kubernetes/sig-api-machinery-pr-reviews @ncdc
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -43,6 +43,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"
|
||||
@@ -124,6 +125,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.
|
||||
@@ -180,7 +184,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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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...)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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!")
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -287,8 +287,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)
|
||||
}
|
||||
|
||||
|
||||
4
vendor/BUILD
vendored
4
vendor/BUILD
vendored
@@ -10501,6 +10501,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",
|
||||
],
|
||||
@@ -10640,7 +10641,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"],
|
||||
@@ -10660,6 +10661,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",
|
||||
],
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user