From 63f65e5b2a20ad94c5eea6fb2963166baca3c1a6 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Thu, 17 Dec 2020 10:06:03 +0100 Subject: [PATCH 1/8] Disable router when a rule has an error --- pkg/rules/rules.go | 9 ++++++++- pkg/rules/rules_test.go | 10 ++++++++++ pkg/server/router/router_test.go | 23 +++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/pkg/rules/rules.go b/pkg/rules/rules.go index 469bcbe56..a6bfedb1b 100644 --- a/pkg/rules/rules.go +++ b/pkg/rules/rules.go @@ -59,7 +59,14 @@ func (r *Router) AddRoute(rule string, priority int, handler http.Handler) error } route := r.NewRoute().Handler(handler).Priority(priority) - return addRuleOnRoute(route, buildTree()) + + err = addRuleOnRoute(route, buildTree()) + if err != nil { + route.BuildOnly() + return err + } + + return nil } type tree struct { diff --git a/pkg/rules/rules_test.go b/pkg/rules/rules_test.go index a6a79eace..ca38ef28f 100644 --- a/pkg/rules/rules_test.go +++ b/pkg/rules/rules_test.go @@ -29,6 +29,16 @@ func Test_addRoute(t *testing.T) { rule: "rulewithnotmatcher", expectedError: true, }, + { + desc: "Host empty", + rule: "Host(``)", + expectedError: true, + }, + { + desc: "PathPrefix empty", + rule: "PathPrefix(``)", + expectedError: true, + }, { desc: "PathPrefix", rule: "PathPrefix(`/foo`)", diff --git a/pkg/server/router/router_test.go b/pkg/server/router/router_test.go index 703de3c37..19ed56252 100644 --- a/pkg/server/router/router_test.go +++ b/pkg/server/router/router_test.go @@ -62,6 +62,29 @@ func TestRouterManager_Get(t *testing.T) { entryPoints: []string{"web"}, expected: expectedResult{StatusCode: http.StatusOK}, }, + { + desc: "empty host", + routersConfig: map[string]*dynamic.Router{ + "foo": { + EntryPoints: []string{"web"}, + Service: "foo-service", + Rule: "Host(``)", + }, + }, + serviceConfig: map[string]*dynamic.Service{ + "foo-service": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Servers: []dynamic.Server{ + { + URL: server.URL, + }, + }, + }, + }, + }, + entryPoints: []string{"web"}, + expected: expectedResult{StatusCode: http.StatusNotFound}, + }, { desc: "no load balancer", routersConfig: map[string]*dynamic.Router{ From 3ff83fc1f8281851e56dcc5f18600be8fbb6fe9f Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Doumenjou <925513+jbdoumenjou@users.noreply.github.com> Date: Thu, 17 Dec 2020 17:02:04 +0100 Subject: [PATCH 2/8] Prepare release v2.3.6 --- CHANGELOG.md | 12 ++++++++++++ script/gcg/traefik-bugfix.toml | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7b266e52..b80555cd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [v2.3.6](https://github.com/traefik/traefik/tree/v2.3.6) (2020-12-17) +[All Commits](https://github.com/traefik/traefik/compare/v2.3.5...v2.3.6) + +**Bug fixes:** +- **[logs]** Update Logrus to v1.7.0 ([#7663](https://github.com/traefik/traefik/pull/7663) by [jspdown](https://github.com/jspdown)) +- **[plugins]** Update Yaegi to v0.9.8 ([#7659](https://github.com/traefik/traefik/pull/7659) by [ldez](https://github.com/ldez)) +- **[rules]** Disable router when a rule has an error ([#7680](https://github.com/traefik/traefik/pull/7680) by [ldez](https://github.com/ldez)) + +**Documentation:** +- **[logs]** Add configuration example for access log filePath ([#7655](https://github.com/traefik/traefik/pull/7655) by [wernerfred](https://github.com/wernerfred)) +- **[middleware]** Add missing quotes in errorpages k8s example yaml ([#7675](https://github.com/traefik/traefik/pull/7675) by [icelynjennings](https://github.com/icelynjennings)) + ## [v2.3.5](https://github.com/traefik/traefik/tree/v2.3.5) (2020-12-10) [All Commits](https://github.com/traefik/traefik/compare/v2.3.4...v2.3.5) diff --git a/script/gcg/traefik-bugfix.toml b/script/gcg/traefik-bugfix.toml index 408b454d1..01c1e79c1 100644 --- a/script/gcg/traefik-bugfix.toml +++ b/script/gcg/traefik-bugfix.toml @@ -6,9 +6,9 @@ FileName = "traefik_changelog.md" # example new bugfix v2.3.5 CurrentRef = "v2.3" -PreviousRef = "v2.3.4" +PreviousRef = "v2.3.5" BaseBranch = "v2.3" -FutureCurrentRefName = "v2.3.5" +FutureCurrentRefName = "v2.3.6" ThresholdPreviousRef = 10 ThresholdCurrentRef = 10 From 544dc2eaa5d23a050728241e26e200521b565cd3 Mon Sep 17 00:00:00 2001 From: Kevin Pollet Date: Tue, 22 Dec 2020 14:20:03 +0100 Subject: [PATCH 3/8] docs: fix broken links to docker-compose documentation --- docs/content/providers/docker.md | 8 ++++---- docs/content/routing/providers/docker.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/content/providers/docker.md b/docs/content/providers/docker.md index 5b1b455ee..2f9c9e55f 100644 --- a/docs/content/providers/docker.md +++ b/docs/content/providers/docker.md @@ -98,8 +98,8 @@ See the list of labels in the dedicated [routing](../routing/providers/docker.md By default, Traefik watches for [container level labels](https://docs.docker.com/config/labels-custom-metadata/) on a standalone Docker Engine. When using Docker Compose, labels are specified by the directive -[`labels`](https://docs.docker.com/compose/compose-file/#labels) from the -["services" objects](https://docs.docker.com/compose/compose-file/#service-configuration-reference). +[`labels`](https://docs.docker.com/compose/compose-file/compose-file-v3/#labels) from the +["services" objects](https://docs.docker.com/compose/compose-file/compose-file-v3/#service-configuration-reference). !!! tip "Not Only Docker" Please note that any tool like Nomad, Terraform, Ansible, etc. @@ -186,9 +186,9 @@ set the [`swarmMode`](#swarmmode) directive to `true`. While in Swarm Mode, Traefik uses labels found on services, not on individual containers. Therefore, if you use a compose file with Swarm Mode, labels should be defined in the -[`deploy`](https://docs.docker.com/compose/compose-file/#labels-1) part of your service. +[`deploy`](https://docs.docker.com/compose/compose-file/compose-file-v3/#labels-1) part of your service. -This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file)). +This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/compose-file-v3/)). ### Port Detection diff --git a/docs/content/routing/providers/docker.md b/docs/content/routing/providers/docker.md index d3af40057..c55bbf611 100644 --- a/docs/content/routing/providers/docker.md +++ b/docs/content/routing/providers/docker.md @@ -124,7 +124,7 @@ Attach labels to your containers and let Traefik do the rest! !!! important "Labels in Docker Swarm Mode" While in Swarm Mode, Traefik uses labels found on services, not on individual containers. Therefore, if you use a compose file with Swarm Mode, labels should be defined in the `deploy` part of your service. - This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/#labels-1)). + This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/compose-file-v3/#labels-1)). ## Routing Configuration From da1c9f48b72bfa02d47493dc436723205d873d03 Mon Sep 17 00:00:00 2001 From: Robin van Boven <497556+Beanow@users.noreply.github.com> Date: Tue, 22 Dec 2020 15:36:03 +0100 Subject: [PATCH 4/8] docs: rephrase forwardauth.authRequestHeaders --- docs/content/middlewares/forwardauth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/middlewares/forwardauth.md b/docs/content/middlewares/forwardauth.md index 4211a191e..f0a64ca89 100644 --- a/docs/content/middlewares/forwardauth.md +++ b/docs/content/middlewares/forwardauth.md @@ -285,7 +285,7 @@ http: ### `authRequestHeaders` The `authRequestHeaders` option is the list of the headers to copy from the request to the authentication server. -It allows to prevent passing headers that have not to be passed to the authentication server. +It allows filtering headers that should not be passed to the authentication server. If not set or empty then all request headers will be passed. ```yaml tab="Docker" From 5dd1728bf856bd2734f9e8e9f9e7cf14ce3bb0c1 Mon Sep 17 00:00:00 2001 From: Kevin Pollet Date: Sun, 27 Dec 2020 20:48:04 +0100 Subject: [PATCH 5/8] webui: fix missing custom request and response header names --- webui/src/components/_commons/PanelMiddlewares.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webui/src/components/_commons/PanelMiddlewares.vue b/webui/src/components/_commons/PanelMiddlewares.vue index 266a12f16..7d2d4885d 100644 --- a/webui/src/components/_commons/PanelMiddlewares.vue +++ b/webui/src/components/_commons/PanelMiddlewares.vue @@ -316,7 +316,7 @@ v-for="(val, key) in exData(middleware).customRequestHeaders" :key="key" dense class="app-chip app-chip-green"> - {{ val }} + {{ key }}: {{ val }} @@ -330,7 +330,7 @@ v-for="(val, key) in exData(middleware).customResponseHeaders" :key="key" dense class="app-chip app-chip-green"> - {{ val }} + {{ key }}: {{ val }} From f54136b6025ea951562a90a3ef178ce425a13234 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Tue, 29 Dec 2020 10:54:03 +0100 Subject: [PATCH 6/8] chore: update linter. --- .golangci.toml | 3 +++ build.Dockerfile | 2 +- pkg/metrics/pilot_test.go | 10 ++++++++++ pkg/metrics/prometheus_test.go | 10 ++++++++++ pkg/middlewares/accesslog/logger_test.go | 12 ++++++++++++ pkg/provider/file/file_test.go | 16 +++++++++------- pkg/server/server_entrypoint_tcp_test.go | 4 ++++ pkg/server/server_entrypoint_udp_test.go | 2 ++ pkg/server/service/proxy_websocket_test.go | 4 ++++ pkg/tcp/proxy_test.go | 2 ++ pkg/udp/conn_test.go | 4 ++++ pkg/udp/proxy_test.go | 2 ++ 12 files changed, 63 insertions(+), 8 deletions(-) diff --git a/.golangci.toml b/.golangci.toml index 64e06b670..c028010c2 100644 --- a/.golangci.toml +++ b/.golangci.toml @@ -57,7 +57,10 @@ "nlreturn", # Not relevant "wrapcheck", # Too strict "tparallel", # Not relevant + "paralleltest", # Not relevant "exhaustivestruct", # Not relevant + "makezero", # not relevant + "forbidigo", # not relevant ] [issues] diff --git a/build.Dockerfile b/build.Dockerfile index 6df51c544..29b4c1b24 100644 --- a/build.Dockerfile +++ b/build.Dockerfile @@ -19,7 +19,7 @@ RUN mkdir -p /usr/local/bin \ && chmod +x /usr/local/bin/go-bindata # Download golangci-lint binary to bin folder in $GOPATH -RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.32.2 +RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.34.0 # Download misspell binary to bin folder in $GOPATH RUN curl -sfL https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.3.4 diff --git a/pkg/metrics/pilot_test.go b/pkg/metrics/pilot_test.go index 73ffb0335..451c1eb93 100644 --- a/pkg/metrics/pilot_test.go +++ b/pkg/metrics/pilot_test.go @@ -300,6 +300,8 @@ func findPilotMetric(name string, metrics []PilotMetric) *PilotMetric { } func buildPilotCounterAssert(t *testing.T, metricName string, expectedValue float64) func(metric *PilotMetric) { + t.Helper() + return func(metric *PilotMetric) { for _, value := range metric.Observations { if cv := value.(float64); cv != expectedValue { @@ -311,6 +313,8 @@ func buildPilotCounterAssert(t *testing.T, metricName string, expectedValue floa } func buildPilotGreaterThanCounterAssert(t *testing.T, metricName string, expectedMinValue float64) func(metric *PilotMetric) { + t.Helper() + return func(metric *PilotMetric) { for _, value := range metric.Observations { if cv := value.(float64); cv < expectedMinValue { @@ -322,6 +326,8 @@ func buildPilotGreaterThanCounterAssert(t *testing.T, metricName string, expecte } func buildPilotHistogramAssert(t *testing.T, metricName string, expectedSampleCount float64) func(metric *PilotMetric) { + t.Helper() + return func(metric *PilotMetric) { for _, value := range metric.Observations { if pho := value.(*pilotHistogramObservation); pho.Count != expectedSampleCount { @@ -333,6 +339,8 @@ func buildPilotHistogramAssert(t *testing.T, metricName string, expectedSampleCo } func buildPilotGaugeAssert(t *testing.T, metricName string, expectedValue float64) func(metric *PilotMetric) { + t.Helper() + return func(metric *PilotMetric) { for _, value := range metric.Observations { if gv := value.(float64); gv != expectedValue { @@ -344,6 +352,8 @@ func buildPilotGaugeAssert(t *testing.T, metricName string, expectedValue float6 } func buildPilotTimestampAssert(t *testing.T, metricName string) func(metric *PilotMetric) { + t.Helper() + return func(metric *PilotMetric) { for _, value := range metric.Observations { if ts := time.Unix(int64(value.(float64)), 0); time.Since(ts) > time.Minute { diff --git a/pkg/metrics/prometheus_test.go b/pkg/metrics/prometheus_test.go index 87fc1b650..af6ed5d2a 100644 --- a/pkg/metrics/prometheus_test.go +++ b/pkg/metrics/prometheus_test.go @@ -472,6 +472,8 @@ func assertCounterValue(t *testing.T, want float64, family *dto.MetricFamily, la } func buildCounterAssert(t *testing.T, metricName string, expectedValue int) func(family *dto.MetricFamily) { + t.Helper() + return func(family *dto.MetricFamily) { if cv := int(family.Metric[0].Counter.GetValue()); cv != expectedValue { t.Errorf("metric %s has value %d, want %d", metricName, cv, expectedValue) @@ -480,6 +482,8 @@ func buildCounterAssert(t *testing.T, metricName string, expectedValue int) func } func buildGreaterThanCounterAssert(t *testing.T, metricName string, expectedMinValue int) func(family *dto.MetricFamily) { + t.Helper() + return func(family *dto.MetricFamily) { if cv := int(family.Metric[0].Counter.GetValue()); cv < expectedMinValue { t.Errorf("metric %s has value %d, want at least %d", metricName, cv, expectedMinValue) @@ -488,6 +492,8 @@ func buildGreaterThanCounterAssert(t *testing.T, metricName string, expectedMinV } func buildHistogramAssert(t *testing.T, metricName string, expectedSampleCount int) func(family *dto.MetricFamily) { + t.Helper() + return func(family *dto.MetricFamily) { if sc := int(family.Metric[0].Histogram.GetSampleCount()); sc != expectedSampleCount { t.Errorf("metric %s has sample count value %d, want %d", metricName, sc, expectedSampleCount) @@ -496,6 +502,8 @@ func buildHistogramAssert(t *testing.T, metricName string, expectedSampleCount i } func buildGaugeAssert(t *testing.T, metricName string, expectedValue int) func(family *dto.MetricFamily) { + t.Helper() + return func(family *dto.MetricFamily) { if gv := int(family.Metric[0].Gauge.GetValue()); gv != expectedValue { t.Errorf("metric %s has value %d, want %d", metricName, gv, expectedValue) @@ -504,6 +512,8 @@ func buildGaugeAssert(t *testing.T, metricName string, expectedValue int) func(f } func buildTimestampAssert(t *testing.T, metricName string) func(family *dto.MetricFamily) { + t.Helper() + return func(family *dto.MetricFamily) { if ts := time.Unix(int64(family.Metric[0].Gauge.GetValue()), 0); time.Since(ts) > time.Minute { t.Errorf("metric %s has wrong timestamp %v", metricName, ts) diff --git a/pkg/middlewares/accesslog/logger_test.go b/pkg/middlewares/accesslog/logger_test.go index 5bc749eab..aaa145e5b 100644 --- a/pkg/middlewares/accesslog/logger_test.go +++ b/pkg/middlewares/accesslog/logger_test.go @@ -683,6 +683,8 @@ func TestNewLogHandlerOutputStdout(t *testing.T) { } func assertValidLogData(t *testing.T, expected string, logData []byte) { + t.Helper() + if len(expected) == 0 { assert.Zero(t, len(logData)) t.Log(string(logData)) @@ -716,6 +718,8 @@ func assertValidLogData(t *testing.T, expected string, logData []byte) { } func captureStdout(t *testing.T) (out *os.File, restoreStdout func()) { + t.Helper() + file, err := ioutil.TempFile("", "testlogger") require.NoError(t, err, "failed to create temp file") @@ -731,6 +735,8 @@ func captureStdout(t *testing.T) (out *os.File, restoreStdout func()) { } func createTempDir(t *testing.T, prefix string) string { + t.Helper() + tmpDir, err := ioutil.TempDir("", prefix) require.NoError(t, err, "failed to create temp dir") @@ -740,6 +746,8 @@ func createTempDir(t *testing.T, prefix string) string { } func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS bool) { + t.Helper() + logger, err := NewHandler(config) require.NoError(t, err) defer logger.Close() @@ -771,10 +779,14 @@ func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS bool) { } func doLoggingTLS(t *testing.T, config *types.AccessLog) { + t.Helper() + doLoggingTLSOpt(t, config, true) } func doLogging(t *testing.T, config *types.AccessLog) { + t.Helper() + doLoggingTLSOpt(t, config, false) } diff --git a/pkg/provider/file/file_test.go b/pkg/provider/file/file_test.go index be4755766..ca6f36728 100644 --- a/pkg/provider/file/file_test.go +++ b/pkg/provider/file/file_test.go @@ -76,8 +76,7 @@ func TestErrorWhenEmptyConfig(t *testing.T) { func TestProvideWithoutWatch(t *testing.T) { for _, test := range getTestCases() { t.Run(test.desc+" without watch", func(t *testing.T) { - provider, clean := createProvider(t, test, false) - defer clean() + provider := createProvider(t, test, false) configChan := make(chan dynamic.Message) provider.DebugLogGeneratedTemplate = true @@ -109,8 +108,7 @@ func TestProvideWithoutWatch(t *testing.T) { func TestProvideWithWatch(t *testing.T) { for _, test := range getTestCases() { t.Run(test.desc+" with watch", func(t *testing.T) { - provider, clean := createProvider(t, test, true) - defer clean() + provider := createProvider(t, test, true) configChan := make(chan dynamic.Message) go func() { @@ -244,7 +242,9 @@ func getTestCases() []ProvideTestCase { } } -func createProvider(t *testing.T, test ProvideTestCase, watch bool) (*Provider, func()) { +func createProvider(t *testing.T, test ProvideTestCase, watch bool) *Provider { + t.Helper() + tempDir := createTempDir(t, "testdir") provider := &Provider{} @@ -276,9 +276,11 @@ func createProvider(t *testing.T, test ProvideTestCase, watch bool) (*Provider, provider.Filename = file.Name() } - return provider, func() { + t.Cleanup(func() { os.RemoveAll(tempDir) - } + }) + + return provider } // createTempDir Helper. diff --git a/pkg/server/server_entrypoint_tcp_test.go b/pkg/server/server_entrypoint_tcp_test.go index 6c76c768d..a8845d16b 100644 --- a/pkg/server/server_entrypoint_tcp_test.go +++ b/pkg/server/server_entrypoint_tcp_test.go @@ -28,6 +28,7 @@ func TestShutdownHijacked(t *testing.T) { err = resp.Write(conn) require.NoError(t, err) })) + testShutdown(t, router) } @@ -37,6 +38,7 @@ func TestShutdownHTTP(t *testing.T) { rw.WriteHeader(http.StatusOK) time.Sleep(time.Second) })) + testShutdown(t, router) } @@ -61,6 +63,8 @@ func TestShutdownTCP(t *testing.T) { } func testShutdown(t *testing.T, router *tcp.Router) { + t.Helper() + epConfig := &static.EntryPointsTransport{} epConfig.SetDefaults() diff --git a/pkg/server/server_entrypoint_udp_test.go b/pkg/server/server_entrypoint_udp_test.go index 00a6ba8cd..2aa5e70d8 100644 --- a/pkg/server/server_entrypoint_udp_test.go +++ b/pkg/server/server_entrypoint_udp_test.go @@ -103,6 +103,8 @@ func TestShutdownUDPConn(t *testing.T) { // It fatals if the read blocks longer than timeout, which is useful to detect // regressions that would make a test wait forever. func requireEcho(t *testing.T, data string, conn io.ReadWriter, timeout time.Duration) { + t.Helper() + _, err := conn.Write([]byte(data)) require.NoError(t, err) diff --git a/pkg/server/service/proxy_websocket_test.go b/pkg/server/service/proxy_websocket_test.go index a759cf95a..a03a06666 100644 --- a/pkg/server/service/proxy_websocket_test.go +++ b/pkg/server/service/proxy_websocket_test.go @@ -696,12 +696,16 @@ func (w *websocketRequest) open() (*websocket.Conn, net.Conn, error) { } func parseURI(t *testing.T, uri string) *url.URL { + t.Helper() + out, err := url.ParseRequestURI(uri) require.NoError(t, err) return out } func createProxyWithForwarder(t *testing.T, proxy http.Handler, url string) *httptest.Server { + t.Helper() + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { path := req.URL.Path // keep the original path // Set new backend URL diff --git a/pkg/tcp/proxy_test.go b/pkg/tcp/proxy_test.go index e83017fba..11fdb47c4 100644 --- a/pkg/tcp/proxy_test.go +++ b/pkg/tcp/proxy_test.go @@ -17,6 +17,8 @@ import ( ) func fakeRedis(t *testing.T, listener net.Listener) { + t.Helper() + for { conn, err := listener.Accept() fmt.Println("Accept on server") diff --git a/pkg/udp/conn_test.go b/pkg/udp/conn_test.go index f97eb3958..3f0116e07 100644 --- a/pkg/udp/conn_test.go +++ b/pkg/udp/conn_test.go @@ -171,6 +171,8 @@ func TestTimeoutWithoutRead(t *testing.T) { } func testTimeout(t *testing.T, withRead bool) { + t.Helper() + addr, err := net.ResolveUDPAddr("udp", ":0") require.NoError(t, err) @@ -312,6 +314,8 @@ func TestShutdown(t *testing.T) { // It fatals if the read blocks longer than timeout, // which is useful to detect regressions that would make a test wait forever. func requireEcho(t *testing.T, data string, conn io.ReadWriter, timeout time.Duration) { + t.Helper() + _, err := conn.Write([]byte(data)) require.NoError(t, err) diff --git a/pkg/udp/proxy_test.go b/pkg/udp/proxy_test.go index 509f9aabd..e2995846d 100644 --- a/pkg/udp/proxy_test.go +++ b/pkg/udp/proxy_test.go @@ -41,6 +41,8 @@ func TestUDPProxy(t *testing.T) { } func newServer(t *testing.T, addr string, handler Handler) { + t.Helper() + addrL, err := net.ResolveUDPAddr("udp", addr) require.NoError(t, err) From c4fa96c41e4ee821094830e37efe89cd3c073230 Mon Sep 17 00:00:00 2001 From: Anil Kumar Maurya Date: Mon, 4 Jan 2021 15:28:03 +0530 Subject: [PATCH 7/8] Add ECS to supported providers list --- docs/content/providers/overview.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/content/providers/overview.md b/docs/content/providers/overview.md index 758afedc3..e9e9a12d8 100644 --- a/docs/content/providers/overview.md +++ b/docs/content/providers/overview.md @@ -131,13 +131,14 @@ Below is the list of the currently supported providers in Traefik. | [Docker](./docker.md) | Orchestrator | Label | | [Kubernetes](./kubernetes-crd.md) | Orchestrator | Custom Resource or Ingress | | [Consul Catalog](./consul-catalog.md) | Orchestrator | Label | +| [ECS](./ecs.md) | Orchestrator | Label | | [Marathon](./marathon.md) | Orchestrator | Label | | [Rancher](./rancher.md) | Orchestrator | Label | | [File](./file.md) | Manual | TOML/YAML format | | [Consul](./consul.md) | KV | KV | | [Etcd](./etcd.md) | KV | KV | -| [Redis](./redis.md) | KV | KV | | [ZooKeeper](./zookeeper.md) | KV | KV | +| [Redis](./redis.md) | KV | KV | | [HTTP](./http.md) | Manual | JSON format | !!! info "More Providers" From d4f0a9ff6296ba7c71b37d7b4433d404a3bea96e Mon Sep 17 00:00:00 2001 From: Avdhoot Dendge Date: Tue, 5 Jan 2021 16:56:04 +0530 Subject: [PATCH 8/8] Fix wildcard hostname issue --- ...h-conflicting-routers-on-host_endpoint.yml | 15 ++++ ...th-conflicting-routers-on-host_ingress.yml | 23 +++++++ ...th-conflicting-routers-on-host_service.yml | 10 +++ ...h-conflicting-routers-on-path_endpoint.yml | 15 ++++ ...th-conflicting-routers-on-path_ingress.yml | 19 ++++++ ...th-conflicting-routers-on-path_service.yml | 10 +++ pkg/provider/kubernetes/ingress/kubernetes.go | 34 +++++++++- .../kubernetes/ingress/kubernetes_test.go | 68 +++++++++++++++++++ 8 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_endpoint.yml create mode 100644 pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_ingress.yml create mode 100644 pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_service.yml create mode 100644 pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_endpoint.yml create mode 100644 pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_ingress.yml create mode 100644 pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_service.yml diff --git a/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_endpoint.yml b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_endpoint.yml new file mode 100644 index 000000000..b19cd5c3f --- /dev/null +++ b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_endpoint.yml @@ -0,0 +1,15 @@ +kind: Endpoints +apiVersion: v1 +metadata: + name: service1 + namespace: testing + +subsets: +- addresses: + - ip: 10.10.0.1 + ports: + - port: 8080 +- addresses: + - ip: 10.21.0.1 + ports: + - port: 8080 diff --git a/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_ingress.yml b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_ingress.yml new file mode 100644 index 000000000..a8aa09dcd --- /dev/null +++ b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_ingress.yml @@ -0,0 +1,23 @@ +kind: Ingress +apiVersion: networking.k8s.io/v1beta1 +metadata: + name: "" + namespace: testing + +spec: + rules: + - host: "*.bar" + http: + paths: + - path: /bar + backend: + serviceName: service1 + servicePort: 80 + + - host: "bar" + http: + paths: + - path: /bar + backend: + serviceName: service1 + servicePort: 80 diff --git a/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_service.yml b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_service.yml new file mode 100644 index 000000000..7c58aeed5 --- /dev/null +++ b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-host_service.yml @@ -0,0 +1,10 @@ +kind: Service +apiVersion: v1 +metadata: + name: service1 + namespace: testing + +spec: + ports: + - port: 80 + clusterIp: 10.0.0.1 diff --git a/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_endpoint.yml b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_endpoint.yml new file mode 100644 index 000000000..b19cd5c3f --- /dev/null +++ b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_endpoint.yml @@ -0,0 +1,15 @@ +kind: Endpoints +apiVersion: v1 +metadata: + name: service1 + namespace: testing + +subsets: +- addresses: + - ip: 10.10.0.1 + ports: + - port: 8080 +- addresses: + - ip: 10.21.0.1 + ports: + - port: 8080 diff --git a/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_ingress.yml b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_ingress.yml new file mode 100644 index 000000000..abfe74519 --- /dev/null +++ b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_ingress.yml @@ -0,0 +1,19 @@ +kind: Ingress +apiVersion: networking.k8s.io/v1beta1 +metadata: + name: "" + namespace: testing + +spec: + rules: + - http: + paths: + - path: /foo/bar + backend: + serviceName: service1 + servicePort: 80 + + - path: /foo-bar + backend: + serviceName: service1 + servicePort: 80 diff --git a/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_service.yml b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_service.yml new file mode 100644 index 000000000..7c58aeed5 --- /dev/null +++ b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-conflicting-routers-on-path_service.yml @@ -0,0 +1,10 @@ +kind: Service +apiVersion: v1 +metadata: + name: service1 + namespace: testing + +spec: + ports: + - port: 80 + clusterIp: 10.0.0.1 diff --git a/pkg/provider/kubernetes/ingress/kubernetes.go b/pkg/provider/kubernetes/ingress/kubernetes.go index 8f06b214b..d3995dcb7 100644 --- a/pkg/provider/kubernetes/ingress/kubernetes.go +++ b/pkg/provider/kubernetes/ingress/kubernetes.go @@ -2,6 +2,7 @@ package ingress import ( "context" + "crypto/sha256" "errors" "fmt" "math" @@ -253,6 +254,8 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl conf.HTTP.Services["default-backend"] = service } + routers := map[string][]*dynamic.Router{} + for _, rule := range ingress.Spec.Rules { if err := p.updateIngressStatus(ingress, client); err != nil { log.FromContext(ctx).Errorf("Error while updating ingress status: %v", err) @@ -276,8 +279,26 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl conf.HTTP.Services[serviceName] = service routerKey := strings.TrimPrefix(provider.Normalize(ingress.Name+"-"+ingress.Namespace+"-"+rule.Host+pa.Path), "-") + routers[routerKey] = append(routers[routerKey], loadRouter(rule, pa, rtConfig, serviceName)) + } + } - conf.HTTP.Routers[routerKey] = loadRouter(rule, pa, rtConfig, serviceName) + for routerKey, conflictingRouters := range routers { + if len(conflictingRouters) == 1 { + conf.HTTP.Routers[routerKey] = conflictingRouters[0] + continue + } + + log.FromContext(ctx).Debugf("Multiple routers are defined with the same key %q, generating hashes to avoid conflicts", routerKey) + + for _, router := range conflictingRouters { + key, err := makeRouterKeyWithHash(routerKey, router.Rule) + if err != nil { + log.FromContext(ctx).Error(err) + continue + } + + conf.HTTP.Routers[key] = router } } } @@ -543,6 +564,17 @@ func getProtocol(portSpec corev1.ServicePort, portName string, svcConfig *Servic return protocol } +func makeRouterKeyWithHash(key, rule string) (string, error) { + h := sha256.New() + if _, err := h.Write([]byte(rule)); err != nil { + return "", err + } + + dupKey := fmt.Sprintf("%s-%.10x", key, h.Sum(nil)) + + return dupKey, nil +} + func loadRouter(rule networkingv1beta1.IngressRule, pa networkingv1beta1.HTTPIngressPath, rtConfig *RouterConfig, serviceName string) *dynamic.Router { var rules []string if len(rule.Host) > 0 { diff --git a/pkg/provider/kubernetes/ingress/kubernetes_test.go b/pkg/provider/kubernetes/ingress/kubernetes_test.go index ee9c98347..90c7b45c3 100644 --- a/pkg/provider/kubernetes/ingress/kubernetes_test.go +++ b/pkg/provider/kubernetes/ingress/kubernetes_test.go @@ -169,6 +169,74 @@ func TestLoadConfigurationFromIngresses(t *testing.T) { }, }, }, + { + desc: "Ingress with conflicting routers on host", + expected: &dynamic.Configuration{ + TCP: &dynamic.TCPConfiguration{}, + HTTP: &dynamic.HTTPConfiguration{ + Middlewares: map[string]*dynamic.Middleware{}, + Routers: map[string]*dynamic.Router{ + "testing-bar-bar-3be6cfd7daba66cf2fdd": { + Rule: "HostRegexp(`{subdomain:[a-zA-Z0-9-]+}.bar`) && PathPrefix(`/bar`)", + Service: "testing-service1-80", + }, + "testing-bar-bar-636bf36c00fedaab3d44": { + Rule: "Host(`bar`) && PathPrefix(`/bar`)", + Service: "testing-service1-80", + }, + }, + Services: map[string]*dynamic.Service{ + "testing-service1-80": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + PassHostHeader: Bool(true), + Servers: []dynamic.Server{ + { + URL: "http://10.10.0.1:8080", + }, + { + URL: "http://10.21.0.1:8080", + }, + }, + }, + }, + }, + }, + }, + }, + { + desc: "Ingress with conflicting routers on path", + expected: &dynamic.Configuration{ + TCP: &dynamic.TCPConfiguration{}, + HTTP: &dynamic.HTTPConfiguration{ + Middlewares: map[string]*dynamic.Middleware{}, + Routers: map[string]*dynamic.Router{ + "testing-foo-bar-d0b30949e54d6a7515ca": { + Rule: "PathPrefix(`/foo/bar`)", + Service: "testing-service1-80", + }, + "testing-foo-bar-dcd54bae39a6d7557f48": { + Rule: "PathPrefix(`/foo-bar`)", + Service: "testing-service1-80", + }, + }, + Services: map[string]*dynamic.Service{ + "testing-service1-80": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + PassHostHeader: Bool(true), + Servers: []dynamic.Server{ + { + URL: "http://10.10.0.1:8080", + }, + { + URL: "http://10.21.0.1:8080", + }, + }, + }, + }, + }, + }, + }, + }, { desc: "Ingress one rule with two paths", expected: &dynamic.Configuration{