1
0
mirror of https://github.com/containous/traefik.git synced 2024-12-23 17:34:13 +03:00

Merge v2.4 into master

This commit is contained in:
Jean-Baptiste Doumenjou 2021-02-04 10:40:53 +01:00
commit d211437d6c
80 changed files with 430 additions and 100 deletions

View File

@ -61,6 +61,7 @@
"exhaustivestruct", # Not relevant "exhaustivestruct", # Not relevant
"makezero", # not relevant "makezero", # not relevant
"forbidigo", # not relevant "forbidigo", # not relevant
"ifshort", # not relevant
] ]
[issues] [issues]

View File

@ -1,3 +1,33 @@
## [v2.4.2](https://github.com/traefik/traefik/tree/v2.4.2) (2021-02-02)
[All Commits](https://github.com/traefik/traefik/compare/v2.4.1...v2.4.2)
**Bug fixes:**
- **[acme]** Fix the redirect entrypoint default priority ([#7851](https://github.com/traefik/traefik/pull/7851) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[middleware]** Fix the infinite loop in forwarded header middleware. ([#7847](https://github.com/traefik/traefik/pull/7847) by [ldez](https://github.com/ldez))
**Documentation:**
- Fix the static configuration generation for environment variables ([#7849](https://github.com/traefik/traefik/pull/7849) by [jbdoumenjou](https://github.com/jbdoumenjou))
## [v2.4.1](https://github.com/traefik/traefik/tree/v2.4.1) (2021-02-01)
[All Commits](https://github.com/traefik/traefik/compare/v2.4.0...v2.4.1)
**Bug fixes:**
- **[acme,provider]** Fix HTTP challenge router unexpected delayed creation ([#7805](https://github.com/traefik/traefik/pull/7805) by [jspdown](https://github.com/jspdown))
- **[acme]** Update go-acme/lego to v4.2.0 ([#7793](https://github.com/traefik/traefik/pull/7793) by [ldez](https://github.com/ldez))
- **[api,plugins]** Fix plugin type on middleware endpoint response ([#7782](https://github.com/traefik/traefik/pull/7782) by [jspdown](https://github.com/jspdown))
- **[authentication,middleware]** Forward Proxy-Authorization header to authentication server ([#7433](https://github.com/traefik/traefik/pull/7433) by [Scapal](https://github.com/Scapal))
- **[k8s,k8s/ingress]** Add support for multiple ingress classes ([#7799](https://github.com/traefik/traefik/pull/7799) by [LandryBe](https://github.com/LandryBe))
- **[middleware]** Improve forwarded header and recovery middlewares performances ([#7783](https://github.com/traefik/traefik/pull/7783) by [juliens](https://github.com/juliens))
- **[pilot]** Reduce pressure of pilot services when errors occurs ([#7824](https://github.com/traefik/traefik/pull/7824) by [darkweaver87](https://github.com/darkweaver87))
- **[provider]** Fix aggregator test comment ([#7840](https://github.com/traefik/traefik/pull/7840) by [rtribotte](https://github.com/rtribotte))
- **[provider]** Fix servers transport not found ([#7839](https://github.com/traefik/traefik/pull/7839) by [jspdown](https://github.com/jspdown))
**Documentation:**
- **[consulcatalog]** Fix refresh interval option description in consulcatalog provider ([#7810](https://github.com/traefik/traefik/pull/7810) by [GabeL7r](https://github.com/GabeL7r))
- **[docker]** Fix missing serverstransport documentation ([#7822](https://github.com/traefik/traefik/pull/7822) by [kevinpollet](https://github.com/kevinpollet))
- **[k8s]** Fix YAML syntax in providers docs ([#7787](https://github.com/traefik/traefik/pull/7787) by [4ops](https://github.com/4ops))
- **[service]** Fix typo in server transports documentation ([#7797](https://github.com/traefik/traefik/pull/7797) by [obezuk](https://github.com/obezuk))
## [v2.4.0](https://github.com/traefik/traefik/tree/v2.4.0) (2021-01-19) ## [v2.4.0](https://github.com/traefik/traefik/tree/v2.4.0) (2021-01-19)
[All Commits](https://github.com/traefik/traefik/compare/v2.3.0-rc1...v2.4.0) [All Commits](https://github.com/traefik/traefik/compare/v2.3.0-rc1...v2.4.0)

View File

@ -19,7 +19,7 @@ RUN mkdir -p /usr/local/bin \
&& chmod +x /usr/local/bin/go-bindata && chmod +x /usr/local/bin/go-bindata
# Download golangci-lint binary to bin folder in $GOPATH # 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.34.0 RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.36.0
# Download misspell binary to bin folder in $GOPATH # 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 RUN curl -sfL https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.3.4

View File

@ -159,6 +159,7 @@
- "traefik.http.services.service01.loadbalancer.sticky.cookie.secure=true" - "traefik.http.services.service01.loadbalancer.sticky.cookie.secure=true"
- "traefik.http.services.service01.loadbalancer.server.port=foobar" - "traefik.http.services.service01.loadbalancer.server.port=foobar"
- "traefik.http.services.service01.loadbalancer.server.scheme=foobar" - "traefik.http.services.service01.loadbalancer.server.scheme=foobar"
- "traefik.http.services.service01.loadbalancer.serverstransport=foobar"
- "traefik.tcp.routers.tcprouter0.entrypoints=foobar, foobar" - "traefik.tcp.routers.tcprouter0.entrypoints=foobar, foobar"
- "traefik.tcp.routers.tcprouter0.rule=foobar" - "traefik.tcp.routers.tcprouter0.rule=foobar"
- "traefik.tcp.routers.tcprouter0.service=foobar" - "traefik.tcp.routers.tcprouter0.service=foobar"

View File

@ -96,6 +96,7 @@ spec:
strategy: RoundRobin strategy: RoundRobin
- name: s2 - name: s2
port: 433 port: 433
serversTransport: mytransport
- match: PathPrefix(`/misc`) - match: PathPrefix(`/misc`)
services: services:
- name: s3 - name: s3

View File

@ -37,6 +37,7 @@
"traefik.http.middlewares.middleware10.headers.accesscontrolallowmethods": "foobar, foobar", "traefik.http.middlewares.middleware10.headers.accesscontrolallowmethods": "foobar, foobar",
"traefik.http.middlewares.middleware10.headers.accesscontrolalloworigin": "foobar", "traefik.http.middlewares.middleware10.headers.accesscontrolalloworigin": "foobar",
"traefik.http.middlewares.middleware10.headers.accesscontrolalloworiginlist": "foobar, foobar", "traefik.http.middlewares.middleware10.headers.accesscontrolalloworiginlist": "foobar, foobar",
"traefik.http.middlewares.middleware10.headers.accesscontrolalloworiginlistregex": "foobar, foobar",
"traefik.http.middlewares.middleware10.headers.accesscontrolexposeheaders": "foobar, foobar", "traefik.http.middlewares.middleware10.headers.accesscontrolexposeheaders": "foobar, foobar",
"traefik.http.middlewares.middleware10.headers.accesscontrolmaxage": "42", "traefik.http.middlewares.middleware10.headers.accesscontrolmaxage": "42",
"traefik.http.middlewares.middleware10.headers.addvaryheader": "true", "traefik.http.middlewares.middleware10.headers.addvaryheader": "true",
@ -120,6 +121,7 @@
"traefik.http.routers.router0.priority": "42", "traefik.http.routers.router0.priority": "42",
"traefik.http.routers.router0.rule": "foobar", "traefik.http.routers.router0.rule": "foobar",
"traefik.http.routers.router0.service": "foobar", "traefik.http.routers.router0.service": "foobar",
"traefik.http.routers.router0.tls": "true",
"traefik.http.routers.router0.tls.certresolver": "foobar", "traefik.http.routers.router0.tls.certresolver": "foobar",
"traefik.http.routers.router0.tls.domains[0].main": "foobar", "traefik.http.routers.router0.tls.domains[0].main": "foobar",
"traefik.http.routers.router0.tls.domains[0].sans": "foobar, foobar", "traefik.http.routers.router0.tls.domains[0].sans": "foobar, foobar",
@ -131,6 +133,7 @@
"traefik.http.routers.router1.priority": "42", "traefik.http.routers.router1.priority": "42",
"traefik.http.routers.router1.rule": "foobar", "traefik.http.routers.router1.rule": "foobar",
"traefik.http.routers.router1.service": "foobar", "traefik.http.routers.router1.service": "foobar",
"traefik.http.routers.router1.tls": "true",
"traefik.http.routers.router1.tls.certresolver": "foobar", "traefik.http.routers.router1.tls.certresolver": "foobar",
"traefik.http.routers.router1.tls.domains[0].main": "foobar", "traefik.http.routers.router1.tls.domains[0].main": "foobar",
"traefik.http.routers.router1.tls.domains[0].sans": "foobar, foobar", "traefik.http.routers.router1.tls.domains[0].sans": "foobar, foobar",
@ -156,9 +159,11 @@
"traefik.http.services.service01.loadbalancer.sticky.cookie.secure": "true", "traefik.http.services.service01.loadbalancer.sticky.cookie.secure": "true",
"traefik.http.services.service01.loadbalancer.server.port": "foobar", "traefik.http.services.service01.loadbalancer.server.port": "foobar",
"traefik.http.services.service01.loadbalancer.server.scheme": "foobar", "traefik.http.services.service01.loadbalancer.server.scheme": "foobar",
"traefik.http.services.service01.loadbalancer.serverstransport": "foobar",
"traefik.tcp.routers.tcprouter0.entrypoints": "foobar, foobar", "traefik.tcp.routers.tcprouter0.entrypoints": "foobar, foobar",
"traefik.tcp.routers.tcprouter0.rule": "foobar", "traefik.tcp.routers.tcprouter0.rule": "foobar",
"traefik.tcp.routers.tcprouter0.service": "foobar", "traefik.tcp.routers.tcprouter0.service": "foobar",
"traefik.tcp.routers.tcprouter0.tls": "true",
"traefik.tcp.routers.tcprouter0.tls.certresolver": "foobar", "traefik.tcp.routers.tcprouter0.tls.certresolver": "foobar",
"traefik.tcp.routers.tcprouter0.tls.domains[0].main": "foobar", "traefik.tcp.routers.tcprouter0.tls.domains[0].main": "foobar",
"traefik.tcp.routers.tcprouter0.tls.domains[0].sans": "foobar, foobar", "traefik.tcp.routers.tcprouter0.tls.domains[0].sans": "foobar, foobar",
@ -169,6 +174,7 @@
"traefik.tcp.routers.tcprouter1.entrypoints": "foobar, foobar", "traefik.tcp.routers.tcprouter1.entrypoints": "foobar, foobar",
"traefik.tcp.routers.tcprouter1.rule": "foobar", "traefik.tcp.routers.tcprouter1.rule": "foobar",
"traefik.tcp.routers.tcprouter1.service": "foobar", "traefik.tcp.routers.tcprouter1.service": "foobar",
"traefik.tcp.routers.tcprouter1.tls": "true",
"traefik.tcp.routers.tcprouter1.tls.certresolver": "foobar", "traefik.tcp.routers.tcprouter1.tls.certresolver": "foobar",
"traefik.tcp.routers.tcprouter1.tls.domains[0].main": "foobar", "traefik.tcp.routers.tcprouter1.tls.domains[0].main": "foobar",
"traefik.tcp.routers.tcprouter1.tls.domains[0].sans": "foobar, foobar", "traefik.tcp.routers.tcprouter1.tls.domains[0].sans": "foobar, foobar",

View File

@ -403,7 +403,7 @@ Expose containers by default. (Default: ```true```)
Prefix for consul service tags. Default 'traefik' (Default: ```traefik```) Prefix for consul service tags. Default 'traefik' (Default: ```traefik```)
`--providers.consulcatalog.refreshinterval`: `--providers.consulcatalog.refreshinterval`:
Interval for check Consul API. Default 100ms (Default: ```15```) Interval for check Consul API. Default 15s (Default: ```15```)
`--providers.consulcatalog.requireconsistent`: `--providers.consulcatalog.requireconsistent`:
Forces the read to be fully consistent. (Default: ```false```) Forces the read to be fully consistent. (Default: ```false```)

View File

@ -138,10 +138,10 @@ Default certificate resolver for the routers linked to the entry point.
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_DOMAINS`: `TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_DOMAINS`:
Default TLS domains for the routers linked to the entry point. Default TLS domains for the routers linked to the entry point.
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_DOMAINS[n]_MAIN`: `TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_DOMAINS_n_MAIN`:
Default subject name. Default subject name.
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_DOMAINS[n]_SANS`: `TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_DOMAINS_n_SANS`:
Subject alternative names. Subject alternative names.
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_OPTIONS`: `TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_OPTIONS`:
@ -376,7 +376,7 @@ Expose containers by default. (Default: ```true```)
Prefix for consul service tags. Default 'traefik' (Default: ```traefik```) Prefix for consul service tags. Default 'traefik' (Default: ```traefik```)
`TRAEFIK_PROVIDERS_CONSULCATALOG_REFRESHINTERVAL`: `TRAEFIK_PROVIDERS_CONSULCATALOG_REFRESHINTERVAL`:
Interval for check Consul API. Default 100ms (Default: ```15```) Interval for check Consul API. Default 15s (Default: ```15```)
`TRAEFIK_PROVIDERS_CONSULCATALOG_REQUIRECONSISTENT`: `TRAEFIK_PROVIDERS_CONSULCATALOG_REQUIRECONSISTENT`:
Forces the read to be fully consistent. (Default: ```false```) Forces the read to be fully consistent. (Default: ```false```)

View File

@ -383,6 +383,7 @@
token = "foobar" token = "foobar"
[experimental] [experimental]
kubernetesGateway = true
[experimental.plugins] [experimental.plugins]
[experimental.plugins.Descriptor0] [experimental.plugins.Descriptor0]
moduleName = "foobar" moduleName = "foobar"

View File

@ -403,6 +403,7 @@ certificatesResolvers:
pilot: pilot:
token: foobar token: foobar
experimental: experimental:
kubernetesGateway: true
plugins: plugins:
Descriptor0: Descriptor0:
moduleName: foobar moduleName: foobar

View File

@ -285,6 +285,14 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
- "traefik.http.services.myservice.loadbalancer.server.scheme=http" - "traefik.http.services.myservice.loadbalancer.server.scheme=http"
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
See [serverstransport](../services/index.md#serverstransport) for more information.
```yaml
- "traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`" ??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
See [pass Host header](../services/index.md#pass-host-header) for more information. See [pass Host header](../services/index.md#pass-host-header) for more information.

View File

@ -335,6 +335,7 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
responseForwarding: responseForwarding:
flushInterval: 1ms flushInterval: 1ms
scheme: https scheme: https
serversTransport: transport
sticky: sticky:
cookie: cookie:
httpOnly: true httpOnly: true

View File

@ -462,7 +462,7 @@ By default, `passHostHeader` is true.
#### ServersTransport #### ServersTransport
`serversTransport` allows to reference a ServersTransport configuration for the communication between Traefik and your servers. `serversTransport` allows to reference a [ServersTransport](./index.md#serverstransport_1) configuration for the communication between Traefik and your servers.
??? example "Specify a transport -- Using the [File Provider](../../providers/file.md)" ??? example "Specify a transport -- Using the [File Provider](../../providers/file.md)"
@ -573,7 +573,7 @@ that will be set as client certificates for mTLS.
http: http:
serversTransports: serversTransports:
mytransport: mytransport:
certficates: certificates:
- certFile: foo.crt - certFile: foo.crt
keyFile: bar.crt keyFile: bar.crt
``` ```

View File

@ -1,7 +1,7 @@
whoami: whoami:
image: traefik/whoami image: traefik/whoami
labels: labels:
- traefik.http.routers.route1.rule=PathPrefix(`/`) - traefik.http.routers.route1.rule=PathPrefix(`/foo`)
- traefik.http.routers.route1.middlewares=passtls - traefik.http.routers.route1.middlewares=passtls
- traefik.http.routers.route1.tls=true - traefik.http.routers.route1.tls=true
- traefik.http.middlewares.passtls.passtlsclientcert.pem=true - traefik.http.middlewares.passtls.passtlsclientcert.pem=true

View File

@ -50,10 +50,10 @@ func (s *TLSClientHeadersSuite) TestTLSClientHeaders(c *check.C) {
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
defer s.killCmd(cmd) defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second, try.BodyContains("PathPrefix(`/`)")) err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second, try.BodyContains("PathPrefix(`/foo`)"))
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
request, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:8443", nil) request, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:8443/foo", nil)
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
certificate, err := tls.LoadX509KeyPair(certPemPath, certKeyPath) certificate, err := tls.LoadX509KeyPair(certPemPath, certKeyPath)

View File

@ -64,7 +64,12 @@ THIS FILE MUST NOT BE EDITED BY HAND
continue continue
} }
if prefix == "" {
w.writeln("`" + prefix + strings.ReplaceAll(flat.Name, "[0]", "_n") + "`: ")
} else {
w.writeln("`" + prefix + strings.ReplaceAll(flat.Name, "[0]", "[n]") + "`: ") w.writeln("`" + prefix + strings.ReplaceAll(flat.Name, "[0]", "[n]") + "`: ")
}
if flat.Default == "" { if flat.Default == "" {
w.writeln(flat.Description) w.writeln(flat.Description)
} else { } else {

View File

@ -76,7 +76,7 @@ type RedirectEntryPoint struct {
func (r *RedirectEntryPoint) SetDefaults() { func (r *RedirectEntryPoint) SetDefaults() {
r.Scheme = "https" r.Scheme = "https"
r.Permanent = true r.Permanent = true
r.Priority = math.MaxInt32 r.Priority = math.MaxInt32 - 1
} }
// TLSConfig is the default TLS configuration for all the routers associated to the concerned entry point. // TLSConfig is the default TLS configuration for all the routers associated to the concerned entry point.

View File

@ -391,12 +391,12 @@ func (d *dynamicConfig) hasServerURL(serviceName, serverURL string) bool {
return false return false
} }
func newCollector(metricName string, labels stdprometheus.Labels, c stdprometheus.Collector, delete func()) *collector { func newCollector(metricName string, labels stdprometheus.Labels, c stdprometheus.Collector, deleteFn func()) *collector {
return &collector{ return &collector{
id: buildMetricID(metricName, labels), id: buildMetricID(metricName, labels),
labels: labels, labels: labels,
collector: c, collector: c,
delete: delete, delete: deleteFn,
} }
} }

View File

@ -284,9 +284,9 @@ func TestIntegrationShouldCompress(t *testing.T) {
} }
} }
func generateBytes(len int) []byte { func generateBytes(length int) []byte {
var value []byte var value []byte
for i := 0; i < len; i++ { for i := 0; i < length; i++ {
value = append(value, 0x61+byte(i)) value = append(value, 0x61+byte(i))
} }
return value return value

View File

@ -29,6 +29,7 @@ func TestHandler(t *testing.T) {
fmt.Fprintln(w, "My error page.") fmt.Fprintln(w, "My error page.")
}), }),
validate: func(t *testing.T, recorder *httptest.ResponseRecorder) { validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
t.Helper()
assert.Equal(t, http.StatusOK, recorder.Code, "HTTP status") assert.Equal(t, http.StatusOK, recorder.Code, "HTTP status")
assert.Contains(t, recorder.Body.String(), http.StatusText(http.StatusOK)) assert.Contains(t, recorder.Body.String(), http.StatusText(http.StatusOK))
}, },
@ -41,6 +42,7 @@ func TestHandler(t *testing.T) {
fmt.Fprintln(w, "My error page.") fmt.Fprintln(w, "My error page.")
}), }),
validate: func(t *testing.T, recorder *httptest.ResponseRecorder) { validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
t.Helper()
assert.Equal(t, http.StatusPartialContent, recorder.Code, "HTTP status") assert.Equal(t, http.StatusPartialContent, recorder.Code, "HTTP status")
assert.Contains(t, recorder.Body.String(), http.StatusText(http.StatusPartialContent)) assert.Contains(t, recorder.Body.String(), http.StatusText(http.StatusPartialContent))
}, },
@ -53,6 +55,7 @@ func TestHandler(t *testing.T) {
fmt.Fprintln(w, "whatever, should not be called") fmt.Fprintln(w, "whatever, should not be called")
}), }),
validate: func(t *testing.T, recorder *httptest.ResponseRecorder) { validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
t.Helper()
assert.Equal(t, http.StatusNotModified, recorder.Code, "HTTP status") assert.Equal(t, http.StatusNotModified, recorder.Code, "HTTP status")
assert.Contains(t, recorder.Body.String(), "") assert.Contains(t, recorder.Body.String(), "")
}, },
@ -65,6 +68,7 @@ func TestHandler(t *testing.T) {
fmt.Fprintln(w, "My error page.") fmt.Fprintln(w, "My error page.")
}), }),
validate: func(t *testing.T, recorder *httptest.ResponseRecorder) { validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
t.Helper()
assert.Equal(t, http.StatusInternalServerError, recorder.Code, "HTTP status") assert.Equal(t, http.StatusInternalServerError, recorder.Code, "HTTP status")
assert.Contains(t, recorder.Body.String(), "My error page.") assert.Contains(t, recorder.Body.String(), "My error page.")
assert.NotContains(t, recorder.Body.String(), "oops", "Should not return the oops page") assert.NotContains(t, recorder.Body.String(), "oops", "Should not return the oops page")
@ -78,6 +82,7 @@ func TestHandler(t *testing.T) {
fmt.Fprintln(w, "My error page.") fmt.Fprintln(w, "My error page.")
}), }),
validate: func(t *testing.T, recorder *httptest.ResponseRecorder) { validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
t.Helper()
assert.Equal(t, http.StatusBadGateway, recorder.Code, "HTTP status") assert.Equal(t, http.StatusBadGateway, recorder.Code, "HTTP status")
assert.Contains(t, recorder.Body.String(), http.StatusText(http.StatusBadGateway)) assert.Contains(t, recorder.Body.String(), http.StatusText(http.StatusBadGateway))
assert.NotContains(t, recorder.Body.String(), "Test Server", "Should return the oops page since we have not configured the 502 code") assert.NotContains(t, recorder.Body.String(), "Test Server", "Should return the oops page since we have not configured the 502 code")
@ -95,6 +100,7 @@ func TestHandler(t *testing.T) {
} }
}), }),
validate: func(t *testing.T, recorder *httptest.ResponseRecorder) { validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
t.Helper()
assert.Equal(t, http.StatusServiceUnavailable, recorder.Code, "HTTP status") assert.Equal(t, http.StatusServiceUnavailable, recorder.Code, "HTTP status")
assert.Contains(t, recorder.Body.String(), "My 503 page.") assert.Contains(t, recorder.Body.String(), "My 503 page.")
assert.NotContains(t, recorder.Body.String(), "oops", "Should not return the oops page") assert.NotContains(t, recorder.Body.String(), "oops", "Should not return the oops page")
@ -112,6 +118,7 @@ func TestHandler(t *testing.T) {
} }
}), }),
validate: func(t *testing.T, recorder *httptest.ResponseRecorder) { validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
t.Helper()
assert.Equal(t, http.StatusServiceUnavailable, recorder.Code, "HTTP status") assert.Equal(t, http.StatusServiceUnavailable, recorder.Code, "HTTP status")
assert.Contains(t, recorder.Body.String(), "My 503 page.") assert.Contains(t, recorder.Body.String(), "My 503 page.")
assert.NotContains(t, recorder.Body.String(), "oops", "Should not return the oops page") assert.NotContains(t, recorder.Body.String(), "oops", "Should not return the oops page")

View File

@ -104,9 +104,10 @@ func isWebsocketRequest(req *http.Request) bool {
return true return true
} }
h = h[pos:] h = h[pos+1:]
} }
} }
return containsHeader(connection, "upgrade") && containsHeader(upgrade, "websocket") return containsHeader(connection, "upgrade") && containsHeader(upgrade, "websocket")
} }

View File

@ -3,6 +3,7 @@ package forwardedheaders
import ( import (
"crypto/tls" "crypto/tls"
"net/http" "net/http"
"net/http/httptest"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -299,3 +300,71 @@ func TestServeHTTP(t *testing.T) {
}) })
} }
} }
func Test_isWebsocketRequest(t *testing.T) {
testCases := []struct {
desc string
connectionHeader string
upgradeHeader string
assert assert.BoolAssertionFunc
}{
{
desc: "connection Header multiple values middle",
connectionHeader: "foo,upgrade,bar",
upgradeHeader: "websocket",
assert: assert.True,
},
{
desc: "connection Header multiple values end",
connectionHeader: "foo,bar,upgrade",
upgradeHeader: "websocket",
assert: assert.True,
},
{
desc: "connection Header multiple values begin",
connectionHeader: "upgrade,foo,bar",
upgradeHeader: "websocket",
assert: assert.True,
},
{
desc: "connection Header no upgrade",
connectionHeader: "foo,bar",
upgradeHeader: "websocket",
assert: assert.False,
},
{
desc: "connection Header empty",
connectionHeader: "",
upgradeHeader: "websocket",
assert: assert.False,
},
{
desc: "no header values",
connectionHeader: "foo,bar",
upgradeHeader: "foo,bar",
assert: assert.False,
},
{
desc: "upgrade header multiple values",
connectionHeader: "upgrade",
upgradeHeader: "foo,bar,websocket",
assert: assert.True,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
req.Header.Set(connection, test.connectionHeader)
req.Header.Set(upgrade, test.upgradeHeader)
ok := isWebsocketRequest(req)
test.assert(t, ok)
})
}
}

