1
0
Fork 0

Adds Docker provider support

Co-authored-by: Julien Salleyron <julien@containo.us>
This commit is contained in:
Ludovic Fernandez 2019-01-18 15:18:04 +01:00 committed by Traefiker Bot
parent 8735263930
commit b54c956c5e
78 changed files with 3476 additions and 5587 deletions

View file

@ -58,19 +58,20 @@ func (b *Builder) BuildChain(ctx context.Context, middlewares []string) *alice.C
for _, middlewareName := range middlewares {
middlewareName := internal.GetQualifiedName(ctx, middlewareName)
constructorContext := internal.AddProviderInContext(ctx, middlewareName)
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
if _, ok := b.configs[middlewareName]; !ok {
return nil, fmt.Errorf("middleware %q does not exist", middlewareName)
}
var err error
if constructorContext, err = checkRecursivity(constructorContext, middlewareName); err != nil {
return nil, err
}
if _, ok := b.configs[middlewareName]; !ok {
return nil, fmt.Errorf("middleware %q does not exist", middlewareName)
}
constructor, err := b.buildConstructor(constructorContext, middlewareName, *b.configs[middlewareName])
if err != nil {
return nil, fmt.Errorf("error while instanciation of %s: %v", middlewareName, err)
return nil, fmt.Errorf("error during instanciation of %s: %v", middlewareName, err)
}
return constructor(next)
})
@ -314,6 +315,10 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string, c
}
}
if middleware == nil {
return nil, fmt.Errorf("middleware %q does not exist", middlewareName)
}
return tracing.Wrap(ctx, middleware), nil
}

View file

