1
0
Fork 0

Add internal provider

Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
This commit is contained in:
Ludovic Fernandez 2019-11-14 16:40:05 +01:00 committed by Traefiker Bot
parent 2ee2e29262
commit 424e2a9439
71 changed files with 2523 additions and 1469 deletions

View file

@ -1,89 +0,0 @@
package router
import (
"context"
"github.com/containous/alice"
"github.com/containous/traefik/v2/pkg/api"
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/config/static"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/metrics"
"github.com/containous/traefik/v2/pkg/types"
"github.com/gorilla/mux"
)
// NewRouteAppenderAggregator Creates a new RouteAppenderAggregator
func NewRouteAppenderAggregator(ctx context.Context, conf static.Configuration,
entryPointName string, runtimeConfiguration *runtime.Configuration) *RouteAppenderAggregator {
aggregator := &RouteAppenderAggregator{}
if conf.Ping != nil && conf.Ping.EntryPoint == entryPointName {
aggregator.AddAppender(conf.Ping)
}
if conf.Metrics != nil && conf.Metrics.Prometheus != nil && conf.Metrics.Prometheus.EntryPoint == entryPointName {
aggregator.AddAppender(metrics.PrometheusHandler{})
}
if entryPointName != "traefik" {
return aggregator
}
if conf.Providers != nil && conf.Providers.Rest != nil && conf.Providers.Rest.Insecure {
aggregator.AddAppender(conf.Providers.Rest)
}
if conf.API != nil && conf.API.Insecure {
aggregator.AddAppender(api.New(conf, runtimeConfiguration))
}
return aggregator
}
// RouteAppenderAggregator RouteAppender that aggregate other RouteAppender
type RouteAppenderAggregator struct {
appenders []types.RouteAppender
}
// Append Adds routes to the router
func (r *RouteAppenderAggregator) Append(systemRouter *mux.Router) {
for _, router := range r.appenders {
router.Append(systemRouter)
}
}
// AddAppender adds a router in the aggregator
func (r *RouteAppenderAggregator) AddAppender(router types.RouteAppender) {
r.appenders = append(r.appenders, router)
}
// WithMiddleware router with internal middleware
type WithMiddleware struct {
appender types.RouteAppender
routerMiddlewares *alice.Chain
}
// Append Adds routes to the router
func (wm *WithMiddleware) Append(systemRouter *mux.Router) {
realRouter := systemRouter.PathPrefix("/").Subrouter()
wm.appender.Append(realRouter)
if err := realRouter.Walk(wrapRoute(wm.routerMiddlewares)); err != nil {
log.WithoutContext().Error(err)
}
}
// wrapRoute with middlewares
func wrapRoute(middlewares *alice.Chain) func(*mux.Route, *mux.Router, []*mux.Route) error {
return func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
handler, err := middlewares.Then(route.GetHandler())
if err != nil {
return err
}
route.Handler(handler)
return nil
}
}

View file

@ -1,79 +0,0 @@
package router
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"github.com/containous/traefik/v2/pkg/config/static"
"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
)
func TestNewRouteAppenderAggregator(t *testing.T) {
testCases := []struct {
desc string
staticConf static.Configuration
expected map[string]int
}{
{
desc: "Secure API",
staticConf: static.Configuration{
Global: &static.Global{},
API: &static.API{
Insecure: false,
},
EntryPoints: static.EntryPoints{
"traefik": {},
},
},
expected: map[string]int{
"/api/providers": http.StatusBadGateway,
},
},
{
desc: "Insecure API",
staticConf: static.Configuration{
Global: &static.Global{},
API: &static.API{
Insecure: true,
},
EntryPoints: static.EntryPoints{
"traefik": {},
},
},
expected: map[string]int{
"/api/rawdata": http.StatusOK,
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
ctx := context.Background()
router := NewRouteAppenderAggregator(ctx, test.staticConf, "traefik", nil)
internalMuxRouter := mux.NewRouter()
router.Append(internalMuxRouter)
internalMuxRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadGateway)
})
actual := make(map[string]int)
for calledURL := range test.expected {
recorder := httptest.NewRecorder()
request := httptest.NewRequest(http.MethodGet, calledURL, nil)
internalMuxRouter.ServeHTTP(recorder, request)
actual[calledURL] = recorder.Code
}
assert.Equal(t, test.expected, actual)
})
}
}

View file

