Merge branch v2.1 into master

This commit is contained in:
Fernandez Ludovic 2020-02-10 16:03:39 +01:00
commit aa21351d0d
76 changed files with 392 additions and 395 deletions

View file

@ -1,3 +1,24 @@
## [v2.1.4](https://github.com/containous/traefik/tree/v2.1.4) (2020-02-06)
[All Commits](https://github.com/containous/traefik/compare/v2.1.3...v2.1.4)
**Bug fixes:**
- **[acme,logs]** Improvement of the certificates resolvers logs ([#6225](https://github.com/containous/traefik/pull/6225) by [ldez](https://github.com/ldez))
- **[acme]** Fix kubernetes providers shutdown and clean safe.Pool ([#6244](https://github.com/containous/traefik/pull/6244) by [juliens](https://github.com/juliens))
- **[authentication,middleware]** don't create http client for each request in forwardAuth middleware ([#6267](https://github.com/containous/traefik/pull/6267) by [juliens](https://github.com/juliens))
- **[k8s,k8s/ingress]** Allow wildcard hosts in ingress provider ([#6251](https://github.com/containous/traefik/pull/6251) by [dtomcej](https://github.com/dtomcej))
- **[logs,tls]** Properly purge default certificate from stores before logging ([#6281](https://github.com/containous/traefik/pull/6281) by [dtomcej](https://github.com/dtomcej))
- **[middleware]** use provider-qualified name when recursing for chain ([#6233](https://github.com/containous/traefik/pull/6233) by [mpl](https://github.com/mpl))
**Documentation:**
- **[acme,cli]** Documentation fix for acme.md CLI ([#6262](https://github.com/containous/traefik/pull/6262) by [altano](https://github.com/altano))
- **[acme,k8s/crd]** Add missing certResolver in IngressRoute examples. ([#6265](https://github.com/containous/traefik/pull/6265) by [ldez](https://github.com/ldez))
- **[k8s]** fix a typo ([#6279](https://github.com/containous/traefik/pull/6279) by [silenceshell](https://github.com/silenceshell))
- **[middleware]** Minor documentation tweaks. ([#6218](https://github.com/containous/traefik/pull/6218) by [stevegroom](https://github.com/stevegroom))
- Correct a trivial spelling mistake in the documentation. ([#6269](https://github.com/containous/traefik/pull/6269) by [nepella](https://github.com/nepella))
- Update install-traefik.md ([#6260](https://github.com/containous/traefik/pull/6260) by [bitfactory-sander-lissenburg](https://github.com/bitfactory-sander-lissenburg))
- doc: use the same entry point name everywhere ([#6219](https://github.com/containous/traefik/pull/6219) by [ldez](https://github.com/ldez))
- readme: update links to use HTTPS ([#6274](https://github.com/containous/traefik/pull/6274) by [imba-tjd](https://github.com/imba-tjd))
## [v2.1.3](https://github.com/containous/traefik/tree/v2.1.3) (2020-01-21)
[All Commits](https://github.com/containous/traefik/compare/v2.1.2...v2.1.3)

View file

@ -5,7 +5,7 @@
[![Build Status SemaphoreCI](https://semaphoreci.com/api/v1/containous/traefik/branches/master/shields_badge.svg)](https://semaphoreci.com/containous/traefik)
[![Docs](https://img.shields.io/badge/docs-current-brightgreen.svg)](https://docs.traefik.io)
[![Go Report Card](https://goreportcard.com/badge/containous/traefik)](http://goreportcard.com/report/containous/traefik)
[![Go Report Card](https://goreportcard.com/badge/containous/traefik)](https://goreportcard.com/report/containous/traefik)
[![](https://images.microbadger.com/badges/image/traefik.svg)](https://microbadger.com/images/traefik)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/containous/traefik/blob/master/LICENSE.md)
[![Join the community support forum at https://community.containo.us/](https://img.shields.io/badge/style-register-green.svg?style=social&label=Discourse)](https://community.containo.us/)
@ -89,7 +89,7 @@ You can access the simple HTML frontend of Traefik.
You can find the complete documentation of Traefik v2 at [https://docs.traefik.io](https://docs.traefik.io).
If you are using Traefik v1, you can find the complete documentation at [https://docs.traefik.io/v1.7/](https://docs.traefik.io/v1.7/)
If you are using Traefik v1, you can find the complete documentation at [https://docs.traefik.io/v1.7/](https://docs.traefik.io/v1.7/).
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
@ -122,7 +122,7 @@ git clone https://github.com/containous/traefik
## Introductory Videos
You can find high level and deep dive videos on [videos.containo.us](https://videos.containo.us)
You can find high level and deep dive videos on [videos.containo.us](https://videos.containo.us).
## Maintainers
@ -138,16 +138,16 @@ By participating in this project, you agree to abide by its terms.
## Release Cycle
- We release a new version (e.g. 1.1.0, 1.2.0, 1.3.0) every other month.
- Release Candidates are available before the release (e.g. 1.1.0-rc1, 1.1.0-rc2, 1.1.0-rc3, 1.1.0-rc4, before 1.1.0)
- Bug-fixes (e.g. 1.1.1, 1.1.2, 1.2.1, 1.2.3) are released as needed (no additional features are delivered in those versions, bug-fixes only)
- Release Candidates are available before the release (e.g. 1.1.0-rc1, 1.1.0-rc2, 1.1.0-rc3, 1.1.0-rc4, before 1.1.0).
- Bug-fixes (e.g. 1.1.1, 1.1.2, 1.2.1, 1.2.3) are released as needed (no additional features are delivered in those versions, bug-fixes only).
Each version is supported until the next one is released (e.g. 1.1.x will be supported until 1.2.0 is out)
Each version is supported until the next one is released (e.g. 1.1.x will be supported until 1.2.0 is out).
We use [Semantic Versioning](http://semver.org/)
We use [Semantic Versioning](https://semver.org/).
## Mailing lists
## Mailing Lists
- General announcements, new releases: mail at news+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/news)
- General announcements, new releases: mail at news+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/news).
- Security announcements: mail at security+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/security).
## Credits
@ -156,5 +156,5 @@ Kudos to [Peka](http://peka.byethost11.com/photoblog/) for his awesome work on t
Traefik's logo is licensed under the Creative Commons 3.0 Attributions license.
Traefik's logo was inspired by the gopher stickers made by Takuya Ueda (https://twitter.com/tenntenn).
The original Go gopher was designed by Renee French (http://reneefrench.blogspot.com/).
Traefik's logo was inspired by the gopher stickers made by [Takuya Ueda](https://twitter.com/tenntenn).
The original Go gopher was designed by [Renee French](https://reneefrench.blogspot.com/).

View file

@ -267,14 +267,18 @@ func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.Pr
}
if err := providerAggregator.AddProvider(p); err != nil {
log.WithoutContext().Errorf("Unable to add ACME provider to the providers list: %v", err)
log.WithoutContext().Errorf("The ACME resolver %q is skipped from the resolvers list because: %v", name, err)
continue
}
p.SetTLSManager(tlsManager)
if p.TLSChallenge != nil {
tlsManager.TLSAlpnGetter = p.GetTLSALPNCertificate
}
p.SetConfigListenerChan(make(chan dynamic.Configuration))
resolvers = append(resolvers, p)
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 KiB

After

Width:  |  Height:  |  Size: 284 KiB

View file

@ -3,11 +3,11 @@
A Quick Guide for Efficient Contributions
{: .subtitle }
So you've decide to improve Traefik?
So you've decided to improve Traefik?
Thank You!
Now the last step is to submit your Pull Request in a way that makes sure it gets the attention it deserves.
Let's go though the classic pitfalls to make sure everything is right.
Let's go through the classic pitfalls to make sure everything is right.
## Title
@ -36,7 +36,7 @@ Help the readers focus on what matters, and help them understand the structure o
- Add tests.
- Address review comments in terms of additional commits (and don't amend/squash existing ones unless the PR is trivial).
!!! note "third-party dependencies"
!!! note "Third-Party Dependencies"
If a PR involves changes to third-party dependencies, the commits pertaining to the vendor folder and the manifest/lock file(s) should be committed separated.

View file

@ -23,7 +23,7 @@ For more details, go to the [Docker provider documentation](../providers/docker.
* Prefer a fixed version than the latest that could be an unexpected version.
ex: `traefik:v2.0.0`
* Docker images are based from the [Alpine Linux Official image](https://hub.docker.com/_/alpine).
* All the orchestrator using docker images could fetch the official Traefik docker image.
* Any orchestrator using docker images can fetch the official Traefik docker image.
## Use the Helm Chart

View file

@ -56,7 +56,7 @@ Please check the [configuration examples below](#configuration-examples) for mor
[entryPoints.web]
address = ":80"
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":443"
[certificatesResolvers.le.acme]
@ -72,7 +72,7 @@ Please check the [configuration examples below](#configuration-examples) for mor
web:
address: ":80"
web-secure:
websecure:
address: ":443"
certificatesResolvers:
@ -196,7 +196,7 @@ when using the `HTTP-01` challenge, `certificatesResolvers.le.acme.httpChallenge
[entryPoints.web]
address = ":80"
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":443"
[certificatesResolvers.le.acme]
@ -210,7 +210,7 @@ when using the `HTTP-01` challenge, `certificatesResolvers.le.acme.httpChallenge
web:
address: ":80"
web-secure:
websecure:
address: ":443"
certificatesResolvers:
@ -379,7 +379,7 @@ certificatesResolvers:
```bash tab="CLI"
# ...
--certificatesResolvers.le.acme.dnsChallenge.resolvers:=1.1.1.1:53,8.8.8.8:53
--certificatesResolvers.le.acme.dnsChallenge.resolvers=1.1.1.1:53,8.8.8.8:53
```
#### Wildcard Domains

View file

@ -22,7 +22,6 @@ deploy:
```
```yaml tab="Kubernetes"
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:

View file

@ -18,7 +18,6 @@ deploy:
```
```yaml tab="Kubernetes"
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
@ -32,7 +31,8 @@ spec:
services:
- name: blog
port: 8080
tls: {}
tls:
certresolver: le
```
```json tab="Marathon"
@ -58,7 +58,7 @@ labels:
[http.routers.blog]
rule = "(Host(`company.com`) && Path(`/blog`)) || Host(`blog.company.org`)"
[http.routers.blog.tls]
certResolver = "le" # From static configuration
certResolver = "le"
```
```yaml tab="File (YAML)"

View file

@ -18,7 +18,6 @@ deploy:
```
```yaml tab="Kubernetes"
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
@ -32,7 +31,8 @@ spec:
services:
- name: blog
port: 8080
tls: {}
tls:
certresolver: le
```
```json tab="Marathon"
@ -55,10 +55,10 @@ labels:
```toml tab="Single Domain"
## Dynamic configuration
[http.routers]
[http.routers.blog]
rule = "Host(`company.com`) && Path(`/blog`)"
[http.routers.blog.tls]
certResolver = "le" # From static configuration
[http.routers.blog]
rule = "Host(`company.com`) && Path(`/blog`)"
[http.routers.blog.tls]
certResolver = "le"
```
```yaml tab="File (YAML)"

View file

@ -20,4 +20,9 @@ Developing Traefik, our main goal is to make it simple to use, and we're sure yo
!!! info
If you're a business running critical services behind Traefik, know that [Containous](https://containo.us), the company that sponsors Traefik's development, can provide [commercial support](https://info.containo.us/commercial-services) and develops an [Enterprise Edition](https://containo.us/traefikee/) of Traefik.
Join our user friendly and active [Community Forum](https://community.containo.us) to discuss, learn, and connect with the traefik community.
If you're a business running critical services behind Traefik,
know that [Containous](https://containo.us), the company that sponsors Traefik's development,
can provide [commercial support](https://info.containo.us/commercial-services)
and develops an [Enterprise Edition](https://containo.us/traefikee/) of Traefik.

View file

@ -5,9 +5,9 @@ Tweaking the Request
![Overview](../assets/img/middleware/overview.png)
Attached to the routers, pieces of middleware are a mean of tweaking the requests before they are sent to your [service](../routing/services/index.md) (or before the answer from the services are sent to the clients).
Attached to the routers, pieces of middleware are a means of tweaking the requests before they are sent to your [service](../routing/services/index.md) (or before the answer from the services are sent to the clients).
There are many different available middlewares in Traefik, some can modify the request, the headers, some are in charge of redirections, some add authentication, and so on.
There are several available middleware in Traefik, some can modify the request, the headers, some are in charge of redirections, some add authentication, and so on.
Pieces of middleware can be combined in chains to fit every scenario.
@ -130,7 +130,7 @@ http:
## Provider Namespace
When you declare a middleware, it lives in its provider namespace.
When you declare a middleware, it lives in its provider's namespace.
For example, if you declare a middleware using a Docker label, under the hoods, it will reside in the docker provider namespace.
If you use multiple providers and wish to reference a middleware declared in another provider

View file

@ -190,17 +190,17 @@ TLS parameters used to be specified in the static configuration, as an entryPoin
With Traefik v2, a new dynamic TLS section at the root contains all the desired TLS configurations.
Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one of the [TLS configurations](../https/tls.md) defined at the root, hence defining the [TLS configuration](../https/tls.md) for that router.
!!! example "TLS on web-secure entryPoint becomes TLS option on Router-1"
!!! example "TLS on websecure entryPoint becomes TLS option on Router-1"
!!! info "v1"
```toml tab="File (TOML)"
# static configuration
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":443"
[entryPoints.web-secure.tls]
[entryPoints.websecure.tls]
minVersion = "VersionTLS12"
cipherSuites = [
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
@ -210,13 +210,13 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
]
[[entryPoints.web-secure.tls.certificates]]
[[entryPoints.websecure.tls.certificates]]
certFile = "path/to/my.cert"
keyFile = "path/to/my.key"
```
```bash tab="CLI"
--entryPoints='Name:web-secure Address::443 TLS:path/to/my.cert,path/to/my.key TLS.MinVersion:VersionTLS12 TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
--entryPoints='Name:websecure Address::443 TLS:path/to/my.cert,path/to/my.key TLS.MinVersion:VersionTLS12 TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
```
!!! info "v2"
@ -818,32 +818,32 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
```toml tab="File (TOML)"
# static configuration
defaultEntryPoints = ["web-secure","web"]
defaultEntryPoints = ["websecure","web"]
[entryPoints.web]
address = ":80"
[entryPoints.web.redirect]
entryPoint = "webs"
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":443"
[entryPoints.https.tls]
[acme]
email = "your-email-here@my-awesome-app.org"
storage = "acme.json"
entryPoint = "web-secure"
entryPoint = "websecure"
onHostRule = true
[acme.httpChallenge]
entryPoint = "web"
```
```bash tab="CLI"
--defaultentrypoints=web-secure,web
--entryPoints=Name:web Address::80 Redirect.EntryPoint:web-secure
--entryPoints=Name:web-secure Address::443 TLS
--defaultentrypoints=websecure,web
--entryPoints=Name:web Address::80 Redirect.EntryPoint:websecure
--entryPoints=Name:websecure Address::443 TLS
--acme.email=your-email-here@my-awesome-app.org
--acme.storage=acme.json
--acme.entryPoint=web-secure
--acme.entryPoint=websecure
--acme.onHostRule=true
--acme.httpchallenge.entrypoint=http
```
@ -856,7 +856,7 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
[entryPoints.web]
address = ":80"
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":443"
[certificatesResolvers.sample.acme]
@ -872,7 +872,7 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
web:
address: ":80"
web-secure:
websecure:
address: ":443"
certificatesResolvers:
@ -1069,7 +1069,7 @@ Each root item has been moved to a related section or removed.
providersThrottleDuration = "2s"
AllowMinWeightZero = true
debug = true
defaultEntryPoints = ["web", "web-secure"]
defaultEntryPoints = ["web", "websecure"]
keepTrailingSlash = false
```
@ -1083,7 +1083,7 @@ Each root item has been moved to a related section or removed.
--providersthrottleduration=2s
--allowminweightzero=true
--debug=true
--defaultentrypoints=web,web-secure
--defaultentrypoints=web,websecure
--keeptrailingslash=true
```
@ -1156,21 +1156,21 @@ As the dashboard access is now secured by default you can either:
## static configuration
# traefik.toml
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":443"
[entryPoints.web-secure.tls]
[entryPoints.web-secure.auth]
[entryPoints.web-secure.auth.basic]
[entryPoints.websecure.tls]
[entryPoints.websecure.auth]
[entryPoints.websecure.auth.basic]
users = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
]
[api]
entryPoint = "web-secure"
entryPoint = "websecure"
```
```bash tab="CLI"
--entryPoints='Name:web-secure Address::443 TLS Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/'
--entryPoints='Name:websecure Address::443 TLS Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/'
--api
```
@ -1180,7 +1180,7 @@ As the dashboard access is now secured by default you can either:
# dynamic configuration
labels:
- "traefik.http.routers.api.rule=Host(`traefik.docker.localhost`)"
- "traefik.http.routers.api.entrypoints=web-secured"
- "traefik.http.routers.api.entrypoints=websecured"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=myAuth"
- "traefik.http.routers.api.tls"
@ -1191,7 +1191,7 @@ As the dashboard access is now secured by default you can either:
## static configuration
# traefik.toml
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":443"
[api]
@ -1206,7 +1206,7 @@ As the dashboard access is now secured by default you can either:
[http.routers.api]
rule = "Host(`traefik.docker.localhost`)"
entrypoints = ["web-secure"]
entrypoints = ["websecure"]
service = "api@internal"
middlewares = ["myAuth"]
[http.routers.api.tls]
@ -1222,7 +1222,7 @@ As the dashboard access is now secured by default you can either:
# traefik.yaml
entryPoints:
web-secure:
websecure:
address: ':443'
api: {}
@ -1241,7 +1241,7 @@ As the dashboard access is now secured by default you can either:
api:
rule: Host(`traefik.docker.localhost`)
entrypoints:
- web-secure
- websecure
service: api@internal
middlewares:
- myAuth

View file

@ -60,7 +60,7 @@ If you require LetsEncrypt with HA in a kubernetes environment, we recommend usi
If you are wanting to continue to run Traefik Community Edition, LetsEncrypt HA can be achieved by using a Certificate Controller such as [Cert-Manager](https://docs.cert-manager.io/en/latest/index.html).
When using Cert-Manager to manage certificates, it will create secrets in your namespaces that can be referenced as TLS secrets in your [ingress objects](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls).
When using the Traefik Kubernetes CRD Provider, unfortunately Cert-Manager cannot interface directly with the CRDs _yet_, but this is being worked on by our team.
A workaround it to enable the [Kubernetes Ingress provider](./kubernetes-ingress.md) to allow Cert-Manager to create ingress objects to complete the challenges.
A workaround is to enable the [Kubernetes Ingress provider](./kubernetes-ingress.md) to allow Cert-Manager to create ingress objects to complete the challenges.
Please note that this still requires manual intervention to create the certificates through Cert-Manager, but once created, Cert-Manager will keep the certificate renewed.
## Provider Configuration

View file

@ -78,7 +78,7 @@ metadata:
spec:
entryPoints:
- web
- web-secure
- websecure
routes:
- match: Host(`foo.com`) && PathPrefix(`/bar`)
kind: Rule

View file

@ -152,7 +152,7 @@ metadata:
spec:
entryPoints:
- web
- web-secure
- websecure
routes:
- match: Host(`foo.com`) && PathPrefix(`/bar`)
kind: Rule

View file

@ -8,7 +8,7 @@
[entryPoints]
[entryPoints.web]
address = "{{ .PortHTTP }}"
[entryPoints.web-secure]
[entryPoints.websecure]
address = "{{ .PortHTTPS }}"
{{range $name, $resolvers := .Acme }}
@ -45,7 +45,7 @@
[http.routers]
[http.routers.test]
entryPoints = ["web-secure"]
entryPoints = ["websecure"]
rule = "Host(`traefik.acme.wtf`)"
service = "test"
[http.routers.test.tls]

View file

@ -8,7 +8,7 @@
[entryPoints]
[entryPoints.web]
address = "{{ .PortHTTP }}"
[entryPoints.web-secure]
[entryPoints.websecure]
address = "{{ .PortHTTPS }}"
{{range $name, $resolvers := .Acme }}
@ -45,7 +45,7 @@
[http.routers]
[http.routers.test]
entryPoints = ["web-secure"]
entryPoints = ["websecure"]
rule = "PathPrefix(`/`)"
service = "test"
[http.routers.test.tls]

View file

@ -8,7 +8,7 @@
[entryPoints]
[entryPoints.web]
address = "{{ .PortHTTP }}"
[entryPoints.web-secure]
[entryPoints.websecure]
address = "{{ .PortHTTPS }}"
{{range $name, $resolvers := .Acme }}
@ -45,14 +45,14 @@
[http.routers]
[http.routers.test]
entryPoints = ["web-secure"]
entryPoints = ["websecure"]
rule = "Host(`traefik.acme.wtf`)"
service = "test"
[http.routers.test.tls]
certResolver = "default"
[http.routers.tchouk]
entryPoints = ["web-secure"]
entryPoints = ["websecure"]
rule = "Host(`tchouk.acme.wtf`)"
service = "test"
[http.routers.tchouk.tls]

View file

@ -8,7 +8,7 @@
[entryPoints]
[entryPoints.web]
address = "{{ .PortHTTP }}"
[entryPoints.web-secure]
[entryPoints.websecure]
address = "{{ .PortHTTPS }}"
{{range $name, $resolvers := .Acme }}
@ -45,7 +45,7 @@
[tcp.routers]
[tcp.routers.test]
entryPoints = ["web-secure"]
entryPoints = ["websecure"]
rule = "HostSNI(`traefik.acme.wtf`)"
service = "test"
[tcp.routers.test.tls]

View file

@ -8,7 +8,7 @@
[entryPoints]
[entryPoints.web]
address = "{{ .PortHTTP }}"
[entryPoints.web-secure]
[entryPoints.websecure]
address = "{{ .PortHTTPS }}"
{{range $name, $resolvers := .Acme }}
@ -45,7 +45,7 @@
[http.routers]
[http.routers.test]
entryPoints = ["web-secure"]
entryPoints = ["websecure"]
rule = "Host(`traefik.acme.wtf`)"
service = "test"
[http.routers.test.tls]

View file

@ -8,7 +8,7 @@
[entryPoints]
[entryPoints.web]
address = "{{ .PortHTTP }}"
[entryPoints.web-secure]
[entryPoints.websecure]
address = "{{ .PortHTTPS }}"
{{range $name, $resolvers := .Acme }}

View file

@ -8,7 +8,7 @@
[entryPoints]
[entryPoints.web]
address = "{{ .PortHTTP }}"
[entryPoints.web-secure]
[entryPoints.websecure]
address = "{{ .PortHTTPS }}"
[entryPoints.traefik]

View file

@ -5,7 +5,7 @@
[http.routers]
[http.routers.test]
entryPoints = ["web-secure"]
entryPoints = ["websecure"]
rule = "Host(`traefik.acme.wtf`)"
service = "test"
[http.routers.test.tls]

View file

@ -9,7 +9,7 @@
rootCAs = [ """{{ .CertContent }}""" ]
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -9,7 +9,7 @@
insecureSkipVerify = true
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -9,7 +9,7 @@
rootCAs = [ """{{ .CertContent }}""" ]
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[entryPoints.https02]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -9,7 +9,7 @@
[entryPoints.web]
address = ":8888"
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":8443"
[api]
@ -28,7 +28,7 @@
service = "service1"
[http.routers.router1TLS]
entryPoints = [ "web-secure" ]
entryPoints = [ "websecure" ]
rule = "Host(`example.com`)"
service = "service1"
[http.routers.router1TLS.tls]
@ -40,7 +40,7 @@
service = "service1"
[http.routers.router2TLS]
entryPoints = [ "web-secure" ]
entryPoints = [ "websecure" ]
rule = "Host(`example2.com`)"
service = "service1"
[http.routers.router2TLS.tls]
@ -52,7 +52,7 @@
service = "service1"
[http.routers.router3TLS]
entryPoints = [ "web-secure" ]
entryPoints = [ "websecure" ]
rule = "Host(`test.com`)"
service = "service1"
[http.routers.router3TLS.tls]
@ -64,7 +64,7 @@
service = "service1"
[http.routers.router4TLS]
entryPoints = [ "web-secure" ]
entryPoints = [ "websecure" ]
rule = "Host(`test2.com`)"
service = "service1"
[http.routers.router4TLS.tls]
@ -76,7 +76,7 @@
service = "service1"
[http.routers.router5TLS]
entryPoints = [ "web-secure" ]
entryPoints = [ "websecure" ]
rule = "Host(`foo.com`)"
service = "service1"
[http.routers.router5TLS.tls]
@ -88,7 +88,7 @@
service = "service1"
[http.routers.router6TLS]
entryPoints = [ "web-secure" ]
entryPoints = [ "websecure" ]
rule = "Host(`foo2.com`)"
service = "service1"
[http.routers.router6TLS.tls]
@ -100,7 +100,7 @@
service = "service1"
[http.routers.router7TLS]
entryPoints = [ "web-secure" ]
entryPoints = [ "websecure" ]
rule = "Host(`bar.com`)"
service = "service1"
[http.routers.router7TLS.tls]
@ -112,7 +112,7 @@
service = "service1"
[http.routers.router8TLS]
entryPoints = [ "web-secure" ]
entryPoints = [ "websecure" ]
rule = "Host(`bar2.com`)"
service = "service1"
[http.routers.router8TLS.tls]
@ -124,7 +124,7 @@
service = "service1"
[http.routers.router9TLS]
entryPoints = [ "web-secure" ]
entryPoints = [ "websecure" ]
rule = "Host(`pow.com`)"
service = "service1"
[http.routers.router9TLS.tls]
@ -136,7 +136,7 @@
service = "service1"
[http.routers.router10TLS]
entryPoints = [ "web-secure" ]
entryPoints = [ "websecure" ]
rule = "Host(`pow2.com`)"
service = "service1"
[http.routers.router10TLS.tls]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -6,7 +6,7 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":4443"
[api]

View file

@ -9,7 +9,7 @@
rootCAs = [ """{{ .RootCertContent }}""" ]
[entryPoints]
[entryPoints.web-secure]
[entryPoints.websecure]
address = ":8443"
[api]

View file

@ -67,7 +67,7 @@ func TestHandler_EntryPoints(t *testing.T) {
TrustedIPs: []string{"192.168.1.3", "192.168.1.4"},
},
},
"web-secure": {
"websecure": {
Address: ":443",
Transport: &static.EntryPointsTransport{
LifeCycle: &static.LifeCycle{

View file

@ -37,7 +37,7 @@
"192.168.1.40"
]
},
"name": "web-secure",
"name": "websecure",
"proxyProtocol": {
"insecure": true,
"trustedIPs": [

View file

@ -2,12 +2,12 @@ package auth
import (
"context"
"crypto/tls"
"fmt"
"io/ioutil"
"net"
"net/http"
"strings"
"time"
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
@ -29,7 +29,7 @@ type forwardAuth struct {
authResponseHeaders []string
next http.Handler
name string
tlsConfig *tls.Config
client http.Client
trustForwardHeader bool
}
@ -45,13 +45,23 @@ func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAu
trustForwardHeader: config.TrustForwardHeader,
}
// Ensure our request client does not follow redirects
fa.client = http.Client{
CheckRedirect: func(r *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
Timeout: 30 * time.Second,
}
if config.TLS != nil {
tlsConfig, err := config.TLS.CreateTLSConfig()
if err != nil {
return nil, err
}
fa.tlsConfig = tlsConfig
tr := http.DefaultTransport.(*http.Transport).Clone()
tr.TLSClientConfig = tlsConfig
fa.client.Transport = tr
}
return fa, nil
@ -64,19 +74,6 @@ func (fa *forwardAuth) GetTracingInformation() (string, ext.SpanKindEnum) {
func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := log.FromContext(middlewares.GetLoggerCtx(req.Context(), fa.name, forwardedTypeName))
// Ensure our request client does not follow redirects
httpClient := http.Client{
CheckRedirect: func(r *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
if fa.tlsConfig != nil {
httpClient.Transport = &http.Transport{
TLSClientConfig: fa.tlsConfig,
}
}
forwardReq, err := http.NewRequest(http.MethodGet, fa.address, nil)
tracing.LogRequest(tracing.GetSpan(req), forwardReq)
if err != nil {
@ -94,7 +91,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
writeHeader(req, forwardReq, fa.trustForwardHeader)
forwardResponse, forwardErr := httpClient.Do(forwardReq)
forwardResponse, forwardErr := fa.client.Do(forwardReq)
if forwardErr != nil {
logMessage := fmt.Sprintf("Error calling %s. Cause: %s", fa.address, forwardErr)
logger.Debug(logMessage)

View file

@ -179,12 +179,12 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
p.renewCertificates(ctx)
ticker := time.NewTicker(24 * time.Hour)
pool.Go(func(stop chan bool) {
pool.GoCtx(func(ctxPool context.Context) {
for {
select {
case <-ticker.C:
p.renewCertificates(ctx)
case <-stop:
case <-ctxPool.Done():
ticker.Stop()
return
}
@ -341,7 +341,7 @@ func (p *Provider) resolveDomains(ctx context.Context, domains []string, tlsStor
}
func (p *Provider) watchNewDomains(ctx context.Context) {
p.pool.Go(func(stop chan bool) {
p.pool.GoCtx(func(ctxPool context.Context) {
for {
select {
case config := <-p.configFromListenerChan:
@ -415,7 +415,7 @@ func (p *Provider) watchNewDomains(ctx context.Context) {
p.resolveDomains(ctxRouter, domains, tlsStore)
}
}
case <-stop:
case <-ctxPool.Done():
return
}
}
@ -556,7 +556,7 @@ func deleteUnnecessaryDomains(ctx context.Context, domains []types.Domain) []typ
func (p *Provider) watchCertificate(ctx context.Context) {
p.certsChan = make(chan *CertAndStore)
p.pool.Go(func(stop chan bool) {
p.pool.GoCtx(func(ctxPool context.Context) {
for {
select {
case cert := <-p.certsChan:
@ -576,7 +576,7 @@ func (p *Provider) watchCertificate(ctx context.Context) {
if err != nil {
log.FromContext(ctx).Error(err)
}
case <-stop:
case <-ctxPool.Done():
return
}
}

View file

@ -103,11 +103,11 @@ func (p *Provider) addWatcher(pool *safe.Pool, directory string, configurationCh
}
// Process events
pool.Go(func(stop chan bool) {
pool.GoCtx(func(ctx context.Context) {
defer watcher.Close()
for {
select {
case <-stop:
case <-ctx.Done():
return
case evt := <-watcher.Events:
if p.Directory == "" {

View file

@ -66,7 +66,7 @@ metadata:
spec:
ports:
- name: web-secure
- name: websecure
port: 443
targetPort: 8443
selector:
@ -85,7 +85,7 @@ subsets:
- ip: 10.10.0.5
- ip: 10.10.0.6
ports:
- name: web-secure
- name: websecure
port: 8443
---
@ -97,7 +97,7 @@ metadata:
spec:
ports:
- name: web-secure2
- name: websecure2
port: 8443
scheme: https
selector:
@ -116,5 +116,5 @@ subsets:
- ip: 10.10.0.7
- ip: 10.10.0.8
ports:
- name: web-secure2
- name: websecure2
port: 8443

View file

@ -66,7 +66,7 @@ metadata:
spec:
ports:
- name: web-secure
- name: websecure
port: 443
selector:
app: containous
@ -84,7 +84,7 @@ subsets:
- ip: 10.10.0.5
- ip: 10.10.0.6
ports:
- name: web-secure
- name: websecure
port: 443
---

View file

@ -98,11 +98,9 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
return err
}
pool.Go(func(stop chan bool) {
pool.GoCtx(func(ctxPool context.Context) {
operation := func() error {
stopWatch := make(chan struct{}, 1)
defer close(stopWatch)
eventsChan, err := k8sClient.WatchAll(p.Namespaces, stopWatch)
eventsChan, err := k8sClient.WatchAll(p.Namespaces, ctxPool.Done())
if err != nil {
logger.Errorf("Error watching kubernetes events: %v", err)
@ -110,20 +108,20 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
select {
case <-timer.C:
return err
case <-stop:
case <-ctxPool.Done():
return nil
}
}
throttleDuration := time.Duration(p.ThrottleDuration)
throttledChan := throttleEvents(ctxLog, throttleDuration, stop, eventsChan)
throttledChan := throttleEvents(ctxLog, throttleDuration, pool, eventsChan)
if throttledChan != nil {
eventsChan = throttledChan
}
for {
select {
case <-stop:
case <-ctxPool.Done():
return nil
case event := <-eventsChan:
// Note that event is the *first* event that came in during this throttling interval -- if we're hitting our throttle, we may have dropped events.
@ -156,7 +154,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
notify := func(err error, time time.Duration) {
logger.Errorf("Provider connection error: %v; retrying in %s", err, time)
}
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
err := backoff.RetryNotify(safe.OperationWithRecover(operation), backoff.WithContext(job.NewBackOff(backoff.NewExponentialBackOff()), ctxPool), notify)
if err != nil {
logger.Errorf("Cannot connect to Provider: %v", err)
}
@ -625,7 +623,7 @@ func getCABlocks(secret *corev1.Secret, namespace, secretName string) (string, e
return cert, nil
}
func throttleEvents(ctx context.Context, throttleDuration time.Duration, stop chan bool, eventsChan <-chan interface{}) chan interface{} {
func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *safe.Pool, eventsChan <-chan interface{}) chan interface{} {
if throttleDuration == 0 {
return nil
}
@ -635,10 +633,10 @@ func throttleEvents(ctx context.Context, throttleDuration time.Duration, stop ch
// Run a goroutine that reads events from eventChan and does a non-blocking write to pendingEvent.
// This guarantees that writing to eventChan will never block,
// and that pendingEvent will have something in it if there's been an event since we read from that channel.
go func() {
pool.GoCtx(func(ctxPool context.Context) {
for {
select {
case <-stop:
case <-ctxPool.Done():
return
case nextEvent := <-eventsChan:
select {
@ -650,7 +648,7 @@ func throttleEvents(ctx context.Context, throttleDuration time.Duration, stop ch
}
}
}
}()
})
return eventsChanBuffered
}

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,15 @@
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: ""
namespace: testing
spec:
rules:
- host: "*.foobar.com"
http:
paths:
- path: /bar
backend:
serviceName: service1
servicePort: 80

View file

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

View file

@ -105,32 +105,29 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
return err
}
pool.Go(func(stop chan bool) {
pool.GoCtx(func(ctxPool context.Context) {
operation := func() error {
stopWatch := make(chan struct{}, 1)
defer close(stopWatch)
eventsChan, err := k8sClient.WatchAll(p.Namespaces, stopWatch)
eventsChan, err := k8sClient.WatchAll(p.Namespaces, ctxPool.Done())
if err != nil {
logger.Errorf("Error watching kubernetes events: %v", err)
timer := time.NewTimer(1 * time.Second)
select {
case <-timer.C:
return err
case <-stop:
case <-ctxPool.Done():
return nil
}
}
throttleDuration := time.Duration(p.ThrottleDuration)
throttledChan := throttleEvents(ctxLog, throttleDuration, stop, eventsChan)
throttledChan := throttleEvents(ctxLog, throttleDuration, pool, eventsChan)
if throttledChan != nil {
eventsChan = throttledChan
}
for {
select {
case <-stop:
case <-ctxPool.Done():
return nil
case event := <-eventsChan:
// Note that event is the *first* event that came in during this
@ -165,7 +162,8 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
notify := func(err error, time time.Duration) {
logger.Errorf("Provider connection error: %s; retrying in %s", err, time)
}
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
err := backoff.RetryNotify(safe.OperationWithRecover(operation), backoff.WithContext(job.NewBackOff(backoff.NewExponentialBackOff()), ctxPool), notify)
if err != nil {
logger.Errorf("Cannot connect to Provider: %s", err)
}
@ -267,6 +265,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
serviceName := provider.Normalize(ingress.Namespace + "-" + pa.Backend.ServiceName + "-" + pa.Backend.ServicePort.String())
conf.HTTP.Services[serviceName] = service
conf.HTTP.Services[serviceName] = service
routerKey := strings.TrimPrefix(provider.Normalize(rule.Host+pa.Path), "-")
conf.HTTP.Routers[routerKey] = loadRouter(ingress, rule, pa, rtConfig, serviceName)
@ -323,6 +322,14 @@ func (p *Provider) updateIngressStatus(ing *v1beta1.Ingress, k8sClient Client) e
return k8sClient.UpdateIngressStatus(ing, service.Status.LoadBalancer.Ingress[0].IP, service.Status.LoadBalancer.Ingress[0].Hostname)
}
func buildHostRule(host string) string {
if strings.HasPrefix(host, "*.") {
return "HostRegexp(`" + strings.Replace(host, "*.", "{subdomain:[a-zA-Z0-9-]+}.", 1) + "`)"
}
return "Host(`" + host + "`)"
}
func shouldProcessIngress(ingressClass string, ingressClassAnnotation string) bool {
return ingressClass == ingressClassAnnotation ||
(len(ingressClass) == 0 && ingressClassAnnotation == traefikDefaultIngressClass)
@ -522,7 +529,7 @@ func getProtocol(portSpec corev1.ServicePort, portName string, svcConfig *Servic
func loadRouter(ingress *v1beta1.Ingress, rule v1beta1.IngressRule, pa v1beta1.HTTPIngressPath, rtConfig *RouterConfig, serviceName string) *dynamic.Router {
var rules []string
if len(rule.Host) > 0 {
rules = []string{"Host(`" + rule.Host + "`)"}
rules = []string{buildHostRule(rule.Host)}
}
if len(pa.Path) > 0 {
@ -562,7 +569,7 @@ func checkStringQuoteValidity(value string) error {
return err
}
func throttleEvents(ctx context.Context, throttleDuration time.Duration, stop chan bool, eventsChan <-chan interface{}) chan interface{} {
func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *safe.Pool, eventsChan <-chan interface{}) chan interface{} {
if throttleDuration == 0 {
return nil
}
@ -573,10 +580,10 @@ func throttleEvents(ctx context.Context, throttleDuration time.Duration, stop ch
// non-blocking write to pendingEvent. This guarantees that writing to
// eventChan will never block, and that pendingEvent will have
// something in it if there's been an event since we read from that channel.
go func() {
pool.GoCtx(func(ctxPool context.Context) {
for {
select {
case <-stop:
case <-ctxPool.Done():
return
case nextEvent := <-eventsChan:
select {
@ -590,7 +597,7 @@ func throttleEvents(ctx context.Context, throttleDuration time.Duration, stop ch
}
}
}
}()
})
return eventsChanBuffered
}

View file

@ -980,6 +980,35 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
},
},
},
{
desc: "Ingress with wildcard host",
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{},
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{
"foobar-com-bar": {
Rule: "HostRegexp(`{subdomain:[a-zA-Z0-9-]+}.foobar.com`) && 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",
Scheme: "",
Port: "",
},
},
},
},
},
},
},
},
}
for _, test := range testCases {

View file

@ -61,7 +61,6 @@ func (p *Provider) Init(storeType store.Backend, name string) error {
// Provide allows the docker provider to provide configurations to traefik using the given configuration channel.
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
ctx := log.With(context.Background(), log.Str(log.ProviderName, p.name))
logger := log.FromContext(ctx)
operation := func() error {
@ -89,8 +88,10 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
}
}
pool.Go(func(stop chan bool) {
err := p.watchKv(ctx, configurationChan, p.RootKey, stop)
pool.GoCtx(func(ctxPool context.Context) {
ctxLog := log.With(ctxPool, log.Str(log.ProviderName, p.name))
err := p.watchKv(ctxLog, configurationChan)
if err != nil {
logger.Errorf("Cannot watch KV store: %v", err)
}
@ -99,16 +100,16 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
return nil
}
func (p *Provider) watchKv(ctx context.Context, configurationChan chan<- dynamic.Message, prefix string, stop chan bool) error {
func (p *Provider) watchKv(ctx context.Context, configurationChan chan<- dynamic.Message) error {
operation := func() error {
events, err := p.kvClient.WatchTree(p.RootKey, make(chan struct{}), nil)
events, err := p.kvClient.WatchTree(p.RootKey, ctx.Done(), nil)
if err != nil {
return fmt.Errorf("failed to watch KV: %w", err)
}
for {
select {
case <-stop:
case <-ctx.Done():
return nil
case _, ok := <-events:
if !ok {
@ -133,7 +134,9 @@ func (p *Provider) watchKv(ctx context.Context, configurationChan chan<- dynamic
notify := func(err error, time time.Duration) {
log.FromContext(ctx).Errorf("KV connection error: %+v, retrying in %s", err, time)
}
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
err := backoff.RetryNotify(safe.OperationWithRecover(operation),
backoff.WithContext(job.NewBackOff(backoff.NewExponentialBackOff()), ctx), notify)
if err != nil {
return fmt.Errorf("cannot connect to KV server: %w", err)
}

View file

@ -857,7 +857,7 @@ func TestKvWatchTree(t *testing.T) {
configChan := make(chan dynamic.Message)
go func() {
err := provider.watchKv(context.Background(), configChan, "prefix", make(chan bool, 1))
err := provider.watchKv(context.Background(), configChan)
require.NoError(t, err)
}()

View file

@ -159,11 +159,11 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
logger.Errorf("Failed to register for events, %s", err)
return err
}
pool.Go(func(stop chan bool) {
pool.GoCtx(func(ctxPool context.Context) {
defer close(update)
for {
select {
case <-stop:
case <-ctxPool.Done():
return
case event := <-update:
logger.Debugf("Received provider event %s", event)

View file

@ -5,6 +5,7 @@ import (
"net/http"
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/server/provider"
)
// NewBuilder creates a builder.
@ -22,21 +23,28 @@ func (f *Builder) Build(ctx context.Context, names []string) func(*http.Response
var modifiers []func(*http.Response) error
for _, middleName := range names {
if conf, ok := f.configs[middleName]; ok {
if conf == nil || conf.Middleware == nil {
getLogger(ctx, middleName, "undefined").Error("Invalid Middleware configuration (ResponseModifier)")
continue
}
if conf.Headers != nil {
getLogger(ctx, middleName, "Headers").Debug("Creating Middleware (ResponseModifier)")
modifiers = append(modifiers, buildHeaders(conf.Headers))
} else if conf.Chain != nil {
getLogger(ctx, middleName, "Chain").Debug("Creating Middleware (ResponseModifier)")
modifiers = append(modifiers, f.Build(ctx, conf.Chain.Middlewares))
conf, ok := f.configs[middleName]
if !ok {
getLogger(ctx, middleName, "undefined").Debug("Middleware name not found in config (ResponseModifier)")
continue
}
if conf == nil || conf.Middleware == nil {
getLogger(ctx, middleName, "undefined").Error("Invalid Middleware configuration (ResponseModifier)")
continue
}
if conf.Headers != nil {
getLogger(ctx, middleName, "Headers").Debug("Creating Middleware (ResponseModifier)")
modifiers = append(modifiers, buildHeaders(conf.Headers))
} else if conf.Chain != nil {
chainCtx := provider.AddInContext(ctx, middleName)
getLogger(chainCtx, middleName, "Chain").Debug("Creating Middleware (ResponseModifier)")
var qualifiedNames []string
for _, name := range conf.Chain.Middlewares {
qualifiedNames = append(qualifiedNames, provider.GetQualifiedName(chainCtx, name))
}
modifiers = append(modifiers, f.Build(ctx, qualifiedNames))
}
}

View file

@ -10,88 +10,37 @@ import (
"github.com/containous/traefik/v2/pkg/log"
)
type routine struct {
goroutine func(chan bool)
stop chan bool
}
type routineCtx func(ctx context.Context)
// Pool is a pool of go routines
type Pool struct {
routines []routine
waitGroup sync.WaitGroup
lock sync.Mutex
baseCtx context.Context
baseCancel context.CancelFunc
ctx context.Context
cancel context.CancelFunc
waitGroup sync.WaitGroup
ctx context.Context
cancel context.CancelFunc
}
// NewPool creates a Pool
func NewPool(parentCtx context.Context) *Pool {
baseCtx, baseCancel := context.WithCancel(parentCtx)
ctx, cancel := context.WithCancel(baseCtx)
ctx, cancel := context.WithCancel(parentCtx)
return &Pool{
baseCtx: baseCtx,
baseCancel: baseCancel,
ctx: ctx,
cancel: cancel,
ctx: ctx,
cancel: cancel,
}
}
// Ctx returns main context
func (p *Pool) Ctx() context.Context {
return p.baseCtx
}
// GoCtx starts a recoverable goroutine with a context
func (p *Pool) GoCtx(goroutine routineCtx) {
p.lock.Lock()
p.waitGroup.Add(1)
Go(func() {
defer p.waitGroup.Done()
goroutine(p.ctx)
})
p.lock.Unlock()
}
// Go starts a recoverable goroutine, and can be stopped with stop chan
func (p *Pool) Go(goroutine func(stop chan bool)) {
p.lock.Lock()
newRoutine := routine{
goroutine: goroutine,
stop: make(chan bool, 1),
}
p.routines = append(p.routines, newRoutine)
p.waitGroup.Add(1)
Go(func() {
defer p.waitGroup.Done()
goroutine(newRoutine.stop)
})
p.lock.Unlock()
}
// Stop stops all started routines, waiting for their termination
func (p *Pool) Stop() {
p.lock.Lock()
defer p.lock.Unlock()
p.cancel()
for _, routine := range p.routines {
routine.stop <- true
}
p.waitGroup.Wait()
for _, routine := range p.routines {
close(routine.stop)
}
}
// Cleanup releases resources used by the pool, and should be called when the pool will no longer be used
func (p *Pool) Cleanup() {
p.Stop()
p.lock.Lock()
defer p.lock.Unlock()
p.baseCancel()
}
// Go starts a recoverable goroutine

View file

@ -18,12 +18,13 @@ func TestNewPoolContext(t *testing.T) {
ctx := context.WithValue(context.Background(), testKey, "test")
p := NewPool(ctx)
retCtx := p.Ctx()
retCtxVal, ok := retCtx.Value(testKey).(string)
if !ok || retCtxVal != "test" {
t.Errorf("Pool.Ctx() did not return a derived context, got %#v, expected context with test value", retCtx)
}
p.GoCtx(func(ctx context.Context) {
retCtxVal, ok := ctx.Value(testKey).(string)
if !ok || retCtxVal != "test" {
t.Errorf("Pool.Ctx() did not return a derived context, got %#v, expected context with test value", ctx)
}
})
p.Stop()
}
type fakeRoutine struct {
@ -46,14 +47,6 @@ func (tr *fakeRoutine) routineCtx(ctx context.Context) {
<-ctx.Done()
}
func (tr *fakeRoutine) routine(stop chan bool) {
tr.Lock()
tr.started = true
tr.Unlock()
tr.startSig <- true
<-stop
}
func TestPoolWithCtx(t *testing.T) {
testRoutine := newFakeRoutine()
@ -79,12 +72,12 @@ func TestPoolWithCtx(t *testing.T) {
defer timer.Stop()
test.fn(p)
defer p.Cleanup()
defer p.Stop()
testDone := make(chan bool, 1)
go func() {
<-testRoutine.startSig
p.Cleanup()
p.Stop()
testDone <- true
}()
@ -100,89 +93,30 @@ func TestPoolWithCtx(t *testing.T) {
}
}
func TestPoolWithStopChan(t *testing.T) {
testRoutine := newFakeRoutine()
func TestPoolCleanupWithGoPanicking(t *testing.T) {
p := NewPool(context.Background())
timer := time.NewTimer(500 * time.Millisecond)
defer timer.Stop()
p.Go(testRoutine.routine)
if len(p.routines) != 1 {
t.Fatalf("After Pool.Go(func), Pool did have %d goroutines, expected 1", len(p.routines))
}
p.GoCtx(func(ctx context.Context) {
panic("BOOM")
})
testDone := make(chan bool, 1)
go func() {
<-testRoutine.startSig
p.Cleanup()
p.Stop()
testDone <- true
}()
select {
case <-timer.C:
testRoutine.Lock()
defer testRoutine.Unlock()
t.Fatalf("Pool test did not complete in time, goroutine started equals '%t'", testRoutine.started)
t.Fatalf("Pool.Cleanup() did not complete in time with a panicking goroutine")
case <-testDone:
return
}
}
func TestPoolCleanupWithGoPanicking(t *testing.T) {
testRoutine := func(stop chan bool) {
panic("BOOM")
}
testCtxRoutine := func(ctx context.Context) {
panic("BOOM")
}
testCases := []struct {
desc string
fn func(*Pool)
}{
{
desc: "Go()",
fn: func(p *Pool) {
p.Go(testRoutine)
},
},
{
desc: "GoCtx()",
fn: func(p *Pool) {
p.GoCtx(testCtxRoutine)
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
p := NewPool(context.Background())
timer := time.NewTimer(500 * time.Millisecond)
defer timer.Stop()
test.fn(p)
testDone := make(chan bool, 1)
go func() {
p.Cleanup()
testDone <- true
}()
select {
case <-timer.C:
t.Fatalf("Pool.Cleanup() did not complete in time with a panicking goroutine")
case <-testDone:
return
}
})
}
}
func TestGoroutineRecover(t *testing.T) {
// if recover fails the test will panic
Go(func() {

View file

@ -3,7 +3,7 @@ package server
import (
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/server/internal"
"github.com/containous/traefik/v2/pkg/server/provider"
"github.com/containous/traefik/v2/pkg/tls"
)
@ -25,25 +25,25 @@ func mergeConfiguration(configurations dynamic.Configurations) dynamic.Configura
}
var defaultTLSOptionProviders []string
for provider, configuration := range configurations {
for pvd, configuration := range configurations {
if configuration.HTTP != nil {
for routerName, router := range configuration.HTTP.Routers {
conf.HTTP.Routers[internal.MakeQualifiedName(provider, routerName)] = router
conf.HTTP.Routers[provider.MakeQualifiedName(pvd, routerName)] = router
}
for middlewareName, middleware := range configuration.HTTP.Middlewares {
conf.HTTP.Middlewares[internal.MakeQualifiedName(provider, middlewareName)] = middleware
conf.HTTP.Middlewares[provider.MakeQualifiedName(pvd, middlewareName)] = middleware
}
for serviceName, service := range configuration.HTTP.Services {
conf.HTTP.Services[internal.MakeQualifiedName(provider, serviceName)] = service
conf.HTTP.Services[provider.MakeQualifiedName(pvd, serviceName)] = service
}
}
if configuration.TCP != nil {
for routerName, router := range configuration.TCP.Routers {
conf.TCP.Routers[internal.MakeQualifiedName(provider, routerName)] = router
conf.TCP.Routers[provider.MakeQualifiedName(pvd, routerName)] = router
}
for serviceName, service := range configuration.TCP.Services {
conf.TCP.Services[internal.MakeQualifiedName(provider, serviceName)] = service
conf.TCP.Services[provider.MakeQualifiedName(pvd, serviceName)] = service
}
}
@ -56,9 +56,9 @@ func mergeConfiguration(configurations dynamic.Configurations) dynamic.Configura
for tlsOptionsName, options := range configuration.TLS.Options {
if tlsOptionsName != "default" {
tlsOptionsName = internal.MakeQualifiedName(provider, tlsOptionsName)
tlsOptionsName = provider.MakeQualifiedName(pvd, tlsOptionsName)
} else {
defaultTLSOptionProviders = append(defaultTLSOptionProviders, provider)
defaultTLSOptionProviders = append(defaultTLSOptionProviders, pvd)
}
conf.TLS.Options[tlsOptionsName] = options

View file

@ -1,6 +1,7 @@
package server
import (
"context"
"encoding/json"
"reflect"
"time"
@ -49,8 +50,8 @@ func NewConfigurationWatcher(routinesPool *safe.Pool, pvd provider.Provider, pro
// Start the configuration watcher.
func (c *ConfigurationWatcher) Start() {
c.routinesPool.Go(c.listenProviders)
c.routinesPool.Go(c.listenConfigurations)
c.routinesPool.GoCtx(c.listenProviders)
c.routinesPool.GoCtx(c.listenConfigurations)
c.startProvider()
}
@ -90,10 +91,10 @@ func (c *ConfigurationWatcher) startProvider() {
// listenProviders receives configuration changes from the providers.
// The configuration message then gets passed along a series of check
// to finally end up in a throttler that sends it to listenConfigurations (through c. configurationValidatedChan).
func (c *ConfigurationWatcher) listenProviders(stop chan bool) {
func (c *ConfigurationWatcher) listenProviders(ctx context.Context) {
for {
select {
case <-stop:
case <-ctx.Done():
return
case configMsg, ok := <-c.configurationChan:
if !ok {
@ -111,10 +112,10 @@ func (c *ConfigurationWatcher) listenProviders(stop chan bool) {
}
}
func (c *ConfigurationWatcher) listenConfigurations(stop chan bool) {
func (c *ConfigurationWatcher) listenConfigurations(ctx context.Context) {
for {
select {
case <-stop:
case <-ctx.Done():
return
case configMsg, ok := <-c.configurationValidatedChan:
if !ok || configMsg.Configuration == nil {
@ -150,8 +151,10 @@ func (c *ConfigurationWatcher) preLoadConfiguration(configMsg dynamic.Message) {
if copyConf.TLS != nil {
copyConf.TLS.Certificates = nil
for _, v := range copyConf.TLS.Stores {
v.DefaultCertificate = nil
for k := range copyConf.TLS.Stores {
st := copyConf.TLS.Stores[k]
st.DefaultCertificate = nil
copyConf.TLS.Stores[k] = st
}
}
@ -178,8 +181,8 @@ func (c *ConfigurationWatcher) preLoadConfiguration(configMsg dynamic.Message) {
if !ok {
providerConfigUpdateCh = make(chan dynamic.Message)
c.providerConfigUpdateMap[configMsg.ProviderName] = providerConfigUpdateCh
c.routinesPool.Go(func(stop chan bool) {
c.throttleProviderConfigReload(c.providersThrottleDuration, c.configurationValidatedChan, providerConfigUpdateCh, stop)
c.routinesPool.GoCtx(func(ctxPool context.Context) {
c.throttleProviderConfigReload(ctxPool, c.providersThrottleDuration, c.configurationValidatedChan, providerConfigUpdateCh)
})
}
@ -190,14 +193,14 @@ func (c *ConfigurationWatcher) preLoadConfiguration(configMsg dynamic.Message) {
// It will immediately publish a new configuration and then only publish the next configuration after the throttle duration.
// Note that in the case it receives N new configs in the timeframe of the throttle duration after publishing,
// it will publish the last of the newly received configurations.
func (c *ConfigurationWatcher) throttleProviderConfigReload(throttle time.Duration, publish chan<- dynamic.Message, in <-chan dynamic.Message, stop chan bool) {
func (c *ConfigurationWatcher) throttleProviderConfigReload(ctx context.Context, throttle time.Duration, publish chan<- dynamic.Message, in <-chan dynamic.Message) {
ring := channels.NewRingChannel(1)
defer ring.Close()
c.routinesPool.Go(func(stop chan bool) {
c.routinesPool.GoCtx(func(ctxPool context.Context) {
for {
select {
case <-stop:
case <-ctxPool.Done():
return
case nextConfig := <-ring.Out():
if config, ok := nextConfig.(dynamic.Message); ok {
@ -210,7 +213,7 @@ func (c *ConfigurationWatcher) throttleProviderConfigReload(throttle time.Durati
for {
select {
case <-stop:
case <-ctx.Done():
return
case nextConfig := <-in:
ring.In() <- nextConfig

View file

@ -28,7 +28,7 @@ import (
"github.com/containous/traefik/v2/pkg/middlewares/stripprefix"
"github.com/containous/traefik/v2/pkg/middlewares/stripprefixregex"
"github.com/containous/traefik/v2/pkg/middlewares/tracing"
"github.com/containous/traefik/v2/pkg/server/internal"
"github.com/containous/traefik/v2/pkg/server/provider"
)
type middlewareStackType int
@ -56,10 +56,10 @@ func NewBuilder(configs map[string]*runtime.MiddlewareInfo, serviceBuilder servi
func (b *Builder) BuildChain(ctx context.Context, middlewares []string) *alice.Chain {
chain := alice.New()
for _, name := range middlewares {
middlewareName := internal.GetQualifiedName(ctx, name)
middlewareName := provider.GetQualifiedName(ctx, name)
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
constructorContext := internal.AddProviderInContext(ctx, middlewareName)
constructorContext := provider.AddInContext(ctx, middlewareName)
if midInf, ok := b.configs[middlewareName]; !ok || midInf.Middleware == nil {
return nil, fmt.Errorf("middleware %q does not exist", middlewareName)
}
@ -144,7 +144,7 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (
var qualifiedNames []string
for _, name := range config.Chain.Middlewares {
qualifiedNames = append(qualifiedNames, internal.GetQualifiedName(ctx, name))
qualifiedNames = append(qualifiedNames, provider.GetQualifiedName(ctx, name))
}
config.Chain.Middlewares = qualifiedNames
middleware = func(next http.Handler) (http.Handler, error) {

View file

@ -9,7 +9,7 @@ import (
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/server/internal"
"github.com/containous/traefik/v2/pkg/server/provider"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -262,7 +262,7 @@ func TestBuilder_BuildChainWithContext(t *testing.T) {
ctx := context.Background()
if len(test.contextProvider) > 0 {
ctx = internal.AddProviderInContext(ctx, "foobar@"+test.contextProvider)
ctx = provider.AddInContext(ctx, "foobar@"+test.contextProvider)
}
rtConf := runtime.NewConfig(dynamic.Configuration{

View file

@ -1,4 +1,4 @@
package internal
package provider
import (
"context"
@ -10,29 +10,29 @@ import (
type contextKey int
const (
providerKey contextKey = iota
key contextKey = iota
)
// AddProviderInContext Adds the provider name in the context
func AddProviderInContext(ctx context.Context, elementName string) context.Context {
// AddInContext Adds the provider name in the context
func AddInContext(ctx context.Context, elementName string) context.Context {
parts := strings.Split(elementName, "@")
if len(parts) == 1 {
log.FromContext(ctx).Debugf("Could not find a provider for %s.", elementName)
return ctx
}
if name, ok := ctx.Value(providerKey).(string); ok && name == parts[1] {
if name, ok := ctx.Value(key).(string); ok && name == parts[1] {
return ctx
}
return context.WithValue(ctx, providerKey, parts[1])
return context.WithValue(ctx, key, parts[1])
}
// GetQualifiedName Gets the fully qualified name.
func GetQualifiedName(ctx context.Context, elementName string) string {
parts := strings.Split(elementName, "@")
if len(parts) == 1 {
if providerName, ok := ctx.Value(providerKey).(string); ok {
if providerName, ok := ctx.Value(key).(string); ok {
return MakeQualifiedName(providerName, parts[0])
}
}

View file

@ -1,4 +1,4 @@
package internal
package provider
import (
"context"
@ -28,19 +28,19 @@ func TestAddProviderInContext(t *testing.T) {
},
{
desc: "provider name in context",
ctx: context.WithValue(context.Background(), providerKey, "foo"),
ctx: context.WithValue(context.Background(), key, "foo"),
name: "test",
expected: "foo",
},
{
desc: "provider name in context and different provider name embedded in element name",
ctx: context.WithValue(context.Background(), providerKey, "foo"),
ctx: context.WithValue(context.Background(), key, "foo"),
name: "test@fii",
expected: "fii",
},
{
desc: "provider name in context and same provider name embedded in element name",
ctx: context.WithValue(context.Background(), providerKey, "foo"),
ctx: context.WithValue(context.Background(), key, "foo"),
name: "test@foo",
expected: "foo",
},
@ -51,10 +51,10 @@ func TestAddProviderInContext(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
newCtx := AddProviderInContext(test.ctx, test.name)
newCtx := AddInContext(test.ctx, test.name)
var providerName string
if name, ok := newCtx.Value(providerKey).(string); ok {
if name, ok := newCtx.Value(key).(string); ok {
providerName = name
}
@ -90,13 +90,13 @@ func TestGetQualifiedName(t *testing.T) {
},
{
desc: "with provider in context",
ctx: context.WithValue(context.Background(), providerKey, "foo"),
ctx: context.WithValue(context.Background(), key, "foo"),
name: "test",
expected: "test@foo",
},
{
desc: "with provider in context and explicit name",
ctx: context.WithValue(context.Background(), providerKey, "foo"),
ctx: context.WithValue(context.Background(), key, "foo"),
name: "test@fii",
expected: "test@fii",
},

View file

@ -12,8 +12,8 @@ import (
"github.com/containous/traefik/v2/pkg/middlewares/recovery"
"github.com/containous/traefik/v2/pkg/middlewares/tracing"
"github.com/containous/traefik/v2/pkg/rules"
"github.com/containous/traefik/v2/pkg/server/internal"
"github.com/containous/traefik/v2/pkg/server/middleware"
"github.com/containous/traefik/v2/pkg/server/provider"
)
const (
@ -121,7 +121,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
}
for routerName, routerConfig := range configs {
ctxRouter := log.With(internal.AddProviderInContext(ctx, routerName), log.Str(log.RouterName, routerName))
ctxRouter := log.With(provider.AddInContext(ctx, routerName), log.Str(log.RouterName, routerName))
logger := log.FromContext(ctxRouter)
handler, err := m.buildRouterHandler(ctxRouter, routerName, routerConfig)
@ -175,7 +175,7 @@ func (m *Manager) buildRouterHandler(ctx context.Context, routerName string, rou
func (m *Manager) buildHTTPHandler(ctx context.Context, router *runtime.RouterInfo, routerName string) (http.Handler, error) {
var qualifiedNames []string
for _, name := range router.Middlewares {
qualifiedNames = append(qualifiedNames, internal.GetQualifiedName(ctx, name))
qualifiedNames = append(qualifiedNames, provider.GetQualifiedName(ctx, name))
}
router.Middlewares = qualifiedNames
rm := m.modifierBuilder.Build(ctx, qualifiedNames)

View file

@ -10,7 +10,7 @@ import (
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/rules"
"github.com/containous/traefik/v2/pkg/server/internal"
"github.com/containous/traefik/v2/pkg/server/provider"
tcpservice "github.com/containous/traefik/v2/pkg/server/service/tcp"
"github.com/containous/traefik/v2/pkg/tcp"
traefiktls "github.com/containous/traefik/v2/pkg/tls"
@ -112,7 +112,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
continue
}
ctxRouter := log.With(internal.AddProviderInContext(ctx, routerHTTPName), log.Str(log.RouterName, routerHTTPName))
ctxRouter := log.With(provider.AddInContext(ctx, routerHTTPName), log.Str(log.RouterName, routerHTTPName))
logger := log.FromContext(ctxRouter)
domains, err := rules.ParseDomains(routerHTTPConfig.Rule)
@ -131,7 +131,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
if routerHTTPConfig.TLS != nil {
tlsOptionsName := routerHTTPConfig.TLS.Options
if tlsOptionsName != defaultTLSConfigName {
tlsOptionsName = internal.GetQualifiedName(ctxRouter, routerHTTPConfig.TLS.Options)
tlsOptionsName = provider.GetQualifiedName(ctxRouter, routerHTTPConfig.TLS.Options)
}
tlsConf, err := m.tlsManager.Get(defaultTLSStoreName, tlsOptionsName)
@ -180,7 +180,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
}
for routerName, routerConfig := range configs {
ctxRouter := log.With(internal.AddProviderInContext(ctx, routerName), log.Str(log.RouterName, routerName))
ctxRouter := log.With(provider.AddInContext(ctx, routerName), log.Str(log.RouterName, routerName))
logger := log.FromContext(ctxRouter)
if routerConfig.Service == "" {
@ -226,7 +226,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
}
if tlsOptionsName != defaultTLSConfigName {
tlsOptionsName = internal.GetQualifiedName(ctxRouter, tlsOptionsName)
tlsOptionsName = provider.GetQualifiedName(ctxRouter, tlsOptionsName)
}
tlsConf, err := m.tlsManager.Get(defaultTLSStoreName, tlsOptionsName)

View file

@ -58,7 +58,7 @@ func (s *Server) Start(ctx context.Context) {
s.tcpEntryPoints.Start()
s.watcher.Start()
s.routinesPool.Go(s.listenSignals)
s.routinesPool.GoCtx(s.listenSignals)
}
// Wait blocks until the server shutdown.
@ -90,7 +90,7 @@ func (s *Server) Close() {
stopMetricsClients()
s.routinesPool.Cleanup()
s.routinesPool.Stop()
signal.Stop(s.signals)
close(s.signals)

View file

@ -3,6 +3,7 @@
package server
import (
"context"
"os/signal"
"syscall"
@ -13,10 +14,10 @@ func (s *Server) configureSignals() {
signal.Notify(s.signals, syscall.SIGUSR1)
}
func (s *Server) listenSignals(stop chan bool) {
func (s *Server) listenSignals(ctx context.Context) {
for {
select {
case <-stop:
case <-ctx.Done():
return
case sig := <-s.signals:
if sig == syscall.SIGUSR1 {

View file

@ -2,6 +2,8 @@
package server
import "context"
func (s *Server) configureSignals() {}
func (s *Server) listenSignals(stop chan bool) {}
func (s *Server) listenSignals(ctx context.Context) {}

View file

@ -22,7 +22,7 @@ import (
"github.com/containous/traefik/v2/pkg/middlewares/pipelining"
"github.com/containous/traefik/v2/pkg/safe"
"github.com/containous/traefik/v2/pkg/server/cookie"
"github.com/containous/traefik/v2/pkg/server/internal"
"github.com/containous/traefik/v2/pkg/server/provider"
"github.com/containous/traefik/v2/pkg/server/service/loadbalancer/mirror"
"github.com/containous/traefik/v2/pkg/server/service/loadbalancer/wrr"
"github.com/vulcand/oxy/roundrobin"
@ -63,8 +63,8 @@ type Manager struct {
func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string, responseModifier func(*http.Response) error) (http.Handler, error) {
ctx := log.With(rootCtx, log.Str(log.ServiceName, serviceName))
serviceName = internal.GetQualifiedName(ctx, serviceName)
ctx = internal.AddProviderInContext(ctx, serviceName)
serviceName = provider.GetQualifiedName(ctx, serviceName)
ctx = provider.AddInContext(ctx, serviceName)
conf, ok := m.configs[serviceName]
if !ok {

View file

@ -9,7 +9,7 @@ import (
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/server/internal"
"github.com/containous/traefik/v2/pkg/server/provider"
"github.com/containous/traefik/v2/pkg/testhelpers"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -336,7 +336,7 @@ func TestManager_Build(t *testing.T) {
ctx := context.Background()
if len(test.providerName) > 0 {
ctx = internal.AddProviderInContext(ctx, "foobar@"+test.providerName)
ctx = provider.AddInContext(ctx, "foobar@"+test.providerName)
}
_, err := manager.BuildHTTP(ctx, test.serviceName, nil)

View file

@ -9,7 +9,7 @@ import (
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/server/internal"
"github.com/containous/traefik/v2/pkg/server/provider"
"github.com/containous/traefik/v2/pkg/tcp"
)
@ -27,8 +27,8 @@ func NewManager(conf *runtime.Configuration) *Manager {
// BuildTCP Creates a tcp.Handler for a service configuration.
func (m *Manager) BuildTCP(rootCtx context.Context, serviceName string) (tcp.Handler, error) {
serviceQualifiedName := internal.GetQualifiedName(rootCtx, serviceName)
ctx := internal.AddProviderInContext(rootCtx, serviceQualifiedName)
serviceQualifiedName := provider.GetQualifiedName(rootCtx, serviceName)
ctx := provider.AddInContext(rootCtx, serviceQualifiedName)
ctx = log.With(ctx, log.Str(log.ServiceName, serviceName))
conf, ok := m.configs[serviceQualifiedName]

View file

@ -6,7 +6,7 @@ import (
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/server/internal"
"github.com/containous/traefik/v2/pkg/server/provider"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -184,7 +184,7 @@ func TestManager_BuildTCP(t *testing.T) {
ctx := context.Background()
if len(test.providerName) > 0 {
ctx = internal.AddProviderInContext(ctx, "foobar@"+test.providerName)
ctx = provider.AddInContext(ctx, "foobar@"+test.providerName)
}
handler, err := manager.BuildTCP(ctx, test.serviceName)