mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-11 04:52:08 +00:00
Merge pull request #33365 from sttts/sttts-custom-handler-chain
Automatic merge from submit-queue Towards custom handler chains in genericapiserver **Based on https://github.com/kubernetes/kubernetes/pull/33478** This PR makes the handler chain construction independent from the genericapiserver instance (with the exception of the `RequestInfoFilter` which will be fixed in https://github.com/kubernetes/kubernetes/pull/33490), i.e. the `Config` is enough to create a custom handler chain.
This commit is contained in:
commit
9e1960c507
@ -19,7 +19,7 @@ package genericapiserver
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"mime"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -53,10 +53,8 @@ import (
|
|||||||
|
|
||||||
// Config is a structure used to configure a GenericAPIServer.
|
// Config is a structure used to configure a GenericAPIServer.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
AuditLogPath string
|
// Destination for audit logs
|
||||||
AuditLogMaxAge int
|
AuditWriter io.Writer
|
||||||
AuditLogMaxBackups int
|
|
||||||
AuditLogMaxSize int
|
|
||||||
// Allow downstream consumers to disable swagger.
|
// Allow downstream consumers to disable swagger.
|
||||||
// This includes returning the generated swagger spec at /swaggerapi and swagger ui at /swagger-ui.
|
// This includes returning the generated swagger spec at /swaggerapi and swagger ui at /swagger-ui.
|
||||||
EnableSwaggerSupport bool
|
EnableSwaggerSupport bool
|
||||||
@ -161,18 +159,29 @@ type Config struct {
|
|||||||
// MaxRequestsInFlight is the maximum number of parallel non-long-running requests. Every further
|
// MaxRequestsInFlight is the maximum number of parallel non-long-running requests. Every further
|
||||||
// request has to wait.
|
// request has to wait.
|
||||||
MaxRequestsInFlight int
|
MaxRequestsInFlight int
|
||||||
LongRunningRequestRE string
|
|
||||||
|
// Predicate which is true for paths of long-running http requests
|
||||||
|
LongRunningFunc genericfilters.LongRunningRequestCheck
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConfig(options *options.ServerRunOptions) *Config {
|
func NewConfig(options *options.ServerRunOptions) *Config {
|
||||||
|
longRunningRE := regexp.MustCompile(options.LongRunningRequestRE)
|
||||||
|
|
||||||
|
var auditWriter io.Writer
|
||||||
|
if len(options.AuditLogPath) != 0 {
|
||||||
|
auditWriter = &lumberjack.Logger{
|
||||||
|
Filename: options.AuditLogPath,
|
||||||
|
MaxAge: options.AuditLogMaxAge,
|
||||||
|
MaxBackups: options.AuditLogMaxBackups,
|
||||||
|
MaxSize: options.AuditLogMaxSize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &Config{
|
return &Config{
|
||||||
APIGroupPrefix: options.APIGroupPrefix,
|
APIGroupPrefix: options.APIGroupPrefix,
|
||||||
APIPrefix: options.APIPrefix,
|
APIPrefix: options.APIPrefix,
|
||||||
CorsAllowedOriginList: options.CorsAllowedOriginList,
|
CorsAllowedOriginList: options.CorsAllowedOriginList,
|
||||||
AuditLogPath: options.AuditLogPath,
|
AuditWriter: auditWriter,
|
||||||
AuditLogMaxAge: options.AuditLogMaxAge,
|
|
||||||
AuditLogMaxBackups: options.AuditLogMaxBackups,
|
|
||||||
AuditLogMaxSize: options.AuditLogMaxSize,
|
|
||||||
EnableGarbageCollection: options.EnableGarbageCollection,
|
EnableGarbageCollection: options.EnableGarbageCollection,
|
||||||
EnableIndex: true,
|
EnableIndex: true,
|
||||||
EnableProfiling: options.EnableProfiling,
|
EnableProfiling: options.EnableProfiling,
|
||||||
@ -197,7 +206,7 @@ func NewConfig(options *options.ServerRunOptions) *Config {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
MaxRequestsInFlight: options.MaxRequestsInFlight,
|
MaxRequestsInFlight: options.MaxRequestsInFlight,
|
||||||
LongRunningRequestRE: options.LongRunningRequestRE,
|
LongRunningFunc: genericfilters.BasicLongRunningRequestCheck(longRunningRE, map[string]string{"watch": "true"}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,6 +333,7 @@ func (c Config) New() (*GenericAPIServer, error) {
|
|||||||
// 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}/{*})
|
// 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.HandlerContainer.Router(restful.CurlyRouter{})
|
||||||
s.Mux = apiserver.NewPathRecorderMux(s.HandlerContainer.ServeMux)
|
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{
|
||||||
@ -332,22 +342,6 @@ func (c Config) New() (*GenericAPIServer, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.AuditLogPath) != 0 {
|
|
||||||
s.auditWriter = &lumberjack.Logger{
|
|
||||||
Filename: c.AuditLogPath,
|
|
||||||
MaxAge: c.AuditLogMaxAge,
|
|
||||||
MaxBackups: c.AuditLogMaxBackups,
|
|
||||||
MaxSize: c.AuditLogMaxSize,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send correct mime type for .svg files.
|
|
||||||
// TODO: remove when https://github.com/golang/go/commit/21e47d831bafb59f22b1ea8098f709677ec8ce33
|
|
||||||
// makes it into all of our supported go versions (only in v1.7.1 now).
|
|
||||||
mime.AddExtensionType(".svg", "image/svg+xml")
|
|
||||||
|
|
||||||
apiserver.InstallServiceErrorHandler(s.Serializer, s.HandlerContainer)
|
|
||||||
|
|
||||||
s.installAPI(&c)
|
s.installAPI(&c)
|
||||||
s.Handler, s.InsecureHandler = s.buildHandlerChains(&c, http.Handler(s.Mux.BaseMux().(*http.ServeMux)))
|
s.Handler, s.InsecureHandler = s.buildHandlerChains(&c, http.Handler(s.Mux.BaseMux().(*http.ServeMux)))
|
||||||
|
|
||||||
@ -355,27 +349,24 @@ func (c Config) New() (*GenericAPIServer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *GenericAPIServer) buildHandlerChains(c *Config, handler http.Handler) (secure http.Handler, insecure http.Handler) {
|
func (s *GenericAPIServer) buildHandlerChains(c *Config, handler http.Handler) (secure http.Handler, insecure http.Handler) {
|
||||||
longRunningRE := regexp.MustCompile(c.LongRunningRequestRE)
|
|
||||||
longRunningFunc := genericfilters.BasicLongRunningRequestCheck(longRunningRE, map[string]string{"watch": "true"})
|
|
||||||
|
|
||||||
// filters which insecure and secure have in common
|
// filters which insecure and secure have in common
|
||||||
handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, "true")
|
handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, "true")
|
||||||
|
|
||||||
// insecure filters
|
// insecure filters
|
||||||
insecure = handler
|
insecure = handler
|
||||||
insecure = genericfilters.WithPanicRecovery(insecure, s.NewRequestInfoResolver())
|
insecure = genericfilters.WithPanicRecovery(insecure, s.NewRequestInfoResolver())
|
||||||
insecure = genericfilters.WithTimeoutForNonLongRunningRequests(insecure, longRunningFunc)
|
insecure = genericfilters.WithTimeoutForNonLongRunningRequests(insecure, c.LongRunningFunc)
|
||||||
|
|
||||||
// secure filters
|
// secure filters
|
||||||
attributeGetter := apiserverfilters.NewRequestAttributeGetter(c.RequestContextMapper, s.NewRequestInfoResolver())
|
attributeGetter := apiserverfilters.NewRequestAttributeGetter(c.RequestContextMapper, s.NewRequestInfoResolver())
|
||||||
secure = handler
|
secure = handler
|
||||||
secure = apiserverfilters.WithAuthorization(secure, attributeGetter, c.Authorizer)
|
secure = apiserverfilters.WithAuthorization(secure, attributeGetter, c.Authorizer)
|
||||||
secure = apiserverfilters.WithImpersonation(secure, c.RequestContextMapper, c.Authorizer)
|
secure = apiserverfilters.WithImpersonation(secure, c.RequestContextMapper, c.Authorizer)
|
||||||
secure = apiserverfilters.WithAudit(secure, attributeGetter, s.auditWriter) // before impersonation to read original user
|
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 = authhandlers.WithAuthentication(secure, c.RequestContextMapper, c.Authenticator, authhandlers.Unauthorized(c.SupportsBasicAuth))
|
||||||
secure = genericfilters.WithPanicRecovery(secure, s.NewRequestInfoResolver())
|
secure = genericfilters.WithPanicRecovery(secure, s.NewRequestInfoResolver())
|
||||||
secure = genericfilters.WithTimeoutForNonLongRunningRequests(secure, longRunningFunc)
|
secure = genericfilters.WithTimeoutForNonLongRunningRequests(secure, c.LongRunningFunc)
|
||||||
secure = genericfilters.WithMaxInFlightLimit(secure, c.MaxRequestsInFlight, longRunningFunc)
|
secure = genericfilters.WithMaxInFlightLimit(secure, c.MaxRequestsInFlight, c.LongRunningFunc)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,9 @@ var errConnKilled = fmt.Errorf("kill connection/stream")
|
|||||||
|
|
||||||
// WithTimeoutForNonLongRunningRequests times out non-long-running requests after the time given by globalTimeout.
|
// WithTimeoutForNonLongRunningRequests times out non-long-running requests after the time given by globalTimeout.
|
||||||
func WithTimeoutForNonLongRunningRequests(handler http.Handler, longRunning LongRunningRequestCheck) http.Handler {
|
func WithTimeoutForNonLongRunningRequests(handler http.Handler, longRunning LongRunningRequestCheck) http.Handler {
|
||||||
|
if longRunning == nil {
|
||||||
|
return handler
|
||||||
|
}
|
||||||
timeoutFunc := func(req *http.Request) (<-chan time.Time, string) {
|
timeoutFunc := func(req *http.Request) (<-chan time.Time, string) {
|
||||||
// TODO unify this with apiserver.MaxInFlightLimit
|
// TODO unify this with apiserver.MaxInFlightLimit
|
||||||
if longRunning(req) {
|
if longRunning(req) {
|
||||||
|
@ -19,7 +19,7 @@ package genericapiserver
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"mime"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
@ -166,9 +166,13 @@ type GenericAPIServer struct {
|
|||||||
postStartHooks map[string]PostStartHookFunc
|
postStartHooks map[string]PostStartHookFunc
|
||||||
postStartHookLock sync.Mutex
|
postStartHookLock sync.Mutex
|
||||||
postStartHooksCalled bool
|
postStartHooksCalled bool
|
||||||
|
}
|
||||||
|
|
||||||
// Writer to write the audit log to.
|
func init() {
|
||||||
auditWriter io.Writer
|
// Send correct mime type for .svg files.
|
||||||
|
// TODO: remove when https://github.com/golang/go/commit/21e47d831bafb59f22b1ea8098f709677ec8ce33
|
||||||
|
// makes it into all of our supported go versions (only in v1.7.1 now).
|
||||||
|
mime.AddExtensionType(".svg", "image/svg+xml")
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestContextMapper is exposed so that third party resource storage can be build in a different location.
|
// RequestContextMapper is exposed so that third party resource storage can be build in a different location.
|
||||||
|
Loading…
Reference in New Issue
Block a user