@ -2,18 +2,18 @@ package middleware
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/containous/traefik/config"
"github.com/containous/traefik/server/internal"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMiddlewaresRegistry_BuildMiddlewareCircuitBreaker(t *testing.T) {
func TestBuilder_buildConstructorCircuitBreaker(t *testing.T) {
testConfig := map[string]*config.Middleware{
"empty": {
CircuitBreaker: &config.CircuitBreaker{
@ -65,7 +65,7 @@ func TestMiddlewaresRegistry_BuildMiddlewareCircuitBreaker(t *testing.T) {
}
}
func TestMiddlewaresRegistry_BuildChainNilConfig(t *testing.T) {
func TestBuilder_BuildChainNilConfig(t *testing.T) {
testConfig := map[string]*config.Middleware{
"empty": {},
}
@ -73,10 +73,21 @@ func TestMiddlewaresRegistry_BuildChainNilConfig(t *testing.T) {
chain := middlewaresBuilder.BuildChain(context.Background(), []string{"empty"})
_, err := chain.Then(nil)
require.NoError(t, err)
require.Error(t, err)
}
func TestMiddlewaresRegistry_BuildMiddlewareAddPrefix(t *testing.T) {
func TestBuilder_BuildChainNonExistentChain(t *testing.T) {
testConfig := map[string]*config.Middleware{
"foobar": {},
}
middlewaresBuilder := NewBuilder(testConfig, nil)
chain := middlewaresBuilder.BuildChain(context.Background(), []string{"empty"})
_, err := chain.Then(nil)
require.Error(t, err)
}
func TestBuilder_buildConstructorAddPrefix(t *testing.T) {
testConfig := map[string]*config.Middleware{
"empty": {
AddPrefix: &config.AddPrefix{
@ -98,7 +109,7 @@ func TestMiddlewaresRegistry_BuildMiddlewareAddPrefix(t *testing.T) {
expectedError bool
}{
{
desc: "Should not create an emty AddPrefix middleware when given an empty prefix",
desc: "Should not create an empty AddPrefix middleware when given an empty prefix",
middlewareID: "empty",
expectedError: true,
}, {
@ -128,7 +139,7 @@ func TestMiddlewaresRegistry_BuildMiddlewareAddPrefix(t *testing.T) {
}
}
func TestChainWithContext(t *testing.T) {
func TestBuild_BuildChainWithContext(t *testing.T) {
testCases := []struct {
desc string
buildChain []string

View file

@ -57,7 +57,16 @@ func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string) m
log.FromContext(ctx).Error(err)
continue
}
entryPointHandlers[entryPointName] = handler
handlerWithAccessLog, err := alice.New(func(next http.Handler) (http.Handler, error) {
return accesslog.NewFieldHandler(next, log.EntryPointName, entryPointName, accesslog.AddOriginFields), nil
}).Then(handler)
if err != nil {
log.FromContext(ctx).Error(err)
entryPointHandlers[entryPointName] = handler
} else {
entryPointHandlers[entryPointName] = handlerWithAccessLog
}
}
m.serviceManager.LaunchHealthCheck()
@ -171,13 +180,9 @@ func (m *Manager) buildHandler(ctx context.Context, router *config.Router, route
mHandler := m.middlewaresBuilder.BuildChain(ctx, router.Middlewares)
alHandler := func(next http.Handler) (http.Handler, error) {
return accesslog.NewFieldHandler(next, accesslog.ServiceName, router.Service, accesslog.AddServiceFields), nil
}
tHandler := func(next http.Handler) (http.Handler, error) {
return tracing.NewForwarder(ctx, routerName, router.Service, next), nil
}
return alice.New().Append(alHandler).Extend(*mHandler).Append(tHandler).Then(sHandler)
return alice.New().Extend(*mHandler).Append(tHandler).Then(sHandler)
}

View file

@ -25,7 +25,7 @@ import (
"github.com/sirupsen/logrus"
)
// loadConfiguration manages dynamically frontends, backends and TLS configurations
// loadConfiguration manages dynamically routers, middlewares, servers and TLS configurations
func (s *Server) loadConfiguration(configMsg config.Message) {
logger := log.FromContext(log.With(context.Background(), log.Str(log.ProviderName, configMsg.ProviderName)))

View file

@ -9,10 +9,12 @@ import (
"net/url"
"time"
"github.com/containous/alice"
"github.com/containous/flaeg/parse"
"github.com/containous/traefik/config"
"github.com/containous/traefik/healthcheck"
"github.com/containous/traefik/log"
"github.com/containous/traefik/middlewares/accesslog"
"github.com/containous/traefik/middlewares/emptybackendhandler"
"github.com/containous/traefik/old/middlewares/pipelining"
"github.com/containous/traefik/server/cookie"
@ -84,14 +86,16 @@ func (m *Manager) getLoadBalancerServiceHandler(
return nil, err
}
fwd = pipelining.NewPipelining(fwd)
alHandler := func(next http.Handler) (http.Handler, error) {
return accesslog.NewFieldHandler(next, accesslog.ServiceName, serviceName, accesslog.AddServiceFields), nil
}
rr, err := roundrobin.New(fwd)
handler, err := alice.New().Append(alHandler).Then(pipelining.NewPipelining(fwd))
if err != nil {
return nil, err
}
balancer, err := m.getLoadBalancer(ctx, serviceName, service, fwd, rr)
balancer, err := m.getLoadBalancer(ctx, serviceName, service, handler)
if err != nil {
return nil, err
}
@ -181,7 +185,7 @@ func buildHealthCheckOptions(ctx context.Context, lb healthcheck.BalancerHandler
}
}
func (m *Manager) getLoadBalancer(ctx context.Context, serviceName string, service *config.LoadBalancerService, fwd http.Handler, rr balancerHandler) (healthcheck.BalancerHandler, error) {
func (m *Manager) getLoadBalancer(ctx context.Context, serviceName string, service *config.LoadBalancerService, fwd http.Handler) (healthcheck.BalancerHandler, error) {
logger := log.FromContext(ctx)
var stickySession *roundrobin.StickySession
@ -192,10 +196,13 @@ func (m *Manager) getLoadBalancer(ctx context.Context, serviceName string, servi
}
var lb healthcheck.BalancerHandler
var err error
if service.Method == "drr" {
logger.Debug("Creating drr load-balancer")
rr, err := roundrobin.New(fwd)
if err != nil {
return nil, err
}
if stickySession != nil {
logger.Debugf("Sticky session cookie name: %v", cookieName)
@ -220,12 +227,17 @@ func (m *Manager) getLoadBalancer(ctx context.Context, serviceName string, servi
if stickySession != nil {
logger.Debugf("Sticky session cookie name: %v", cookieName)
var err error
lb, err = roundrobin.New(fwd, roundrobin.EnableStickySession(stickySession))
if err != nil {
return nil, err
}
} else {
lb = rr
var err error
lb, err = roundrobin.New(fwd)
if err != nil {
return nil, err
}
}
}

View file

@ -2,10 +2,8 @@ package service
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"github.com/containous/traefik/config"
@ -13,41 +11,8 @@ import (
"github.com/containous/traefik/testhelpers"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vulcand/oxy/roundrobin"
)
type MockRR struct {
err error
}
func (*MockRR) Servers() []*url.URL {
panic("implement me")
}
func (*MockRR) ServeHTTP(w http.ResponseWriter, req *http.Request) {
panic("implement me")
}
func (*MockRR) ServerWeight(u *url.URL) (int, bool) {
panic("implement me")
}
func (*MockRR) RemoveServer(u *url.URL) error {
panic("implement me")
}
func (m *MockRR) UpsertServer(u *url.URL, options ...roundrobin.ServerOption) error {
return m.err
}
func (*MockRR) NextServer() (*url.URL, error) {
panic("implement me")
}
func (*MockRR) Next() http.Handler {
panic("implement me")
}
type MockForwarder struct{}
func (MockForwarder) ServeHTTP(http.ResponseWriter, *http.Request) {
@ -62,7 +27,6 @@ func TestGetLoadBalancer(t *testing.T) {
serviceName string
service *config.LoadBalancerService
fwd http.Handler
rr balancerHandler
expectError bool
}{
{
@ -77,22 +41,6 @@ func TestGetLoadBalancer(t *testing.T) {
},
},
fwd: &MockForwarder{},
rr: &MockRR{},
expectError: true,
},
{
desc: "Fails when the server upsert fails",
serviceName: "test",
service: &config.LoadBalancerService{
Servers: []config.Server{
{
URL: "http://foo",
Weight: 0,
},
},
},
fwd: &MockForwarder{},
rr: &MockRR{err: errors.New("upsert fails")},
expectError: true,
},
{
@ -100,7 +48,6 @@ func TestGetLoadBalancer(t *testing.T) {
serviceName: "test",
service: &config.LoadBalancerService{},
fwd: &MockForwarder{},
rr: &MockRR{},
expectError: false,
},
{
@ -110,7 +57,6 @@ func TestGetLoadBalancer(t *testing.T) {
Stickiness: &config.Stickiness{},
},
fwd: &MockForwarder{},
rr: &MockRR{},
expectError: false,
},
}
@ -120,7 +66,7 @@ func TestGetLoadBalancer(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
handler, err := sm.getLoadBalancer(context.Background(), test.serviceName, test.service, test.fwd, test.rr)
handler, err := sm.getLoadBalancer(context.Background(), test.serviceName, test.service, test.fwd)
if test.expectError {
require.Error(t, err)
assert.Nil(t, handler)