View File

@ -33,6 +33,8 @@ const (
pilotInstanceInfoTimer = 5 * time.Minute pilotInstanceInfoTimer = 5 * time.Minute
pilotDynConfTimer = 12 * time.Hour pilotDynConfTimer = 12 * time.Hour
maxElapsedTime = 4 * time.Minute maxElapsedTime = 4 * time.Minute
initialInterval = 5 * time.Second
multiplier = 3
) )
type instanceInfo struct { type instanceInfo struct {
@ -219,6 +221,8 @@ func (c *client) SendInstanceInfo(ctx context.Context, pilotMetrics []metrics.Pi
func (c *client) sendDataRetryable(ctx context.Context, req *http.Request) error { func (c *client) sendDataRetryable(ctx context.Context, req *http.Request) error {
exponentialBackOff := backoff.NewExponentialBackOff() exponentialBackOff := backoff.NewExponentialBackOff()
exponentialBackOff.MaxElapsedTime = maxElapsedTime exponentialBackOff.MaxElapsedTime = maxElapsedTime
exponentialBackOff.InitialInterval = initialInterval
exponentialBackOff.Multiplier = multiplier
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set(tokenHashHeader, c.tokenHash) req.Header.Set(tokenHashHeader, c.tokenHash)

View File

@ -8,12 +8,14 @@ import (
"github.com/traefik/traefik/v2/pkg/log" "github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/provider" "github.com/traefik/traefik/v2/pkg/provider"
"github.com/traefik/traefik/v2/pkg/provider/file" "github.com/traefik/traefik/v2/pkg/provider/file"
"github.com/traefik/traefik/v2/pkg/provider/traefik"
"github.com/traefik/traefik/v2/pkg/safe" "github.com/traefik/traefik/v2/pkg/safe"
) )
// ProviderAggregator aggregates providers. // ProviderAggregator aggregates providers.
type ProviderAggregator struct { type ProviderAggregator struct {
fileProvider *file.Provider internalProvider provider.Provider
fileProvider provider.Provider
providers []provider.Provider providers []provider.Provider
} }
@ -98,11 +100,15 @@ func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
return err return err
} }
if fileProvider, ok := provider.(*file.Provider); ok { switch provider.(type) {
p.fileProvider = fileProvider case *file.Provider:
} else { p.fileProvider = provider
case *traefik.Provider:
p.internalProvider = provider
default:
p.providers = append(p.providers, provider) p.providers = append(p.providers, provider)
} }
return nil return nil
} }
@ -113,6 +119,10 @@ func (p ProviderAggregator) Init() error {
// Provide calls the provide method of every providers. // Provide calls the provide method of every providers.
func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error { func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
if p.internalProvider != nil {
launchProvider(configurationChan, pool, p.internalProvider)
}
if p.fileProvider != nil { if p.fileProvider != nil {
launchProvider(configurationChan, pool, p.fileProvider) launchProvider(configurationChan, pool, p.fileProvider)
} }
@ -123,6 +133,7 @@ func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, po
launchProvider(configurationChan, pool, prd) launchProvider(configurationChan, pool, prd)
}) })
} }
return nil return nil
} }

