Add TCP Middlewares support
This commit is contained in:
parent
679def0151
commit
fc9f41b955
134 changed files with 5865 additions and 1852 deletions
|
@ -18,8 +18,9 @@ func mergeConfiguration(configurations dynamic.Configurations, defaultEntryPoint
|
|||
ServersTransports: make(map[string]*dynamic.ServersTransport),
|
||||
},
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: make(map[string]*dynamic.TCPRouter),
|
||||
Services: make(map[string]*dynamic.TCPService),
|
||||
Routers: make(map[string]*dynamic.TCPRouter),
|
||||
Services: make(map[string]*dynamic.TCPService),
|
||||
Middlewares: make(map[string]*dynamic.TCPMiddleware),
|
||||
},
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: make(map[string]*dynamic.UDPRouter),
|
||||
|
@ -63,6 +64,9 @@ func mergeConfiguration(configurations dynamic.Configurations, defaultEntryPoint
|
|||
for routerName, router := range configuration.TCP.Routers {
|
||||
conf.TCP.Routers[provider.MakeQualifiedName(pvd, routerName)] = router
|
||||
}
|
||||
for middlewareName, middleware := range configuration.TCP.Middlewares {
|
||||
conf.TCP.Middlewares[provider.MakeQualifiedName(pvd, middlewareName)] = middleware
|
||||
}
|
||||
for serviceName, service := range configuration.TCP.Services {
|
||||
conf.TCP.Services[provider.MakeQualifiedName(pvd, serviceName)] = service
|
||||
}
|
||||
|
|
|
@ -253,7 +253,7 @@ func isEmptyConfiguration(conf *dynamic.Configuration) bool {
|
|||
|
||||
httpEmpty := conf.HTTP.Routers == nil && conf.HTTP.Services == nil && conf.HTTP.Middlewares == nil
|
||||
tlsEmpty := conf.TLS == nil || conf.TLS.Certificates == nil && conf.TLS.Stores == nil && conf.TLS.Options == nil
|
||||
tcpEmpty := conf.TCP.Routers == nil && conf.TCP.Services == nil
|
||||
tcpEmpty := conf.TCP.Routers == nil && conf.TCP.Services == nil && conf.TCP.Middlewares == nil
|
||||
udpEmpty := conf.UDP.Routers == nil && conf.UDP.Services == nil
|
||||
|
||||
return httpEmpty && tlsEmpty && tcpEmpty && udpEmpty
|
||||
|
|
|
@ -70,8 +70,9 @@ func TestNewConfigurationWatcher(t *testing.T) {
|
|||
th.WithLoadBalancerServices(),
|
||||
),
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Options: map[string]tls.Options{
|
||||
|
@ -225,8 +226,9 @@ func TestListenProvidersDoesNotSkipFlappingConfiguration(t *testing.T) {
|
|||
th.WithMiddlewares(),
|
||||
),
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
|
@ -284,8 +286,9 @@ func TestListenProvidersPublishesConfigForEachProvider(t *testing.T) {
|
|||
th.WithMiddlewares(),
|
||||
),
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Options: map[string]tls.Options{
|
||||
|
|
110
pkg/server/middleware/tcp/middlewares.go
Normal file
110
pkg/server/middleware/tcp/middlewares.go
Normal file
|
@ -0,0 +1,110 @@
|
|||
package tcpmiddleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/traefik/traefik/v2/pkg/config/runtime"
|
||||
ipwhitelist "github.com/traefik/traefik/v2/pkg/middlewares/tcp/ipwhitelist"
|
||||
"github.com/traefik/traefik/v2/pkg/server/provider"
|
||||
"github.com/traefik/traefik/v2/pkg/tcp"
|
||||
)
|
||||
|
||||
type middlewareStackType int
|
||||
|
||||
const (
|
||||
middlewareStackKey middlewareStackType = iota
|
||||
)
|
||||
|
||||
// Builder the middleware builder.
|
||||
type Builder struct {
|
||||
configs map[string]*runtime.TCPMiddlewareInfo
|
||||
}
|
||||
|
||||
// NewBuilder creates a new Builder.
|
||||
func NewBuilder(configs map[string]*runtime.TCPMiddlewareInfo) *Builder {
|
||||
return &Builder{configs: configs}
|
||||
}
|
||||
|
||||
// BuildChain creates a middleware chain.
|
||||
func (b *Builder) BuildChain(ctx context.Context, middlewares []string) *tcp.Chain {
|
||||
chain := tcp.NewChain()
|
||||
|
||||
for _, name := range middlewares {
|
||||
middlewareName := provider.GetQualifiedName(ctx, name)
|
||||
|
||||
chain = chain.Append(func(next tcp.Handler) (tcp.Handler, error) {
|
||||
constructorContext := provider.AddInContext(ctx, middlewareName)
|
||||
if midInf, ok := b.configs[middlewareName]; !ok || midInf.TCPMiddleware == nil {
|
||||
return nil, fmt.Errorf("middleware %q does not exist", middlewareName)
|
||||
}
|
||||
|
||||
var err error
|
||||
if constructorContext, err = checkRecursion(constructorContext, middlewareName); err != nil {
|
||||
b.configs[middlewareName].AddError(err, true)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
constructor, err := b.buildConstructor(constructorContext, middlewareName)
|
||||
if err != nil {
|
||||
b.configs[middlewareName].AddError(err, true)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
handler, err := constructor(next)
|
||||
if err != nil {
|
||||
b.configs[middlewareName].AddError(err, true)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return handler, nil
|
||||
})
|
||||
}
|
||||
|
||||
return &chain
|
||||
}
|
||||
|
||||
func checkRecursion(ctx context.Context, middlewareName string) (context.Context, error) {
|
||||
currentStack, ok := ctx.Value(middlewareStackKey).([]string)
|
||||
if !ok {
|
||||
currentStack = []string{}
|
||||
}
|
||||
|
||||
if inSlice(middlewareName, currentStack) {
|
||||
return ctx, fmt.Errorf("could not instantiate middleware %s: recursion detected in %s", middlewareName, strings.Join(append(currentStack, middlewareName), "->"))
|
||||
}
|
||||
|
||||
return context.WithValue(ctx, middlewareStackKey, append(currentStack, middlewareName)), nil
|
||||
}
|
||||
|
||||
func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (tcp.Constructor, error) {
|
||||
config := b.configs[middlewareName]
|
||||
if config == nil || config.TCPMiddleware == nil {
|
||||
return nil, fmt.Errorf("invalid middleware %q configuration", middlewareName)
|
||||
}
|
||||
|
||||
var middleware tcp.Constructor
|
||||
|
||||
// IPWhiteList
|
||||
if config.IPWhiteList != nil {
|
||||
middleware = func(next tcp.Handler) (tcp.Handler, error) {
|
||||
return ipwhitelist.New(ctx, next, *config.IPWhiteList, middlewareName)
|
||||
}
|
||||
}
|
||||
|
||||
if middleware == nil {
|
||||
return nil, fmt.Errorf("invalid middleware %q configuration: invalid middleware type or middleware does not exist", middlewareName)
|
||||
}
|
||||
|
||||
return middleware, nil
|
||||
}
|
||||
|
||||
func inSlice(element string, stack []string) bool {
|
||||
for _, value := range stack {
|
||||
if value == element {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -23,29 +23,36 @@ const (
|
|||
defaultTLSStoreName = "default"
|
||||
)
|
||||
|
||||
type middlewareBuilder interface {
|
||||
BuildChain(ctx context.Context, names []string) *tcp.Chain
|
||||
}
|
||||
|
||||
// NewManager Creates a new Manager.
|
||||
func NewManager(conf *runtime.Configuration,
|
||||
serviceManager *tcpservice.Manager,
|
||||
middlewaresBuilder middlewareBuilder,
|
||||
httpHandlers map[string]http.Handler,
|
||||
httpsHandlers map[string]http.Handler,
|
||||
tlsManager *traefiktls.Manager,
|
||||
) *Manager {
|
||||
return &Manager{
|
||||
serviceManager: serviceManager,
|
||||
httpHandlers: httpHandlers,
|
||||
httpsHandlers: httpsHandlers,
|
||||
tlsManager: tlsManager,
|
||||
conf: conf,
|
||||
serviceManager: serviceManager,
|
||||
middlewaresBuilder: middlewaresBuilder,
|
||||
httpHandlers: httpHandlers,
|
||||
httpsHandlers: httpsHandlers,
|
||||
tlsManager: tlsManager,
|
||||
conf: conf,
|
||||
}
|
||||
}
|
||||
|
||||
// Manager is a route/router manager.
|
||||
type Manager struct {
|
||||
serviceManager *tcpservice.Manager
|
||||
httpHandlers map[string]http.Handler
|
||||
httpsHandlers map[string]http.Handler
|
||||
tlsManager *traefiktls.Manager
|
||||
conf *runtime.Configuration
|
||||
serviceManager *tcpservice.Manager
|
||||
middlewaresBuilder middlewareBuilder
|
||||
httpHandlers map[string]http.Handler
|
||||
httpsHandlers map[string]http.Handler
|
||||
tlsManager *traefiktls.Manager
|
||||
conf *runtime.Configuration
|
||||
}
|
||||
|
||||
func (m *Manager) getTCPRouters(ctx context.Context, entryPoints []string) map[string]map[string]*runtime.TCPRouterInfo {
|
||||
|
@ -239,7 +246,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
|
|||
continue
|
||||
}
|
||||
|
||||
handler, err := m.serviceManager.BuildTCP(ctxRouter, routerConfig.Service)
|
||||
handler, err := m.buildTCPHandler(ctxRouter, routerConfig)
|
||||
if err != nil {
|
||||
routerConfig.AddError(err, true)
|
||||
logger.Error(err)
|
||||
|
@ -299,6 +306,27 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
|
|||
return router, nil
|
||||
}
|
||||
|
||||
func (m *Manager) buildTCPHandler(ctx context.Context, router *runtime.TCPRouterInfo) (tcp.Handler, error) {
|
||||
var qualifiedNames []string
|
||||
for _, name := range router.Middlewares {
|
||||
qualifiedNames = append(qualifiedNames, provider.GetQualifiedName(ctx, name))
|
||||
}
|
||||
router.Middlewares = qualifiedNames
|
||||
|
||||
if router.Service == "" {
|
||||
return nil, errors.New("the service is missing on the router")
|
||||
}
|
||||
|
||||
sHandler, err := m.serviceManager.BuildTCP(ctx, router.Service)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mHandler := m.middlewaresBuilder.BuildChain(ctx, router.Middlewares)
|
||||
|
||||
return tcp.NewChain().Extend(*mHandler).Then(sHandler)
|
||||
}
|
||||
|
||||
func findTLSOptionName(tlsOptionsForHost map[string]string, host string) string {
|
||||
tlsOptions, ok := tlsOptionsForHost[host]
|
||||
if ok {
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v2/pkg/config/runtime"
|
||||
tcpmiddleware "github.com/traefik/traefik/v2/pkg/server/middleware/tcp"
|
||||
"github.com/traefik/traefik/v2/pkg/server/service/tcp"
|
||||
traefiktls "github.com/traefik/traefik/v2/pkg/tls"
|
||||
)
|
||||
|
@ -302,7 +303,9 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
},
|
||||
[]*traefiktls.CertAndStores{})
|
||||
|
||||
routerManager := NewManager(conf, serviceManager,
|
||||
middlewaresBuilder := tcpmiddleware.NewBuilder(conf.TCPMiddlewares)
|
||||
|
||||
routerManager := NewManager(conf, serviceManager, middlewaresBuilder,
|
||||
nil, nil, tlsManager)
|
||||
|
||||
_ = routerManager.BuildHandlers(context.Background(), entryPoints)
|
||||
|
@ -532,7 +535,9 @@ func TestDomainFronting(t *testing.T) {
|
|||
"web": http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {}),
|
||||
}
|
||||
|
||||
routerManager := NewManager(conf, serviceManager, nil, httpsHandler, tlsManager)
|
||||
middlewaresBuilder := tcpmiddleware.NewBuilder(conf.TCPMiddlewares)
|
||||
|
||||
routerManager := NewManager(conf, serviceManager, middlewaresBuilder, nil, httpsHandler, tlsManager)
|
||||
|
||||
routers := routerManager.BuildHandlers(context.Background(), entryPoints)
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/traefik/traefik/v2/pkg/log"
|
||||
"github.com/traefik/traefik/v2/pkg/metrics"
|
||||
"github.com/traefik/traefik/v2/pkg/server/middleware"
|
||||
middlewaretcp "github.com/traefik/traefik/v2/pkg/server/middleware/tcp"
|
||||
"github.com/traefik/traefik/v2/pkg/server/router"
|
||||
routertcp "github.com/traefik/traefik/v2/pkg/server/router/tcp"
|
||||
routerudp "github.com/traefik/traefik/v2/pkg/server/router/udp"
|
||||
|
@ -81,7 +82,9 @@ func (f *RouterFactory) CreateRouters(rtConf *runtime.Configuration) (map[string
|
|||
// TCP
|
||||
svcTCPManager := tcp.NewManager(rtConf)
|
||||
|
||||
rtTCPManager := routertcp.NewManager(rtConf, svcTCPManager, handlersNonTLS, handlersTLS, f.tlsManager)
|
||||
middlewaresTCPBuilder := middlewaretcp.NewBuilder(rtConf.TCPMiddlewares)
|
||||
|
||||
rtTCPManager := routertcp.NewManager(rtConf, svcTCPManager, middlewaresTCPBuilder, handlersNonTLS, handlersTLS, f.tlsManager)
|
||||
routersTCP := rtTCPManager.BuildHandlers(ctx, f.entryPointsTCP)
|
||||
|
||||
// UDP
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue