diff --git a/CHANGELOG.md b/CHANGELOG.md index 977ffb520..83b6007e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/README.md b/README.md index 0c3da953c..628c5c303 100644 --- a/README.md +++ b/README.md @@ -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/). diff --git a/cmd/traefik/traefik.go b/cmd/traefik/traefik.go index d457f1232..bc7a3ae7c 100644 --- a/cmd/traefik/traefik.go +++ b/cmd/traefik/traefik.go @@ -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) } } diff --git a/docs/content/assets/img/quickstart-diagram.png b/docs/content/assets/img/quickstart-diagram.png index 35648547c..99b7b970d 100644 Binary files a/docs/content/assets/img/quickstart-diagram.png and b/docs/content/assets/img/quickstart-diagram.png differ diff --git a/docs/content/contributing/submitting-pull-requests.md b/docs/content/contributing/submitting-pull-requests.md index bb3183f40..1de31241a 100644 --- a/docs/content/contributing/submitting-pull-requests.md +++ b/docs/content/contributing/submitting-pull-requests.md @@ -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. diff --git a/docs/content/getting-started/install-traefik.md b/docs/content/getting-started/install-traefik.md index b9d158243..ae9ceef34 100644 --- a/docs/content/getting-started/install-traefik.md +++ b/docs/content/getting-started/install-traefik.md @@ -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 diff --git a/docs/content/https/acme.md b/docs/content/https/acme.md index e59919bd2..6949bba65 100644 --- a/docs/content/https/acme.md +++ b/docs/content/https/acme.md @@ -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 diff --git a/docs/content/https/include-acme-multiple-domains-example.md b/docs/content/https/include-acme-multiple-domains-example.md index 2fe5b156c..0c4832105 100644 --- a/docs/content/https/include-acme-multiple-domains-example.md +++ b/docs/content/https/include-acme-multiple-domains-example.md @@ -22,7 +22,6 @@ deploy: ``` ```yaml tab="Kubernetes" ---- apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: diff --git a/docs/content/https/include-acme-multiple-domains-from-rule-example.md b/docs/content/https/include-acme-multiple-domains-from-rule-example.md index b33f368fa..26ad0ed6d 100644 --- a/docs/content/https/include-acme-multiple-domains-from-rule-example.md +++ b/docs/content/https/include-acme-multiple-domains-from-rule-example.md @@ -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)" diff --git a/docs/content/https/include-acme-single-domain-example.md b/docs/content/https/include-acme-single-domain-example.md index b153222ff..41fff7c44 100644 --- a/docs/content/https/include-acme-single-domain-example.md +++ b/docs/content/https/include-acme-single-domain-example.md @@ -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)" diff --git a/docs/content/index.md b/docs/content/index.md index b10303154..4806ab7ca 100644 --- a/docs/content/index.md +++ b/docs/content/index.md @@ -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. diff --git a/docs/content/middlewares/overview.md b/docs/content/middlewares/overview.md index 9af25e8fd..71d16ac7a 100644 --- a/docs/content/middlewares/overview.md +++ b/docs/content/middlewares/overview.md @@ -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 diff --git a/docs/content/migration/v1-to-v2.md b/docs/content/migration/v1-to-v2.md index d37f0001e..b19bda009 100644 --- a/docs/content/migration/v1-to-v2.md +++ b/docs/content/migration/v1-to-v2.md @@ -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://:/`. 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://:/`. 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://:/`. 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 diff --git a/docs/content/providers/kubernetes-crd.md b/docs/content/providers/kubernetes-crd.md index e0130899a..cbdbae76c 100644 --- a/docs/content/providers/kubernetes-crd.md +++ b/docs/content/providers/kubernetes-crd.md @@ -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 diff --git a/docs/content/reference/dynamic-configuration/kubernetes-crd-resource.yml b/docs/content/reference/dynamic-configuration/kubernetes-crd-resource.yml index 5f6054d13..7c755da06 100644 --- a/docs/content/reference/dynamic-configuration/kubernetes-crd-resource.yml +++ b/docs/content/reference/dynamic-configuration/kubernetes-crd-resource.yml @@ -78,7 +78,7 @@ metadata: spec: entryPoints: - web - - web-secure + - websecure routes: - match: Host(`foo.com`) && PathPrefix(`/bar`) kind: Rule diff --git a/docs/content/reference/dynamic-configuration/kubernetes-crd.yml b/docs/content/reference/dynamic-configuration/kubernetes-crd.yml index 67967d898..62916b201 100644 --- a/docs/content/reference/dynamic-configuration/kubernetes-crd.yml +++ b/docs/content/reference/dynamic-configuration/kubernetes-crd.yml @@ -152,7 +152,7 @@ metadata: spec: entryPoints: - web - - web-secure + - websecure routes: - match: Host(`foo.com`) && PathPrefix(`/bar`) kind: Rule diff --git a/integration/fixtures/acme/acme_base.toml b/integration/fixtures/acme/acme_base.toml index 9a8242e63..75682d94b 100644 --- a/integration/fixtures/acme/acme_base.toml +++ b/integration/fixtures/acme/acme_base.toml @@ -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] diff --git a/integration/fixtures/acme/acme_domains.toml b/integration/fixtures/acme/acme_domains.toml index e9b150eb3..a88e634bc 100644 --- a/integration/fixtures/acme/acme_domains.toml +++ b/integration/fixtures/acme/acme_domains.toml @@ -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] diff --git a/integration/fixtures/acme/acme_multiple_resolvers.toml b/integration/fixtures/acme/acme_multiple_resolvers.toml index 6da4a2a48..bd16de8c2 100644 --- a/integration/fixtures/acme/acme_multiple_resolvers.toml +++ b/integration/fixtures/acme/acme_multiple_resolvers.toml @@ -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] diff --git a/integration/fixtures/acme/acme_tcp.toml b/integration/fixtures/acme/acme_tcp.toml index 3bf7e3721..898eb859a 100644 --- a/integration/fixtures/acme/acme_tcp.toml +++ b/integration/fixtures/acme/acme_tcp.toml @@ -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] diff --git a/integration/fixtures/acme/acme_tls.toml b/integration/fixtures/acme/acme_tls.toml index 990ba69d4..06f18bb49 100644 --- a/integration/fixtures/acme/acme_tls.toml +++ b/integration/fixtures/acme/acme_tls.toml @@ -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] diff --git a/integration/fixtures/acme/acme_tls_dynamic.toml b/integration/fixtures/acme/acme_tls_dynamic.toml index 832ae1f27..5460933ea 100644 --- a/integration/fixtures/acme/acme_tls_dynamic.toml +++ b/integration/fixtures/acme/acme_tls_dynamic.toml @@ -8,7 +8,7 @@ [entryPoints] [entryPoints.web] address = "{{ .PortHTTP }}" - [entryPoints.web-secure] + [entryPoints.websecure] address = "{{ .PortHTTPS }}" {{range $name, $resolvers := .Acme }} diff --git a/integration/fixtures/acme/acme_tls_multiple_entrypoints.toml b/integration/fixtures/acme/acme_tls_multiple_entrypoints.toml index 3ffbdfad8..a2bca6c51 100644 --- a/integration/fixtures/acme/acme_tls_multiple_entrypoints.toml +++ b/integration/fixtures/acme/acme_tls_multiple_entrypoints.toml @@ -8,7 +8,7 @@ [entryPoints] [entryPoints.web] address = "{{ .PortHTTP }}" - [entryPoints.web-secure] + [entryPoints.websecure] address = "{{ .PortHTTPS }}" [entryPoints.traefik] diff --git a/integration/fixtures/acme/certificates.toml b/integration/fixtures/acme/certificates.toml index 4ee5ced2d..ba6414025 100644 --- a/integration/fixtures/acme/certificates.toml +++ b/integration/fixtures/acme/certificates.toml @@ -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] diff --git a/integration/fixtures/grpc/config.toml b/integration/fixtures/grpc/config.toml index 1e8aac3a0..9d448ae5b 100644 --- a/integration/fixtures/grpc/config.toml +++ b/integration/fixtures/grpc/config.toml @@ -9,7 +9,7 @@ rootCAs = [ """{{ .CertContent }}""" ] [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/grpc/config_h2c_termination.toml b/integration/fixtures/grpc/config_h2c_termination.toml index f4188fbe7..a51bcc21b 100644 --- a/integration/fixtures/grpc/config_h2c_termination.toml +++ b/integration/fixtures/grpc/config_h2c_termination.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/grpc/config_insecure.toml b/integration/fixtures/grpc/config_insecure.toml index 997a23c5b..264360ad5 100644 --- a/integration/fixtures/grpc/config_insecure.toml +++ b/integration/fixtures/grpc/config_insecure.toml @@ -9,7 +9,7 @@ insecureSkipVerify = true [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/grpc/config_retry.toml b/integration/fixtures/grpc/config_retry.toml index e3d5efe99..6f7a3a96a 100644 --- a/integration/fixtures/grpc/config_retry.toml +++ b/integration/fixtures/grpc/config_retry.toml @@ -9,7 +9,7 @@ rootCAs = [ """{{ .CertContent }}""" ] [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/https/clientca/https_1ca1config.toml b/integration/fixtures/https/clientca/https_1ca1config.toml index 951fa703d..bfa9617ee 100644 --- a/integration/fixtures/https/clientca/https_1ca1config.toml +++ b/integration/fixtures/https/clientca/https_1ca1config.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/https/clientca/https_2ca1config.toml b/integration/fixtures/https/clientca/https_2ca1config.toml index 1ccc98954..5d2320416 100644 --- a/integration/fixtures/https/clientca/https_2ca1config.toml +++ b/integration/fixtures/https/clientca/https_2ca1config.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/https/clientca/https_2ca2config.toml b/integration/fixtures/https/clientca/https_2ca2config.toml index 43725bcb2..0530b52d2 100644 --- a/integration/fixtures/https/clientca/https_2ca2config.toml +++ b/integration/fixtures/https/clientca/https_2ca2config.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/https/dynamic_https_sni.toml b/integration/fixtures/https/dynamic_https_sni.toml index 20b82c0dd..a06c7129a 100644 --- a/integration/fixtures/https/dynamic_https_sni.toml +++ b/integration/fixtures/https/dynamic_https_sni.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [entryPoints.https02] diff --git a/integration/fixtures/https/dynamic_https_sni_default_cert.toml b/integration/fixtures/https/dynamic_https_sni_default_cert.toml index d8e6f8d45..f954d9845 100644 --- a/integration/fixtures/https/dynamic_https_sni_default_cert.toml +++ b/integration/fixtures/https/dynamic_https_sni_default_cert.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/https/https_redirect.toml b/integration/fixtures/https/https_redirect.toml index 6ee48d0ca..488e2bc00 100644 --- a/integration/fixtures/https/https_redirect.toml +++ b/integration/fixtures/https/https_redirect.toml @@ -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] diff --git a/integration/fixtures/https/https_sni.toml b/integration/fixtures/https/https_sni.toml index a847d3de0..bd034d468 100644 --- a/integration/fixtures/https/https_sni.toml +++ b/integration/fixtures/https/https_sni.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/https/https_sni_case_insensitive_dynamic.toml b/integration/fixtures/https/https_sni_case_insensitive_dynamic.toml index 9e63fff4b..ef5814caf 100644 --- a/integration/fixtures/https/https_sni_case_insensitive_dynamic.toml +++ b/integration/fixtures/https/https_sni_case_insensitive_dynamic.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/https/https_sni_default_cert.toml b/integration/fixtures/https/https_sni_default_cert.toml index d8e6f8d45..f954d9845 100644 --- a/integration/fixtures/https/https_sni_default_cert.toml +++ b/integration/fixtures/https/https_sni_default_cert.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/https/https_sni_strict.toml b/integration/fixtures/https/https_sni_strict.toml index 09f442c00..fca8d9656 100644 --- a/integration/fixtures/https/https_sni_strict.toml +++ b/integration/fixtures/https/https_sni_strict.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/https/https_tls_options.toml b/integration/fixtures/https/https_tls_options.toml index 9bd67c277..e8eccf3a5 100644 --- a/integration/fixtures/https/https_tls_options.toml +++ b/integration/fixtures/https/https_tls_options.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/router_errors.toml b/integration/fixtures/router_errors.toml index db9429e3c..014c5bc51 100644 --- a/integration/fixtures/router_errors.toml +++ b/integration/fixtures/router_errors.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/service_errors.toml b/integration/fixtures/service_errors.toml index cb0997a83..77b8d80b6 100644 --- a/integration/fixtures/service_errors.toml +++ b/integration/fixtures/service_errors.toml @@ -6,7 +6,7 @@ level = "DEBUG" [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":4443" [api] diff --git a/integration/fixtures/tlsclientheaders/simple.toml b/integration/fixtures/tlsclientheaders/simple.toml index 207ad6006..a9a1bf5cb 100644 --- a/integration/fixtures/tlsclientheaders/simple.toml +++ b/integration/fixtures/tlsclientheaders/simple.toml @@ -9,7 +9,7 @@ rootCAs = [ """{{ .RootCertContent }}""" ] [entryPoints] - [entryPoints.web-secure] + [entryPoints.websecure] address = ":8443" [api] diff --git a/pkg/api/handler_entrypoint_test.go b/pkg/api/handler_entrypoint_test.go index 74bec5905..350734ec8 100644 --- a/pkg/api/handler_entrypoint_test.go +++ b/pkg/api/handler_entrypoint_test.go @@ -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{ diff --git a/pkg/api/testdata/entrypoints.json b/pkg/api/testdata/entrypoints.json index 4c8e5ae55..3f0e5cbef 100644 --- a/pkg/api/testdata/entrypoints.json +++ b/pkg/api/testdata/entrypoints.json @@ -37,7 +37,7 @@ "192.168.1.40" ] }, - "name": "web-secure", + "name": "websecure", "proxyProtocol": { "insecure": true, "trustedIPs": [ diff --git a/pkg/middlewares/auth/forward.go b/pkg/middlewares/auth/forward.go index 4bd5bbaf6..a39abbea4 100644 --- a/pkg/middlewares/auth/forward.go +++ b/pkg/middlewares/auth/forward.go @@ -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) diff --git a/pkg/provider/acme/provider.go b/pkg/provider/acme/provider.go index 5a4278320..e0fddd06f 100644 --- a/pkg/provider/acme/provider.go +++ b/pkg/provider/acme/provider.go @@ -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 } } diff --git a/pkg/provider/file/file.go b/pkg/provider/file/file.go index 862b9e1a2..3902ad12c 100644 --- a/pkg/provider/file/file.go +++ b/pkg/provider/file/file.go @@ -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 == "" { diff --git a/pkg/provider/kubernetes/crd/fixtures/services.yml b/pkg/provider/kubernetes/crd/fixtures/services.yml index b5d785193..967e9d96a 100644 --- a/pkg/provider/kubernetes/crd/fixtures/services.yml +++ b/pkg/provider/kubernetes/crd/fixtures/services.yml @@ -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 diff --git a/pkg/provider/kubernetes/crd/fixtures/tcp/services.yml b/pkg/provider/kubernetes/crd/fixtures/tcp/services.yml index aa38c760b..00018456c 100644 --- a/pkg/provider/kubernetes/crd/fixtures/tcp/services.yml +++ b/pkg/provider/kubernetes/crd/fixtures/tcp/services.yml @@ -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 --- diff --git a/pkg/provider/kubernetes/crd/kubernetes.go b/pkg/provider/kubernetes/crd/kubernetes.go index 6b9c6f332..c4ff55019 100644 --- a/pkg/provider/kubernetes/crd/kubernetes.go +++ b/pkg/provider/kubernetes/crd/kubernetes.go @@ -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 } diff --git a/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-wildcard-host_endpoint.yml b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-wildcard-host_endpoint.yml new file mode 100644 index 000000000..6ed60d79c --- /dev/null +++ b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-wildcard-host_endpoint.yml @@ -0,0 +1,11 @@ +kind: Endpoints +apiVersion: v1 +metadata: + name: service1 + namespace: testing + +subsets: +- addresses: + - ip: 10.10.0.1 + ports: + - port: 8080 diff --git a/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-wildcard-host_ingress.yml b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-wildcard-host_ingress.yml new file mode 100644 index 000000000..c72c09d85 --- /dev/null +++ b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-wildcard-host_ingress.yml @@ -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 diff --git a/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-wildcard-host_service.yml b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-wildcard-host_service.yml new file mode 100644 index 000000000..af223a1af --- /dev/null +++ b/pkg/provider/kubernetes/ingress/fixtures/Ingress-with-wildcard-host_service.yml @@ -0,0 +1,11 @@ +--- +kind: Service +apiVersion: v1 +metadata: + name: service1 + namespace: testing + +spec: + ports: + - port: 80 + clusterIp: 10.0.0.1 diff --git a/pkg/provider/kubernetes/ingress/kubernetes.go b/pkg/provider/kubernetes/ingress/kubernetes.go index e806a4700..42783db6b 100644 --- a/pkg/provider/kubernetes/ingress/kubernetes.go +++ b/pkg/provider/kubernetes/ingress/kubernetes.go @@ -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 } diff --git a/pkg/provider/kubernetes/ingress/kubernetes_test.go b/pkg/provider/kubernetes/ingress/kubernetes_test.go index 323b41b42..c09f3a33a 100644 --- a/pkg/provider/kubernetes/ingress/kubernetes_test.go +++ b/pkg/provider/kubernetes/ingress/kubernetes_test.go @@ -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 { diff --git a/pkg/provider/kv/kv.go b/pkg/provider/kv/kv.go index fdf6ac4f0..f9c326cfa 100644 --- a/pkg/provider/kv/kv.go +++ b/pkg/provider/kv/kv.go @@ -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) } diff --git a/pkg/provider/kv/kv_test.go b/pkg/provider/kv/kv_test.go index d4e0f7996..a00ae8e28 100644 --- a/pkg/provider/kv/kv_test.go +++ b/pkg/provider/kv/kv_test.go @@ -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) }() diff --git a/pkg/provider/marathon/marathon.go b/pkg/provider/marathon/marathon.go index 78213f8e7..e1aabf0eb 100644 --- a/pkg/provider/marathon/marathon.go +++ b/pkg/provider/marathon/marathon.go @@ -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) diff --git a/pkg/responsemodifiers/response_modifier.go b/pkg/responsemodifiers/response_modifier.go index 97c83e895..bc7b272cf 100644 --- a/pkg/responsemodifiers/response_modifier.go +++ b/pkg/responsemodifiers/response_modifier.go @@ -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)) } } diff --git a/pkg/safe/routine.go b/pkg/safe/routine.go index c1f81e5c3..a8de1e872 100644 --- a/pkg/safe/routine.go +++ b/pkg/safe/routine.go @@ -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 diff --git a/pkg/safe/routine_test.go b/pkg/safe/routine_test.go index caeef93ca..85d87bf10 100644 --- a/pkg/safe/routine_test.go +++ b/pkg/safe/routine_test.go @@ -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() { diff --git a/pkg/server/aggregator.go b/pkg/server/aggregator.go index 8f5a8d4a2..f6d745dc8 100644 --- a/pkg/server/aggregator.go +++ b/pkg/server/aggregator.go @@ -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 diff --git a/pkg/server/configurationwatcher.go b/pkg/server/configurationwatcher.go index 06b07aedd..056d7ea1d 100644 --- a/pkg/server/configurationwatcher.go +++ b/pkg/server/configurationwatcher.go @@ -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 diff --git a/pkg/server/middleware/middlewares.go b/pkg/server/middleware/middlewares.go index c04d49065..aa4cf6daa 100644 --- a/pkg/server/middleware/middlewares.go +++ b/pkg/server/middleware/middlewares.go @@ -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) { diff --git a/pkg/server/middleware/middlewares_test.go b/pkg/server/middleware/middlewares_test.go index 52a89484b..e0749095e 100644 --- a/pkg/server/middleware/middlewares_test.go +++ b/pkg/server/middleware/middlewares_test.go @@ -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{ diff --git a/pkg/server/internal/provider.go b/pkg/server/provider/provider.go similarity index 65% rename from pkg/server/internal/provider.go rename to pkg/server/provider/provider.go index c8e9a53e6..a6f3c83e4 100644 --- a/pkg/server/internal/provider.go +++ b/pkg/server/provider/provider.go @@ -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]) } } diff --git a/pkg/server/internal/provider_test.go b/pkg/server/provider/provider_test.go similarity index 80% rename from pkg/server/internal/provider_test.go rename to pkg/server/provider/provider_test.go index e6849e9f7..b6673e055 100644 --- a/pkg/server/internal/provider_test.go +++ b/pkg/server/provider/provider_test.go @@ -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", }, diff --git a/pkg/server/router/router.go b/pkg/server/router/router.go index ed7fdee85..ac461c800 100644 --- a/pkg/server/router/router.go +++ b/pkg/server/router/router.go @@ -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) diff --git a/pkg/server/router/tcp/router.go b/pkg/server/router/tcp/router.go index 1fdfb06fd..ed56193f5 100644 --- a/pkg/server/router/tcp/router.go +++ b/pkg/server/router/tcp/router.go @@ -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) diff --git a/pkg/server/server.go b/pkg/server/server.go index 7e395a759..99950a62d 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -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) diff --git a/pkg/server/server_signals.go b/pkg/server/server_signals.go index a1411dc65..e02702652 100644 --- a/pkg/server/server_signals.go +++ b/pkg/server/server_signals.go @@ -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 { diff --git a/pkg/server/server_signals_windows.go b/pkg/server/server_signals_windows.go index 05cf4eace..91c14979d 100644 --- a/pkg/server/server_signals_windows.go +++ b/pkg/server/server_signals_windows.go @@ -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) {} diff --git a/pkg/server/service/service.go b/pkg/server/service/service.go index ccc66b783..4ff4d213b 100644 --- a/pkg/server/service/service.go +++ b/pkg/server/service/service.go @@ -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 { diff --git a/pkg/server/service/service_test.go b/pkg/server/service/service_test.go index 6e1349496..522f5308b 100644 --- a/pkg/server/service/service_test.go +++ b/pkg/server/service/service_test.go @@ -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) diff --git a/pkg/server/service/tcp/service.go b/pkg/server/service/tcp/service.go index a9a8223ca..7fcdd3cb0 100644 --- a/pkg/server/service/tcp/service.go +++ b/pkg/server/service/tcp/service.go @@ -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] diff --git a/pkg/server/service/tcp/service_test.go b/pkg/server/service/tcp/service_test.go index 495602f08..fd9b35194 100644 --- a/pkg/server/service/tcp/service_test.go +++ b/pkg/server/service/tcp/service_test.go @@ -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)