View File

@ -0,0 +1,79 @@
package aggregator
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/provider"
"github.com/traefik/traefik/v2/pkg/safe"
)
func TestProviderAggregator_Provide(t *testing.T) {
aggregator := ProviderAggregator{
internalProvider: &providerMock{"internal"},
fileProvider: &providerMock{"file"},
providers: []provider.Provider{
&providerMock{"salad"},
&providerMock{"tomato"},
&providerMock{"onion"},
},
}
cfgCh := make(chan dynamic.Message)
errCh := make(chan error)
pool := safe.NewPool(context.Background())
t.Cleanup(pool.Stop)
go func() {
errCh <- aggregator.Provide(cfgCh, pool)
}()
// Make sure the internal provider is always called first, followed by the file provider.
requireReceivedMessageFromProviders(t, cfgCh, []string{"internal"})
requireReceivedMessageFromProviders(t, cfgCh, []string{"file"})
// Check if all providers have been called, the order doesn't matter.
requireReceivedMessageFromProviders(t, cfgCh, []string{"salad", "tomato", "onion"})
require.NoError(t, <-errCh)
}
// requireReceivedMessageFromProviders makes sure the given providers have emitted a message on the given message channel.
// Providers order is not enforced.
func requireReceivedMessageFromProviders(t *testing.T, cfgCh <-chan dynamic.Message, names []string) {
t.Helper()
var msg dynamic.Message
var receivedMessagesFrom []string
for range names {
select {
case <-time.After(10 * time.Millisecond):
case msg = <-cfgCh:
receivedMessagesFrom = append(receivedMessagesFrom, msg.ProviderName)
}
}
require.ElementsMatch(t, names, receivedMessagesFrom)
}
type providerMock struct {
Name string
}
func (p *providerMock) Init() error {
return nil
}
func (p *providerMock) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
configurationChan <- dynamic.Message{
ProviderName: p.Name,
Configuration: &dynamic.Configuration{},
}
return nil
}

View File

@ -42,7 +42,7 @@ type Provider struct {
Constraints string `description:"Constraints is an expression that Traefik matches against the container's labels to determine whether to create any route for that container." json:"constraints,omitempty" toml:"constraints,omitempty" yaml:"constraints,omitempty" export:"true"` Constraints string `description:"Constraints is an expression that Traefik matches against the container's labels to determine whether to create any route for that container." json:"constraints,omitempty" toml:"constraints,omitempty" yaml:"constraints,omitempty" export:"true"`
Endpoint *EndpointConfig `description:"Consul endpoint settings" json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" export:"true"` Endpoint *EndpointConfig `description:"Consul endpoint settings" json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" export:"true"`
Prefix string `description:"Prefix for consul service tags. Default 'traefik'" json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty" export:"true"` Prefix string `description:"Prefix for consul service tags. Default 'traefik'" json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty" export:"true"`
RefreshInterval ptypes.Duration `description:"Interval for check Consul API. Default 100ms" json:"refreshInterval,omitempty" toml:"refreshInterval,omitempty" yaml:"refreshInterval,omitempty" export:"true"` RefreshInterval ptypes.Duration `description:"Interval for check Consul API. Default 15s" json:"refreshInterval,omitempty" toml:"refreshInterval,omitempty" yaml:"refreshInterval,omitempty" export:"true"`
RequireConsistent bool `description:"Forces the read to be fully consistent." json:"requireConsistent,omitempty" toml:"requireConsistent,omitempty" yaml:"requireConsistent,omitempty" export:"true"` RequireConsistent bool `description:"Forces the read to be fully consistent." json:"requireConsistent,omitempty" toml:"requireConsistent,omitempty" yaml:"requireConsistent,omitempty" export:"true"`
Stale bool `description:"Use stale consistency for catalog reads." json:"stale,omitempty" toml:"stale,omitempty" yaml:"stale,omitempty" export:"true"` Stale bool `description:"Use stale consistency for catalog reads." json:"stale,omitempty" toml:"stale,omitempty" yaml:"stale,omitempty" export:"true"`
Cache bool `description:"Use local agent caching for catalog reads." json:"cache,omitempty" toml:"cache,omitempty" yaml:"cache,omitempty" export:"true"` Cache bool `description:"Use local agent caching for catalog reads." json:"cache,omitempty" toml:"cache,omitempty" yaml:"cache,omitempty" export:"true"`

View File

@ -56,7 +56,7 @@ func (reh *resourceEventHandler) OnDelete(obj interface{}) {
type Client interface { type Client interface {
WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error)
GetIngresses() []*networkingv1beta1.Ingress GetIngresses() []*networkingv1beta1.Ingress
GetIngressClass() (*networkingv1beta1.IngressClass, error) GetIngressClasses() ([]*networkingv1beta1.IngressClass, error)
GetService(namespace, name string) (*corev1.Service, bool, error) GetService(namespace, name string) (*corev1.Service, bool, error)
GetSecret(namespace, name string) (*corev1.Secret, bool, error) GetSecret(namespace, name string) (*corev1.Secret, bool, error)
GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error)
@ -393,9 +393,9 @@ func (c *clientWrapper) GetSecret(namespace, name string) (*corev1.Secret, bool,
return secret, exist, err return secret, exist, err
} }
func (c *clientWrapper) GetIngressClass() (*networkingv1beta1.IngressClass, error) { func (c *clientWrapper) GetIngressClasses() ([]*networkingv1beta1.IngressClass, error) {
if c.clusterFactory == nil { if c.clusterFactory == nil {
return nil, errors.New("failed to find ingressClass: factory not loaded") return nil, errors.New("cluster factory not loaded")
} }
ingressClasses, err := c.clusterFactory.Networking().V1beta1().IngressClasses().Lister().List(labels.Everything()) ingressClasses, err := c.clusterFactory.Networking().V1beta1().IngressClasses().Lister().List(labels.Everything())
@ -403,13 +403,14 @@ func (c *clientWrapper) GetIngressClass() (*networkingv1beta1.IngressClass, erro
return nil, err return nil, err
} }
var ics []*networkingv1beta1.IngressClass
for _, ic := range ingressClasses { for _, ic := range ingressClasses {
if ic.Spec.Controller == traefikDefaultIngressClassController { if ic.Spec.Controller == traefikDefaultIngressClassController {
return ic, nil ics = append(ics, ic)
} }
} }
return nil, nil return ics, nil
} }
// lookupNamespace returns the lookup namespace key for the given namespace. // lookupNamespace returns the lookup namespace key for the given namespace.

