From ec245d604a68beee28128f9b7352fa00baa1befc Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Fri, 7 Apr 2017 15:48:58 +0200 Subject: [PATCH 1/7] Fix postLoadConfig Signed-off-by: Emile Vauge --- server/server.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/server/server.go b/server/server.go index b8f8b502d..1d247b617 100644 --- a/server/server.go +++ b/server/server.go @@ -315,15 +315,16 @@ func (server *Server) postLoadConfig() { for _, frontend := range configuration.Frontends { // check if one of the frontend entrypoints is configured with TLS - TLSEnabled := false + // and is configured with ACME + ACMEEnabled := false for _, entrypoint := range frontend.EntryPoints { - if server.globalConfiguration.EntryPoints[entrypoint].TLS != nil { - TLSEnabled = true + if server.globalConfiguration.ACME.EntryPoint == entrypoint && server.globalConfiguration.EntryPoints[entrypoint].TLS != nil { + ACMEEnabled = true break } } - if TLSEnabled { + if ACMEEnabled { for _, route := range frontend.Routes { rules := Rules{} domains, err := rules.ParseDomains(route.Rule) From bf3f6e20294ff9c6f8c732e8fc979eaa1842f387 Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Fri, 7 Apr 2017 16:30:57 +0200 Subject: [PATCH 2/7] Fix Docker filter empty rule Signed-off-by: Emile Vauge --- provider/docker/docker.go | 12 +- provider/docker/docker_test.go | 378 ++++++++++++++++++++++++--------- provider/docker/swarm_test.go | 106 +++++---- 3 files changed, 352 insertions(+), 144 deletions(-) diff --git a/provider/docker/docker.go b/provider/docker/docker.go index c31ff7a04..b2128bbfc 100644 --- a/provider/docker/docker.go +++ b/provider/docker/docker.go @@ -523,6 +523,11 @@ func (p *Provider) containerFilter(container dockerData) bool { return false } + if len(p.getFrontendRule(container)) == 0 { + log.Debugf("Filtering container with empty frontend rule %s", container.Name) + return false + } + return true } @@ -537,11 +542,10 @@ func (p *Provider) getFrontendRule(container dockerData) string { if label, err := getLabel(container, "traefik.frontend.rule"); err == nil { return label } - if labels, err := getLabels(container, []string{"com.docker.compose.project", "com.docker.compose.service"}); err == nil { - return "Host:" + p.getSubDomain(labels["com.docker.compose.service"]+"."+labels["com.docker.compose.project"]) + "." + p.Domain + if len(p.Domain) > 0 { + return "Host:" + p.getSubDomain(container.ServiceName) + "." + p.Domain } - - return "Host:" + p.getSubDomain(container.ServiceName) + "." + p.Domain + return "" } func (p *Provider) getBackend(container dockerData) string { diff --git a/provider/docker/docker_test.go b/provider/docker/docker_test.go index 30746b73b..5f9fa42f0 100644 --- a/provider/docker/docker_test.go +++ b/provider/docker/docker_test.go @@ -8,6 +8,7 @@ import ( "github.com/containous/traefik/types" docker "github.com/docker/engine-api/types" + "github.com/docker/engine-api/types/container" "github.com/docker/go-connections/nat" ) @@ -488,127 +489,300 @@ func TestDockerGetLabels(t *testing.T) { func TestDockerTraefikFilter(t *testing.T) { containers := []struct { - container docker.ContainerJSON - exposedByDefault bool - expected bool + container docker.ContainerJSON + expected bool + provider *Provider }{ { - container: containerJSON(), - exposedByDefault: true, - expected: false, + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{}, + NetworkSettings: &docker.NetworkSettings{}, + }, + expected: false, + provider: &Provider{ + Domain: "test", + ExposedByDefault: true, + }, }, { - container: containerJSON( - labels(map[string]string{ - "traefik.enable": "false", - }), - ports(nat.PortMap{ - "80/tcp": {}, - }), - ), - exposedByDefault: true, - expected: false, + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{ + Labels: map[string]string{ + "traefik.enable": "false", + }, + }, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + Domain: "test", + ExposedByDefault: true, + }, + expected: false, }, { - container: containerJSON( - labels(map[string]string{ - "traefik.frontend.rule": "Host:foo.bar", - }), - ports(nat.PortMap{ - "80/tcp": {}, - }), - ), - exposedByDefault: true, - expected: true, + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{ + Labels: map[string]string{ + "traefik.frontend.rule": "Host:foo.bar", + }, + }, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + Domain: "test", + ExposedByDefault: true, + }, + expected: true, }, { - container: containerJSON( - ports(nat.PortMap{ - "80/tcp": {}, - "443/tcp": {}, - }), - ), - exposedByDefault: true, - expected: true, + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container-multi-ports", + }, + Config: &container.Config{}, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + "443/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + Domain: "test", + ExposedByDefault: true, + }, + expected: true, }, { - container: containerJSON( - ports(nat.PortMap{ - "80/tcp": {}, - }), - ), - exposedByDefault: true, - expected: true, + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{}, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + Domain: "test", + ExposedByDefault: true, + }, + expected: true, }, { - container: containerJSON( - labels(map[string]string{ - "traefik.port": "80", - }), - ports(nat.PortMap{ - "80/tcp": {}, - "443/tcp": {}, - }), - ), - exposedByDefault: true, - expected: true, + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{ + Labels: map[string]string{ + "traefik.port": "80", + }, + }, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + "443/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + Domain: "test", + ExposedByDefault: true, + }, + expected: true, }, { - container: containerJSON( - labels(map[string]string{ - "traefik.enable": "true", - }), - ports(nat.PortMap{ - "80/tcp": {}, - }), - ), - exposedByDefault: true, - expected: true, + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{ + Labels: map[string]string{ + "traefik.enable": "true", + }, + }, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + Domain: "test", + ExposedByDefault: true, + }, + expected: true, }, { - container: containerJSON( - labels(map[string]string{ - "traefik.enable": "anything", - }), - ports(nat.PortMap{ - "80/tcp": {}, - }), - ), - exposedByDefault: true, - expected: true, + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{ + Labels: map[string]string{ + "traefik.enable": "anything", + }, + }, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + Domain: "test", + ExposedByDefault: true, + }, + expected: true, }, { - container: containerJSON( - labels(map[string]string{ - "traefik.frontend.rule": "Host:foo.bar", - }), - ports(nat.PortMap{ - "80/tcp": {}, - }), - ), - exposedByDefault: true, - expected: true, + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{ + Labels: map[string]string{ + "traefik.frontend.rule": "Host:foo.bar", + }, + }, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + Domain: "test", + ExposedByDefault: true, + }, + expected: true, }, { - container: containerJSON( - ports(nat.PortMap{ - "80/tcp": {}, - }), - ), - exposedByDefault: false, - expected: false, + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{}, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + Domain: "test", + ExposedByDefault: false, + }, + expected: false, }, { - container: containerJSON( - labels(map[string]string{ - "traefik.enable": "true", - }), - ports(nat.PortMap{ - "80/tcp": {}, - }), - ), - exposedByDefault: false, - expected: true, + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{ + Labels: map[string]string{ + "traefik.enable": "true", + }, + }, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + Domain: "test", + ExposedByDefault: false, + }, + expected: true, + }, + { + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{ + Labels: map[string]string{ + "traefik.enable": "true", + }, + }, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + ExposedByDefault: false, + }, + expected: false, + }, + { + container: docker.ContainerJSON{ + ContainerJSONBase: &docker.ContainerJSONBase{ + Name: "container", + }, + Config: &container.Config{ + Labels: map[string]string{ + "traefik.enable": "true", + "traefik.frontend.rule": "Host:i.love.this.host", + }, + }, + NetworkSettings: &docker.NetworkSettings{ + NetworkSettingsBase: docker.NetworkSettingsBase{ + Ports: nat.PortMap{ + "80/tcp": {}, + }, + }, + }, + }, + provider: &Provider{ + ExposedByDefault: false, + }, + expected: true, }, } @@ -616,12 +790,10 @@ func TestDockerTraefikFilter(t *testing.T) { e := e t.Run(strconv.Itoa(containerID), func(t *testing.T) { t.Parallel() - provider := Provider{} - provider.ExposedByDefault = e.exposedByDefault dockerData := parseContainer(e.container) - actual := provider.containerFilter(dockerData) + actual := e.provider.containerFilter(dockerData) if actual != e.expected { - t.Errorf("expected %v for %+v (%+v, %+v), got %+v", e.expected, e.container, e.container.NetworkSettings, e.container.ContainerJSONBase, actual) + t.Errorf("expected %v for %+v, got %+v", e.expected, e, actual) } }) } diff --git a/provider/docker/swarm_test.go b/provider/docker/swarm_test.go index 56cfb8acf..b757118ba 100644 --- a/provider/docker/swarm_test.go +++ b/provider/docker/swarm_test.go @@ -503,86 +503,122 @@ func TestSwarmGetLabels(t *testing.T) { func TestSwarmTraefikFilter(t *testing.T) { services := []struct { - service swarm.Service - exposedByDefault bool - expected bool - networks map[string]*docker.NetworkResource + service swarm.Service + expected bool + networks map[string]*docker.NetworkResource + provider *Provider }{ { - service: swarmService(), - exposedByDefault: true, - expected: false, - networks: map[string]*docker.NetworkResource{}, + service: swarmService(), + expected: false, + networks: map[string]*docker.NetworkResource{}, + provider: &Provider{ + SwarmMode: true, + Domain: "test", + ExposedByDefault: true, + }, }, { service: swarmService(serviceLabels(map[string]string{ "traefik.enable": "false", "traefik.port": "80", })), - exposedByDefault: true, - expected: false, - networks: map[string]*docker.NetworkResource{}, + expected: false, + networks: map[string]*docker.NetworkResource{}, + provider: &Provider{ + SwarmMode: true, + Domain: "test", + ExposedByDefault: true, + }, }, { service: swarmService(serviceLabels(map[string]string{ "traefik.frontend.rule": "Host:foo.bar", "traefik.port": "80", })), - exposedByDefault: true, - expected: true, - networks: map[string]*docker.NetworkResource{}, + expected: true, + networks: map[string]*docker.NetworkResource{}, + provider: &Provider{ + SwarmMode: true, + Domain: "test", + ExposedByDefault: true, + }, }, { service: swarmService(serviceLabels(map[string]string{ "traefik.port": "80", })), - exposedByDefault: true, - expected: true, - networks: map[string]*docker.NetworkResource{}, + expected: true, + networks: map[string]*docker.NetworkResource{}, + provider: &Provider{ + SwarmMode: true, + Domain: "test", + ExposedByDefault: true, + }, }, { service: swarmService(serviceLabels(map[string]string{ "traefik.enable": "true", "traefik.port": "80", })), - exposedByDefault: true, - expected: true, - networks: map[string]*docker.NetworkResource{}, + expected: true, + networks: map[string]*docker.NetworkResource{}, + provider: &Provider{ + SwarmMode: true, + Domain: "test", + ExposedByDefault: true, + }, }, { service: swarmService(serviceLabels(map[string]string{ "traefik.enable": "anything", "traefik.port": "80", })), - exposedByDefault: true, - expected: true, - networks: map[string]*docker.NetworkResource{}, + expected: true, + networks: map[string]*docker.NetworkResource{}, + provider: &Provider{ + SwarmMode: true, + Domain: "test", + ExposedByDefault: true, + }, }, { service: swarmService(serviceLabels(map[string]string{ "traefik.frontend.rule": "Host:foo.bar", "traefik.port": "80", })), - exposedByDefault: true, - expected: true, - networks: map[string]*docker.NetworkResource{}, + expected: true, + networks: map[string]*docker.NetworkResource{}, + provider: &Provider{ + SwarmMode: true, + Domain: "test", + ExposedByDefault: true, + }, }, { service: swarmService(serviceLabels(map[string]string{ "traefik.port": "80", })), - exposedByDefault: false, - expected: false, - networks: map[string]*docker.NetworkResource{}, + expected: false, + networks: map[string]*docker.NetworkResource{}, + provider: &Provider{ + SwarmMode: true, + Domain: "test", + ExposedByDefault: false, + }, }, { service: swarmService(serviceLabels(map[string]string{ "traefik.enable": "true", "traefik.port": "80", })), - exposedByDefault: false, - expected: true, - networks: map[string]*docker.NetworkResource{}, + expected: true, + networks: map[string]*docker.NetworkResource{}, + provider: &Provider{ + SwarmMode: true, + Domain: "test", + ExposedByDefault: false, + }, }, } @@ -591,11 +627,7 @@ func TestSwarmTraefikFilter(t *testing.T) { t.Run(strconv.Itoa(serviceID), func(t *testing.T) { t.Parallel() dockerData := parseService(e.service, e.networks) - provider := &Provider{ - SwarmMode: true, - } - provider.ExposedByDefault = e.exposedByDefault - actual := provider.containerFilter(dockerData) + actual := e.provider.containerFilter(dockerData) if actual != e.expected { t.Errorf("expected %v for %+v, got %+v", e.expected, e, actual) } From 138fea17ed5c3c28d40a39410ce22b55ef935375 Mon Sep 17 00:00:00 2001 From: Adam Geiger Date: Fri, 10 Mar 2017 13:43:20 -0500 Subject: [PATCH 3/7] Fix redirect empty backend Issue-#679 --- server/server.go | 81 +++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/server/server.go b/server/server.go index 1d247b617..51479cb36 100644 --- a/server/server.go +++ b/server/server.go @@ -548,7 +548,7 @@ func (server *Server) buildEntryPoints(globalConfiguration GlobalConfiguration) // provider configurations. func (server *Server) loadConfig(configurations configs, globalConfiguration GlobalConfiguration) (map[string]*serverEntryPoint, error) { serverEntryPoints := server.buildEntryPoints(globalConfiguration) - redirectHandlers := make(map[string]http.Handler) + redirectHandlers := make(map[string]negroni.Handler) backends := map[string]http.Handler{} @@ -596,42 +596,43 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo } entryPoint := globalConfiguration.EntryPoints[entryPointName] + negroni := negroni.New() if entryPoint.Redirect != nil { if redirectHandlers[entryPointName] != nil { - newServerRoute.route.Handler(redirectHandlers[entryPointName]) + negroni.Use(redirectHandlers[entryPointName]) } else if handler, err := server.loadEntryPointConfig(entryPointName, entryPoint); err != nil { log.Errorf("Error loading entrypoint configuration for frontend %s: %v", frontendName, err) log.Errorf("Skipping frontend %s...", frontendName) continue frontend } else { - newServerRoute.route.Handler(handler) + negroni.Use(handler) redirectHandlers[entryPointName] = handler } - } else { - if backends[frontend.Backend] == nil { - log.Debugf("Creating backend %s", frontend.Backend) - var lb http.Handler - rr, _ := roundrobin.New(saveBackend) - if configuration.Backends[frontend.Backend] == nil { - log.Errorf("Undefined backend '%s' for frontend %s", frontend.Backend, frontendName) - log.Errorf("Skipping frontend %s...", frontendName) - continue frontend - } + } + if backends[frontend.Backend] == nil { + log.Debugf("Creating backend %s", frontend.Backend) + var lb http.Handler + rr, _ := roundrobin.New(saveBackend) + if configuration.Backends[frontend.Backend] == nil { + log.Errorf("Undefined backend '%s' for frontend %s", frontend.Backend, frontendName) + log.Errorf("Skipping frontend %s...", frontendName) + continue frontend + } - lbMethod, err := types.NewLoadBalancerMethod(configuration.Backends[frontend.Backend].LoadBalancer) - if err != nil { - log.Errorf("Error loading load balancer method '%+v' for frontend %s: %v", configuration.Backends[frontend.Backend].LoadBalancer, frontendName, err) - log.Errorf("Skipping frontend %s...", frontendName) - continue frontend - } + lbMethod, err := types.NewLoadBalancerMethod(configuration.Backends[frontend.Backend].LoadBalancer) + if err != nil { + log.Errorf("Error loading load balancer method '%+v' for frontend %s: %v", configuration.Backends[frontend.Backend].LoadBalancer, frontendName, err) + log.Errorf("Skipping frontend %s...", frontendName) + continue frontend + } - stickysession := configuration.Backends[frontend.Backend].LoadBalancer.Sticky - cookiename := "_TRAEFIK_BACKEND" - var sticky *roundrobin.StickySession + stickysession := configuration.Backends[frontend.Backend].LoadBalancer.Sticky + cookiename := "_TRAEFIK_BACKEND" + var sticky *roundrobin.StickySession - if stickysession { - sticky = roundrobin.NewStickySession(cookiename) - } + if stickysession { + sticky = roundrobin.NewStickySession(cookiename) + } switch lbMethod { case types.Drr: @@ -656,9 +657,9 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo log.Errorf("Skipping frontend %s...", frontendName) continue frontend } - hcOpts := parseHealthCheckOptions(rebalancer, frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck, *globalConfiguration.HealthCheck) - if hcOpts != nil { - log.Debugf("Setting up backend health check %s", *hcOpts) + hcOpts := parseHealthCheckOptions(rebalancer,frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck, *globalConfiguration.HealthCheck) + if hcOpts != nil { + log.Debugf("Setting up backend health check %s", *hcOpts) backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts) } } @@ -684,9 +685,9 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo continue frontend } } - hcOpts := parseHealthCheckOptions(rr, frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck, *globalConfiguration.HealthCheck) - if hcOpts != nil { - log.Debugf("Setting up backend health check %s", *hcOpts) + hcOpts := parseHealthCheckOptions(rr,frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck, *globalConfiguration.HealthCheck) + if hcOpts != nil { + log.Debugf("Setting up backend health check %s", *hcOpts) backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts) } } @@ -716,15 +717,14 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo log.Debugf("Creating retries max attempts %d", retries) } - var negroni = negroni.New() + if server.globalConfiguration.Web != nil && server.globalConfiguration.Web.Metrics != nil { if server.globalConfiguration.Web.Metrics.Prometheus != nil { metricsMiddlewareBackend := middlewares.NewMetricsWrapper(middlewares.NewPrometheus(frontend.Backend, server.globalConfiguration.Web.Metrics.Prometheus)) negroni.Use(metricsMiddlewareBackend) } } - - if len(frontend.BasicAuth) > 0 { + if len(frontend.BasicAuth) > 0 { users := types.Users{} for _, user := range frontend.BasicAuth { users = append(users, user) @@ -739,9 +739,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo log.Fatal("Error creating Auth: ", err) } negroni.Use(authMiddleware) - } - - if configuration.Backends[frontend.Backend].CircuitBreaker != nil { + } if configuration.Backends[frontend.Backend].CircuitBreaker != nil { log.Debugf("Creating circuit breaker %s", configuration.Backends[frontend.Backend].CircuitBreaker.Expression) cbreaker, err := middlewares.NewCircuitBreaker(lb, configuration.Backends[frontend.Backend].CircuitBreaker.Expression, cbreaker.Logger(oxyLogger)) if err != nil { @@ -761,7 +759,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo newServerRoute.route.Priority(frontend.Priority) } server.wireFrontendBackend(newServerRoute, backends[frontend.Backend]) - } + err := newServerRoute.route.GetError() if err != nil { log.Errorf("Error building route: %s", err) @@ -811,7 +809,7 @@ func (server *Server) wireFrontendBackend(serverRoute *serverRoute, handler http serverRoute.route.Handler(handler) } -func (server *Server) loadEntryPointConfig(entryPointName string, entryPoint *EntryPoint) (http.Handler, error) { +func (server *Server) loadEntryPointConfig(entryPointName string, entryPoint *EntryPoint) (negroni.Handler, error) { regex := entryPoint.Redirect.Regex replacement := entryPoint.Redirect.Replacement if len(entryPoint.Redirect.EntryPoint) > 0 { @@ -835,9 +833,8 @@ func (server *Server) loadEntryPointConfig(entryPointName string, entryPoint *En return nil, err } log.Debugf("Creating entryPoint redirect %s -> %s : %s -> %s", entryPointName, entryPoint.Redirect.EntryPoint, regex, replacement) - negroni := negroni.New() - negroni.Use(rewrite) - return negroni, nil + + return rewrite, nil } func (server *Server) buildDefaultHTTPRouter() *mux.Router { From ca9e36ebe339b462b93d5fb447ac2254f3bdc664 Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Tue, 11 Apr 2017 20:13:18 +0200 Subject: [PATCH 4/7] Prepare release v1.2.2 Signed-off-by: Emile Vauge --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8eea2baff..ad7a55719 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## [v1.2.2](https://github.com/containous/traefik/tree/v1.2.2) (2017-04-11) +[Full Changelog](https://github.com/containous/traefik/compare/v1.2.1...v1.2.2) + +**Merged pull requests:** + +- Carry PR 1271 [\#1417](https://github.com/containous/traefik/pull/1417) ([emilevauge](https://github.com/emilevauge)) +- Fix postloadconfig acme & Docker filter empty rule [\#1401](https://github.com/containous/traefik/pull/1401) ([emilevauge](https://github.com/emilevauge)) + ## [v1.2.1](https://github.com/containous/traefik/tree/v1.2.1) (2017-03-27) [Full Changelog](https://github.com/containous/traefik/compare/v1.2.0...v1.2.1) From e7a73d3fb32fb89b8b03bf805854641fd2c48ab1 Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Thu, 13 Apr 2017 16:37:07 +0200 Subject: [PATCH 5/7] Fix too many redirect Signed-off-by: Emile Vauge --- server/server.go | 218 +++++++++++++++++++++++------------------------ 1 file changed, 108 insertions(+), 110 deletions(-) diff --git a/server/server.go b/server/server.go index 51479cb36..da99e366d 100644 --- a/server/server.go +++ b/server/server.go @@ -549,12 +549,10 @@ func (server *Server) buildEntryPoints(globalConfiguration GlobalConfiguration) func (server *Server) loadConfig(configurations configs, globalConfiguration GlobalConfiguration) (map[string]*serverEntryPoint, error) { serverEntryPoints := server.buildEntryPoints(globalConfiguration) redirectHandlers := make(map[string]negroni.Handler) - backends := map[string]http.Handler{} - backendsHealthcheck := map[string]*healthcheck.BackendHealthCheck{} - backend2FrontendMap := map[string]string{} + for _, configuration := range configurations { frontendNames := sortedFrontendNamesForConfig(configuration) frontend: @@ -609,7 +607,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo redirectHandlers[entryPointName] = handler } } - if backends[frontend.Backend] == nil { + if backends[entryPointName+frontend.Backend] == nil { log.Debugf("Creating backend %s", frontend.Backend) var lb http.Handler rr, _ := roundrobin.New(saveBackend) @@ -634,131 +632,131 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo sticky = roundrobin.NewStickySession(cookiename) } - switch lbMethod { - case types.Drr: - log.Debugf("Creating load-balancer drr") - rebalancer, _ := roundrobin.NewRebalancer(rr, roundrobin.RebalancerLogger(oxyLogger)) - if stickysession { - log.Debugf("Sticky session with cookie %v", cookiename) - rebalancer, _ = roundrobin.NewRebalancer(rr, roundrobin.RebalancerLogger(oxyLogger), roundrobin.RebalancerStickySession(sticky)) + switch lbMethod { + case types.Drr: + log.Debugf("Creating load-balancer drr") + rebalancer, _ := roundrobin.NewRebalancer(rr, roundrobin.RebalancerLogger(oxyLogger)) + if stickysession { + log.Debugf("Sticky session with cookie %v", cookiename) + rebalancer, _ = roundrobin.NewRebalancer(rr, roundrobin.RebalancerLogger(oxyLogger), roundrobin.RebalancerStickySession(sticky)) + } + lb = rebalancer + for serverName, server := range configuration.Backends[frontend.Backend].Servers { + url, err := url.Parse(server.URL) + if err != nil { + log.Errorf("Error parsing server URL %s: %v", server.URL, err) + log.Errorf("Skipping frontend %s...", frontendName) + continue frontend } - lb = rebalancer - for serverName, server := range configuration.Backends[frontend.Backend].Servers { - url, err := url.Parse(server.URL) - if err != nil { - log.Errorf("Error parsing server URL %s: %v", server.URL, err) - log.Errorf("Skipping frontend %s...", frontendName) - continue frontend - } - backend2FrontendMap[url.String()] = frontendName - log.Debugf("Creating server %s at %s with weight %d", serverName, url.String(), server.Weight) - if err := rebalancer.UpsertServer(url, roundrobin.Weight(server.Weight)); err != nil { - log.Errorf("Error adding server %s to load balancer: %v", server.URL, err) - log.Errorf("Skipping frontend %s...", frontendName) - continue frontend - } - hcOpts := parseHealthCheckOptions(rebalancer,frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck, *globalConfiguration.HealthCheck) - if hcOpts != nil { - log.Debugf("Setting up backend health check %s", *hcOpts) - backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts) - } + backend2FrontendMap[url.String()] = frontendName + log.Debugf("Creating server %s at %s with weight %d", serverName, url.String(), server.Weight) + if err := rebalancer.UpsertServer(url, roundrobin.Weight(server.Weight)); err != nil { + log.Errorf("Error adding server %s to load balancer: %v", server.URL, err) + log.Errorf("Skipping frontend %s...", frontendName) + continue frontend } - case types.Wrr: - log.Debugf("Creating load-balancer wrr") - if stickysession { - log.Debugf("Sticky session with cookie %v", cookiename) - rr, _ = roundrobin.New(saveBackend, roundrobin.EnableStickySession(sticky)) - } - lb = rr - for serverName, server := range configuration.Backends[frontend.Backend].Servers { - url, err := url.Parse(server.URL) - if err != nil { - log.Errorf("Error parsing server URL %s: %v", server.URL, err) - log.Errorf("Skipping frontend %s...", frontendName) - continue frontend - } - backend2FrontendMap[url.String()] = frontendName - log.Debugf("Creating server %s at %s with weight %d", serverName, url.String(), server.Weight) - if err := rr.UpsertServer(url, roundrobin.Weight(server.Weight)); err != nil { - log.Errorf("Error adding server %s to load balancer: %v", server.URL, err) - log.Errorf("Skipping frontend %s...", frontendName) - continue frontend - } - } - hcOpts := parseHealthCheckOptions(rr,frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck, *globalConfiguration.HealthCheck) - if hcOpts != nil { - log.Debugf("Setting up backend health check %s", *hcOpts) + hcOpts := parseHealthCheckOptions(rebalancer, frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck, *globalConfiguration.HealthCheck) + if hcOpts != nil { + log.Debugf("Setting up backend health check %s", *hcOpts) backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts) } } - maxConns := configuration.Backends[frontend.Backend].MaxConn - if maxConns != nil && maxConns.Amount != 0 { - extractFunc, err := utils.NewExtractor(maxConns.ExtractorFunc) + case types.Wrr: + log.Debugf("Creating load-balancer wrr") + if stickysession { + log.Debugf("Sticky session with cookie %v", cookiename) + rr, _ = roundrobin.New(saveBackend, roundrobin.EnableStickySession(sticky)) + } + lb = rr + for serverName, server := range configuration.Backends[frontend.Backend].Servers { + url, err := url.Parse(server.URL) if err != nil { - log.Errorf("Error creating connlimit: %v", err) + log.Errorf("Error parsing server URL %s: %v", server.URL, err) log.Errorf("Skipping frontend %s...", frontendName) continue frontend } - log.Debugf("Creating load-balancer connlimit") - lb, err = connlimit.New(lb, extractFunc, maxConns.Amount, connlimit.Logger(oxyLogger)) - if err != nil { - log.Errorf("Error creating connlimit: %v", err) + backend2FrontendMap[url.String()] = frontendName + log.Debugf("Creating server %s at %s with weight %d", serverName, url.String(), server.Weight) + if err := rr.UpsertServer(url, roundrobin.Weight(server.Weight)); err != nil { + log.Errorf("Error adding server %s to load balancer: %v", server.URL, err) log.Errorf("Skipping frontend %s...", frontendName) continue frontend } } - // retry ? - if globalConfiguration.Retry != nil { - retries := len(configuration.Backends[frontend.Backend].Servers) - if globalConfiguration.Retry.Attempts > 0 { - retries = globalConfiguration.Retry.Attempts - } - lb = middlewares.NewRetry(retries, lb) - log.Debugf("Creating retries max attempts %d", retries) + hcOpts := parseHealthCheckOptions(rr, frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck, *globalConfiguration.HealthCheck) + if hcOpts != nil { + log.Debugf("Setting up backend health check %s", *hcOpts) + backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts) + } + } + maxConns := configuration.Backends[frontend.Backend].MaxConn + if maxConns != nil && maxConns.Amount != 0 { + extractFunc, err := utils.NewExtractor(maxConns.ExtractorFunc) + if err != nil { + log.Errorf("Error creating connlimit: %v", err) + log.Errorf("Skipping frontend %s...", frontendName) + continue frontend + } + log.Debugf("Creating load-balancer connlimit") + lb, err = connlimit.New(lb, extractFunc, maxConns.Amount, connlimit.Logger(oxyLogger)) + if err != nil { + log.Errorf("Error creating connlimit: %v", err) + log.Errorf("Skipping frontend %s...", frontendName) + continue frontend + } + } + // retry ? + if globalConfiguration.Retry != nil { + retries := len(configuration.Backends[frontend.Backend].Servers) + if globalConfiguration.Retry.Attempts > 0 { + retries = globalConfiguration.Retry.Attempts + } + lb = middlewares.NewRetry(retries, lb) + log.Debugf("Creating retries max attempts %d", retries) + } + + if server.globalConfiguration.Web != nil && server.globalConfiguration.Web.Metrics != nil { + if server.globalConfiguration.Web.Metrics.Prometheus != nil { + metricsMiddlewareBackend := middlewares.NewMetricsWrapper(middlewares.NewPrometheus(frontend.Backend, server.globalConfiguration.Web.Metrics.Prometheus)) + negroni.Use(metricsMiddlewareBackend) + } + } + if len(frontend.BasicAuth) > 0 { + users := types.Users{} + for _, user := range frontend.BasicAuth { + users = append(users, user) } - - if server.globalConfiguration.Web != nil && server.globalConfiguration.Web.Metrics != nil { - if server.globalConfiguration.Web.Metrics.Prometheus != nil { - metricsMiddlewareBackend := middlewares.NewMetricsWrapper(middlewares.NewPrometheus(frontend.Backend, server.globalConfiguration.Web.Metrics.Prometheus)) - negroni.Use(metricsMiddlewareBackend) - } + auth := &types.Auth{} + auth.Basic = &types.Basic{ + Users: users, } - if len(frontend.BasicAuth) > 0 { - users := types.Users{} - for _, user := range frontend.BasicAuth { - users = append(users, user) - } - - auth := &types.Auth{} - auth.Basic = &types.Basic{ - Users: users, - } - authMiddleware, err := middlewares.NewAuthenticator(auth) - if err != nil { - log.Fatal("Error creating Auth: ", err) - } - negroni.Use(authMiddleware) - } if configuration.Backends[frontend.Backend].CircuitBreaker != nil { - log.Debugf("Creating circuit breaker %s", configuration.Backends[frontend.Backend].CircuitBreaker.Expression) - cbreaker, err := middlewares.NewCircuitBreaker(lb, configuration.Backends[frontend.Backend].CircuitBreaker.Expression, cbreaker.Logger(oxyLogger)) - if err != nil { - log.Errorf("Error creating circuit breaker: %v", err) - log.Errorf("Skipping frontend %s...", frontendName) - continue frontend - } - negroni.Use(cbreaker) - } else { - negroni.UseHandler(lb) + authMiddleware, err := middlewares.NewAuthenticator(auth) + if err != nil { + log.Fatal("Error creating Auth: ", err) } - backends[frontend.Backend] = negroni + negroni.Use(authMiddleware) + } + if configuration.Backends[frontend.Backend].CircuitBreaker != nil { + log.Debugf("Creating circuit breaker %s", configuration.Backends[frontend.Backend].CircuitBreaker.Expression) + cbreaker, err := middlewares.NewCircuitBreaker(lb, configuration.Backends[frontend.Backend].CircuitBreaker.Expression, cbreaker.Logger(oxyLogger)) + if err != nil { + log.Errorf("Error creating circuit breaker: %v", err) + log.Errorf("Skipping frontend %s...", frontendName) + continue frontend + } + negroni.Use(cbreaker) } else { - log.Debugf("Reusing backend %s", frontend.Backend) + negroni.UseHandler(lb) } - if frontend.Priority > 0 { - newServerRoute.route.Priority(frontend.Priority) - } - server.wireFrontendBackend(newServerRoute, backends[frontend.Backend]) + backends[entryPointName+frontend.Backend] = negroni + } else { + log.Debugf("Reusing backend %s", frontend.Backend) + } + if frontend.Priority > 0 { + newServerRoute.route.Priority(frontend.Priority) + } + server.wireFrontendBackend(newServerRoute, backends[entryPointName+frontend.Backend]) err := newServerRoute.route.GetError() if err != nil { From 8ac281f9e3e216489df17ad588c187288a38f7de Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Thu, 13 Apr 2017 20:06:25 +0200 Subject: [PATCH 6/7] Prepare release v1.2.3 Signed-off-by: Emile Vauge --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad7a55719..addc308f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## [v1.2.3](https://github.com/containous/traefik/tree/v1.2.3) (2017-04-13) +[Full Changelog](https://github.com/containous/traefik/compare/v1.2.2...v1.2.3) + +**Merged pull requests:** + +- Fix too many redirect [\#1433](https://github.com/containous/traefik/pull/1433) ([emilevauge](https://github.com/emilevauge)) + ## [v1.2.2](https://github.com/containous/traefik/tree/v1.2.2) (2017-04-11) [Full Changelog](https://github.com/containous/traefik/compare/v1.2.1...v1.2.2) From 4e186cecf9c8f153d7b2fd811a44f01f725753cb Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Wed, 3 May 2017 23:24:53 +0200 Subject: [PATCH 7/7] Merge v1.2.3 master --- provider/docker/docker.go | 3 +++ provider/docker/service_test.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/provider/docker/docker.go b/provider/docker/docker.go index b2128bbfc..6ecbc775d 100644 --- a/provider/docker/docker.go +++ b/provider/docker/docker.go @@ -542,6 +542,9 @@ func (p *Provider) getFrontendRule(container dockerData) string { if label, err := getLabel(container, "traefik.frontend.rule"); err == nil { return label } + if labels, err := getLabels(container, []string{"com.docker.compose.project", "com.docker.compose.service"}); err == nil { + return "Host:" + p.getSubDomain(labels["com.docker.compose.service"]+"."+labels["com.docker.compose.project"]) + "." + p.Domain + } if len(p.Domain) > 0 { return "Host:" + p.getSubDomain(container.ServiceName) + "." + p.Domain } diff --git a/provider/docker/service_test.go b/provider/docker/service_test.go index 46749c553..a5f03b8fb 100644 --- a/provider/docker/service_test.go +++ b/provider/docker/service_test.go @@ -133,7 +133,7 @@ func TestDockerGetServiceFrontendRule(t *testing.T) { }{ { container: containerJSON(name("foo")), - expected: "Host:foo.", + expected: "", }, { container: containerJSON(labels(map[string]string{