mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 14:07:14 +00:00
Make genericapiserver handler chain customizable
This commit is contained in:
parent
7cfd0150e4
commit
68cee1d9ac
@ -231,8 +231,8 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
routes.UIRedirect{}.Install(m.Mux, m.HandlerContainer)
|
routes.UIRedirect{}.Install(m.HandlerContainer)
|
||||||
routes.Logs{}.Install(m.Mux, m.HandlerContainer)
|
routes.Logs{}.Install(m.HandlerContainer)
|
||||||
|
|
||||||
restOptionsFactory := restOptionsFactory{
|
restOptionsFactory := restOptionsFactory{
|
||||||
storageFactory: storageFactory,
|
storageFactory: storageFactory,
|
||||||
|
@ -100,6 +100,7 @@ pkg/controller/volume/statusupdater
|
|||||||
pkg/conversion/queryparams
|
pkg/conversion/queryparams
|
||||||
pkg/credentialprovider/aws
|
pkg/credentialprovider/aws
|
||||||
pkg/genericapiserver/filters
|
pkg/genericapiserver/filters
|
||||||
|
pkg/genericapiserver/mux
|
||||||
pkg/genericapiserver/routes
|
pkg/genericapiserver/routes
|
||||||
pkg/hyperkube
|
pkg/hyperkube
|
||||||
pkg/kubelet/api
|
pkg/kubelet/api
|
||||||
|
@ -29,7 +29,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
"github.com/go-openapi/spec"
|
"github.com/go-openapi/spec"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"gopkg.in/natefinch/lumberjack.v2"
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
@ -46,6 +45,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/client/restclient"
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
genericfilters "k8s.io/kubernetes/pkg/genericapiserver/filters"
|
genericfilters "k8s.io/kubernetes/pkg/genericapiserver/filters"
|
||||||
|
"k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/openapi/common"
|
"k8s.io/kubernetes/pkg/genericapiserver/openapi/common"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/options"
|
"k8s.io/kubernetes/pkg/genericapiserver/options"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/routes"
|
"k8s.io/kubernetes/pkg/genericapiserver/routes"
|
||||||
@ -94,9 +94,6 @@ type Config struct {
|
|||||||
// Required, the interface for serializing and converting objects to and from the wire
|
// Required, the interface for serializing and converting objects to and from the wire
|
||||||
Serializer runtime.NegotiatedSerializer
|
Serializer runtime.NegotiatedSerializer
|
||||||
|
|
||||||
// If specified, all web services will be registered into this container
|
|
||||||
RestfulContainer *restful.Container
|
|
||||||
|
|
||||||
// If specified, requests will be allocated a random timeout between this value, and twice this value.
|
// If specified, requests will be allocated a random timeout between this value, and twice this value.
|
||||||
// Note that it is up to the request handlers to ignore or honor this timeout. In seconds.
|
// Note that it is up to the request handlers to ignore or honor this timeout. In seconds.
|
||||||
MinRequestTimeout int
|
MinRequestTimeout int
|
||||||
@ -152,6 +149,8 @@ type Config struct {
|
|||||||
// Port names should align with ports defined in ExtraServicePorts
|
// Port names should align with ports defined in ExtraServicePorts
|
||||||
ExtraEndpointPorts []api.EndpointPort
|
ExtraEndpointPorts []api.EndpointPort
|
||||||
|
|
||||||
|
// If non-zero, the "kubernetes" services uses this port as NodePort.
|
||||||
|
// TODO(sttts): move into master
|
||||||
KubernetesServiceNodePort int
|
KubernetesServiceNodePort int
|
||||||
|
|
||||||
// EnableOpenAPISupport enables OpenAPI support. Allow downstream customers to disable OpenAPI spec.
|
// EnableOpenAPISupport enables OpenAPI support. Allow downstream customers to disable OpenAPI spec.
|
||||||
@ -173,6 +172,9 @@ type Config struct {
|
|||||||
|
|
||||||
// Predicate which is true for paths of long-running http requests
|
// Predicate which is true for paths of long-running http requests
|
||||||
LongRunningFunc genericfilters.LongRunningRequestCheck
|
LongRunningFunc genericfilters.LongRunningRequestCheck
|
||||||
|
|
||||||
|
// Build the handler chains by decorating the apiHandler.
|
||||||
|
BuildHandlerChainsFunc func(apiHandler http.Handler, c *Config) (secure, insecure http.Handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServingInfo struct {
|
type ServingInfo struct {
|
||||||
@ -323,6 +325,9 @@ func (c *Config) Complete() completedConfig {
|
|||||||
}
|
}
|
||||||
c.ExternalHost = hostAndPort
|
c.ExternalHost = hostAndPort
|
||||||
}
|
}
|
||||||
|
if c.BuildHandlerChainsFunc == nil {
|
||||||
|
c.BuildHandlerChainsFunc = DefaultBuildHandlerChain
|
||||||
|
}
|
||||||
return completedConfig{c}
|
return completedConfig{c}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,15 +396,7 @@ func (c completedConfig) New() (*GenericAPIServer, error) {
|
|||||||
openAPIDefinitions: c.OpenAPIDefinitions,
|
openAPIDefinitions: c.OpenAPIDefinitions,
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.RestfulContainer != nil {
|
s.HandlerContainer = mux.NewAPIContainer(http.NewServeMux(), c.Serializer)
|
||||||
s.HandlerContainer = c.RestfulContainer
|
|
||||||
} else {
|
|
||||||
s.HandlerContainer = NewHandlerContainer(http.NewServeMux(), c.Serializer)
|
|
||||||
}
|
|
||||||
// Use CurlyRouter to be able to use regular expressions in paths. Regular expressions are required in paths for example for proxy (where the path is proxy/{kind}/{name}/{*})
|
|
||||||
s.HandlerContainer.Router(restful.CurlyRouter{})
|
|
||||||
s.Mux = apiserver.NewPathRecorderMux(s.HandlerContainer.ServeMux)
|
|
||||||
apiserver.InstallServiceErrorHandler(s.Serializer, s.HandlerContainer)
|
|
||||||
|
|
||||||
if c.ProxyDialer != nil || c.ProxyTLSClientConfig != nil {
|
if c.ProxyDialer != nil || c.ProxyTLSClientConfig != nil {
|
||||||
s.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{
|
s.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{
|
||||||
@ -409,50 +406,50 @@ func (c completedConfig) New() (*GenericAPIServer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.installAPI(c.Config)
|
s.installAPI(c.Config)
|
||||||
s.Handler, s.InsecureHandler = s.buildHandlerChains(c.Config, http.Handler(s.Mux.BaseMux().(*http.ServeMux)))
|
|
||||||
|
s.Handler, s.InsecureHandler = c.BuildHandlerChainsFunc(s.HandlerContainer.ServeMux, c.Config)
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GenericAPIServer) buildHandlerChains(c *Config, handler http.Handler) (secure http.Handler, insecure http.Handler) {
|
func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) (secure, insecure http.Handler) {
|
||||||
// filters which insecure and secure have in common
|
|
||||||
handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true")
|
|
||||||
|
|
||||||
// insecure filters
|
|
||||||
insecure = handler
|
|
||||||
insecure = genericfilters.WithPanicRecovery(insecure, c.RequestContextMapper)
|
|
||||||
insecure = apiserverfilters.WithRequestInfo(insecure, NewRequestInfoResolver(c), c.RequestContextMapper)
|
|
||||||
insecure = api.WithRequestContext(insecure, c.RequestContextMapper)
|
|
||||||
insecure = genericfilters.WithTimeoutForNonLongRunningRequests(insecure, c.LongRunningFunc)
|
|
||||||
|
|
||||||
// secure filters
|
|
||||||
attributeGetter := apiserverfilters.NewRequestAttributeGetter(c.RequestContextMapper)
|
attributeGetter := apiserverfilters.NewRequestAttributeGetter(c.RequestContextMapper)
|
||||||
secure = handler
|
|
||||||
secure = apiserverfilters.WithAuthorization(secure, attributeGetter, c.Authorizer)
|
|
||||||
secure = apiserverfilters.WithImpersonation(secure, c.RequestContextMapper, c.Authorizer)
|
|
||||||
secure = apiserverfilters.WithAudit(secure, attributeGetter, c.AuditWriter) // before impersonation to read original user
|
|
||||||
secure = authhandlers.WithAuthentication(secure, c.RequestContextMapper, c.Authenticator, authhandlers.Unauthorized(c.SupportsBasicAuth))
|
|
||||||
secure = genericfilters.WithPanicRecovery(secure, c.RequestContextMapper)
|
|
||||||
secure = apiserverfilters.WithRequestInfo(secure, NewRequestInfoResolver(c), c.RequestContextMapper)
|
|
||||||
secure = api.WithRequestContext(secure, c.RequestContextMapper)
|
|
||||||
secure = genericfilters.WithTimeoutForNonLongRunningRequests(secure, c.LongRunningFunc)
|
|
||||||
secure = genericfilters.WithMaxInFlightLimit(secure, c.MaxRequestsInFlight, c.LongRunningFunc)
|
|
||||||
|
|
||||||
return
|
generic := func(handler http.Handler) http.Handler {
|
||||||
|
handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true")
|
||||||
|
handler = genericfilters.WithPanicRecovery(handler, c.RequestContextMapper)
|
||||||
|
handler = apiserverfilters.WithRequestInfo(handler, NewRequestInfoResolver(c), c.RequestContextMapper)
|
||||||
|
handler = api.WithRequestContext(handler, c.RequestContextMapper)
|
||||||
|
handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.LongRunningFunc)
|
||||||
|
handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.LongRunningFunc)
|
||||||
|
return handler
|
||||||
|
}
|
||||||
|
audit := func(handler http.Handler) http.Handler {
|
||||||
|
return apiserverfilters.WithAudit(handler, attributeGetter, c.AuditWriter)
|
||||||
|
}
|
||||||
|
protect := func(handler http.Handler) http.Handler {
|
||||||
|
handler = apiserverfilters.WithAuthorization(handler, attributeGetter, c.Authorizer)
|
||||||
|
handler = apiserverfilters.WithImpersonation(handler, c.RequestContextMapper, c.Authorizer)
|
||||||
|
handler = audit(handler) // before impersonation to read original user
|
||||||
|
handler = authhandlers.WithAuthentication(handler, c.RequestContextMapper, c.Authenticator, authhandlers.Unauthorized(c.SupportsBasicAuth))
|
||||||
|
return handler
|
||||||
|
}
|
||||||
|
|
||||||
|
return generic(protect(apiHandler)), generic(audit(apiHandler))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GenericAPIServer) installAPI(c *Config) {
|
func (s *GenericAPIServer) installAPI(c *Config) {
|
||||||
if c.EnableIndex {
|
if c.EnableIndex {
|
||||||
routes.Index{}.Install(s.Mux, s.HandlerContainer)
|
routes.Index{}.Install(s.HandlerContainer)
|
||||||
}
|
}
|
||||||
if c.EnableSwaggerSupport && c.EnableSwaggerUI {
|
if c.EnableSwaggerSupport && c.EnableSwaggerUI {
|
||||||
routes.SwaggerUI{}.Install(s.Mux, s.HandlerContainer)
|
routes.SwaggerUI{}.Install(s.HandlerContainer)
|
||||||
}
|
}
|
||||||
if c.EnableProfiling {
|
if c.EnableProfiling {
|
||||||
routes.Profiling{}.Install(s.Mux, s.HandlerContainer)
|
routes.Profiling{}.Install(s.HandlerContainer)
|
||||||
}
|
}
|
||||||
if c.EnableVersion {
|
if c.EnableVersion {
|
||||||
routes.Version{}.Install(s.Mux, s.HandlerContainer)
|
routes.Version{}.Install(s.HandlerContainer)
|
||||||
}
|
}
|
||||||
s.HandlerContainer.Add(s.DynamicApisDiscovery())
|
s.HandlerContainer.Add(s.DynamicApisDiscovery())
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
"k8s.io/kubernetes/pkg/client/restclient"
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
|
genericmux "k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/openapi"
|
"k8s.io/kubernetes/pkg/genericapiserver/openapi"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/openapi/common"
|
"k8s.io/kubernetes/pkg/genericapiserver/openapi/common"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
@ -118,9 +119,8 @@ type GenericAPIServer struct {
|
|||||||
// requestContextMapper provides a way to get the context for a request. It may be nil.
|
// requestContextMapper provides a way to get the context for a request. It may be nil.
|
||||||
requestContextMapper api.RequestContextMapper
|
requestContextMapper api.RequestContextMapper
|
||||||
|
|
||||||
Mux *apiserver.PathRecorderMux
|
// The registered APIs
|
||||||
HandlerContainer *restful.Container
|
HandlerContainer *genericmux.APIContainer
|
||||||
MasterCount int
|
|
||||||
|
|
||||||
SecureServingInfo *ServingInfo
|
SecureServingInfo *ServingInfo
|
||||||
InsecureServingInfo *ServingInfo
|
InsecureServingInfo *ServingInfo
|
||||||
@ -128,13 +128,9 @@ type GenericAPIServer struct {
|
|||||||
// ExternalAddress is the address (hostname or IP and port) that should be used in
|
// ExternalAddress is the address (hostname or IP and port) that should be used in
|
||||||
// external (public internet) URLs for this GenericAPIServer.
|
// external (public internet) URLs for this GenericAPIServer.
|
||||||
ExternalAddress string
|
ExternalAddress string
|
||||||
|
|
||||||
// ClusterIP is the IP address of the GenericAPIServer within the cluster.
|
// ClusterIP is the IP address of the GenericAPIServer within the cluster.
|
||||||
ClusterIP net.IP
|
ClusterIP net.IP
|
||||||
PublicReadWritePort int
|
|
||||||
ServiceReadWriteIP net.IP
|
|
||||||
ServiceReadWritePort int
|
|
||||||
ExtraServicePorts []api.ServicePort
|
|
||||||
ExtraEndpointPorts []api.EndpointPort
|
|
||||||
|
|
||||||
// storage contains the RESTful endpoints exposed by this GenericAPIServer
|
// storage contains the RESTful endpoints exposed by this GenericAPIServer
|
||||||
storage map[string]rest.Storage
|
storage map[string]rest.Storage
|
||||||
@ -150,26 +146,31 @@ type GenericAPIServer struct {
|
|||||||
// Used for custom proxy dialing, and proxy TLS options
|
// Used for custom proxy dialing, and proxy TLS options
|
||||||
ProxyTransport http.RoundTripper
|
ProxyTransport http.RoundTripper
|
||||||
|
|
||||||
KubernetesServiceNodePort int
|
|
||||||
|
|
||||||
// Map storing information about all groups to be exposed in discovery response.
|
// Map storing information about all groups to be exposed in discovery response.
|
||||||
// The map is from name to the group.
|
// The map is from name to the group.
|
||||||
apiGroupsForDiscoveryLock sync.RWMutex
|
apiGroupsForDiscoveryLock sync.RWMutex
|
||||||
apiGroupsForDiscovery map[string]unversioned.APIGroup
|
apiGroupsForDiscovery map[string]unversioned.APIGroup
|
||||||
|
|
||||||
// See Config.$name for documentation of these flags
|
|
||||||
|
|
||||||
enableOpenAPISupport bool
|
|
||||||
openAPIInfo spec.Info
|
|
||||||
openAPIDefaultResponse spec.Response
|
|
||||||
openAPIDefinitions *common.OpenAPIDefinitions
|
|
||||||
|
|
||||||
// PostStartHooks are each called after the server has started listening, in a separate go func for each
|
// PostStartHooks are each called after the server has started listening, in a separate go func for each
|
||||||
// with no guaranteee of ordering between them. The map key is a name used for error reporting.
|
// with no guaranteee of ordering between them. The map key is a name used for error reporting.
|
||||||
// It may kill the process with a panic if it wishes to by returning an error
|
// It may kill the process with a panic if it wishes to by returning an error
|
||||||
postStartHooks map[string]PostStartHookFunc
|
postStartHooks map[string]PostStartHookFunc
|
||||||
postStartHookLock sync.Mutex
|
postStartHookLock sync.Mutex
|
||||||
postStartHooksCalled bool
|
postStartHooksCalled bool
|
||||||
|
|
||||||
|
// See Config.$name for documentation of these flags:
|
||||||
|
|
||||||
|
enableOpenAPISupport bool
|
||||||
|
openAPIInfo spec.Info
|
||||||
|
openAPIDefaultResponse spec.Response
|
||||||
|
openAPIDefinitions *common.OpenAPIDefinitions
|
||||||
|
MasterCount int
|
||||||
|
KubernetesServiceNodePort int // TODO(sttts): move into master
|
||||||
|
PublicReadWritePort int
|
||||||
|
ServiceReadWriteIP net.IP
|
||||||
|
ServiceReadWritePort int
|
||||||
|
ExtraServicePorts []api.ServicePort
|
||||||
|
ExtraEndpointPorts []api.EndpointPort
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -191,33 +192,6 @@ func (s *GenericAPIServer) MinRequestTimeout() time.Duration {
|
|||||||
return s.minRequestTimeout
|
return s.minRequestTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleWithAuth adds an http.Handler for pattern to an http.ServeMux
|
|
||||||
// Applies the same authentication and authorization (if any is configured)
|
|
||||||
// to the request is used for the GenericAPIServer's built-in endpoints.
|
|
||||||
func (s *GenericAPIServer) HandleWithAuth(pattern string, handler http.Handler) {
|
|
||||||
// TODO: Add a way for plugged-in endpoints to translate their
|
|
||||||
// URLs into attributes that an Authorizer can understand, and have
|
|
||||||
// sensible policy defaults for plugged-in endpoints. This will be different
|
|
||||||
// for generic endpoints versus REST object endpoints.
|
|
||||||
// TODO: convert to go-restful
|
|
||||||
s.Mux.Handle(pattern, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleFuncWithAuth adds an http.Handler for pattern to an http.ServeMux
|
|
||||||
// Applies the same authentication and authorization (if any is configured)
|
|
||||||
// to the request is used for the GenericAPIServer's built-in endpoints.
|
|
||||||
func (s *GenericAPIServer) HandleFuncWithAuth(pattern string, handler func(http.ResponseWriter, *http.Request)) {
|
|
||||||
// TODO: convert to go-restful
|
|
||||||
s.Mux.HandleFunc(pattern, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandlerContainer(mux *http.ServeMux, s runtime.NegotiatedSerializer) *restful.Container {
|
|
||||||
container := restful.NewContainer()
|
|
||||||
container.ServeMux = mux
|
|
||||||
apiserver.InstallRecoverHandler(s, container)
|
|
||||||
return container
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *GenericAPIServer) Run() {
|
func (s *GenericAPIServer) Run() {
|
||||||
// install APIs which depend on other APIs to be installed
|
// install APIs which depend on other APIs to be installed
|
||||||
if s.enableSwaggerSupport {
|
if s.enableSwaggerSupport {
|
||||||
@ -227,7 +201,7 @@ func (s *GenericAPIServer) Run() {
|
|||||||
s.InstallOpenAPI()
|
s.InstallOpenAPI()
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.SecureServingInfo != nil {
|
if s.SecureServingInfo != nil && s.Handler != nil {
|
||||||
secureServer := &http.Server{
|
secureServer := &http.Server{
|
||||||
Addr: s.SecureServingInfo.BindAddress,
|
Addr: s.SecureServingInfo.BindAddress,
|
||||||
Handler: s.Handler,
|
Handler: s.Handler,
|
||||||
@ -282,7 +256,7 @@ func (s *GenericAPIServer) Run() {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.InsecureServingInfo != nil {
|
if s.InsecureServingInfo != nil && s.InsecureHandler != nil {
|
||||||
insecureServer := &http.Server{
|
insecureServer := &http.Server{
|
||||||
Addr: s.InsecureServingInfo.BindAddress,
|
Addr: s.InsecureServingInfo.BindAddress,
|
||||||
Handler: s.InsecureHandler,
|
Handler: s.InsecureHandler,
|
||||||
@ -343,14 +317,14 @@ func (s *GenericAPIServer) InstallAPIGroup(apiGroupInfo *APIGroupInfo) error {
|
|||||||
apiGroupVersion.OptionsExternalVersion = apiGroupInfo.OptionsExternalVersion
|
apiGroupVersion.OptionsExternalVersion = apiGroupInfo.OptionsExternalVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := apiGroupVersion.InstallREST(s.HandlerContainer); err != nil {
|
if err := apiGroupVersion.InstallREST(s.HandlerContainer.Container); err != nil {
|
||||||
return fmt.Errorf("Unable to setup API %v: %v", apiGroupInfo, err)
|
return fmt.Errorf("Unable to setup API %v: %v", apiGroupInfo, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Install the version handler.
|
// Install the version handler.
|
||||||
if apiGroupInfo.IsLegacyGroup {
|
if apiGroupInfo.IsLegacyGroup {
|
||||||
// Add a handler at /api to enumerate the supported api versions.
|
// Add a handler at /api to enumerate the supported api versions.
|
||||||
apiserver.AddApiWebService(s.Serializer, s.HandlerContainer, apiPrefix, func(req *restful.Request) *unversioned.APIVersions {
|
apiserver.AddApiWebService(s.Serializer, s.HandlerContainer.Container, apiPrefix, func(req *restful.Request) *unversioned.APIVersions {
|
||||||
apiVersionsForDiscovery := unversioned.APIVersions{
|
apiVersionsForDiscovery := unversioned.APIVersions{
|
||||||
ServerAddressByClientCIDRs: s.getServerAddressByClientCIDRs(req.Request),
|
ServerAddressByClientCIDRs: s.getServerAddressByClientCIDRs(req.Request),
|
||||||
Versions: apiVersions,
|
Versions: apiVersions,
|
||||||
@ -487,7 +461,7 @@ func (s *GenericAPIServer) getSwaggerConfig() *swagger.Config {
|
|||||||
// of swagger, so that other resource types show up in the documentation.
|
// of swagger, so that other resource types show up in the documentation.
|
||||||
func (s *GenericAPIServer) InstallSwaggerAPI() {
|
func (s *GenericAPIServer) InstallSwaggerAPI() {
|
||||||
// Enable swagger UI and discovery API
|
// Enable swagger UI and discovery API
|
||||||
swagger.RegisterSwaggerService(*s.getSwaggerConfig(), s.HandlerContainer)
|
swagger.RegisterSwaggerService(*s.getSwaggerConfig(), s.HandlerContainer.Container)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallOpenAPI installs spec endpoints for each web service.
|
// InstallOpenAPI installs spec endpoints for each web service.
|
||||||
@ -508,7 +482,7 @@ func (s *GenericAPIServer) InstallOpenAPI() {
|
|||||||
Info: &info,
|
Info: &info,
|
||||||
DefaultResponse: &s.openAPIDefaultResponse,
|
DefaultResponse: &s.openAPIDefaultResponse,
|
||||||
OpenAPIDefinitions: s.openAPIDefinitions,
|
OpenAPIDefinitions: s.openAPIDefinitions,
|
||||||
}, s.HandlerContainer)
|
}, s.HandlerContainer.Container)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to register open api spec for %v: %v", w.RootPath(), err)
|
glog.Fatalf("Failed to register open api spec for %v: %v", w.RootPath(), err)
|
||||||
}
|
}
|
||||||
@ -521,7 +495,7 @@ func (s *GenericAPIServer) InstallOpenAPI() {
|
|||||||
Info: &s.openAPIInfo,
|
Info: &s.openAPIInfo,
|
||||||
DefaultResponse: &s.openAPIDefaultResponse,
|
DefaultResponse: &s.openAPIDefaultResponse,
|
||||||
OpenAPIDefinitions: s.openAPIDefinitions,
|
OpenAPIDefinitions: s.openAPIDefinitions,
|
||||||
}, s.HandlerContainer)
|
}, s.HandlerContainer.Container)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to register open api spec for root: %v", err)
|
glog.Fatalf("Failed to register open api spec for root: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -32,12 +33,11 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/rest"
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/api/testapi"
|
"k8s.io/kubernetes/pkg/api/testapi"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
"k8s.io/kubernetes/pkg/auth/user"
|
"k8s.io/kubernetes/pkg/auth/user"
|
||||||
|
genericmux "k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||||
ipallocator "k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
ipallocator "k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||||
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
|
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
|
||||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||||
@ -138,7 +138,7 @@ func TestInstallAPIGroups(t *testing.T) {
|
|||||||
s.InstallAPIGroup(&apiGroupsInfo[i])
|
s.InstallAPIGroup(&apiGroupsInfo[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
server := httptest.NewServer(s.HandlerContainer.ServeMux)
|
server := httptest.NewServer(s.InsecureHandler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
validPaths := []string{
|
validPaths := []string{
|
||||||
// "/api"
|
// "/api"
|
||||||
@ -158,41 +158,64 @@ func TestInstallAPIGroups(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestNewHandlerContainer verifies that NewHandlerContainer uses the
|
// TestCustomHandlerChain verifies the handler chain with custom handler chain builder functions.
|
||||||
// mux provided
|
func TestCustomHandlerChain(t *testing.T) {
|
||||||
func TestNewHandlerContainer(t *testing.T) {
|
etcdserver, config, _ := setUp(t)
|
||||||
assert := assert.New(t)
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
container := NewHandlerContainer(mux, nil)
|
|
||||||
assert.Equal(mux, container.ServeMux, "ServerMux's do not match")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestHandleWithAuth verifies HandleWithAuth adds the path
|
|
||||||
// to the MuxHelper.RegisteredPaths.
|
|
||||||
func TestHandleWithAuth(t *testing.T) {
|
|
||||||
etcdserver, _, assert := setUp(t)
|
|
||||||
defer etcdserver.Terminate(t)
|
defer etcdserver.Terminate(t)
|
||||||
|
|
||||||
server := &GenericAPIServer{}
|
var protected, called bool
|
||||||
server.Mux = apiserver.NewPathRecorderMux(http.NewServeMux())
|
|
||||||
handler := func(r http.ResponseWriter, w *http.Request) { w.Write(nil) }
|
|
||||||
server.HandleWithAuth("/test", http.HandlerFunc(handler))
|
|
||||||
|
|
||||||
assert.Contains(server.Mux.HandledPaths(), "/test", "Path not found in MuxHelper")
|
config.Serializer = api.Codecs
|
||||||
}
|
config.BuildHandlerChainsFunc = func(apiHandler http.Handler, c *Config) (secure, insecure http.Handler) {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
protected = true
|
||||||
|
apiHandler.ServeHTTP(w, req)
|
||||||
|
}), http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
protected = false
|
||||||
|
apiHandler.ServeHTTP(w, req)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
handler := http.HandlerFunc(func(r http.ResponseWriter, req *http.Request) {
|
||||||
|
called = true
|
||||||
|
})
|
||||||
|
|
||||||
// TestHandleFuncWithAuth verifies HandleFuncWithAuth adds the path
|
s, err := config.Complete().New()
|
||||||
// to the MuxHelper.RegisteredPaths.
|
if err != nil {
|
||||||
func TestHandleFuncWithAuth(t *testing.T) {
|
t.Fatalf("Error in bringing up the server: %v", err)
|
||||||
etcdserver, _, assert := setUp(t)
|
}
|
||||||
defer etcdserver.Terminate(t)
|
|
||||||
|
|
||||||
server := &GenericAPIServer{}
|
s.HandlerContainer.NonSwaggerRoutes.Handle("/nonswagger", handler)
|
||||||
server.Mux = apiserver.NewPathRecorderMux(http.NewServeMux())
|
s.HandlerContainer.SecretRoutes.Handle("/secret", handler)
|
||||||
handler := func(r http.ResponseWriter, w *http.Request) { w.Write(nil) }
|
|
||||||
server.HandleFuncWithAuth("/test", handler)
|
|
||||||
|
|
||||||
assert.Contains(server.Mux.HandledPaths(), "/test", "Path not found in MuxHelper")
|
type Test struct {
|
||||||
|
handler http.Handler
|
||||||
|
path string
|
||||||
|
protected bool
|
||||||
|
}
|
||||||
|
for i, test := range []Test{
|
||||||
|
{s.Handler, "/nonswagger", true},
|
||||||
|
{s.Handler, "/secret", true},
|
||||||
|
{s.InsecureHandler, "/nonswagger", false},
|
||||||
|
{s.InsecureHandler, "/secret", false},
|
||||||
|
} {
|
||||||
|
protected, called = false, false
|
||||||
|
|
||||||
|
var w io.Reader
|
||||||
|
req, err := http.NewRequest("GET", test.path, w)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d: Unexpected http error: %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
test.handler.ServeHTTP(httptest.NewRecorder(), req)
|
||||||
|
|
||||||
|
if !called {
|
||||||
|
t.Errorf("%d: Expected handler to be called.", i)
|
||||||
|
}
|
||||||
|
if test.protected != protected {
|
||||||
|
t.Errorf("%d: Expected protected=%v, got protected=%v.", i, test.protected, protected)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestNotRestRoutesHaveAuth checks that special non-routes are behind authz/authn.
|
// TestNotRestRoutesHaveAuth checks that special non-routes are behind authz/authn.
|
||||||
@ -267,7 +290,7 @@ func TestInstallSwaggerAPI(t *testing.T) {
|
|||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
server := &GenericAPIServer{}
|
server := &GenericAPIServer{}
|
||||||
server.HandlerContainer = NewHandlerContainer(mux, nil)
|
server.HandlerContainer = genericmux.NewAPIContainer(mux, nil)
|
||||||
|
|
||||||
// Ensure swagger isn't installed without the call
|
// Ensure swagger isn't installed without the call
|
||||||
ws := server.HandlerContainer.RegisteredWebServices()
|
ws := server.HandlerContainer.RegisteredWebServices()
|
||||||
@ -286,7 +309,7 @@ func TestInstallSwaggerAPI(t *testing.T) {
|
|||||||
|
|
||||||
// Empty externalHost verification
|
// Empty externalHost verification
|
||||||
mux = http.NewServeMux()
|
mux = http.NewServeMux()
|
||||||
server.HandlerContainer = NewHandlerContainer(mux, nil)
|
server.HandlerContainer = genericmux.NewAPIContainer(mux, nil)
|
||||||
server.ExternalAddress = ""
|
server.ExternalAddress = ""
|
||||||
server.ClusterIP = net.IPv4(10, 10, 10, 10)
|
server.ClusterIP = net.IPv4(10, 10, 10, 10)
|
||||||
server.PublicReadWritePort = 1010
|
server.PublicReadWritePort = 1010
|
||||||
@ -328,7 +351,7 @@ func TestDiscoveryAtAPIS(t *testing.T) {
|
|||||||
master, etcdserver, _, assert := newMaster(t)
|
master, etcdserver, _, assert := newMaster(t)
|
||||||
defer etcdserver.Terminate(t)
|
defer etcdserver.Terminate(t)
|
||||||
|
|
||||||
server := httptest.NewServer(master.HandlerContainer.ServeMux)
|
server := httptest.NewServer(master.InsecureHandler)
|
||||||
groupList, err := getGroupList(server)
|
groupList, err := getGroupList(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
52
pkg/genericapiserver/mux/container.go
Normal file
52
pkg/genericapiserver/mux/container.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
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 (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/emicklei/go-restful"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
NonSwaggerRoutes PathRecorderMux
|
||||||
|
SecretRoutes Mux
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAPIContainer constructs a new container for APIs
|
||||||
|
func NewAPIContainer(mux *http.ServeMux, s runtime.NegotiatedSerializer) *APIContainer {
|
||||||
|
c := APIContainer{
|
||||||
|
Container: restful.NewContainer(),
|
||||||
|
NonSwaggerRoutes: PathRecorderMux{
|
||||||
|
mux: mux,
|
||||||
|
},
|
||||||
|
SecretRoutes: mux,
|
||||||
|
}
|
||||||
|
c.Container.ServeMux = mux
|
||||||
|
c.Container.Router(restful.CurlyRouter{}) // e.g. for proxy/{kind}/{name}/{*}
|
||||||
|
|
||||||
|
apiserver.InstallRecoverHandler(s, c.Container)
|
||||||
|
apiserver.InstallServiceErrorHandler(s, c.Container)
|
||||||
|
|
||||||
|
return &c
|
||||||
|
}
|
40
pkg/genericapiserver/mux/container_test.go
Normal file
40
pkg/genericapiserver/mux/container_test.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
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 (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewAPIContainer(t *testing.T) {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
c := NewAPIContainer(mux, nil)
|
||||||
|
assert.Equal(t, mux, c.SecretRoutes.(*http.ServeMux), "SecretRoutes 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.SecretRoutes.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")
|
||||||
|
}
|
18
pkg/genericapiserver/mux/doc.go
Normal file
18
pkg/genericapiserver/mux/doc.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
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 contains abstractions for http multiplexing of APIs.
|
||||||
|
package mux
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2015 The Kubernetes Authors.
|
Copyright 2016 The Kubernetes Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package apiserver
|
package mux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
@ -20,19 +20,17 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
|
"k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Index provides a webservice for the http root / listing all known paths.
|
// Index provides a webservice for the http root / listing all known paths.
|
||||||
type Index struct{}
|
type Index struct{}
|
||||||
|
|
||||||
// Install adds the Index webservice to the given mux.
|
// Install adds the Index webservice to the given mux.
|
||||||
func (i Index) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
func (i Index) Install(c *mux.APIContainer) {
|
||||||
// do not register this using restful Webservice since we do not want to surface this in api docs.
|
c.SecretRoutes.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
mux.BaseMux().HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
status := http.StatusOK
|
status := http.StatusOK
|
||||||
if r.URL.Path != "/" && r.URL.Path != "/index.html" {
|
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 registered.
|
// Since "/" matches all paths, handleIndex is called for all paths for which there is no handler registered.
|
||||||
@ -45,7 +43,7 @@ func (i Index) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
|||||||
handledPaths = append(handledPaths, ws.RootPath())
|
handledPaths = append(handledPaths, ws.RootPath())
|
||||||
}
|
}
|
||||||
// Extract the paths handled using mux handler.
|
// Extract the paths handled using mux handler.
|
||||||
handledPaths = append(handledPaths, mux.HandledPaths()...)
|
handledPaths = append(handledPaths, c.NonSwaggerRoutes.HandledPaths()...)
|
||||||
sort.Strings(handledPaths)
|
sort.Strings(handledPaths)
|
||||||
apiserver.WriteRawJSON(status, unversioned.RootPaths{Paths: handledPaths}, w)
|
apiserver.WriteRawJSON(status, unversioned.RootPaths{Paths: handledPaths}, w)
|
||||||
})
|
})
|
||||||
|
@ -17,18 +17,17 @@ limitations under the License.
|
|||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
|
||||||
"net/http/pprof"
|
"net/http/pprof"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Profiling adds handlers for pprof under /debug/pprof.
|
// Profiling adds handlers for pprof under /debug/pprof.
|
||||||
type Profiling struct{}
|
type Profiling struct{}
|
||||||
|
|
||||||
// Install adds the Profiling webservice to the given mux.
|
// Install adds the Profiling webservice to the given mux.
|
||||||
func (d Profiling) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
func (d Profiling) Install(c *mux.APIContainer) {
|
||||||
mux.BaseMux().HandleFunc("/debug/pprof/", pprof.Index)
|
c.SecretRoutes.HandleFunc("/debug/pprof/", pprof.Index)
|
||||||
mux.BaseMux().HandleFunc("/debug/pprof/profile", pprof.Profile)
|
c.SecretRoutes.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||||
mux.BaseMux().HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
c.SecretRoutes.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
assetfs "github.com/elazarl/go-bindata-assetfs"
|
assetfs "github.com/elazarl/go-bindata-assetfs"
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/routes/data/swagger"
|
"k8s.io/kubernetes/pkg/genericapiserver/routes/data/swagger"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,12 +29,12 @@ import (
|
|||||||
type SwaggerUI struct{}
|
type SwaggerUI struct{}
|
||||||
|
|
||||||
// Install adds the SwaggerUI webservice to the given mux.
|
// Install adds the SwaggerUI webservice to the given mux.
|
||||||
func (l SwaggerUI) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
func (l SwaggerUI) Install(c *mux.APIContainer) {
|
||||||
fileServer := http.FileServer(&assetfs.AssetFS{
|
fileServer := http.FileServer(&assetfs.AssetFS{
|
||||||
Asset: swagger.Asset,
|
Asset: swagger.Asset,
|
||||||
AssetDir: swagger.AssetDir,
|
AssetDir: swagger.AssetDir,
|
||||||
Prefix: "third_party/swagger-ui",
|
Prefix: "third_party/swagger-ui",
|
||||||
})
|
})
|
||||||
prefix := "/swagger-ui/"
|
prefix := "/swagger-ui/"
|
||||||
mux.Handle(prefix, http.StripPrefix(prefix, fileServer))
|
c.NonSwaggerRoutes.Handle(prefix, http.StripPrefix(prefix, fileServer))
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
|
"k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||||
"k8s.io/kubernetes/pkg/version"
|
"k8s.io/kubernetes/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ import (
|
|||||||
type Version struct{}
|
type Version struct{}
|
||||||
|
|
||||||
// Install registers the APIServer's `/version` handler.
|
// Install registers the APIServer's `/version` handler.
|
||||||
func (v Version) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
func (v Version) Install(c *mux.APIContainer) {
|
||||||
// Set up a service to return the git code version.
|
// Set up a service to return the git code version.
|
||||||
versionWS := new(restful.WebService)
|
versionWS := new(restful.WebService)
|
||||||
versionWS.Path("/version")
|
versionWS.Path("/version")
|
||||||
|
@ -192,10 +192,10 @@ func (c completedConfig) New() (*Master, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.EnableUISupport {
|
if c.EnableUISupport {
|
||||||
routes.UIRedirect{}.Install(s.Mux, s.HandlerContainer)
|
routes.UIRedirect{}.Install(s.HandlerContainer)
|
||||||
}
|
}
|
||||||
if c.EnableLogsSupport {
|
if c.EnableLogsSupport {
|
||||||
routes.Logs{}.Install(s.Mux, s.HandlerContainer)
|
routes.Logs{}.Install(s.HandlerContainer)
|
||||||
}
|
}
|
||||||
|
|
||||||
m := &Master{
|
m := &Master{
|
||||||
@ -284,12 +284,12 @@ func (m *Master) InstallAPIs(c *Config) {
|
|||||||
Help: "The time since the last successful synchronization of the SSH tunnels for proxy requests.",
|
Help: "The time since the last successful synchronization of the SSH tunnels for proxy requests.",
|
||||||
}, func() float64 { return float64(m.tunneler.SecondsSinceSync()) })
|
}, func() float64 { return float64(m.tunneler.SecondsSinceSync()) })
|
||||||
}
|
}
|
||||||
healthz.InstallHandler(m.Mux, healthzChecks...)
|
healthz.InstallHandler(&m.HandlerContainer.NonSwaggerRoutes, healthzChecks...)
|
||||||
|
|
||||||
if c.GenericConfig.EnableProfiling {
|
if c.GenericConfig.EnableProfiling {
|
||||||
routes.MetricsWithReset{}.Install(m.Mux, m.HandlerContainer)
|
routes.MetricsWithReset{}.Install(m.HandlerContainer)
|
||||||
} else {
|
} else {
|
||||||
routes.DefaultMetrics{}.Install(m.Mux, m.HandlerContainer)
|
routes.DefaultMetrics{}.Install(m.HandlerContainer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install third party resource support if requested
|
// Install third party resource support if requested
|
||||||
@ -612,10 +612,10 @@ func (m *Master) InstallThirdPartyResource(rsrc *extensions.ThirdPartyResource)
|
|||||||
// the group with the new API
|
// the group with the new API
|
||||||
if m.hasThirdPartyGroupStorage(path) {
|
if m.hasThirdPartyGroupStorage(path) {
|
||||||
m.addThirdPartyResourceStorage(path, plural.Resource, thirdparty.Storage[plural.Resource].(*thirdpartyresourcedataetcd.REST), apiGroup)
|
m.addThirdPartyResourceStorage(path, plural.Resource, thirdparty.Storage[plural.Resource].(*thirdpartyresourcedataetcd.REST), apiGroup)
|
||||||
return thirdparty.UpdateREST(m.HandlerContainer)
|
return thirdparty.UpdateREST(m.HandlerContainer.Container)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := thirdparty.InstallREST(m.HandlerContainer); err != nil {
|
if err := thirdparty.InstallREST(m.HandlerContainer.Container); err != nil {
|
||||||
glog.Errorf("Unable to setup thirdparty api: %v", err)
|
glog.Errorf("Unable to setup thirdparty api: %v", err)
|
||||||
}
|
}
|
||||||
m.HandlerContainer.Add(apiserver.NewGroupWebService(api.Codecs, path, apiGroup))
|
m.HandlerContainer.Add(apiserver.NewGroupWebService(api.Codecs, path, apiGroup))
|
||||||
|
@ -22,13 +22,13 @@ import (
|
|||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Logs adds handlers for the /logs path serving log files from /var/log.
|
// Logs adds handlers for the /logs path serving log files from /var/log.
|
||||||
type Logs struct{}
|
type Logs struct{}
|
||||||
|
|
||||||
func (l Logs) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
func (l Logs) Install(c *mux.APIContainer) {
|
||||||
// use restful: ws.Route(ws.GET("/logs/{logpath:*}").To(fileHandler))
|
// use restful: ws.Route(ws.GET("/logs/{logpath:*}").To(fileHandler))
|
||||||
// See github.com/emicklei/go-restful/blob/master/examples/restful-serve-static.go
|
// See github.com/emicklei/go-restful/blob/master/examples/restful-serve-static.go
|
||||||
ws := new(restful.WebService)
|
ws := new(restful.WebService)
|
||||||
|
@ -20,28 +20,27 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
|
||||||
apiservermetrics "k8s.io/kubernetes/pkg/apiserver/metrics"
|
apiservermetrics "k8s.io/kubernetes/pkg/apiserver/metrics"
|
||||||
|
"k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||||
etcdmetrics "k8s.io/kubernetes/pkg/storage/etcd/metrics"
|
etcdmetrics "k8s.io/kubernetes/pkg/storage/etcd/metrics"
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultMetrics installs the default prometheus metrics handler
|
// DefaultMetrics installs the default prometheus metrics handler
|
||||||
type DefaultMetrics struct{}
|
type DefaultMetrics struct{}
|
||||||
|
|
||||||
func (m DefaultMetrics) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
func (m DefaultMetrics) Install(c *mux.APIContainer) {
|
||||||
mux.HandleFunc("/metrics", prometheus.Handler().ServeHTTP)
|
c.NonSwaggerRoutes.Handle("/metrics", prometheus.Handler())
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetricsWithReset install the prometheus metrics handler extended with support for the DELETE method
|
// MetricsWithReset install the prometheus metrics handler extended with support for the DELETE method
|
||||||
// which resets the metrics.
|
// which resets the metrics.
|
||||||
type MetricsWithReset struct{}
|
type MetricsWithReset struct{}
|
||||||
|
|
||||||
func (m MetricsWithReset) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
func (m MetricsWithReset) Install(c *mux.APIContainer) {
|
||||||
defaultMetricsHandler := prometheus.Handler().ServeHTTP
|
defaultMetricsHandler := prometheus.Handler().ServeHTTP
|
||||||
mux.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
|
c.NonSwaggerRoutes.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
|
||||||
if req.Method == "DELETE" {
|
if req.Method == "DELETE" {
|
||||||
apiservermetrics.Reset()
|
apiservermetrics.Reset()
|
||||||
etcdmetrics.Reset()
|
etcdmetrics.Reset()
|
||||||
|
@ -19,9 +19,7 @@ package routes
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
"k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const dashboardPath = "/api/v1/proxy/namespaces/kube-system/services/kubernetes-dashboard"
|
const dashboardPath = "/api/v1/proxy/namespaces/kube-system/services/kubernetes-dashboard"
|
||||||
@ -29,8 +27,8 @@ const dashboardPath = "/api/v1/proxy/namespaces/kube-system/services/kubernetes-
|
|||||||
// UIRediect redirects /ui to the kube-ui proxy path.
|
// UIRediect redirects /ui to the kube-ui proxy path.
|
||||||
type UIRedirect struct{}
|
type UIRedirect struct{}
|
||||||
|
|
||||||
func (r UIRedirect) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
func (r UIRedirect) Install(c *mux.APIContainer) {
|
||||||
mux.HandleFunc("/ui/", func(w http.ResponseWriter, r *http.Request) {
|
c.NonSwaggerRoutes.HandleFunc("/ui/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, dashboardPath, http.StatusTemporaryRedirect)
|
http.Redirect(w, r, dashboardPath, http.StatusTemporaryRedirect)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ func TestMasterExportsSymbols(t *testing.T) {
|
|||||||
_ = &master.Config{
|
_ = &master.Config{
|
||||||
GenericConfig: &genericapiserver.Config{
|
GenericConfig: &genericapiserver.Config{
|
||||||
EnableSwaggerSupport: false,
|
EnableSwaggerSupport: false,
|
||||||
RestfulContainer: nil,
|
|
||||||
},
|
},
|
||||||
EnableCoreControllers: false,
|
EnableCoreControllers: false,
|
||||||
EnableUISupport: false,
|
EnableUISupport: false,
|
||||||
|
Loading…
Reference in New Issue
Block a user