View File

@ -18,7 +18,7 @@ type clientMock struct {
services []*corev1.Service services []*corev1.Service
secrets []*corev1.Secret secrets []*corev1.Secret
endpoints []*corev1.Endpoints endpoints []*corev1.Endpoints
ingressClass *networkingv1beta1.IngressClass ingressClasses []*networkingv1beta1.IngressClass
serverVersion *version.Version serverVersion *version.Version
@ -59,7 +59,7 @@ func newClientMock(serverVersion string, paths ...string) clientMock {
} }
c.ingresses = append(c.ingresses, ing) c.ingresses = append(c.ingresses, ing)
case *networkingv1beta1.IngressClass: case *networkingv1beta1.IngressClass:
c.ingressClass = o c.ingressClasses = append(c.ingressClasses, o)
default: default:
panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o)) panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o))
} }
@ -117,8 +117,8 @@ func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, err
return nil, false, nil return nil, false, nil
} }
func (c clientMock) GetIngressClass() (*networkingv1beta1.IngressClass, error) { func (c clientMock) GetIngressClasses() ([]*networkingv1beta1.IngressClass, error) {
return c.ingressClass, nil return c.ingressClasses, nil
} }
func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) { func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) {

View File

@ -8,7 +8,7 @@ spec:
ports: ports:
- name: tchouk - name: tchouk
port: 80 port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1
--- ---
kind: Service kind: Service
@ -21,4 +21,4 @@ spec:
ports: ports:
- name: tchouk - name: tchouk
port: 80 port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,7 +7,7 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1
--- ---
kind: Service kind: Service
@ -19,4 +19,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -8,7 +8,7 @@ spec:
ports: ports:
- name: http - name: http
port: 8080 port: 8080
clusterIp: "fc00:f853:ccd:e793::1" clusterIP: "fc00:f853:ccd:e793::1"
type: ClusterIP type: ClusterIP
--- ---

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -8,4 +8,4 @@ spec:
ports: ports:
- port: 443 - port: 443
targetPort: 8443 targetPort: 8443
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -9,4 +9,4 @@ spec:
- name: https - name: https
protocol: "" protocol: ""
port: 8443 port: 8443
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -9,4 +9,4 @@ spec:
- name: https-foo - name: https-foo
protocol: "" protocol: ""
port: 8443 port: 8443
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -8,4 +8,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -17,4 +17,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -8,5 +8,5 @@ spec:
ports: ports:
- name: http - name: http
port: 80 port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1
type: ClusterIP type: ClusterIP

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -10,5 +10,5 @@ spec:
port: 8082 port: 8082
- name: tchouk - name: tchouk
port: 80 port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -10,5 +10,5 @@ spec:
port: 8082 port: 8082
- name: tchouk - name: tchouk
port: 80 port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,7 +7,7 @@ metadata:
spec: spec:
ports: ports:
- port: 8080 - port: 8080
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1
type: ExternalName type: ExternalName
externalName: traefik.wtf externalName: traefik.wtf

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -10,5 +10,5 @@ spec:
port: 8082 port: 8082
- name: tchouk - name: tchouk
port: 80 port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,7 +7,7 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1
--- ---
kind: Service kind: Service
@ -19,4 +19,4 @@ metadata:
spec: spec:
ports: ports:
- port: 8082 - port: 8082
clusterIp: 10.1.0.1 clusterIP: 10.1.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -8,4 +8,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -10,5 +10,5 @@ spec:
port: 8082 port: 8082
- name: tchouk - name: tchouk
port: 80 port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -8,7 +8,7 @@ spec:
ports: ports:
- name: http - name: http
port: 80 port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1
type: ClusterIP type: ClusterIP
--- ---
@ -22,5 +22,5 @@ spec:
ports: ports:
- name: http - name: http
port: 80 port: 80
clusterIp: 10.0.0.2 clusterIP: 10.0.0.2
type: ClusterIP type: ClusterIP

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -0,0 +1,11 @@
kind: Endpoints
apiVersion: v1
metadata:
name: service1
namespace: testing
subsets:
- addresses:
- ip: 10.10.0.1
ports:
- port: 8080

View File

@ -0,0 +1,30 @@
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: ""
namespace: testing
spec:
ingressClassName: traefik-lb
rules:
- http:
paths:
- path: /bar
backend:
serviceName: service1
servicePort: 80
---
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: ""
namespace: testing
spec:
ingressClassName: traefik-lb2
rules:
- http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 80

View File

@ -0,0 +1,14 @@
apiVersion: networking.k8s.io/v1beta1
kind: IngressClass
metadata:
name: traefik-lb2
spec:
controller: traefik.io/ingress-controller
---
apiVersion: networking.k8s.io/v1beta1
kind: IngressClass
metadata:
name: traefik-lb
spec:
controller: traefik.io/ingress-controller

View File

@ -0,0 +1,10 @@
kind: Service
apiVersion: v1
metadata:
name: service1
namespace: testing
spec:
ports:
- port: 80
clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -7,4 +7,4 @@ metadata:
spec: spec:
ports: ports:
- port: 80 - port: 80
clusterIp: 10.0.0.1 clusterIP: 10.0.0.1

View File

@ -190,15 +190,15 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
return conf return conf
} }
var ingressClass *networkingv1beta1.IngressClass var ingressClasses []*networkingv1beta1.IngressClass
if supportsIngressClass(serverVersion) { if supportsIngressClass(serverVersion) {
ic, err := client.GetIngressClass() ics, err := client.GetIngressClasses()
if err != nil { if err != nil {
log.FromContext(ctx).Warnf("Failed to find an ingress class: %v", err) log.FromContext(ctx).Warnf("Failed to list ingress classes: %v", err)
} }
ingressClass = ic ingressClasses = ics
} }
ingresses := client.GetIngresses() ingresses := client.GetIngresses()
@ -207,7 +207,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
for _, ingress := range ingresses { for _, ingress := range ingresses {
ctx = log.With(ctx, log.Str("ingress", ingress.Name), log.Str("namespace", ingress.Namespace)) ctx = log.With(ctx, log.Str("ingress", ingress.Name), log.Str("namespace", ingress.Namespace))
if !p.shouldProcessIngress(p.IngressClass, ingress, ingressClass) { if !p.shouldProcessIngress(ingress, ingressClasses) {
continue continue
} }
@ -351,14 +351,20 @@ func (p *Provider) updateIngressStatus(ing *networkingv1beta1.Ingress, k8sClient
return k8sClient.UpdateIngressStatus(ing, service.Status.LoadBalancer.Ingress) return k8sClient.UpdateIngressStatus(ing, service.Status.LoadBalancer.Ingress)
} }
func (p *Provider) shouldProcessIngress(providerIngressClass string, ingress *networkingv1beta1.Ingress, ingressClass *networkingv1beta1.IngressClass) bool { func (p *Provider) shouldProcessIngress(ingress *networkingv1beta1.Ingress, ingressClasses []*networkingv1beta1.IngressClass) bool {
// configuration through the new kubernetes ingressClass // configuration through the new kubernetes ingressClass
if ingress.Spec.IngressClassName != nil { if ingress.Spec.IngressClassName != nil {
return ingressClass != nil && ingressClass.ObjectMeta.Name == *ingress.Spec.IngressClassName for _, ic := range ingressClasses {
if *ingress.Spec.IngressClassName == ic.ObjectMeta.Name {
return true
}
} }
return providerIngressClass == ingress.Annotations[annotationKubernetesIngressClass] || return false
len(providerIngressClass) == 0 && ingress.Annotations[annotationKubernetesIngressClass] == traefikDefaultIngressClass }
return p.IngressClass == ingress.Annotations[annotationKubernetesIngressClass] ||
len(p.IngressClass) == 0 && ingress.Annotations[annotationKubernetesIngressClass] == traefikDefaultIngressClass
} }
func buildHostRule(host string) string { func buildHostRule(host string) string {

View File

@ -1061,6 +1061,38 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
}, },
}, },
}, },
{
desc: "v18 Ingress with multiple ingressClasses",
serverVersion: "v1.18",
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{},
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{
"testing-foo": {
Rule: "PathPrefix(`/foo`)",
Service: "testing-service1-80",
},
"testing-bar": {
Rule: "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",
},
},
},
},
},
},
},
},
{ {
desc: "v18 Ingress with no pathType", desc: "v18 Ingress with no pathType",
serverVersion: "v1.18", serverVersion: "v1.18",

View File

@ -4,11 +4,11 @@ RepositoryName = "traefik"
OutputType = "file" OutputType = "file"
FileName = "traefik_changelog.md" FileName = "traefik_changelog.md"
# example new bugfix v2.3.7 # example new bugfix v2.4.2
CurrentRef = "v2.3" CurrentRef = "v2.4"
PreviousRef = "v2.3.6" PreviousRef = "v2.4.1"
BaseBranch = "v2.3" BaseBranch = "v2.4"
FutureCurrentRefName = "v2.3.7" FutureCurrentRefName = "v2.4.2"
ThresholdPreviousRef = 10 ThresholdPreviousRef = 10
ThresholdCurrentRef = 10 ThresholdCurrentRef = 10