@ -1,40 +0,0 @@
package router
import (
"context"
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/config/static"
"github.com/containous/traefik/v2/pkg/provider/acme"
"github.com/containous/traefik/v2/pkg/types"
)
// NewRouteAppenderFactory Creates a new RouteAppenderFactory
func NewRouteAppenderFactory(staticConfiguration static.Configuration, entryPointName string, acmeProvider []*acme.Provider) *RouteAppenderFactory {
return &RouteAppenderFactory{
staticConfiguration: staticConfiguration,
entryPointName: entryPointName,
acmeProvider: acmeProvider,
}
}
// RouteAppenderFactory A factory of RouteAppender
type RouteAppenderFactory struct {
staticConfiguration static.Configuration
entryPointName string
acmeProvider []*acme.Provider
}
// NewAppender Creates a new RouteAppender
func (r *RouteAppenderFactory) NewAppender(ctx context.Context, runtimeConfiguration *runtime.Configuration) types.RouteAppender {
aggregator := NewRouteAppenderAggregator(ctx, r.staticConfiguration, r.entryPointName, runtimeConfiguration)
for _, p := range r.acmeProvider {
if p != nil && p.HTTPChallenge != nil && p.HTTPChallenge.EntryPoint == r.entryPointName {
aggregator.AddAppender(p)
break
}
}
return aggregator
}

View file

@ -11,41 +11,55 @@ import (
"github.com/containous/traefik/v2/pkg/middlewares/accesslog"
"github.com/containous/traefik/v2/pkg/middlewares/recovery"
"github.com/containous/traefik/v2/pkg/middlewares/tracing"
"github.com/containous/traefik/v2/pkg/responsemodifiers"
"github.com/containous/traefik/v2/pkg/rules"
"github.com/containous/traefik/v2/pkg/server/internal"
"github.com/containous/traefik/v2/pkg/server/middleware"
"github.com/containous/traefik/v2/pkg/server/service"
)
const (
recoveryMiddlewareName = "traefik-internal-recovery"
)
type middlewareBuilder interface {
BuildChain(ctx context.Context, names []string) *alice.Chain
}
type responseModifierBuilder interface {
Build(ctx context.Context, names []string) func(*http.Response) error
}
type serviceManager interface {
BuildHTTP(rootCtx context.Context, serviceName string, responseModifier func(*http.Response) error) (http.Handler, error)
LaunchHealthCheck()
}
// Manager A route/router manager
type Manager struct {
routerHandlers map[string]http.Handler
serviceManager serviceManager
middlewaresBuilder middlewareBuilder
chainBuilder *middleware.ChainBuilder
modifierBuilder responseModifierBuilder
conf *runtime.Configuration
}
// NewManager Creates a new Manager
func NewManager(conf *runtime.Configuration,
serviceManager *service.Manager,
middlewaresBuilder *middleware.Builder,
modifierBuilder *responsemodifiers.Builder,
serviceManager serviceManager,
middlewaresBuilder middlewareBuilder,
modifierBuilder responseModifierBuilder,
chainBuilder *middleware.ChainBuilder,
) *Manager {
return &Manager{
routerHandlers: make(map[string]http.Handler),
serviceManager: serviceManager,
middlewaresBuilder: middlewaresBuilder,
modifierBuilder: modifierBuilder,
chainBuilder: chainBuilder,
conf: conf,
}
}
// Manager A route/router manager
type Manager struct {
routerHandlers map[string]http.Handler
serviceManager *service.Manager
middlewaresBuilder *middleware.Builder
modifierBuilder *responsemodifiers.Builder
conf *runtime.Configuration
}
func (m *Manager) getHTTPRouters(ctx context.Context, entryPoints []string, tls bool) map[string]map[string]*runtime.RouterInfo {
if m.conf != nil {
return m.conf.GetRoutersByEntryPoints(ctx, entryPoints, tls)
@ -79,6 +93,22 @@ func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string, t
}
}
for _, entryPointName := range entryPoints {
ctx := log.With(rootCtx, log.Str(log.EntryPointName, entryPointName))
handler, ok := entryPointHandlers[entryPointName]
if !ok || handler == nil {
handler = BuildDefaultHTTPRouter()
}
handlerWithMiddlewares, err := m.chainBuilder.Build(ctx, entryPointName).Then(handler)
if err != nil {
log.FromContext(ctx).Error(err)
continue
}
entryPointHandlers[entryPointName] = handlerWithMiddlewares
}
m.serviceManager.LaunchHealthCheck()
return entryPointHandlers
@ -167,3 +197,8 @@ func (m *Manager) buildHTTPHandler(ctx context.Context, router *runtime.RouterIn
return alice.New().Extend(*mHandler).Append(tHandler).Then(sHandler)
}
// BuildDefaultHTTPRouter creates a default HTTP router.
func BuildDefaultHTTPRouter() http.Handler {
return http.NotFoundHandler()
}

View file

@ -10,6 +10,7 @@ import (
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/config/static"
"github.com/containous/traefik/v2/pkg/middlewares/accesslog"
"github.com/containous/traefik/v2/pkg/middlewares/requestdecorator"
"github.com/containous/traefik/v2/pkg/responsemodifiers"
@ -24,7 +25,7 @@ import (
func TestRouterManager_Get(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
type ExpectedResult struct {
type expectedResult struct {
StatusCode int
RequestHeaders map[string]string
}
@ -35,7 +36,7 @@ func TestRouterManager_Get(t *testing.T) {
serviceConfig map[string]*dynamic.Service
middlewaresConfig map[string]*dynamic.Middleware
entryPoints []string
expected ExpectedResult
expected expectedResult
}{
{
desc: "no middleware",
@ -58,7 +59,7 @@ func TestRouterManager_Get(t *testing.T) {
},
},
entryPoints: []string{"web"},
expected: ExpectedResult{StatusCode: http.StatusOK},
expected: expectedResult{StatusCode: http.StatusOK},
},
{
desc: "no load balancer",
@ -73,7 +74,7 @@ func TestRouterManager_Get(t *testing.T) {
"foo-service": {},
},
entryPoints: []string{"web"},
expected: ExpectedResult{StatusCode: http.StatusNotFound},
expected: expectedResult{StatusCode: http.StatusNotFound},
},
{
desc: "no middleware, default entry point",
@ -95,7 +96,7 @@ func TestRouterManager_Get(t *testing.T) {
},
},
entryPoints: []string{"web"},
expected: ExpectedResult{StatusCode: http.StatusOK},
expected: expectedResult{StatusCode: http.StatusOK},
},
{
desc: "no middleware, no matching",
@ -118,7 +119,7 @@ func TestRouterManager_Get(t *testing.T) {
},
},
entryPoints: []string{"web"},
expected: ExpectedResult{StatusCode: http.StatusNotFound},
expected: expectedResult{StatusCode: http.StatusNotFound},
},
{
desc: "middleware: headers > auth",
@ -154,7 +155,7 @@ func TestRouterManager_Get(t *testing.T) {
},
},
entryPoints: []string{"web"},
expected: ExpectedResult{
expected: expectedResult{
StatusCode: http.StatusUnauthorized,
RequestHeaders: map[string]string{
"X-Apero": "beer",
@ -195,7 +196,7 @@ func TestRouterManager_Get(t *testing.T) {
},
},
entryPoints: []string{"web"},
expected: ExpectedResult{
expected: expectedResult{
StatusCode: http.StatusUnauthorized,
RequestHeaders: map[string]string{
"X-Apero": "",
@ -223,7 +224,7 @@ func TestRouterManager_Get(t *testing.T) {
},
},
entryPoints: []string{"web"},
expected: ExpectedResult{StatusCode: http.StatusOK},
expected: expectedResult{StatusCode: http.StatusOK},
},
{
desc: "no middleware with specified provider name",
@ -246,7 +247,7 @@ func TestRouterManager_Get(t *testing.T) {
},
},
entryPoints: []string{"web"},
expected: ExpectedResult{StatusCode: http.StatusOK},
expected: expectedResult{StatusCode: http.StatusOK},
},
{
desc: "middleware: chain with provider name",
@ -285,7 +286,7 @@ func TestRouterManager_Get(t *testing.T) {
},
},
entryPoints: []string{"web"},
expected: ExpectedResult{
expected: expectedResult{
StatusCode: http.StatusUnauthorized,
RequestHeaders: map[string]string{
"X-Apero": "",
@ -306,10 +307,13 @@ func TestRouterManager_Get(t *testing.T) {
Middlewares: test.middlewaresConfig,
},
})
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil, nil, nil)
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil)
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory, chainBuilder)
handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false)
@ -407,10 +411,12 @@ func TestAccessLog(t *testing.T) {
},
})
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil, nil, nil)
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil)
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory, chainBuilder)
handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false)
@ -680,7 +686,6 @@ func TestRuntimeConfiguration(t *testing.T) {
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
@ -693,10 +698,13 @@ func TestRuntimeConfiguration(t *testing.T) {
Middlewares: test.middlewareConfig,
},
})
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil, nil, nil)
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil)
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
responseModifierFactory := responsemodifiers.NewBuilder(map[string]*runtime.MiddlewareInfo{})
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory, chainBuilder)
_ = routerManager.BuildHandlers(context.Background(), entryPoints, false)
@ -762,10 +770,13 @@ func TestProviderOnMiddlewares(t *testing.T) {
},
},
})
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil, nil, nil)
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil)
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
responseModifierFactory := responsemodifiers.NewBuilder(map[string]*runtime.MiddlewareInfo{})
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory, chainBuilder)
_ = routerManager.BuildHandlers(context.Background(), entryPoints, false)
@ -790,6 +801,7 @@ func BenchmarkRouterServe(b *testing.B) {
StatusCode: 200,
Body: ioutil.NopCloser(strings.NewReader("")),
}
routersConfig := map[string]*dynamic.Router{
"foo": {
EntryPoints: []string{"web"},
@ -817,10 +829,13 @@ func BenchmarkRouterServe(b *testing.B) {
Middlewares: map[string]*dynamic.Middleware{},
},
})
serviceManager := service.NewManager(rtConf.Services, &staticTransport{res}, nil, nil, nil, nil)
serviceManager := service.NewManager(rtConf.Services, &staticTransport{res}, nil, nil)
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory, chainBuilder)
handlers := routerManager.BuildHandlers(context.Background(), entryPoints, false)
@ -857,7 +872,8 @@ func BenchmarkService(b *testing.B) {
Services: serviceConfig,
},
})
serviceManager := service.NewManager(rtConf.Services, &staticTransport{res}, nil, nil, nil, nil)
serviceManager := service.NewManager(rtConf.Services, &staticTransport{res}, nil, nil)
w := httptest.NewRecorder()
req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil)

View file

@ -16,6 +16,11 @@ import (
traefiktls "github.com/containous/traefik/v2/pkg/tls"
)
const (
defaultTLSConfigName = "default"
defaultTLSStoreName = "default"
)
// NewManager Creates a new Manager
func NewManager(conf *runtime.Configuration,
serviceManager *tcpservice.Manager,
@ -88,15 +93,18 @@ type nameAndConfig struct {
func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string]*runtime.TCPRouterInfo, configsHTTP map[string]*runtime.RouterInfo, handlerHTTP http.Handler, handlerHTTPS http.Handler) (*tcp.Router, error) {
router := &tcp.Router{}
router.HTTPHandler(handlerHTTP)
const defaultTLSConfigName = "default"
defaultTLSConf, err := m.tlsManager.Get("default", defaultTLSConfigName)
defaultTLSConf, err := m.tlsManager.Get(defaultTLSStoreName, defaultTLSConfigName)
if err != nil {
log.FromContext(ctx).Errorf("Error during the build of the default TLS configuration: %v", err)
}
router.HTTPSHandler(handlerHTTPS, defaultTLSConf)
if len(configsHTTP) > 0 {
router.AddRouteHTTPTLS("*", defaultTLSConf)
}
// Keyed by domain, then by options reference.
tlsOptionsForHostSNI := map[string]map[string]nameAndConfig{}
for routerHTTPName, routerHTTPConfig := range configsHTTP {
@ -126,12 +134,13 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
tlsOptionsName = internal.GetQualifiedName(ctxRouter, routerHTTPConfig.TLS.Options)
}
tlsConf, err := m.tlsManager.Get("default", tlsOptionsName)
tlsConf, err := m.tlsManager.Get(defaultTLSStoreName, tlsOptionsName)
if err != nil {
routerHTTPConfig.AddError(err, true)
logger.Debug(err)
continue
}
if tlsOptionsForHostSNI[domain] == nil {
tlsOptionsForHostSNI[domain] = make(map[string]nameAndConfig)
}
@ -153,7 +162,9 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
config = v.TLSConfig
break
}
logger.Debugf("Adding route for %s with TLS options %s", hostSNI, optionsName)
router.AddRouteHTTPTLS(hostSNI, config)
} else {
routers := make([]string, 0, len(tlsConfigs))
@ -161,7 +172,9 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
configsHTTP[v.routerName].AddError(fmt.Errorf("found different TLS options for routers on the same host %v, so using the default TLS options instead", hostSNI), false)
routers = append(routers, v.routerName)
}
logger.Warnf("Found different TLS options for routers on the same host %v, so using the default TLS options instead for these routers: %#v", hostSNI, routers)
router.AddRouteHTTPTLS(hostSNI, defaultTLSConf)
}
}
@ -216,7 +229,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
tlsOptionsName = internal.GetQualifiedName(ctxRouter, tlsOptionsName)
}
tlsConf, err := m.tlsManager.Get("default", tlsOptionsName)
tlsConf, err := m.tlsManager.Get(defaultTLSStoreName, tlsOptionsName)
if err != nil {
routerConfig.AddError(err, true)
logger.Debug(err)