Merge branch 'v2.0' into master

This commit is contained in:
Fernandez Ludovic 2019-09-17 17:37:22 +02:00
commit 56e0580aa5
134 changed files with 2201 additions and 818 deletions

View file

@ -1,4 +1,346 @@
# Change Log ## [v2.0.0](https://github.com/containous/traefik/tree/v2.0.0) (2019-09-16)
[All Commits](https://github.com/containous/traefik/compare/v2.0.0-alpha1...v2.0.0)
**Enhancements:**
- **[acme,api,tracing]** New API security ([#5311](https://github.com/containous/traefik/pull/5311) by [juliens](https://github.com/juliens))
- **[acme,k8s,k8s/crd]** Document the TLS with ACME case ([#4654](https://github.com/containous/traefik/pull/4654) by [mpl](https://github.com/mpl))
- **[acme,kv]** Remove Deprecated StorageFile ([#4252](https://github.com/containous/traefik/pull/4252) by [juliens](https://github.com/juliens))
- **[acme]** Remove timeout/interval from the ACME Provider ([#4842](https://github.com/containous/traefik/pull/4842) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[acme]** Certificate resolvers. ([#5116](https://github.com/containous/traefik/pull/5116) by [ldez](https://github.com/ldez))
- **[acme]** Improve acme logs. ([#5139](https://github.com/containous/traefik/pull/5139) by [ldez](https://github.com/ldez))
- **[acme]** Migrate to go-acme/lego. ([#4589](https://github.com/containous/traefik/pull/4589) by [ldez](https://github.com/ldez))
- **[api,provider]** Enhance REST provider ([#5072](https://github.com/containous/traefik/pull/5072) by [dtomcej](https://github.com/dtomcej))
- **[api]** Adding content-header to api endpoints ([#5019](https://github.com/containous/traefik/pull/5019) by [dalanmiller](https://github.com/dalanmiller))
- **[api]** Deal with multiple errors and their criticality ([#5070](https://github.com/containous/traefik/pull/5070) by [mpl](https://github.com/mpl))
- **[api]** API: remove configuration of Entrypoint and Middlewares ([#5119](https://github.com/containous/traefik/pull/5119) by [mpl](https://github.com/mpl))
- **[api]** Improve API endpoints ([#5080](https://github.com/containous/traefik/pull/5080) by [ldez](https://github.com/ldez))
- **[api]** API: new contract ([#4964](https://github.com/containous/traefik/pull/4964) by [mpl](https://github.com/mpl))
- **[api]** Improve API for the web UI ([#5267](https://github.com/containous/traefik/pull/5267) by [ldez](https://github.com/ldez))
- **[api]** Manage status for TCP element in the endpoint overview. ([#5108](https://github.com/containous/traefik/pull/5108) by [ldez](https://github.com/ldez))
- **[api]** API: expose runtime representation ([#4841](https://github.com/containous/traefik/pull/4841) by [mpl](https://github.com/mpl))
- **[authentication,middleware,k8s,k8s/crd]** Auth middlewares in kubernetes CRD use secrets ([#5299](https://github.com/containous/traefik/pull/5299) by [juliens](https://github.com/juliens))
- **[authentication,logs,etcd]** Remove deprecated elements ([#3715](https://github.com/containous/traefik/pull/3715) by [geraldcroes](https://github.com/geraldcroes))
- **[authentication,middleware]** Basic Auth custom realm ([#3917](https://github.com/containous/traefik/pull/3917) by [tcoupin](https://github.com/tcoupin))
- **[cli]** New static configuration loading system. ([#4935](https://github.com/containous/traefik/pull/4935) by [ldez](https://github.com/ldez))
- **[docker,k8s,k8s/crd,k8s/ingress]** chore: update docker and k8s ([#5174](https://github.com/containous/traefik/pull/5174) by [ldez](https://github.com/ldez))
- **[docker,k8s,k8s/crd,marathon,rancher,tcp]** Add weighted round robin load balancer on TCP ([#5380](https://github.com/containous/traefik/pull/5380) by [juliens](https://github.com/juliens))
- **[docker,tcp]** Add support for TCP labels in Docker provider ([#4621](https://github.com/containous/traefik/pull/4621) by [juliens](https://github.com/juliens))
- **[docker]** Adds default rule system on Docker provider. ([#4413](https://github.com/containous/traefik/pull/4413) by [ldez](https://github.com/ldez))
- **[docker]** Adds Docker provider support ([#4399](https://github.com/containous/traefik/pull/4399) by [ldez](https://github.com/ldez))
- **[docker]** Update to Go1.12. Support of TLS1.3 ([#4540](https://github.com/containous/traefik/pull/4540) by [ldez](https://github.com/ldez))
- **[etcd]** Remove etcd v2 ([#3739](https://github.com/containous/traefik/pull/3739) by [geraldcroes](https://github.com/geraldcroes))
- **[file]** Restrict traefik.toml to static configuration. ([#5090](https://github.com/containous/traefik/pull/5090) by [ldez](https://github.com/ldez))
- **[file]** Support YAML for the dynamic configuration. ([#5024](https://github.com/containous/traefik/pull/5024) by [ldez](https://github.com/ldez))
- **[k8s,k8s/crd,k8s/ingress]** Correct Kubernetes Ingress and IngressRoute port heuristic for choosing HTTPS ([#5167](https://github.com/containous/traefik/pull/5167) by [seh](https://github.com/seh))
- **[k8s,k8s/crd,k8s/ingress]** Fix kubernetes id name ([#5383](https://github.com/containous/traefik/pull/5383) by [mmatur](https://github.com/mmatur))
- **[k8s,k8s/crd,tcp]** Add support for TCP (in kubernetes CRD) ([#4885](https://github.com/containous/traefik/pull/4885) by [mpl](https://github.com/mpl))
- **[k8s,k8s/crd,tls]** Define TLS options on the Router configuration for Kubernetes ([#4973](https://github.com/containous/traefik/pull/4973) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[k8s,k8s/crd]** Add passHostHeader and responseForwarding in IngressRoute ([#5368](https://github.com/containous/traefik/pull/5368) by [juliens](https://github.com/juliens))
- **[k8s,k8s/crd]** Add scheme to IngressRoute. ([#5062](https://github.com/containous/traefik/pull/5062) by [ldez](https://github.com/ldez))
- **[k8s,k8s/ingress]** Renamed `kubernetes` provider in `kubernetesIngress` provider ([#5068](https://github.com/containous/traefik/pull/5068) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[k8s,k8s/ingress]** Add TLS-enabled Router ([#5162](https://github.com/containous/traefik/pull/5162) by [dtomcej](https://github.com/dtomcej))
- **[k8s/ingress]** Adds Kubernetes provider support ([#4476](https://github.com/containous/traefik/pull/4476) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[k8s/ingress]** Adds update ingress status ([#4603](https://github.com/containous/traefik/pull/4603) by [juliens](https://github.com/juliens))
- **[k8s/ingress]** k8s integration tests ([#4569](https://github.com/containous/traefik/pull/4569) by [juliens](https://github.com/juliens))
- **[k8s/ingress]** Custom resource definition ([#4591](https://github.com/containous/traefik/pull/4591) by [ldez](https://github.com/ldez))
- **[logs]** Improve error on router without service. ([#5126](https://github.com/containous/traefik/pull/5126) by [ldez](https://github.com/ldez))
- **[logs]** log.loglevel becomes log.level in configuration ([#4775](https://github.com/containous/traefik/pull/4775) by [juliens](https://github.com/juliens))
- **[logs]** Drop headers by default in access logs. ([#5034](https://github.com/containous/traefik/pull/5034) by [ldez](https://github.com/ldez))
- **[logs]** Default to CLF when accesslog format is unsupported ([#5314](https://github.com/containous/traefik/pull/5314) by [mpl](https://github.com/mpl))
- **[marathon,tcp]** Handle TCP in the marathon provider ([#4728](https://github.com/containous/traefik/pull/4728) by [juliens](https://github.com/juliens))
- **[marathon]** Adds Marathon support. ([#4415](https://github.com/containous/traefik/pull/4415) by [ldez](https://github.com/ldez))
- **[metrics]** Add Metrics ([#5111](https://github.com/containous/traefik/pull/5111) by [mmatur](https://github.com/mmatur))
- **[metrics]** Add HTTP authentication to influxdb metric backend ([#3600](https://github.com/containous/traefik/pull/3600) by [halfa](https://github.com/halfa))
- **[middleware,k8s,k8s/crd]** k8s ErrorPage middleware now uses k8s service ([#5339](https://github.com/containous/traefik/pull/5339) by [juliens](https://github.com/juliens))
- **[middleware,k8s/crd]** Handle cross-provider middleware in kubernetes CRD ([#5009](https://github.com/containous/traefik/pull/5009) by [mpl](https://github.com/mpl))
- **[middleware,provider]** Change the provider separator from . to @ ([#4982](https://github.com/containous/traefik/pull/4982) by [ldez](https://github.com/ldez))
- **[middleware,provider]** Add Feature-Policy header support ([#5156](https://github.com/containous/traefik/pull/5156) by [dtomcej](https://github.com/dtomcej))
- **[middleware,tracing]** Re enable ratelimit integration tests ([#5288](https://github.com/containous/traefik/pull/5288) by [mmatur](https://github.com/mmatur))
- **[middleware,provider]** IPStrategy for selecting IP in whitelist ([#3778](https://github.com/containous/traefik/pull/3778) by [juliens](https://github.com/juliens))
- **[middleware,provider]** Enables the use of elements declared in other providers ([#4372](https://github.com/containous/traefik/pull/4372) by [geraldcroes](https://github.com/geraldcroes))
- **[middleware]** Migrates the pass client tls cert middleware ([#4373](https://github.com/containous/traefik/pull/4373) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[middleware]** Migrates Compress from bool to struct ([#3714](https://github.com/containous/traefik/pull/3714) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[middleware]** Updates for jaeger tracing client. ([#3688](https://github.com/containous/traefik/pull/3688) by [tcolgate](https://github.com/tcolgate))
- **[middleware]** Add forwarded headers on entry point configuration ([#4364](https://github.com/containous/traefik/pull/4364) by [juliens](https://github.com/juliens))
- **[middleware]** SchemeRedirect Middleware ([#4400](https://github.com/containous/traefik/pull/4400) by [geraldcroes](https://github.com/geraldcroes))
- **[middleware]** Add rate limiter, rename maxConn into inFlightReq ([#5246](https://github.com/containous/traefik/pull/5246) by [mpl](https://github.com/mpl))
- **[middleware]** Disable RateLimit temporarily ([#5123](https://github.com/containous/traefik/pull/5123) by [juliens](https://github.com/juliens))
- **[middleware]** Enable CORS configuration ([#3809](https://github.com/containous/traefik/pull/3809) by [dtomcej](https://github.com/dtomcej))
- **[provider]** New constraints management. ([#4965](https://github.com/containous/traefik/pull/4965) by [ldez](https://github.com/ldez))
- **[provider]** Remove BaseProvider ([#4661](https://github.com/containous/traefik/pull/4661) by [ldez](https://github.com/ldez))
- **[provider]** Use name@provider instead of provider@name. ([#4990](https://github.com/containous/traefik/pull/4990) by [ldez](https://github.com/ldez))
- **[provider]** Add health check timeout parameter ([#3813](https://github.com/containous/traefik/pull/3813) by [jbiel](https://github.com/jbiel))
- **[provider]** Removes deprecated templates ([#3649](https://github.com/containous/traefik/pull/3649) by [geraldcroes](https://github.com/geraldcroes))
- **[provider]** Remove everything templates related ([#4595](https://github.com/containous/traefik/pull/4595) by [mpl](https://github.com/mpl))
- **[provider]** Small code enhancements on providers ([#3707](https://github.com/containous/traefik/pull/3707) by [vdemeester](https://github.com/vdemeester))
- **[provider]** Migrate rest provider ([#4253](https://github.com/containous/traefik/pull/4253) by [juliens](https://github.com/juliens))
- **[provider]** Labels parser. ([#4236](https://github.com/containous/traefik/pull/4236) by [ldez](https://github.com/ldez))
- **[rancher]** Add Rancher provider ([#4647](https://github.com/containous/traefik/pull/4647) by [SantoDE](https://github.com/SantoDE))
- **[rules]** New rule syntax ([#4437](https://github.com/containous/traefik/pull/4437) by [juliens](https://github.com/juliens))
- **[server]** Adds mirroring service ([#5251](https://github.com/containous/traefik/pull/5251) by [juliens](https://github.com/juliens))
- **[server]** Add support proxyprotocol v2 ([#4755](https://github.com/containous/traefik/pull/4755) by [c0va23](https://github.com/c0va23))
- **[server]** WeightedRoundRobin load balancer ([#5237](https://github.com/containous/traefik/pull/5237) by [juliens](https://github.com/juliens))
- **[server]** Make HTTP Keep-Alive timeout configurable for backend connections ([#4983](https://github.com/containous/traefik/pull/4983) by [mszabo-wikia](https://github.com/mszabo-wikia))
- **[server]** Rework loadbalancer support ([#4933](https://github.com/containous/traefik/pull/4933) by [juliens](https://github.com/juliens))
- **[server]** Use h2c from x/net to handle h2c requests ([#5045](https://github.com/containous/traefik/pull/5045) by [juliens](https://github.com/juliens))
- **[server]** Dynamic Configuration Refactoring ([#4168](https://github.com/containous/traefik/pull/4168) by [ldez](https://github.com/ldez))
- **[server]** Remove old global config and use new static config ([#4222](https://github.com/containous/traefik/pull/4222) by [juliens](https://github.com/juliens))
- **[sticky-session]** HttpOnly and Secure flags on the affinity cookie ([#4947](https://github.com/containous/traefik/pull/4947) by [gheibia](https://github.com/gheibia))
- **[tcp]** Adds TCP support ([#4587](https://github.com/containous/traefik/pull/4587) by [juliens](https://github.com/juliens))
- **[tls]** Define a TLS section to group TLS, TLSOptions, and TLSStores. ([#5031](https://github.com/containous/traefik/pull/5031) by [ldez](https://github.com/ldez))
- **[tls]** TLSOptions: handle conflict: same host name, different TLS options ([#5056](https://github.com/containous/traefik/pull/5056) by [mpl](https://github.com/mpl))
- **[tls]** Define TLS options on the Router configuration ([#4931](https://github.com/containous/traefik/pull/4931) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[tls]** Expand Client Auth Type configuration ([#5078](https://github.com/containous/traefik/pull/5078) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[tracing]** Improve tracing ([#5010](https://github.com/containous/traefik/pull/5010) by [mmatur](https://github.com/mmatur))
- **[tracing]** Add Jaeger collector endpoint ([#5082](https://github.com/containous/traefik/pull/5082) by [rmfitzpatrick](https://github.com/rmfitzpatrick))
- **[tracing]** Update tracing dependencies ([#4721](https://github.com/containous/traefik/pull/4721) by [ldez](https://github.com/ldez))
- **[tracing]** Added support for Haystack tracing ([#4555](https://github.com/containous/traefik/pull/4555) by [aantono](https://github.com/aantono))
- **[tracing]** Update Zipkin OpenTracing driver to latest 0.4.3 release ([#5283](https://github.com/containous/traefik/pull/5283) by [basvanbeek](https://github.com/basvanbeek))
- **[tracing]** Instana tracer implementation ([#4453](https://github.com/containous/traefik/pull/4453) by [notsureifkevin](https://github.com/notsureifkevin))
- **[tracing]** Make Zipkin trace rate configurable ([#3968](https://github.com/containous/traefik/pull/3968) by [negz](https://github.com/negz))
- **[webui]** refactor(webui): use @vue/cli to bootstrap new ui ([#5091](https://github.com/containous/traefik/pull/5091) by [Slashgear](https://github.com/Slashgear))
- **[webui]** Add a new dashboard page ([#5249](https://github.com/containous/traefik/pull/5249) by [Basgrani](https://github.com/Basgrani))
- **[webui]** Add doc and version in navbar ([#5137](https://github.com/containous/traefik/pull/5137) by [Slashgear](https://github.com/Slashgear))
- **[webui]** Use components to split Home concerns ([#5136](https://github.com/containous/traefik/pull/5136) by [Slashgear](https://github.com/Slashgear))
- **[webui]** Add more pages in the WebUI ([#5278](https://github.com/containous/traefik/pull/5278) by [Basgrani](https://github.com/Basgrani))
- **[webui]** feat(webui/dashboard): init new dashboard ([#5105](https://github.com/containous/traefik/pull/5105) by [Slashgear](https://github.com/Slashgear))
- **[webui]** Upgrade angular cli version ([#4450](https://github.com/containous/traefik/pull/4450) by [Slashgear](https://github.com/Slashgear))
- **[webui]** Update docker node version ([#4448](https://github.com/containous/traefik/pull/4448) by [Slashgear](https://github.com/Slashgear))
- **[webui]** Ignore target/dependencies in docker copy ([#4449](https://github.com/containous/traefik/pull/4449) by [Slashgear](https://github.com/Slashgear))
- **[webui]** Format code with prettier ([#4463](https://github.com/containous/traefik/pull/4463) by [Slashgear](https://github.com/Slashgear))
- **[webui]** No need for npm progress=false ([#3702](https://github.com/containous/traefik/pull/3702) by [vdemeester](https://github.com/vdemeester))
- **[webui]** Migrate to a work in progress webui ([#4568](https://github.com/containous/traefik/pull/4568) by [Slashgear](https://github.com/Slashgear))
- **[webui]** Include lint in build process ([#4462](https://github.com/containous/traefik/pull/4462) by [Slashgear](https://github.com/Slashgear))
- **[webui]** Dropping rxjs-compat in favor of pipe ([#4520](https://github.com/containous/traefik/pull/4520) by [imcotton](https://github.com/imcotton))
- Move dynamic config into a dedicated package. ([#5075](https://github.com/containous/traefik/pull/5075) by [ldez](https://github.com/ldez))
- Disable collect data by default. ([#5393](https://github.com/containous/traefik/pull/5393) by [ldez](https://github.com/ldez))
- Bump x/sys to support Risc-V architecture ([#5245](https://github.com/containous/traefik/pull/5245) by [carlosedp](https://github.com/carlosedp))
- New packaging system. ([#4593](https://github.com/containous/traefik/pull/4593) by [ldez](https://github.com/ldez))
- Updates Backoff ([#4457](https://github.com/containous/traefik/pull/4457) by [ldez](https://github.com/ldez))
- Remove the bug command ([#4556](https://github.com/containous/traefik/pull/4556) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Small code enhancements ([#3712](https://github.com/containous/traefik/pull/3712) by [mmatur](https://github.com/mmatur))
- Remove deprecated elements ([#3666](https://github.com/containous/traefik/pull/3666) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Clean old ([#4612](https://github.com/containous/traefik/pull/4612) by [ldez](https://github.com/ldez))
- Update anonymize/collect ([#4590](https://github.com/containous/traefik/pull/4590) by [jbdoumenjou](https://github.com/jbdoumenjou))
**Bug fixes:**
- **[api,webui]** Improve documentation about API and Dashboard. ([#5364](https://github.com/containous/traefik/pull/5364) by [ldez](https://github.com/ldez))
- **[api]** Add errors about unknown entryPoint in runtime api ([#5265](https://github.com/containous/traefik/pull/5265) by [juliens](https://github.com/juliens))
- **[api]** Add provider in middleware chain ([#5334](https://github.com/containous/traefik/pull/5334) by [juliens](https://github.com/juliens))
- **[cli]** fix: boolean flag parsing with map. ([#5372](https://github.com/containous/traefik/pull/5372) by [ldez](https://github.com/ldez))
- **[cli]** Return an error when help is called on a non existing command. ([#4977](https://github.com/containous/traefik/pull/4977) by [ldez](https://github.com/ldez))
- **[cli]** Filter env vars configuration ([#4985](https://github.com/containous/traefik/pull/4985) by [ldez](https://github.com/ldez))
- **[cli]** Fix some CLI bugs ([#4989](https://github.com/containous/traefik/pull/4989) by [ldez](https://github.com/ldez))
- **[cli]** Change the loading resource order ([#5007](https://github.com/containous/traefik/pull/5007) by [ldez](https://github.com/ldez))
- **[cli]** Apply the case of the CLI flags for the configuration ([#5153](https://github.com/containous/traefik/pull/5153) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[cli]** Don't allow non flag arguments by default. ([#4970](https://github.com/containous/traefik/pull/4970) by [ldez](https://github.com/ldez))
- **[docker]** Insensitive case for allow-empty value. ([#4745](https://github.com/containous/traefik/pull/4745) by [ldez](https://github.com/ldez))
- **[file]** fix: TLS configuration from directory. ([#5118](https://github.com/containous/traefik/pull/5118) by [ldez](https://github.com/ldez))
- **[k8s,k8s/crd]** Fix log messages about label selector ([#4629](https://github.com/containous/traefik/pull/4629) by [mpl](https://github.com/mpl))
- **[k8s,k8s/crd]** fix: TLS domains with IngressRoute. ([#5327](https://github.com/containous/traefik/pull/5327) by [ldez](https://github.com/ldez))
- **[k8s,k8s/crd]** Remove IngressEndpoint in CRD provider ([#4616](https://github.com/containous/traefik/pull/4616) by [juliens](https://github.com/juliens))
- **[logs]** fix: logger and context. ([#5370](https://github.com/containous/traefik/pull/5370) by [ldez](https://github.com/ldez))
- **[logs]** fix: error log message. ([#5020](https://github.com/containous/traefik/pull/5020) by [ldez](https://github.com/ldez))
- **[logs]** Fix typos in data collection message ([#4891](https://github.com/containous/traefik/pull/4891) by [mpl](https://github.com/mpl))
- **[logs]** Allow user to configure traefik log ([#4604](https://github.com/containous/traefik/pull/4604) by [mmatur](https://github.com/mmatur))
- **[metrics,tracing]** fix: Datadog case. ([#5272](https://github.com/containous/traefik/pull/5272) by [ldez](https://github.com/ldez))
- **[metrics]** Fix prometheus metrics ([#5152](https://github.com/containous/traefik/pull/5152) by [mmatur](https://github.com/mmatur))
- **[middleware,k8s,k8s/crd]** The chain middleware in k8s use middlewareRef ([#5290](https://github.com/containous/traefik/pull/5290) by [juliens](https://github.com/juliens))
- **[middleware]** Set X-Forwarded-* headers ([#4707](https://github.com/containous/traefik/pull/4707) by [mpl](https://github.com/mpl))
- **[middleware]** Fix `url.Parse` due to go1.12.8 changes. ([#5207](https://github.com/containous/traefik/pull/5207) by [ldez](https://github.com/ldez))
- **[middleware]** fix: stripPrefix and stripPrefixRegex. ([#5291](https://github.com/containous/traefik/pull/5291) by [ldez](https://github.com/ldez))
- **[middleware]** Improve rate limiter tests ([#5310](https://github.com/containous/traefik/pull/5310) by [mpl](https://github.com/mpl))
- **[middleware]** Fix response modifier initial building ([#4719](https://github.com/containous/traefik/pull/4719) by [mpl](https://github.com/mpl))
- **[middleware]** Remove X-Forwarded-(Uri, Method, Tls-Client-Cert and Tls-Client-Cert-Info) from untrusted IP ([#5012](https://github.com/containous/traefik/pull/5012) by [stffabi](https://github.com/stffabi))
- **[middleware]** fix buffering middleware ([#5281](https://github.com/containous/traefik/pull/5281) by [ldez](https://github.com/ldez))
- **[middleware]** Don't panic with undefined middleware ([#5289](https://github.com/containous/traefik/pull/5289) by [ldez](https://github.com/ldez))
- **[middleware]** Properly add response headers for CORS ([#4857](https://github.com/containous/traefik/pull/4857) by [dtomcej](https://github.com/dtomcej))
- **[rules]** Allow matching with FQDN hosts with trailing periods ([#4763](https://github.com/containous/traefik/pull/4763) by [dtomcej](https://github.com/dtomcej))
- **[server]** Fix panic while server shutdown ([#4644](https://github.com/containous/traefik/pull/4644) by [juliens](https://github.com/juliens))
- **[server]** Write HTTP server logs into the global logger. ([#5329](https://github.com/containous/traefik/pull/5329) by [ldez](https://github.com/ldez))
- **[server]** Fix problem in aggregator provider ([#4625](https://github.com/containous/traefik/pull/4625) by [juliens](https://github.com/juliens))
- **[server]** Fix lock problem in server ([#4600](https://github.com/containous/traefik/pull/4600) by [juliens](https://github.com/juliens))
- **[service,websocket]** Fix recovered panic when websocket is mirrored ([#5255](https://github.com/containous/traefik/pull/5255) by [juliens](https://github.com/juliens))
- **[tcp]** Fix EOF error ([#4733](https://github.com/containous/traefik/pull/4733) by [juliens](https://github.com/juliens))
- **[tcp]** Don't add TCP proxy when error occurs during creation. ([#4858](https://github.com/containous/traefik/pull/4858) by [ldez](https://github.com/ldez))
- **[tcp]** Remove first byte wait when tcp catches all ([#4938](https://github.com/containous/traefik/pull/4938) by [juliens](https://github.com/juliens))
- **[tcp]** On client CloseWrite, do CloseWrite instead of Close for backend ([#5366](https://github.com/containous/traefik/pull/5366) by [juliens](https://github.com/juliens))
- **[tls]** Fix panic in TLS stores handling ([#4997](https://github.com/containous/traefik/pull/4997) by [juliens](https://github.com/juliens))
- **[webui]** Rest provider icon in the webui ([#5261](https://github.com/containous/traefik/pull/5261) by [mmatur](https://github.com/mmatur))
- **[webui]** Web UI graph names. ([#5389](https://github.com/containous/traefik/pull/5389) by [ldez](https://github.com/ldez))
- **[webui]** fix: passHostHeader in the webUI. ([#5369](https://github.com/containous/traefik/pull/5369) by [ldez](https://github.com/ldez))
- Fix trailing slash with check new version ([#5266](https://github.com/containous/traefik/pull/5266) by [mmatur](https://github.com/mmatur))
- Ensure WaitGroup.Done() is always called ([#5026](https://github.com/containous/traefik/pull/5026) by [bsdelf](https://github.com/bsdelf))
- Clean files during tests. ([#4607](https://github.com/containous/traefik/pull/4607) by [ldez](https://github.com/ldez))
**Documentation:**
- **[acme,docker]** Removed extra colon before the 8080 docker port ([#5209](https://github.com/containous/traefik/pull/5209) by [fairwood136](https://github.com/fairwood136))
- **[acme,docker]** Add a docker-compose & let's encrypt user-guide ([#5121](https://github.com/containous/traefik/pull/5121) by [pbenefice](https://github.com/pbenefice))
- **[acme,docker]** Synchronize documentation ([#4571](https://github.com/containous/traefik/pull/4571) by [juliens](https://github.com/juliens))
- **[acme,k8s,k8s/crd]** Full ACME+CRD example ([#4652](https://github.com/containous/traefik/pull/4652) by [mpl](https://github.com/mpl))
- **[acme,k8s/crd]** Fix: CRD user guide ([#5244](https://github.com/containous/traefik/pull/5244) by [ldez](https://github.com/ldez))
- **[acme,tls]** docs: rewrite of the HTTPS and TLS section ([#4980](https://github.com/containous/traefik/pull/4980) by [mpl](https://github.com/mpl))
- **[acme]** Lets encrypt documentation typo ([#5127](https://github.com/containous/traefik/pull/5127) by [juliens](https://github.com/juliens))
- **[acme]** Use the same case every where for entryPoints. ([#4764](https://github.com/containous/traefik/pull/4764) by [ldez](https://github.com/ldez))
- **[acme]** doc/crd-acme: specify required kubectl version ([#5015](https://github.com/containous/traefik/pull/5015) by [mpl](https://github.com/mpl))
- **[acme]** Enhance manual dnsChallenge documentation ([#4636](https://github.com/containous/traefik/pull/4636) by [ntaranov](https://github.com/ntaranov))
- **[acme]** Fix error in the documentation for CLI configuration example ([#5392](https://github.com/containous/traefik/pull/5392) by [MycTl](https://github.com/MycTl))
- **[acme]** Add note about ACME renewal ([#4860](https://github.com/containous/traefik/pull/4860) by [dtomcej](https://github.com/dtomcej))
- **[acme]** Fix acme example ([#5130](https://github.com/containous/traefik/pull/5130) by [jamct](https://github.com/jamct))
- **[acme]** Rename Docker_Acme.md to Readme.md ([#4025](https://github.com/containous/traefik/pull/4025) by [vineetvermait](https://github.com/vineetvermait))
- **[acme]** Enhance acme page. ([#4611](https://github.com/containous/traefik/pull/4611) by [ldez](https://github.com/ldez))
- **[acme]** fix: some DNS provider link. ([#3637](https://github.com/containous/traefik/pull/3637) by [ldez](https://github.com/ldez))
- **[docker,marathon]** Update Dynamic Configuration Reference for both Docker and Marathon ([#5100](https://github.com/containous/traefik/pull/5100) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[docker]** Remove traefik.port from documentation ([#4886](https://github.com/containous/traefik/pull/4886) by [ldez](https://github.com/ldez))
- **[docker]** Fix two minor nits in Traefik 2.0 docs ([#4692](https://github.com/containous/traefik/pull/4692) by [cfra](https://github.com/cfra))
- **[docker]** Fix Getting started ([#4646](https://github.com/containous/traefik/pull/4646) by [mmatur](https://github.com/mmatur))
- **[docker]** docker-compose examples ([#4642](https://github.com/containous/traefik/pull/4642) by [karnthis](https://github.com/karnthis))
- **[docker]** Clarify docs with labels in Swarm Mode ([#4847](https://github.com/containous/traefik/pull/4847) by [mikesir87](https://github.com/mikesir87))
- **[file]** Update the file provider documentation ([#4588](https://github.com/containous/traefik/pull/4588) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[k8s,k8s/crd]** k8s static configuration explanation ([#4767](https://github.com/containous/traefik/pull/4767) by [ldez](https://github.com/ldez))
- **[k8s,k8s/crd]** doc: kubernetes CRD provider ([#4620](https://github.com/containous/traefik/pull/4620) by [mpl](https://github.com/mpl))
- **[k8s,k8s/ingress]** Add documentation about Kubernetes Ingress provider ([#5112](https://github.com/containous/traefik/pull/5112) by [mpl](https://github.com/mpl))
- **[k8s/crd]** user guide: fix a mistake in the deployment definition ([#5096](https://github.com/containous/traefik/pull/5096) by [ldez](https://github.com/ldez))
- **[k8s]** Fix typo in the CRD documentation ([#4902](https://github.com/containous/traefik/pull/4902) by [llussy](https://github.com/llussy))
- **[marathon]** Enhance Marathon documentation ([#4776](https://github.com/containous/traefik/pull/4776) by [ldez](https://github.com/ldez))
- **[middleware,k8s,k8s/crd]** Fix typo: middleware -> middlewares. ([#4781](https://github.com/containous/traefik/pull/4781) by [ldez](https://github.com/ldez))
- **[middleware,k8s/crd]** doc: fix middleware names for CRD. ([#4966](https://github.com/containous/traefik/pull/4966) by [ldez](https://github.com/ldez))
- **[middleware,provider]** fix the documentation about middleware labels. ([#4888](https://github.com/containous/traefik/pull/4888) by [ldez](https://github.com/ldez))
- **[middleware]** Fix Kubernetes Docs for Middlewares ([#4943](https://github.com/containous/traefik/pull/4943) by [HurricanKai](https://github.com/HurricanKai))
- **[middleware]** Adds a reference to the middleware overview. ([#4824](https://github.com/containous/traefik/pull/4824) by [ldez](https://github.com/ldez))
- **[middleware]** docker-compose labels require $'s to be escaped ([#5225](https://github.com/containous/traefik/pull/5225) by [Makeshift](https://github.com/Makeshift))
- **[middleware]** Fix doc about removing headers ([#4708](https://github.com/containous/traefik/pull/4708) by [mpl](https://github.com/mpl))
- **[middleware]** Remove invalid commas. ([#4706](https://github.com/containous/traefik/pull/4706) by [ldez](https://github.com/ldez))
- **[middleware]** Adds middlewares examples for k8s. ([#4713](https://github.com/containous/traefik/pull/4713) by [ldez](https://github.com/ldez))
- **[middleware]** Update the middleware documentation ([#4729](https://github.com/containous/traefik/pull/4729) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[middleware]** fix: stripPrefixRegex documentation. ([#5273](https://github.com/containous/traefik/pull/5273) by [ldez](https://github.com/ldez))
- **[middleware]** Correct typo in documentation on rate limiting ([#4939](https://github.com/containous/traefik/pull/4939) by [ableuler](https://github.com/ableuler))
- **[middleware]** Improve middleware documentation. ([#5003](https://github.com/containous/traefik/pull/5003) by [ldez](https://github.com/ldez))
- **[middleware]** Enhance middleware examples. ([#4680](https://github.com/containous/traefik/pull/4680) by [ldez](https://github.com/ldez))
- **[middleware]** docker-compose basic auth needs double dollar signs ([#4831](https://github.com/containous/traefik/pull/4831) by [muhlemmer](https://github.com/muhlemmer))
- **[middleware]** Fixed a typo in label. ([#5128](https://github.com/containous/traefik/pull/5128) by [jamct](https://github.com/jamct))
- **[middleware]** Review documentation ([#4798](https://github.com/containous/traefik/pull/4798) by [ldez](https://github.com/ldez))
- **[middleware]** Kubernetes CRD documentation fixes ([#4971](https://github.com/containous/traefik/pull/4971) by [orhanhenrik](https://github.com/orhanhenrik))
- **[middleware]** compress link fixed ([#4817](https://github.com/containous/traefik/pull/4817) by [gato](https://github.com/gato))
- **[middleware]** Fix typo in forwardAuth middleware documentation ([#4638](https://github.com/containous/traefik/pull/4638) by [AkeemMcLennon](https://github.com/AkeemMcLennon))
- **[middleware]** change doc references to scheme[Rr]edirect -> redirect[Ss]cheme ([#4959](https://github.com/containous/traefik/pull/4959) by [topiaruss](https://github.com/topiaruss))
- **[middleware]** Update headers middleware docs for kubernetes crd ([#4955](https://github.com/containous/traefik/pull/4955) by [orhanhenrik](https://github.com/orhanhenrik))
- **[middleware]** Fix strip prefix documentation ([#4829](https://github.com/containous/traefik/pull/4829) by [mmatur](https://github.com/mmatur))
- **[provider]** Improve providers documentation. ([#5050](https://github.com/containous/traefik/pull/5050) by [ldez](https://github.com/ldez))
- **[rancher]** fix: Rancher documentation. ([#4818](https://github.com/containous/traefik/pull/4818) by [ldez](https://github.com/ldez))
- **[rancher]** Specify that Rancher provider is for 1.x only ([#4923](https://github.com/containous/traefik/pull/4923) by [bradjones1](https://github.com/bradjones1))
- **[server]** Add gRPC user guide ([#5042](https://github.com/containous/traefik/pull/5042) by [ldez](https://github.com/ldez))
- **[tcp]** Use rule HostSNI in documentation ([#4592](https://github.com/containous/traefik/pull/4592) by [bbinet](https://github.com/bbinet))
- **[tls]** fix: typo in routing example. ([#4849](https://github.com/containous/traefik/pull/4849) by [ldez](https://github.com/ldez))
- **[tracing]** Improve tracing documentation ([#5102](https://github.com/containous/traefik/pull/5102) by [mmatur](https://github.com/mmatur))
- **[tracing]** Fix typo in tracing docs ([#4737](https://github.com/containous/traefik/pull/4737) by [timoschwarzer](https://github.com/timoschwarzer))
- **[webui]** change docs and adjust dashboard for v2 alpha ([#4632](https://github.com/containous/traefik/pull/4632) by [SantoDE](https://github.com/SantoDE))
- doc: improve examples. ([#5132](https://github.com/containous/traefik/pull/5132) by [ldez](https://github.com/ldez))
- Fixed readme misspelling ([#4882](https://github.com/containous/traefik/pull/4882) by [antondalgren](https://github.com/antondalgren))
- Prepare release v2.0.0-rc2 ([#5293](https://github.com/containous/traefik/pull/5293) by [ldez](https://github.com/ldez))
- Fix typos in documentation ([#4884](https://github.com/containous/traefik/pull/4884) by [michael-k](https://github.com/michael-k))
- Fixed spelling typo ([#4848](https://github.com/containous/traefik/pull/4848) by [mikesir87](https://github.com/mikesir87))
- Enhance the Retry Middleware Documentation ([#5298](https://github.com/containous/traefik/pull/5298) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Clarification of the correct pronunciation of the word "Traefik" ([#4834](https://github.com/containous/traefik/pull/4834) by [ylamlum-g4m](https://github.com/ylamlum-g4m))
- Improve the "reading path" for new contributors ([#4908](https://github.com/containous/traefik/pull/4908) by [dduportal](https://github.com/dduportal))
- Fix some documentation issues ([#5286](https://github.com/containous/traefik/pull/5286) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Entry points CLI description. ([#4896](https://github.com/containous/traefik/pull/4896) by [ldez](https://github.com/ldez))
- Add Mathieu Lonjaret to maintainers ([#4950](https://github.com/containous/traefik/pull/4950) by [emilevauge](https://github.com/emilevauge))
- Prepare release v2.0.0-alpha5 ([#4967](https://github.com/containous/traefik/pull/4967) by [ldez](https://github.com/ldez))
- Minor fix in documentation ([#4811](https://github.com/containous/traefik/pull/4811) by [mmatur](https://github.com/mmatur))
- Prepare release v2.0.0-alpha6. ([#4975](https://github.com/containous/traefik/pull/4975) by [ldez](https://github.com/ldez))
- Fix a typo in documentation ([#4794](https://github.com/containous/traefik/pull/4794) by [groovytron](https://github.com/groovytron))
- Prepare release v2.0.0-alpha4. ([#4788](https://github.com/containous/traefik/pull/4788) by [ldez](https://github.com/ldez))
- Remove dumpcerts.sh ([#4783](https://github.com/containous/traefik/pull/4783) by [ldez](https://github.com/ldez))
- Base of the migration guide ([#5263](https://github.com/containous/traefik/pull/5263) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Prepare release v2.0.0-alpha7 ([#5001](https://github.com/containous/traefik/pull/5001) by [ldez](https://github.com/ldez))
- misc documentation fixes ([#5302](https://github.com/containous/traefik/pull/5302) by [mpl](https://github.com/mpl))
- Fix some minors errors on the documentation ([#4664](https://github.com/containous/traefik/pull/4664) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Adds a note in traefik.sample.toml ([#4757](https://github.com/containous/traefik/pull/4757) by [ldez](https://github.com/ldez))
- Prepare release v2.0.0-rc1 ([#5252](https://github.com/containous/traefik/pull/5252) by [ldez](https://github.com/ldez))
- Use the same case everywhere ([#5043](https://github.com/containous/traefik/pull/5043) by [ldez](https://github.com/ldez))
- Improve the Documentation with a Reference Section ([#4714](https://github.com/containous/traefik/pull/4714) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Prepare release v2.0.0-alpha8 ([#5049](https://github.com/containous/traefik/pull/5049) by [ldez](https://github.com/ldez))
- Add a basic Traefik install guide ([#5117](https://github.com/containous/traefik/pull/5117) by [jbdoumenjou](https://github.com/jbdoumenjou))
- AML indent for domains under TLS documentation section ([#5173](https://github.com/containous/traefik/pull/5173) by [edvincent](https://github.com/edvincent))
- Update to v2.0 readme links ([#4700](https://github.com/containous/traefik/pull/4700) by [karnthis](https://github.com/karnthis))
- Prepare release v2.0.0-alpha3. ([#4693](https://github.com/containous/traefik/pull/4693) by [ldez](https://github.com/ldez))
- Misc documentation fixes ([#5307](https://github.com/containous/traefik/pull/5307) by [ldez](https://github.com/ldez))
- Update restrictions in the documentation. ([#5270](https://github.com/containous/traefik/pull/5270) by [ldez](https://github.com/ldez))
- Prepare release v2.0.0-rc3 ([#5343](https://github.com/containous/traefik/pull/5343) by [ldez](https://github.com/ldez))
- Fix typos in docs ([#4662](https://github.com/containous/traefik/pull/4662) by [SeMeKh](https://github.com/SeMeKh))
- Update traefik.sample.toml ([#4657](https://github.com/containous/traefik/pull/4657) by [ldez](https://github.com/ldez))
- fix: services configuration documentation. ([#5359](https://github.com/containous/traefik/pull/5359) by [ldez](https://github.com/ldez))
- Remove old links in readme ([#4651](https://github.com/containous/traefik/pull/4651) by [ldez](https://github.com/ldez))
- fix a service with one server .yaml example ([#5373](https://github.com/containous/traefik/pull/5373) by [zaverden](https://github.com/zaverden))
- Prepare release v2.0.0-rc4 ([#5384](https://github.com/containous/traefik/pull/5384) by [ldez](https://github.com/ldez))
- Fix dead maintainers link on the README.md ([#4639](https://github.com/containous/traefik/pull/4639) by [benjaminch](https://github.com/benjaminch))
- Prepare release v2.0.0-beta1 ([#5129](https://github.com/containous/traefik/pull/5129) by [ldez](https://github.com/ldez))
- Fix typo in documentation ([#5386](https://github.com/containous/traefik/pull/5386) by [adrienbrignon](https://github.com/adrienbrignon))
- Prepare release v2.0.0-alpha2 ([#4635](https://github.com/containous/traefik/pull/4635) by [ldez](https://github.com/ldez))
- Fix malformed rule ([#5133](https://github.com/containous/traefik/pull/5133) by [dtomcej](https://github.com/dtomcej))
- Improve various parts of the documentation. ([#4996](https://github.com/containous/traefik/pull/4996) by [ldez](https://github.com/ldez))
- Documentation Revamp ([#4475](https://github.com/containous/traefik/pull/4475) by [geraldcroes](https://github.com/geraldcroes))
- Adds a maintainer's page into the documentation. ([#4614](https://github.com/containous/traefik/pull/4614) by [ldez](https://github.com/ldez))
- Add Gerald, Jean-Baptiste and Damien to maintainers ([#3982](https://github.com/containous/traefik/pull/3982) by [emilevauge](https://github.com/emilevauge))
- fix broken links in readme.md ([#3967](https://github.com/containous/traefik/pull/3967) by [AndrewSav](https://github.com/AndrewSav))
- Add master overhaul notice ([#3961](https://github.com/containous/traefik/pull/3961) by [emilevauge](https://github.com/emilevauge))
- Complete maintainers processes ([#3696](https://github.com/containous/traefik/pull/3696) by [mmatur](https://github.com/mmatur))
- Complete maintainers processes ([#3681](https://github.com/containous/traefik/pull/3681) by [emilevauge](https://github.com/emilevauge))
- Prepare release v2.0.0-alpha1 ([#4617](https://github.com/containous/traefik/pull/4617) by [ldez](https://github.com/ldez))
**Misc:**
- Cherry pick v1.7 into v2.0 ([#5341](https://github.com/containous/traefik/pull/5341) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Cherry pick v1.7 into v2.0 ([#5192](https://github.com/containous/traefik/pull/5192) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into v2.0 ([#5115](https://github.com/containous/traefik/pull/5115) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Cherry pick v1.7 into v2.0 ([#4948](https://github.com/containous/traefik/pull/4948) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into v2.0 ([#4823](https://github.com/containous/traefik/pull/4823) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into v2.0 ([#4787](https://github.com/containous/traefik/pull/4787) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into v2.0 ([#4695](https://github.com/containous/traefik/pull/4695) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Merge v2.0.0-rc1 into master ([#5253](https://github.com/containous/traefik/pull/5253) by [ldez](https://github.com/ldez))
- Merge branch v2.0 into master ([#5180](https://github.com/containous/traefik/pull/5180) by [ldez](https://github.com/ldez))
- Merge v2.0.0-alpha8 into master ([#5055](https://github.com/containous/traefik/pull/5055) by [ldez](https://github.com/ldez))
- Merge current v2.0.0-alpha into master ([#5022](https://github.com/containous/traefik/pull/5022) by [ldez](https://github.com/ldez))
- Merge v2.0.0-alpha6 into master ([#4984](https://github.com/containous/traefik/pull/4984) by [ldez](https://github.com/ldez))
- Merge v2.0.0-alpha4 into master ([#4789](https://github.com/containous/traefik/pull/4789) by [ldez](https://github.com/ldez))
- Merge v2.0.0-alpha3 into master ([#4694](https://github.com/containous/traefik/pull/4694) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into master ([#4565](https://github.com/containous/traefik/pull/4565) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Cherry pick v1.7 into master ([#4511](https://github.com/containous/traefik/pull/4511) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into master ([#4492](https://github.com/containous/traefik/pull/4492) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into master ([#4440](https://github.com/containous/traefik/pull/4440) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into master ([#4365](https://github.com/containous/traefik/pull/4365) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into master ([#4303](https://github.com/containous/traefik/pull/4303) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into master ([#4271](https://github.com/containous/traefik/pull/4271) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into master ([#4268](https://github.com/containous/traefik/pull/4268) by [ldez](https://github.com/ldez))
- Cherry pick v1.7 into master ([#4229](https://github.com/containous/traefik/pull/4229) by [juliens](https://github.com/juliens))
- Cherry pick v1.7 into master ([#4206](https://github.com/containous/traefik/pull/4206) by [ldez](https://github.com/ldez))
- Merge v1.7.4 into master ([#4137](https://github.com/containous/traefik/pull/4137) by [ldez](https://github.com/ldez))
- Merge v1.7.3 into master ([#4046](https://github.com/containous/traefik/pull/4046) by [ldez](https://github.com/ldez))
- Merge current v1.7 into master ([#3992](https://github.com/containous/traefik/pull/3992) by [ldez](https://github.com/ldez))
- Merge v1.7.2 into master ([#3983](https://github.com/containous/traefik/pull/3983) by [ldez](https://github.com/ldez))
- Merge v1.7.0 into master ([#3925](https://github.com/containous/traefik/pull/3925) by [ldez](https://github.com/ldez))
- Merge v1.7.0-rc5 into master ([#3903](https://github.com/containous/traefik/pull/3903) by [ldez](https://github.com/ldez))
- Merge v1.7.0-rc4 into master ([#3867](https://github.com/containous/traefik/pull/3867) by [ldez](https://github.com/ldez))
- Merge v1.7.0-rc2 into master ([#3634](https://github.com/containous/traefik/pull/3634) by [ldez](https://github.com/ldez))
## [v2.0.0-rc4](https://github.com/containous/traefik/tree/v2.0.0-rc4) (2019-09-13)
[All Commits](https://github.com/containous/traefik/compare/v2.0.0-rc3...v2.0.0-rc4)
**Enhancements:**
- **[docker,k8s,k8s/crd,marathon,rancher,tcp]** Add weighted round robin load balancer on TCP ([#5380](https://github.com/containous/traefik/pull/5380) by [juliens](https://github.com/juliens))
- **[k8s,k8s/crd,k8s/ingress]** Fix kubernetes id name ([#5383](https://github.com/containous/traefik/pull/5383) by [mmatur](https://github.com/mmatur))
- **[k8s,k8s/crd]** Add passHostHeader and responseForwarding in IngressRoute ([#5368](https://github.com/containous/traefik/pull/5368) by [juliens](https://github.com/juliens))
**Bug fixes:**
- **[api,webui]** Improve documentation about API and Dashboard. ([#5364](https://github.com/containous/traefik/pull/5364) by [ldez](https://github.com/ldez))
- **[cli]** fix: boolean flag parsing with map. ([#5372](https://github.com/containous/traefik/pull/5372) by [ldez](https://github.com/ldez))
- **[logs]** fix: logger and context. ([#5370](https://github.com/containous/traefik/pull/5370) by [ldez](https://github.com/ldez))
- **[tcp]** On client CloseWrite, do CloseWrite instead of Close for backend ([#5366](https://github.com/containous/traefik/pull/5366) by [juliens](https://github.com/juliens))
- **[webui]** fix: passHostHeader in the webUI. ([#5369](https://github.com/containous/traefik/pull/5369) by [ldez](https://github.com/ldez))
**Documentation:**
- fix a service with one server .yaml example ([#5373](https://github.com/containous/traefik/pull/5373) by [zaverden](https://github.com/zaverden))
- fix: services configuration documentation. ([#5359](https://github.com/containous/traefik/pull/5359) by [ldez](https://github.com/ldez))
## [v2.0.0-rc3](https://github.com/containous/traefik/tree/v2.0.0-rc3) (2019-09-10) ## [v2.0.0-rc3](https://github.com/containous/traefik/tree/v2.0.0-rc3) (2019-09-10)
[All Commits](https://github.com/containous/traefik/compare/v2.0.0-rc2...v2.0.0-rc3) [All Commits](https://github.com/containous/traefik/compare/v2.0.0-rc2...v2.0.0-rc3)

View file

@ -286,24 +286,16 @@ func checkNewVersion() {
} }
func stats(staticConfiguration *static.Configuration) { func stats(staticConfiguration *static.Configuration) {
if staticConfiguration.Global.SendAnonymousUsage == nil { logger := log.WithoutContext()
log.WithoutContext().Error(`
You haven't specified the sendAnonymousUsage option, it will be enabled by default.
`)
sendAnonymousUsage := true
staticConfiguration.Global.SendAnonymousUsage = &sendAnonymousUsage
}
if *staticConfiguration.Global.SendAnonymousUsage { if staticConfiguration.Global.SendAnonymousUsage {
log.WithoutContext().Info(` logger.Info(`Stats collection is enabled.`)
Stats collection is enabled. logger.Info(`Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration.`)
Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration. logger.Info(`Help us improve Traefik by leaving this feature on :)`)
Help us improve Traefik by leaving this feature on :) logger.Info(`More details on: https://docs.traefik.io/v2.0/contributing/data-collection/`)
More details on: https://docs.traefik.io/v2.0/contributing/data-collection/
`)
collect(staticConfiguration) collect(staticConfiguration)
} else { } else {
log.WithoutContext().Info(` logger.Info(`
Stats collection is disabled. Stats collection is disabled.
Help us improve Traefik by turning this feature on :) Help us improve Traefik by turning this feature on :)
More details on: https://docs.traefik.io/v2.0/contributing/data-collection/ More details on: https://docs.traefik.io/v2.0/contributing/data-collection/

View file

@ -8,9 +8,6 @@ Understanding How Traefik is Being Used
Understanding how you use Traefik is very important to us: it helps us improve the solution in many different ways. Understanding how you use Traefik is very important to us: it helps us improve the solution in many different ways.
For this very reason, the sendAnonymousUsage option is mandatory: we want you to take time to consider whether or not you wish to share anonymous data with us so we can benefit from your experience and use cases. For this very reason, the sendAnonymousUsage option is mandatory: we want you to take time to consider whether or not you wish to share anonymous data with us so we can benefit from your experience and use cases.
!!! warning
Before the GA, leaving this option unset will not prevent Traefik from running but will generate an error log indicating that it enables data collection by default.
!!! example "Enabling Data Collection" !!! example "Enabling Data Collection"
```toml tab="File (TOML)" ```toml tab="File (TOML)"
@ -71,14 +68,6 @@ Once a day (the first call begins 10 minutes after the start of Traefik), we col
cert = "dockerCert" cert = "dockerCert"
key = "dockerKey" key = "dockerKey"
insecureSkipVerify = true insecureSkipVerify = true
[providers.ecs]
domain = "foo.bar"
exposedByDefault = true
clusters = ["foo-bar"]
region = "us-west-2"
accessKeyID = "AccessKeyID"
secretAccessKey = "SecretAccessKey"
``` ```
??? example "Resulting Obfuscated Configuration" ??? example "Resulting Obfuscated Configuration"
@ -92,7 +81,6 @@ Once a day (the first call begins 10 minutes after the start of Traefik), we col
[providers.docker] [providers.docker]
endpoint = "xxxx" endpoint = "xxxx"
domain = "xxxx"
exposedByDefault = true exposedByDefault = true
swarmMode = true swarmMode = true
@ -101,14 +89,6 @@ Once a day (the first call begins 10 minutes after the start of Traefik), we col
cert = "xxxx" cert = "xxxx"
key = "xxxx" key = "xxxx"
insecureSkipVerify = false insecureSkipVerify = false
[providers.ecs]
domain = "xxxx"
exposedByDefault = true
clusters = []
region = "us-west-2"
accessKeyID = "xxxx"
secretAccessKey = "xxxx"
``` ```
## The Code for Data Collection ## The Code for Data Collection

View file

@ -17,11 +17,11 @@ services:
# The official v2.0 Traefik docker image # The official v2.0 Traefik docker image
image: traefik:v2.0 image: traefik:v2.0
# Enables the web UI and tells Traefik to listen to docker # Enables the web UI and tells Traefik to listen to docker
command: --api --providers.docker command: --api.insecure=true --providers.docker
ports: ports:
# The HTTP port # The HTTP port
- "80:80" - "80:80"
# The Web UI (enabled by --api) # The Web UI (enabled by --api.insecure=true)
- "8080:8080" - "8080:8080"
volumes: volumes:
# So that Traefik can listen to the Docker events # So that Traefik can listen to the Docker events

View file

@ -50,10 +50,10 @@ You can configure Traefik to use an ACME provider (like Let's Encrypt) for autom
--entryPoints.web.address=":80" --entryPoints.web.address=":80"
--entryPoints.websecure.address=":443" --entryPoints.websecure.address=":443"
# ... # ...
--certificatesResolvers.sample.acme.email: your-email@your-domain.org --certificatesResolvers.sample.acme.email="your-email@your-domain.org"
--certificatesResolvers.sample.acme.storage: acme.json --certificatesResolvers.sample.acme.storage="acme.json"
# used during the challenge # used during the challenge
--certificatesResolvers.sample.acme.httpChallenge.entryPoint: web --certificatesResolvers.sample.acme.httpChallenge.entryPoint=web
``` ```
??? note "Configuration Reference" ??? note "Configuration Reference"

View file

@ -1,4 +0,0 @@
{
"extends": "../../.markdownlint.json",
"MD041": false
}

View file

@ -1 +0,0 @@
To learn more about configuration options in the command line, refer to the [configuration overview](../getting-started/configuration-overview.md)

View file

@ -1 +0,0 @@
To learn more about the configuration file, refer to [configuration overview](../getting-started/configuration-overview.md)

View file

@ -1,2 +0,0 @@
!!! info "More On Entry Points"
Learn more about entry points and their configuration options in the dedicated section.

View file

@ -1 +0,0 @@
To learn more about configuration in key-value stores, refer to the [configuration overview](../getting-started/configuration-overview.md)

View file

@ -1,2 +0,0 @@
!!! info "More On Routers"
Learn more about routers and their configuration options in the [dedicated section](../routing/routers/index.md).

View file

@ -97,8 +97,7 @@ metadata:
data: data:
users: |2 users: |2
dGVzdDokYXByMSRINnVza2trVyRJZ1hMUDZld1RyU3VCa1RycUU4d2ovCnRlc3QyOiRhcHIxJGQ5 dGVzdDp0cmFlZmlrOmEyNjg4ZTAzMWVkYjRiZTZhMzc5N2YzODgyNjU1YzA1CnRlc3QyOnRyYWVmaWs6NTE4ODQ1ODAwZjllMmJmYjFmMWY3NDBlYzI0ZjA3NGUKCg==
aHI5SEJCJDRIeHdnVWlyM0hQNEVzZ2dQL1FObzAK
``` ```
```json tab="Marathon" ```json tab="Marathon"

View file

@ -47,7 +47,7 @@ InfluxDB's address protocol (udp or http).
```toml tab="File (TOML)" ```toml tab="File (TOML)"
[metrics] [metrics]
[metrics.influxdb] [metrics.influxdb]
protocol = "upd" protocol = "udp"
``` ```
```yaml tab="File (YAML)" ```yaml tab="File (YAML)"

View file

@ -12,13 +12,13 @@ The dashboard is the central place that shows you the current active routes hand
By default, the dashboard is available on `/` on port `:8080`. By default, the dashboard is available on `/` on port `:8080`.
!!! tip "Did You Know?" !!! note "Did You Know?"
It is possible to customize the dashboard endpoint. It is possible to customize the dashboard endpoint.
To learn how, refer to the [API documentation](./api.md) To learn how, refer to the [API documentation](./api.md)
## Enabling the Dashboard ## Enabling the Dashboard
To enable the dashboard, you need to enable Traefik's API. To enable the dashboard, you need to enable [Traefik's API](./api.md).
```toml tab="File (TOML)" ```toml tab="File (TOML)"
[api] [api]
@ -49,10 +49,12 @@ api:
--api.dashboard=true --api.dashboard=true
``` ```
{!more-on-command-line.md!} !!! important "API/Dashboard Security"
{!more-on-configuration-file.md!} To secure your dashboard, the use of a `service` named `api@internal` is mandatory and requires the definition of a router using one or more security [middlewares](../middlewares/overview.md)
like authentication ([basicAuth](../middlewares/basicauth.md) , [digestAuth](../middlewares/digestauth.md), [forwardAuth](../middlewares/forwardauth.md)) or [whitelisting](../middlewares/ipwhitelist.md).
More information about `api@internal` can be found in the [API documentation](./api.md#configuration)
!!! tip "Did You Know?" !!! note "Did You Know?"
The API provides more features than the Dashboard. The API provides more features than the Dashboard.
To learn more about it, refer to the [API documentation](./api.md) To learn more about it, refer to the [API documentation](./api.md)

View file

@ -226,6 +226,13 @@ spec:
port: 80 port: 80
# (default 1) A weight used by the weighted round-robin strategy (WRR). # (default 1) A weight used by the weighted round-robin strategy (WRR).
weight: 1 weight: 1
# (default true) PassHostHeader controls whether to leave the request's Host
# Header as it was before it reached the proxy, or whether to let the proxy set it
# to the destination (backend) host.
passHostHeader: true
responseForwarding:
# (default 100ms) Interval between flushes of the buffered response body to the client.
flushInterval: 100ms
--- ---
apiVersion: traefik.containo.us/v1alpha1 apiVersion: traefik.containo.us/v1alpha1

View file

@ -184,4 +184,6 @@
- "traefik.tcp.routers.tcprouter1.tls.options=foobar" - "traefik.tcp.routers.tcprouter1.tls.options=foobar"
- "traefik.tcp.routers.tcprouter1.tls.passthrough=true" - "traefik.tcp.routers.tcprouter1.tls.passthrough=true"
- "traefik.tcp.services.tcpservice0.loadbalancer.server.port=foobar" - "traefik.tcp.services.tcpservice0.loadbalancer.server.port=foobar"
- "traefik.tcp.services.tcpservice0.loadbalancer.terminationdelay=100"
- "traefik.tcp.services.tcpservice1.loadbalancer.server.port=foobar" - "traefik.tcp.services.tcpservice1.loadbalancer.server.port=foobar"
- "traefik.tcp.services.tcpservice1.loadbalancer.terminationdelay=100"

View file

@ -286,14 +286,17 @@
[tcp.services] [tcp.services]
[tcp.services.TCPService0] [tcp.services.TCPService0]
[tcp.services.TCPService0.loadBalancer] [tcp.services.TCPService0.loadBalancer]
terminationDelay = 100
[[tcp.services.TCPService0.loadBalancer.servers]] [[tcp.services.TCPService0.loadBalancer.servers]]
address = "foobar" address = "foobar"
[[tcp.services.TCPService0.loadBalancer.servers]] [[tcp.services.TCPService0.loadBalancer.servers]]
address = "foobar" address = "foobar"
[tcp.services.TCPService1] [tcp.services.TCPService1]
[tcp.services.TCPService1.loadBalancer] [tcp.services.TCPService1.loadBalancer]
terminationDelay = 100
[[tcp.services.TCPService1.loadBalancer.servers]] [[tcp.services.TCPService1.loadBalancer.servers]]
address = "foobar" address = "foobar"

View file

@ -324,11 +324,13 @@ tcp:
services: services:
TCPService0: TCPService0:
loadBalancer: loadBalancer:
terminationDelay: 100
servers: servers:
- address: foobar - address: foobar
- address: foobar - address: foobar
TCPService1: TCPService1:
loadBalancer: loadBalancer:
terminationDelay: 100
servers: servers:
- address: foobar - address: foobar
- address: foobar - address: foobar

View file

@ -184,4 +184,6 @@
"traefik.tcp.routers.tcprouter1.tls.options": "foobar", "traefik.tcp.routers.tcprouter1.tls.options": "foobar",
"traefik.tcp.routers.tcprouter1.tls.passthrough": "true", "traefik.tcp.routers.tcprouter1.tls.passthrough": "true",
"traefik.tcp.services.tcpservice0.loadbalancer.server.port": "foobar", "traefik.tcp.services.tcpservice0.loadbalancer.server.port": "foobar",
"traefik.tcp.services.tcpservice0.loadbalancer.terminationDelay": "100",
"traefik.tcp.services.tcpservice1.loadbalancer.server.port": "foobar" "traefik.tcp.services.tcpservice1.loadbalancer.server.port": "foobar"
"traefik.tcp.services.tcpservice1.loadbalancer.terminationDelay": "100",

View file

@ -105,7 +105,7 @@ The `url` option point to a specific instance.
my-service: my-service:
loadBalancer: loadBalancer:
servers: servers:
url: "http://private-ip-server-1/" - url: "http://private-ip-server-1/"
``` ```
#### Load-balancing #### Load-balancing
@ -312,11 +312,11 @@ This strategy can be defined only with [File](../../providers/file.md).
```toml tab="TOML" ```toml tab="TOML"
[http.services] [http.services]
[http.services.canary] [http.services.app]
[[http.services.canary.weighted.services]] [[http.services.app.weighted.services]]
name = "appv1" name = "appv1"
weight = 3 weight = 3
[[http.services.canary.weighted.services]] [[http.services.app.weighted.services]]
name = "appv2" name = "appv2"
weight = 1 weight = 1
@ -334,7 +334,7 @@ This strategy can be defined only with [File](../../providers/file.md).
```yaml tab="YAML" ```yaml tab="YAML"
http: http:
services: services:
canary: app:
weighted: weighted:
services: services:
- name: appv1 - name: appv1
@ -361,40 +361,40 @@ This strategy can be defined only with [File](../../providers/file.md).
```toml tab="TOML" ```toml tab="TOML"
[http.services] [http.services]
[http.services.mirroring] [http.services.mirrored-api]
[http.services.mirroring.mirroring] [http.services.mirrored-api.mirroring]
service = "app" service = "appv1"
[[http.services.mirroring.mirroring.mirrors]] [[http.services.mirrored-api.mirroring.mirrors]]
name = "mirror" name = "appv2"
percent = 10 percent = 10
[http.services.app] [http.services.appv1]
[http.services.app.loadBalancer] [http.services.appv1.loadBalancer]
[[http.services.appv1.loadBalancer.servers]] [[http.services.appv1.loadBalancer.servers]]
url = "http://private-ip-server-1/" url = "http://private-ip-server-1/"
[http.services.mirror] [http.services.appv2]
[http.services.mirror.loadBalancer] [http.services.appv2.loadBalancer]
[[http.services.mirror.loadBalancer.servers]] [[http.services.appv2.loadBalancer.servers]]
url = "http://private-ip-server-2/" url = "http://private-ip-server-2/"
``` ```
```yaml tab="YAML" ```yaml tab="YAML"
http: http:
services: services:
mirroring: mirrored-api:
mirroring: mirroring:
service: app service: appv1
mirrors: mirrors:
- name: mirror - name: appv2
percent: 10 percent: 10
app: appv1:
loadBalancer: loadBalancer:
servers: servers:
- url: "http://private-ip-server-1/" - url: "http://private-ip-server-1/"
mirror: appv2:
loadBalancer: loadBalancer:
servers: servers:
- url: "http://private-ip-server-2/" - url: "http://private-ip-server-2/"
@ -404,13 +404,14 @@ http:
### General ### General
Currently, `LoadBalancer` is the only supported kind of TCP `Service`. Each of the fields of the service section represents a kind of service.
However, since Traefik is an ever evolving project, other kind of TCP Services will be available in the future, Which means, that for each specified service, one of the fields, and only one,
reason why you have to specify it. has to be enabled to define what kind of service is created.
Currently, the two available kinds are `LoadBalancer`, and `Weighted`.
### Load Balancer ### Servers Load Balancer
The load balancers are able to load balance the requests between multiple instances of your programs. The servers load balancer is in charge of balancing the requests between the servers of the same service.
??? example "Declaring a Service with Two Servers -- Using the [File Provider](../../providers/file.md)" ??? example "Declaring a Service with Two Servers -- Using the [File Provider](../../providers/file.md)"
@ -455,3 +456,85 @@ The `address` option (IP:Port) point to a specific instance.
servers: servers:
address: "xx.xx.xx.xx:xx" address: "xx.xx.xx.xx:xx"
``` ```
#### Termination Delay
As a proxy between a client and a server, it can happen that either side (e.g. client side) decides to terminate its writing capability on the connection (i.e. issuance of a FIN packet).
The proxy needs to propagate that intent to the other side, and so when that happens, it also does the same on its connection with the other side (e.g. backend side).
However, if for some reason (bad implementation, or malicious intent) the other side does not eventually do the same as well,
the connection would stay half-open, which would lock resources for however long.
To that end, as soon as the proxy enters this termination sequence, it sets a deadline on fully terminating the connections on both sides.
The termination delay controls that deadline.
It is a duration in milliseconds, defaulting to 100.
A negative value means an infinite deadline (i.e. the connection is never fully terminated by the proxy itself).
??? example "A Service with a termination delay -- Using the [File Provider](../../providers/file.md)"
```toml tab="TOML"
[tcp.services]
[tcp.services.my-service.loadBalancer]
[[tcp.services.my-service.loadBalancer]]
terminationDelay = 200
```
```yaml tab="YAML"
tcp:
services:
my-service:
loadBalancer:
terminationDelay: 200
```
### Weighted
The Weighted Round Robin (alias `WRR`) load-balancer of services is in charge of balancing the requests between multiple services based on provided weights.
This strategy is only available to load balance between [services](./index.md) and not between [servers](./index.md#servers).
This strategy can only be defined with [File](../../providers/file.md).
```toml tab="TOML"
[tcp.services]
[tcp.services.app]
[[tcp.services.app.weighted.services]]
name = "appv1"
weight = 3
[[tcp.services.app.weighted.services]]
name = "appv2"
weight = 1
[tcp.services.appv1]
[tcp.services.appv1.loadBalancer]
[[tcp.services.appv1.loadBalancer.servers]]
address = "private-ip-server-1/:8080"
[tcp.services.appv2]
[tcp.services.appv2.loadBalancer]
[[tcp.services.appv2.loadBalancer.servers]]
address = "private-ip-server-2/:8080"
```
```yaml tab="YAML"
tcp:
services:
app:
weighted:
services:
- name: appv1
weight: 3
- name: appv2
weight: 1
appv1:
loadBalancer:
servers:
- address: "xxx.xxx.xxx.xxx:8080"
appv2:
loadBalancer:
servers:
- address: "xxx.xxx.xxx.xxx:8080"
```

View file

@ -28,7 +28,7 @@ spec:
- name: traefik - name: traefik
image: traefik:v2.0 image: traefik:v2.0
args: args:
- --api - --api.insecure
- --accesslog - --accesslog
- --entrypoints.web.Address=:8000 - --entrypoints.web.Address=:8000
- --entrypoints.websecure.Address=:4443 - --entrypoints.websecure.Address=:4443

View file

@ -3,11 +3,11 @@ version: "3.3"
services: services:
traefik: traefik:
image: "traefik:v2.0.0-beta1" image: "traefik:v2.0.0-rc3"
container_name: "traefik" container_name: "traefik"
command: command:
#- "--log.level=DEBUG" #- "--log.level=DEBUG"
- "--api=true" - "--api.insecure=true"
- "--providers.docker=true" - "--providers.docker=true"
- "--providers.docker.exposedbydefault=false" - "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80" - "--entrypoints.web.address=:80"

View file

@ -13,11 +13,11 @@ secrets:
services: services:
traefik: traefik:
image: "traefik:v2.0.0-beta1" image: "traefik:v2.0.0-rc3"
container_name: "traefik" container_name: "traefik"
command: command:
#- "--log.level=DEBUG" #- "--log.level=DEBUG"
- "--api=true" - "--api.insecure=true"
- "--providers.docker=true" - "--providers.docker=true"
- "--providers.docker.exposedbydefault=false" - "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80" - "--entrypoints.web.address=:80"

View file

@ -3,11 +3,11 @@ version: "3.3"
services: services:
traefik: traefik:
image: "traefik:v2.0.0-beta1" image: "traefik:v2.0.0-rc3"
container_name: "traefik" container_name: "traefik"
command: command:
#- "--log.level=DEBUG" #- "--log.level=DEBUG"
- "--api=true" - "--api.insecure=true"
- "--providers.docker=true" - "--providers.docker=true"
- "--providers.docker.exposedbydefault=false" - "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80" - "--entrypoints.web.address=:80"

View file

@ -3,11 +3,11 @@ version: "3.3"
services: services:
traefik: traefik:
image: "traefik:v2.0.0-beta1" image: "traefik:v2.0.0-rc3"
container_name: "traefik" container_name: "traefik"
command: command:
#- "--log.level=DEBUG" #- "--log.level=DEBUG"
- "--api=true" - "--api.insecure=true"
- "--providers.docker=true" - "--providers.docker=true"
- "--providers.docker.exposedbydefault=false" - "--providers.docker.exposedbydefault=false"
- "--entrypoints.websecure.address=:443" - "--entrypoints.websecure.address=:443"

View file

@ -3,11 +3,11 @@ version: "3.3"
services: services:
traefik: traefik:
image: "traefik:v2.0.0-beta1" image: "traefik:v2.0.0-rc3"
container_name: "traefik" container_name: "traefik"
command: command:
#- "--log.level=DEBUG" #- "--log.level=DEBUG"
- "--api=true" - "--api.insecure=true"
- "--providers.docker=true" - "--providers.docker=true"
- "--providers.docker.exposedbydefault=false" - "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80" - "--entrypoints.web.address=:80"

View file

@ -53,7 +53,7 @@ ports:
```yaml ```yaml
command: command:
# Traefik will listen on port 8080 by default for API request. # Traefik will listen on port 8080 by default for API request.
- "--api=true" - "--api.insecure=true"
ports: ports:
- "8080:8080" - "8080:8080"

View file

@ -34,7 +34,7 @@ api: {}
```yaml tab="CLI" ```yaml tab="CLI"
--entryPoints.web.address=":80" --entryPoints.web.address=":80"
--providers.file.filename=dynamic_conf.toml --providers.file.filename=dynamic_conf.toml
--api=true --api.insecure=true
``` ```
`dynamic_conf.{toml,yml}`: `dynamic_conf.{toml,yml}`:
@ -157,7 +157,7 @@ api: {}
# For secure connection on backend.local # For secure connection on backend.local
--serversTransport.rootCAs=./backend.cert --serversTransport.rootCAs=./backend.cert
--providers.file.filename=dynamic_conf.toml --providers.file.filename=dynamic_conf.toml
--api=true --api.insecure=true
``` ```
`dynamic_conf.{toml,yml}`: `dynamic_conf.{toml,yml}`:

View file

@ -58,9 +58,9 @@ markdown_extensions:
- pymdownx.tasklist - pymdownx.tasklist
- pymdownx.snippets: - pymdownx.snippets:
check_paths: true check_paths: true
- markdown_include.include: # - markdown_include.include:
base_path: content/includes/ # base_path: content/includes/
encoding: utf-8 # encoding: utf-8
- toc: - toc:
permalink: true permalink: true

2
go.mod
View file

@ -51,7 +51,7 @@ require (
github.com/huandu/xstrings v1.2.0 // indirect github.com/huandu/xstrings v1.2.0 // indirect
github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc
github.com/instana/go-sensor v1.4.17-0.20190515112224-78c14625025a github.com/instana/go-sensor v1.4.17-0.20190515112224-78c14625025a
github.com/labbsr0x/goh v0.0.0-20190610190554-60aa50bcbca7 // indirect github.com/labbsr0x/goh v0.0.0-20190830205702-3d6988c73e10 // indirect
github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad
github.com/libkermit/docker v0.0.0-20171122101128-e6674d32b807 github.com/libkermit/docker v0.0.0-20171122101128-e6674d32b807
github.com/libkermit/docker-check v0.0.0-20171122104347-1113af38e591 github.com/libkermit/docker-check v0.0.0-20171122104347-1113af38e591

4
go.sum
View file

@ -307,8 +307,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/labbsr0x/bindman-dns-webhook v1.0.0 h1:gooRvyQtVOCtV/l9ZCI4CManZeVN/kUWG/vugRqHqv4= github.com/labbsr0x/bindman-dns-webhook v1.0.0 h1:gooRvyQtVOCtV/l9ZCI4CManZeVN/kUWG/vugRqHqv4=
github.com/labbsr0x/bindman-dns-webhook v1.0.0/go.mod h1:pn4jcNjxSywRWDPDyGkFzgSnwty18OFdiUFc6S6fpgc= github.com/labbsr0x/bindman-dns-webhook v1.0.0/go.mod h1:pn4jcNjxSywRWDPDyGkFzgSnwty18OFdiUFc6S6fpgc=
github.com/labbsr0x/goh v0.0.0-20190417202808-8b16b4848295/go.mod h1:RBxeaayaaMmp7GxwHiKANjkg9e+rxjOm4mB5vD5rt/I= github.com/labbsr0x/goh v0.0.0-20190417202808-8b16b4848295/go.mod h1:RBxeaayaaMmp7GxwHiKANjkg9e+rxjOm4mB5vD5rt/I=
github.com/labbsr0x/goh v0.0.0-20190610190554-60aa50bcbca7 h1:ocfbpesrzMqybD816LDEjourU4jiHj6gDGMieAcU8Io= github.com/labbsr0x/goh v0.0.0-20190830205702-3d6988c73e10 h1:mrPTy7qNJPGHaUkkN301r8Y+13l2/vsiC8Lvi09e6sI=
github.com/labbsr0x/goh v0.0.0-20190610190554-60aa50bcbca7/go.mod h1:RBxeaayaaMmp7GxwHiKANjkg9e+rxjOm4mB5vD5rt/I= github.com/labbsr0x/goh v0.0.0-20190830205702-3d6988c73e10/go.mod h1:RBxeaayaaMmp7GxwHiKANjkg9e+rxjOm4mB5vD5rt/I=
github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad h1:nTyRWZ864mnHUnusBCVA628AZFgfGHwRUpbHqGhRQr8= github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad h1:nTyRWZ864mnHUnusBCVA628AZFgfGHwRUpbHqGhRQr8=
github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad/go.mod h1:GyCk/ifDcqsU1tsRMMWqXANnTtxzcwEWscb7j5qmblM= github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad/go.mod h1:GyCk/ifDcqsU1tsRMMWqXANnTtxzcwEWscb7j5qmblM=
github.com/libkermit/docker v0.0.0-20171122101128-e6674d32b807 h1:/7J1WDQd6Xn1Pr8KtE2I/7/cKw66AV3hBUOyxqyXo84= github.com/libkermit/docker v0.0.0-20171122101128-e6674d32b807 h1:/7J1WDQd6Xn1Pr8KtE2I/7/cKw66AV3hBUOyxqyXo84=

View file

@ -46,7 +46,7 @@ func (s *AccessLogSuite) SetUpSuite(c *check.C) {
func (s *AccessLogSuite) TearDownTest(c *check.C) { func (s *AccessLogSuite) TearDownTest(c *check.C) {
displayTraefikLogFile(c, traefikTestLogFile) displayTraefikLogFile(c, traefikTestLogFile)
os.Remove(traefikTestAccessLogFile) _ = os.Remove(traefikTestAccessLogFile)
} }
func (s *AccessLogSuite) TestAccessLog(c *check.C) { func (s *AccessLogSuite) TestAccessLog(c *check.C) {
@ -59,7 +59,7 @@ func (s *AccessLogSuite) TestAccessLog(c *check.C) {
defer func() { defer func() {
traefikLog, err := ioutil.ReadFile(traefikTestLogFile) traefikLog, err := ioutil.ReadFile(traefikTestLogFile)
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
log.Info(string(traefikLog)) log.WithoutContext().Info(string(traefikLog))
}() }()
err := cmd.Start() err := cmd.Start()
@ -233,7 +233,7 @@ func digestParts(resp *http.Response) map[string]string {
func getMD5(data string) string { func getMD5(data string) string {
digest := md5.New() digest := md5.New()
if _, err := digest.Write([]byte(data)); err != nil { if _, err := digest.Write([]byte(data)); err != nil {
log.Error(err) log.WithoutContext().Error(err)
} }
return fmt.Sprintf("%x", digest.Sum(nil)) return fmt.Sprintf("%x", digest.Sum(nil))
} }
@ -241,7 +241,7 @@ func getMD5(data string) string {
func getCnonce() string { func getCnonce() string {
b := make([]byte, 8) b := make([]byte, 8)
if _, err := io.ReadFull(rand.Reader, b); err != nil { if _, err := io.ReadFull(rand.Reader, b); err != nil {
log.Error(err) log.WithoutContext().Error(err)
} }
return fmt.Sprintf("%x", b)[:16] return fmt.Sprintf("%x", b)[:16]
} }

View file

@ -15,6 +15,8 @@ type handler struct{}
// Simplified version of the Challenge Test Server from Boulder // Simplified version of the Challenge Test Server from Boulder
// https://github.com/letsencrypt/boulder/blob/a6597b9f120207eff192c3e4107a7e49972a0250/test/challtestsrv/dnsone.go#L40 // https://github.com/letsencrypt/boulder/blob/a6597b9f120207eff192c3e4107a7e49972a0250/test/challtestsrv/dnsone.go#L40
func (s *handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { func (s *handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
logger := log.WithoutContext()
m := new(dns.Msg) m := new(dns.Msg)
m.SetReply(r) m.SetReply(r)
m.Compress = false m.Compress = false
@ -23,8 +25,9 @@ func (s *handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
if fakeDNS == "" { if fakeDNS == "" {
fakeDNS = "127.0.0.1" fakeDNS = "127.0.0.1"
} }
for _, q := range r.Question { for _, q := range r.Question {
log.Infof("Query -- [%s] %s", q.Name, dns.TypeToString[q.Qtype]) logger.Infof("Query -- [%s] %s", q.Name, dns.TypeToString[q.Qtype])
switch q.Qtype { switch q.Qtype {
case dns.TypeA: case dns.TypeA:
@ -94,7 +97,7 @@ func (s *handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
m.Ns = append(m.Ns, auth) m.Ns = append(m.Ns, auth)
if err := w.WriteMsg(m); err != nil { if err := w.WriteMsg(m); err != nil {
log.Fatalf("Failed to write message %v", err) logger.Fatalf("Failed to write message %v", err)
} }
} }
@ -106,9 +109,9 @@ func startFakeDNSServer() *dns.Server {
} }
go func() { go func() {
log.Infof("Start a fake DNS server.") log.WithoutContext().Infof("Start a fake DNS server.")
if err := srv.ListenAndServe(); err != nil { if err := srv.ListenAndServe(); err != nil {
log.Fatalf("Failed to set udp listener %v", err) log.WithoutContext().Fatalf("Failed to set udp listener %v", err)
} }
}() }()

View file

@ -0,0 +1,42 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
[entryPoints]
[entryPoints.tcp]
address = ":8093"
[api]
insecure = true
[providers.file]
filename = "{{ .SelfFilename }}"
## dynamic configuration ##
[tcp]
[tcp.routers]
[tcp.routers.to-whoami-a]
rule = "HostSNI(`whoami-a.test`)"
service = "whoami"
entryPoints = [ "tcp" ]
[tcp.routers.to-whoami-a.tls]
passthrough=true
[[tcp.services.whoami.weighted.services]]
name="whoami-a"
weight=3
[[tcp.services.whoami.weighted.services]]
name="whoami-b"
weight=1
[tcp.services.whoami-a.loadBalancer]
[[tcp.services.whoami-a.loadBalancer.servers]]
address = "localhost:8081"
[tcp.services.whoami-b.loadBalancer]
[[tcp.services.whoami-b.loadBalancer.servers]]
address = "localhost:8082"

View file

@ -50,7 +50,7 @@ func (s *myserver) StreamExample(in *helloworld.StreamExampleRequest, server hel
} }
if err := server.Send(&helloworld.StreamExampleReply{Data: string(data)}); err != nil { if err := server.Send(&helloworld.StreamExampleReply{Data: string(data)}); err != nil {
log.Error(err) log.WithoutContext().Error(err)
} }
<-s.stopStreamExample <-s.stopStreamExample

View file

@ -28,7 +28,7 @@ var showLog = flag.Bool("tlog", false, "always show Traefik logs")
func Test(t *testing.T) { func Test(t *testing.T) {
if !*integration { if !*integration {
log.Info("Integration tests disabled.") log.WithoutContext().Info("Integration tests disabled.")
return return
} }
@ -91,7 +91,7 @@ func (s *BaseSuite) createComposeProject(c *check.C, name string) {
ip, _, err := net.ParseCIDR(addr.String()) ip, _, err := net.ParseCIDR(addr.String())
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
if !ip.IsLoopback() && ip.To4() != nil { if !ip.IsLoopback() && ip.To4() != nil {
os.Setenv("DOCKER_HOST_IP", ip.String()) _ = os.Setenv("DOCKER_HOST_IP", ip.String())
break break
} }
} }

View file

@ -79,7 +79,7 @@ func (s *RestSuite) TestSimpleConfigurationInsecure(c *check.C) {
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"service1": { "service1": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80", Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",
@ -183,7 +183,7 @@ func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"service1": { "service1": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80", Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",

View file

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os" "os"
"strings"
"time" "time"
"github.com/containous/traefik/v2/integration/try" "github.com/containous/traefik/v2/integration/try"
@ -266,3 +267,35 @@ func guessWhoTLSMaxVersion(addr, serverName string, tlsCall bool, tlsMaxVersion
return string(out[:n]), nil return string(out[:n]), nil
} }
func (s *TCPSuite) TestWRR(c *check.C) {
file := s.adaptFile(c, "fixtures/tcp/wrr.toml", struct{}{})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI"))
c.Assert(err, checker.IsNil)
call := map[string]int{}
for i := 0; i < 4; i++ {
// Traefik passes through, termination handled by whoami-a
out, err := guessWho("127.0.0.1:8093", "whoami-a.test", true)
c.Assert(err, checker.IsNil)
switch {
case strings.Contains(out, "whoami-a"):
call["whoami-a"]++
case strings.Contains(out, "whoami-b"):
call["whoami-b"]++
default:
call["unknown"]++
}
}
c.Assert(call, checker.DeepEquals, map[string]int{"whoami-a": 3, "whoami-b": 1})
}

View file

@ -1,28 +1,28 @@
{ {
"routers": { "routers": {
"default/test.route-6b204d94623b3df4370c@kubernetescrd": { "default-test.route-6b204d94623b3df4370c@kubernetescrd": {
"entryPoints": [ "entryPoints": [
"web" "web"
], ],
"service": "default/test.route-6b204d94623b3df4370c", "service": "default-test.route-6b204d94623b3df4370c",
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/bar`)", "rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/bar`)",
"priority": 12, "priority": 12,
"tls": { "tls": {
"options": "default/mytlsoption" "options": "default-mytlsoption"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
"web" "web"
] ]
}, },
"default/test2.route-23c7f4c450289ee29016@kubernetescrd": { "default-test2.route-23c7f4c450289ee29016@kubernetescrd": {
"entryPoints": [ "entryPoints": [
"web" "web"
], ],
"middlewares": [ "middlewares": [
"default/mychain@kubernetescrd" "default-mychain@kubernetescrd"
], ],
"service": "default/test2.route-23c7f4c450289ee29016", "service": "default-test2.route-23c7f4c450289ee29016",
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/tobestripped`)", "rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/tobestripped`)",
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -31,18 +31,18 @@
} }
}, },
"middlewares": { "middlewares": {
"default/mychain@kubernetescrd": { "default-mychain@kubernetescrd": {
"chain": { "chain": {
"middlewares": [ "middlewares": [
"default/stripprefix@kubernetescrd" "default-stripprefix@kubernetescrd"
] ]
}, },
"status": "enabled", "status": "enabled",
"usedBy": [ "usedBy": [
"default/test2.route-23c7f4c450289ee29016@kubernetescrd" "default-test2.route-23c7f4c450289ee29016@kubernetescrd"
] ]
}, },
"default/stripprefix@kubernetescrd": { "default-stripprefix@kubernetescrd": {
"stripPrefix": { "stripPrefix": {
"prefixes": [ "prefixes": [
"/tobestripped" "/tobestripped"
@ -52,7 +52,7 @@
} }
}, },
"services": { "services": {
"default/test.route-6b204d94623b3df4370c@kubernetescrd": { "default-test.route-6b204d94623b3df4370c@kubernetescrd": {
"loadBalancer": { "loadBalancer": {
"servers": [ "servers": [
{ {
@ -66,14 +66,14 @@
}, },
"status": "enabled", "status": "enabled",
"usedBy": [ "usedBy": [
"default/test.route-6b204d94623b3df4370c@kubernetescrd" "default-test.route-6b204d94623b3df4370c@kubernetescrd"
], ],
"serverStatus": { "serverStatus": {
"http://10.42.0.2:80": "UP", "http://10.42.0.2:80": "UP",
"http://10.42.0.6:80": "UP" "http://10.42.0.6:80": "UP"
} }
}, },
"default/test2.route-23c7f4c450289ee29016@kubernetescrd": { "default-test2.route-23c7f4c450289ee29016@kubernetescrd": {
"loadBalancer": { "loadBalancer": {
"servers": [ "servers": [
{ {
@ -87,7 +87,7 @@
}, },
"status": "enabled", "status": "enabled",
"usedBy": [ "usedBy": [
"default/test2.route-23c7f4c450289ee29016@kubernetescrd" "default-test2.route-23c7f4c450289ee29016@kubernetescrd"
], ],
"serverStatus": { "serverStatus": {
"http://10.42.0.2:80": "UP", "http://10.42.0.2:80": "UP",
@ -96,15 +96,15 @@
} }
}, },
"tcpRouters": { "tcpRouters": {
"default/test3.route-673acf455cb2dab0b43a@kubernetescrd": { "default-test3.route-673acf455cb2dab0b43a@kubernetescrd": {
"entryPoints": [ "entryPoints": [
"footcp" "footcp"
], ],
"service": "default/test3.route-673acf455cb2dab0b43a", "service": "default-test3.route-673acf455cb2dab0b43a",
"rule": "HostSNI(`*`)", "rule": "HostSNI(`*`)",
"tls": { "tls": {
"passthrough": false, "passthrough": false,
"options": "default/mytlsoption" "options": "default-mytlsoption"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -113,8 +113,9 @@
} }
}, },
"tcpServices": { "tcpServices": {
"default/test3.route-673acf455cb2dab0b43a@kubernetescrd": { "default-test3.route-673acf455cb2dab0b43a@kubernetescrd": {
"loadBalancer": { "loadBalancer": {
"terminationDelay": 100,
"servers": [ "servers": [
{ {
"address": "10.42.0.4:8080" "address": "10.42.0.4:8080"
@ -126,7 +127,7 @@
}, },
"status": "enabled", "status": "enabled",
"usedBy": [ "usedBy": [
"default/test3.route-673acf455cb2dab0b43a@kubernetescrd" "default-test3.route-673acf455cb2dab0b43a@kubernetescrd"
] ]
} }
} }

View file

@ -1,7 +1,7 @@
{ {
"routers": { "routers": {
"whoami-test-https/whoami-tls@kubernetes": { "whoami-test-https-whoami-tls@kubernetes": {
"service": "default/whoami/http", "service": "default-whoami-http",
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)", "rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
"tls": {}, "tls": {},
"status": "enabled", "status": "enabled",
@ -10,8 +10,8 @@
"web" "web"
] ]
}, },
"whoami-test-https/whoami@kubernetes": { "whoami-test-https-whoami@kubernetes": {
"service": "default/whoami/http", "service": "default-whoami-http",
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)", "rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -19,8 +19,8 @@
"web" "web"
] ]
}, },
"whoami-test/whoami@kubernetes": { "whoami-test-whoami@kubernetes": {
"service": "default/whoami/http", "service": "default-whoami-http",
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)", "rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -30,7 +30,7 @@
} }
}, },
"services": { "services": {
"default/whoami/http@kubernetes": { "default-whoami-http@kubernetes": {
"loadBalancer": { "loadBalancer": {
"servers": [ "servers": [
{ {
@ -44,9 +44,9 @@
}, },
"status": "enabled", "status": "enabled",
"usedBy": [ "usedBy": [
"whoami-test-https/whoami-tls@kubernetes", "whoami-test-https-whoami-tls@kubernetes",
"whoami-test-https/whoami@kubernetes", "whoami-test-https-whoami@kubernetes",
"whoami-test/whoami@kubernetes" "whoami-test-whoami@kubernetes"
], ],
"serverStatus": { "serverStatus": {
"http://10.42.0.2:80": "UP", "http://10.42.0.2:80": "UP",

View file

@ -26,10 +26,9 @@ import (
func TestDo_globalConfiguration(t *testing.T) { func TestDo_globalConfiguration(t *testing.T) {
config := &static.Configuration{} config := &static.Configuration{}
sendAnonymousUsage := true
config.Global = &static.Global{ config.Global = &static.Global{
CheckNewVersion: true, CheckNewVersion: true,
SendAnonymousUsage: &sendAnonymousUsage, SendAnonymousUsage: true,
} }
config.AccessLog = &types.AccessLog{ config.AccessLog = &types.AccessLog{

View file

@ -136,7 +136,7 @@ func TestHandler_Overview(t *testing.T) {
TCPServices: map[string]*runtime.TCPServiceInfo{ TCPServices: map[string]*runtime.TCPServiceInfo{
"tcpfoo-service@myprovider": { "tcpfoo-service@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1", Address: "127.0.0.1",
@ -148,7 +148,7 @@ func TestHandler_Overview(t *testing.T) {
}, },
"tcpbar-service@myprovider": { "tcpbar-service@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.2", Address: "127.0.0.2",
@ -160,7 +160,7 @@ func TestHandler_Overview(t *testing.T) {
}, },
"tcpfii-service@myprovider": { "tcpfii-service@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.2", Address: "127.0.0.2",

View file

@ -255,7 +255,7 @@ func TestHandler_TCP(t *testing.T) {
TCPServices: map[string]*runtime.TCPServiceInfo{ TCPServices: map[string]*runtime.TCPServiceInfo{
"bar@myprovider": { "bar@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1:2345", Address: "127.0.0.1:2345",
@ -268,7 +268,7 @@ func TestHandler_TCP(t *testing.T) {
}, },
"baz@myprovider": { "baz@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.2:2345", Address: "127.0.0.2:2345",
@ -281,7 +281,7 @@ func TestHandler_TCP(t *testing.T) {
}, },
"foz@myprovider": { "foz@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.2:2345", Address: "127.0.0.2:2345",
@ -307,7 +307,7 @@ func TestHandler_TCP(t *testing.T) {
TCPServices: map[string]*runtime.TCPServiceInfo{ TCPServices: map[string]*runtime.TCPServiceInfo{
"bar@myprovider": { "bar@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1:2345", Address: "127.0.0.1:2345",
@ -320,7 +320,7 @@ func TestHandler_TCP(t *testing.T) {
}, },
"baz@myprovider": { "baz@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.2:2345", Address: "127.0.0.2:2345",
@ -333,7 +333,7 @@ func TestHandler_TCP(t *testing.T) {
}, },
"foz@myprovider": { "foz@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.2:2345", Address: "127.0.0.2:2345",
@ -359,7 +359,7 @@ func TestHandler_TCP(t *testing.T) {
TCPServices: map[string]*runtime.TCPServiceInfo{ TCPServices: map[string]*runtime.TCPServiceInfo{
"bar@myprovider": { "bar@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1:2345", Address: "127.0.0.1:2345",
@ -372,7 +372,7 @@ func TestHandler_TCP(t *testing.T) {
}, },
"baz@myprovider": { "baz@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.2:2345", Address: "127.0.0.2:2345",
@ -385,7 +385,7 @@ func TestHandler_TCP(t *testing.T) {
}, },
"foz@myprovider": { "foz@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.2:2345", Address: "127.0.0.2:2345",
@ -411,7 +411,7 @@ func TestHandler_TCP(t *testing.T) {
TCPServices: map[string]*runtime.TCPServiceInfo{ TCPServices: map[string]*runtime.TCPServiceInfo{
"bar@myprovider": { "bar@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1:2345", Address: "127.0.0.1:2345",
@ -423,7 +423,7 @@ func TestHandler_TCP(t *testing.T) {
}, },
"baz@myprovider": { "baz@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.2:2345", Address: "127.0.0.2:2345",
@ -435,7 +435,7 @@ func TestHandler_TCP(t *testing.T) {
}, },
"test@myprovider": { "test@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.3:2345", Address: "127.0.0.3:2345",
@ -459,7 +459,7 @@ func TestHandler_TCP(t *testing.T) {
TCPServices: map[string]*runtime.TCPServiceInfo{ TCPServices: map[string]*runtime.TCPServiceInfo{
"bar@myprovider": { "bar@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1:2345", Address: "127.0.0.1:2345",
@ -483,7 +483,7 @@ func TestHandler_TCP(t *testing.T) {
TCPServices: map[string]*runtime.TCPServiceInfo{ TCPServices: map[string]*runtime.TCPServiceInfo{
"bar@myprovider": { "bar@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1:2345", Address: "127.0.0.1:2345",

View file

@ -91,7 +91,7 @@ func TestHandler_RawData(t *testing.T) {
TCPServices: map[string]*runtime.TCPServiceInfo{ TCPServices: map[string]*runtime.TCPServiceInfo{
"tcpfoo-service@myprovider": { "tcpfoo-service@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1", Address: "127.0.0.1",

View file

@ -35,7 +35,7 @@ func Collect(staticConfiguration *static.Configuration) error {
return err return err
} }
log.Infof("Anonymous stats sent to %s: %s", collectorURL, anonConfig) log.WithoutContext().Infof("Anonymous stats sent to %s: %s", collectorURL, anonConfig)
hashConf, err := hashstructure.Hash(staticConfiguration, nil) hashConf, err := hashstructure.Hash(staticConfiguration, nil)
if err != nil { if err != nil {

View file

@ -77,7 +77,7 @@ type WRRService struct {
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty"` Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty"`
} }
// SetDefaults Default values for a ServersLoadBalancer. // SetDefaults Default values for a WRRService.
func (w *WRRService) SetDefaults() { func (w *WRRService) SetDefaults() {
defaultWeight := 1 defaultWeight := 1
w.Weight = &defaultWeight w.Weight = &defaultWeight

View file

@ -18,7 +18,29 @@ type TCPConfiguration struct {
// TCPService holds a tcp service configuration (can only be of one type at the same time). // TCPService holds a tcp service configuration (can only be of one type at the same time).
type TCPService struct { type TCPService struct {
LoadBalancer *TCPLoadBalancerService `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"` LoadBalancer *TCPServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
Weighted *TCPWeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-"`
}
// +k8s:deepcopy-gen=true
// TCPWeightedRoundRobin is a weighted round robin tcp load-balancer of services.
type TCPWeightedRoundRobin struct {
Services []TCPWRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
}
// +k8s:deepcopy-gen=true
// TCPWRRService is a reference to a tcp service load-balanced with weighted round robin.
type TCPWRRService struct {
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty"`
}
// SetDefaults Default values for a TCPWRRService.
func (w *TCPWRRService) SetDefaults() {
defaultWeight := 1
w.Weight = &defaultWeight
} }
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true
@ -43,13 +65,25 @@ type RouterTCPTLSConfig struct {
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true
// TCPLoadBalancerService holds the LoadBalancerService configuration. // TCPServersLoadBalancer holds the LoadBalancerService configuration.
type TCPLoadBalancerService struct { type TCPServersLoadBalancer struct {
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"` // TerminationDelay, corresponds to the deadline that the proxy sets, after one
// of its connected peers indicates it has closed the writing capability of its
// connection, to close the reading capability as well, hence fully terminating the
// connection. It is a duration in milliseconds, defaulting to 100. A negative value
// means an infinite deadline (i.e. the reading capability is never closed).
TerminationDelay *int `json:"terminationDelay,omitempty" toml:"terminationDelay,omitempty" yaml:"terminationDelay,omitempty"`
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
}
// SetDefaults Default values for a TCPServersLoadBalancer
func (l *TCPServersLoadBalancer) SetDefaults() {
defaultTerminationDelay := 100 // in milliseconds
l.TerminationDelay = &defaultTerminationDelay
} }
// Mergeable tells if the given service is mergeable. // Mergeable tells if the given service is mergeable.
func (l *TCPLoadBalancerService) Mergeable(loadBalancer *TCPLoadBalancerService) bool { func (l *TCPServersLoadBalancer) Mergeable(loadBalancer *TCPServersLoadBalancer) bool {
savedServers := l.Servers savedServers := l.Servers
defer func() { defer func() {
l.Servers = savedServers l.Servers = savedServers

View file

@ -1152,27 +1152,6 @@ func (in *TCPConfiguration) DeepCopy() *TCPConfiguration {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TCPLoadBalancerService) DeepCopyInto(out *TCPLoadBalancerService) {
*out = *in
if in.Servers != nil {
in, out := &in.Servers, &out.Servers
*out = make([]TCPServer, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCPLoadBalancerService.
func (in *TCPLoadBalancerService) DeepCopy() *TCPLoadBalancerService {
if in == nil {
return nil
}
out := new(TCPLoadBalancerService)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TCPRouter) DeepCopyInto(out *TCPRouter) { func (in *TCPRouter) DeepCopyInto(out *TCPRouter) {
*out = *in *out = *in
@ -1215,12 +1194,43 @@ func (in *TCPServer) DeepCopy() *TCPServer {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TCPServersLoadBalancer) DeepCopyInto(out *TCPServersLoadBalancer) {
*out = *in
if in.TerminationDelay != nil {
in, out := &in.TerminationDelay, &out.TerminationDelay
*out = new(int)
**out = **in
}
if in.Servers != nil {
in, out := &in.Servers, &out.Servers
*out = make([]TCPServer, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCPServersLoadBalancer.
func (in *TCPServersLoadBalancer) DeepCopy() *TCPServersLoadBalancer {
if in == nil {
return nil
}
out := new(TCPServersLoadBalancer)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TCPService) DeepCopyInto(out *TCPService) { func (in *TCPService) DeepCopyInto(out *TCPService) {
*out = *in *out = *in
if in.LoadBalancer != nil { if in.LoadBalancer != nil {
in, out := &in.LoadBalancer, &out.LoadBalancer in, out := &in.LoadBalancer, &out.LoadBalancer
*out = new(TCPLoadBalancerService) *out = new(TCPServersLoadBalancer)
(*in).DeepCopyInto(*out)
}
if in.Weighted != nil {
in, out := &in.Weighted, &out.Weighted
*out = new(TCPWeightedRoundRobin)
(*in).DeepCopyInto(*out) (*in).DeepCopyInto(*out)
} }
return return
@ -1236,6 +1246,50 @@ func (in *TCPService) DeepCopy() *TCPService {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TCPWRRService) DeepCopyInto(out *TCPWRRService) {
*out = *in
if in.Weight != nil {
in, out := &in.Weight, &out.Weight
*out = new(int)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCPWRRService.
func (in *TCPWRRService) DeepCopy() *TCPWRRService {
if in == nil {
return nil
}
out := new(TCPWRRService)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TCPWeightedRoundRobin) DeepCopyInto(out *TCPWeightedRoundRobin) {
*out = *in
if in.Services != nil {
in, out := &in.Services, &out.Services
*out = make([]TCPWRRService, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCPWeightedRoundRobin.
func (in *TCPWeightedRoundRobin) DeepCopy() *TCPWeightedRoundRobin {
if in == nil {
return nil
}
out := new(TCPWeightedRoundRobin)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TLSCLientCertificateDNInfo) DeepCopyInto(out *TLSCLientCertificateDNInfo) { func (in *TLSCLientCertificateDNInfo) DeepCopyInto(out *TLSCLientCertificateDNInfo) {
*out = *in *out = *in

View file

@ -3,6 +3,7 @@ package flag
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"regexp"
"strings" "strings"
"github.com/containous/traefik/v2/pkg/config/parser" "github.com/containous/traefik/v2/pkg/config/parser"
@ -80,8 +81,8 @@ func (f *flagSet) parseOne() (bool, error) {
return true, nil return true, nil
} }
n := strings.ToLower(name) flagType := f.getFlagType(name)
if f.flagTypes[n] == reflect.Bool || f.flagTypes[n] == reflect.Ptr { if flagType == reflect.Bool || flagType == reflect.Ptr {
f.setValue(name, "true") f.setValue(name, "true")
return true, nil return true, nil
} }
@ -111,10 +112,30 @@ func (f *flagSet) setValue(name string, value string) {
} }
v, ok := f.values[key] v, ok := f.values[key]
if ok && f.flagTypes[strings.ToLower(name)] == reflect.Slice { if ok && f.getFlagType(name) == reflect.Slice {
f.values[key] = v + "," + value f.values[key] = v + "," + value
return return
} }
f.values[key] = value f.values[key] = value
} }
func (f *flagSet) getFlagType(name string) reflect.Kind {
neutral := strings.ToLower(name)
kind, ok := f.flagTypes[neutral]
if ok {
return kind
}
for n, k := range f.flagTypes {
if strings.Contains(n, parser.MapNamePlaceholder) {
p := strings.NewReplacer(".", `\.`, parser.MapNamePlaceholder, `([^.]+)`).Replace(n)
if regexp.MustCompile(p).MatchString(neutral) {
return k
}
}
}
return reflect.Invalid
}

View file

@ -250,7 +250,7 @@ func TestParse(t *testing.T) {
}, },
}, },
{ {
desc: "map struct with sub-map case senstitive", desc: "map struct with sub-map case sensitive",
args: []string{"--foo.Name1.bar.name2.value=firstValue", "--foo.naMe1.bar.name2.value=secondValue"}, args: []string{"--foo.Name1.bar.name2.value=firstValue", "--foo.naMe1.bar.name2.value=secondValue"},
element: &struct { element: &struct {
Foo map[string]struct { Foo map[string]struct {
@ -273,6 +273,20 @@ func TestParse(t *testing.T) {
"traefik.foo.Name1.bar.name2.value": "secondValue", "traefik.foo.Name1.bar.name2.value": "secondValue",
}, },
}, },
{
desc: "pointer of struct and map without explicit value",
args: []string{"--foo.default.bar.fuu"},
element: &struct {
Foo map[string]struct {
Bar *struct {
Fuu *struct{ Value string }
}
}
}{},
expected: map[string]string{
"traefik.foo.default.bar.fuu": "true",
},
},
{ {
desc: "slice with several flags 2 and different cases.", desc: "slice with several flags 2 and different cases.",
args: []string{"--foo", "bar", "--Foo", "baz"}, args: []string{"--foo", "bar", "--Foo", "baz"},

View file

@ -170,7 +170,9 @@ func TestDecodeConfiguration(t *testing.T) {
"traefik.tcp.routers.Router1.tls.options": "foo", "traefik.tcp.routers.Router1.tls.options": "foo",
"traefik.tcp.routers.Router1.tls.passthrough": "false", "traefik.tcp.routers.Router1.tls.passthrough": "false",
"traefik.tcp.services.Service0.loadbalancer.server.Port": "42", "traefik.tcp.services.Service0.loadbalancer.server.Port": "42",
"traefik.tcp.services.Service0.loadbalancer.TerminationDelay": "42",
"traefik.tcp.services.Service1.loadbalancer.server.Port": "42", "traefik.tcp.services.Service1.loadbalancer.server.Port": "42",
"traefik.tcp.services.Service1.loadbalancer.TerminationDelay": "42",
} }
configuration, err := DecodeConfiguration(labels) configuration, err := DecodeConfiguration(labels)
@ -206,21 +208,23 @@ func TestDecodeConfiguration(t *testing.T) {
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"Service0": { "Service0": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Port: "42", Port: "42",
}, },
}, },
TerminationDelay: func(i int) *int { return &i }(42),
}, },
}, },
"Service1": { "Service1": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Port: "42", Port: "42",
}, },
}, },
TerminationDelay: func(i int) *int { return &i }(42),
}, },
}, },
}, },
@ -610,7 +614,7 @@ func TestEncodeConfiguration(t *testing.T) {
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"Service0": { "Service0": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Port: "42", Port: "42",
@ -619,7 +623,7 @@ func TestEncodeConfiguration(t *testing.T) {
}, },
}, },
"Service1": { "Service1": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Port: "42", Port: "42",

View file

@ -488,7 +488,7 @@ func TestPopulateUsedBy(t *testing.T) {
TCPServices: map[string]*runtime.TCPServiceInfo{ TCPServices: map[string]*runtime.TCPServiceInfo{
"foo-service@myprovider": { "foo-service@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1", Address: "127.0.0.1",
@ -522,7 +522,7 @@ func TestPopulateUsedBy(t *testing.T) {
TCPServices: map[string]*runtime.TCPServiceInfo{ TCPServices: map[string]*runtime.TCPServiceInfo{
"foo-service@myprovider": { "foo-service@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1", Address: "127.0.0.1",
@ -598,7 +598,7 @@ func TestPopulateUsedBy(t *testing.T) {
TCPServices: map[string]*runtime.TCPServiceInfo{ TCPServices: map[string]*runtime.TCPServiceInfo{
"foo-service@myprovider": { "foo-service@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1", Address: "127.0.0.1",
@ -614,7 +614,7 @@ func TestPopulateUsedBy(t *testing.T) {
}, },
"bar-service@myprovider": { "bar-service@myprovider": {
TCPService: &dynamic.TCPService{ TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1", Address: "127.0.0.1",

View file

@ -71,8 +71,8 @@ type CertificateResolver struct {
// Global holds the global configuration. // Global holds the global configuration.
type Global struct { type Global struct {
CheckNewVersion bool `description:"Periodically check if a new version has been released." json:"checkNewVersion,omitempty" toml:"checkNewVersion,omitempty" yaml:"checkNewVersion,omitempty" label:"allowEmpty" export:"true"` CheckNewVersion bool `description:"Periodically check if a new version has been released." json:"checkNewVersion,omitempty" toml:"checkNewVersion,omitempty" yaml:"checkNewVersion,omitempty" label:"allowEmpty" export:"true"`
SendAnonymousUsage *bool `description:"Periodically send anonymous usage statistics. If the option is not specified, it will be enabled by default." json:"sendAnonymousUsage,omitempty" toml:"sendAnonymousUsage,omitempty" yaml:"sendAnonymousUsage,omitempty" label:"allowEmpty" export:"true"` SendAnonymousUsage bool `description:"Periodically send anonymous usage statistics. If the option is not specified, it will be enabled by default." json:"sendAnonymousUsage,omitempty" toml:"sendAnonymousUsage,omitempty" yaml:"sendAnonymousUsage,omitempty" label:"allowEmpty" export:"true"`
} }
// ServersTransport options to configure communication between Traefik and the servers // ServersTransport options to configure communication between Traefik and the servers
@ -238,13 +238,15 @@ func getSafeACMECAServer(caServerSrc string) string {
if strings.HasPrefix(caServerSrc, "https://acme-v01.api.letsencrypt.org") { if strings.HasPrefix(caServerSrc, "https://acme-v01.api.letsencrypt.org") {
caServer := strings.Replace(caServerSrc, "v01", "v02", 1) caServer := strings.Replace(caServerSrc, "v01", "v02", 1)
log.Warnf("The CA server %[1]q refers to a v01 endpoint of the ACME API, please change to %[2]q. Fallback to %[2]q.", caServerSrc, caServer) log.WithoutContext().
Warnf("The CA server %[1]q refers to a v01 endpoint of the ACME API, please change to %[2]q. Fallback to %[2]q.", caServerSrc, caServer)
return caServer return caServer
} }
if strings.HasPrefix(caServerSrc, "https://acme-staging.api.letsencrypt.org") { if strings.HasPrefix(caServerSrc, "https://acme-staging.api.letsencrypt.org") {
caServer := strings.Replace(caServerSrc, "https://acme-staging.api.letsencrypt.org", "https://acme-staging-v02.api.letsencrypt.org", 1) caServer := strings.Replace(caServerSrc, "https://acme-staging.api.letsencrypt.org", "https://acme-staging-v02.api.letsencrypt.org", 1)
log.Warnf("The CA server %[1]q refers to a v01 endpoint of the ACME API, please change to %[2]q. Fallback to %[2]q.", caServerSrc, caServer) log.WithoutContext().
Warnf("The CA server %[1]q refers to a v01 endpoint of the ACME API, please change to %[2]q. Fallback to %[2]q.", caServerSrc, caServer)
return caServer return caServer
} }

View file

@ -122,37 +122,41 @@ func (hc *HealthCheck) SetBackendsConfiguration(parentCtx context.Context, backe
} }
func (hc *HealthCheck) execute(ctx context.Context, backend *BackendConfig) { func (hc *HealthCheck) execute(ctx context.Context, backend *BackendConfig) {
log.Debugf("Initial health check for backend: %q", backend.name) logger := log.FromContext(ctx)
hc.checkBackend(backend) logger.Debugf("Initial health check for backend: %q", backend.name)
hc.checkBackend(ctx, backend)
ticker := time.NewTicker(backend.Interval) ticker := time.NewTicker(backend.Interval)
defer ticker.Stop() defer ticker.Stop()
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
log.Debugf("Stopping current health check goroutines of backend: %s", backend.name) logger.Debugf("Stopping current health check goroutines of backend: %s", backend.name)
return return
case <-ticker.C: case <-ticker.C:
log.Debugf("Refreshing health check for backend: %s", backend.name) logger.Debugf("Refreshing health check for backend: %s", backend.name)
hc.checkBackend(backend) hc.checkBackend(ctx, backend)
} }
} }
} }
func (hc *HealthCheck) checkBackend(backend *BackendConfig) { func (hc *HealthCheck) checkBackend(ctx context.Context, backend *BackendConfig) {
logger := log.FromContext(ctx)
enabledURLs := backend.LB.Servers() enabledURLs := backend.LB.Servers()
var newDisabledURLs []backendURL var newDisabledURLs []backendURL
// FIXME re enable metrics // FIXME re enable metrics
for _, disableURL := range backend.disabledURLs { for _, disableURL := range backend.disabledURLs {
// FIXME serverUpMetricValue := float64(0) // FIXME serverUpMetricValue := float64(0)
if err := checkHealth(disableURL.url, backend); err == nil { if err := checkHealth(disableURL.url, backend); err == nil {
log.Warnf("Health check up: Returning to server list. Backend: %q URL: %q Weight: %d", logger.Warnf("Health check up: Returning to server list. Backend: %q URL: %q Weight: %d",
backend.name, disableURL.url.String(), disableURL.weight) backend.name, disableURL.url.String(), disableURL.weight)
if err = backend.LB.UpsertServer(disableURL.url, roundrobin.Weight(disableURL.weight)); err != nil { if err = backend.LB.UpsertServer(disableURL.url, roundrobin.Weight(disableURL.weight)); err != nil {
log.Error(err) logger.Error(err)
} }
// FIXME serverUpMetricValue = 1 // FIXME serverUpMetricValue = 1
} else { } else {
log.Warnf("Health check still failing. Backend: %q URL: %q Reason: %s", backend.name, disableURL.url.String(), err) logger.Warnf("Health check still failing. Backend: %q URL: %q Reason: %s", backend.name, disableURL.url.String(), err)
newDisabledURLs = append(newDisabledURLs, disableURL) newDisabledURLs = append(newDisabledURLs, disableURL)
} }
// FIXME labelValues := []string{"backend", backend.name, "url", backendurl.url.String()} // FIXME labelValues := []string{"backend", backend.name, "url", backendurl.url.String()}
@ -173,9 +177,9 @@ func (hc *HealthCheck) checkBackend(backend *BackendConfig) {
weight = 1 weight = 1
} }
} }
log.Warnf("Health check failed: Remove from server list. Backend: %q URL: %q Weight: %d Reason: %s", backend.name, enableURL.String(), weight, err) logger.Warnf("Health check failed: Remove from server list. Backend: %q URL: %q Weight: %d Reason: %s", backend.name, enableURL.String(), weight, err)
if err := backend.LB.RemoveServer(enableURL); err != nil { if err := backend.LB.RemoveServer(enableURL); err != nil {
log.Error(err) logger.Error(err)
} }
backend.disabledURLs = append(backend.disabledURLs, backendURL{enableURL, weight}) backend.disabledURLs = append(backend.disabledURLs, backendURL{enableURL, weight})
// FIXME serverUpMetricValue = 0 // FIXME serverUpMetricValue = 0
@ -244,10 +248,10 @@ func checkHealth(serverURL *url.URL, backend *BackendConfig) error {
} }
// NewLBStatusUpdater returns a new LbStatusUpdater // NewLBStatusUpdater returns a new LbStatusUpdater
func NewLBStatusUpdater(bh BalancerHandler, svinfo *runtime.ServiceInfo) *LbStatusUpdater { func NewLBStatusUpdater(bh BalancerHandler, info *runtime.ServiceInfo) *LbStatusUpdater {
return &LbStatusUpdater{ return &LbStatusUpdater{
BalancerHandler: bh, BalancerHandler: bh,
serviceInfo: svinfo, serviceInfo: info,
} }
} }

View file

@ -62,12 +62,6 @@ func Panic(args ...interface{}) {
mainLogger.Panic(args...) mainLogger.Panic(args...)
} }
// Panicf logs a message at level Panic on the standard logger.
// Deprecated
func Panicf(format string, args ...interface{}) {
mainLogger.Panicf(format, args...)
}
// Fatal logs a message at level Fatal on the standard logger. // Fatal logs a message at level Fatal on the standard logger.
// Deprecated // Deprecated
func Fatal(args ...interface{}) { func Fatal(args ...interface{}) {

View file

@ -12,4 +12,5 @@ const (
MetricsProviderName = "metricsProviderName" MetricsProviderName = "metricsProviderName"
TracingProviderName = "tracingProviderName" TracingProviderName = "tracingProviderName"
ServerName = "serverName" ServerName = "serverName"
TLSStoreName = "tlsStoreName"
) )

View file

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/ext"
@ -24,7 +25,7 @@ type addPrefix struct {
// New creates a new handler. // New creates a new handler.
func New(ctx context.Context, next http.Handler, config dynamic.AddPrefix, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.AddPrefix, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
var result *addPrefix var result *addPrefix
if len(config.Prefix) > 0 { if len(config.Prefix) > 0 {
@ -45,7 +46,7 @@ func (ap *addPrefix) GetTracingInformation() (string, ext.SpanKindEnum) {
} }
func (ap *addPrefix) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (ap *addPrefix) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), ap.name, typeName) logger := log.FromContext(middlewares.GetLoggerCtx(req.Context(), ap.name, typeName))
oldURLPath := req.URL.Path oldURLPath := req.URL.Path
req.URL.Path = ap.prefix + req.URL.Path req.URL.Path = ap.prefix + req.URL.Path

View file

@ -9,6 +9,7 @@ import (
goauth "github.com/abbot/go-http-auth" goauth "github.com/abbot/go-http-auth"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/middlewares/accesslog" "github.com/containous/traefik/v2/pkg/middlewares/accesslog"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
@ -30,7 +31,7 @@ type basicAuth struct {
// NewBasic creates a basicAuth middleware. // NewBasic creates a basicAuth middleware.
func NewBasic(ctx context.Context, next http.Handler, authConfig dynamic.BasicAuth, name string) (http.Handler, error) { func NewBasic(ctx context.Context, next http.Handler, authConfig dynamic.BasicAuth, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, basicTypeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, basicTypeName)).Debug("Creating middleware")
users, err := getUsers(authConfig.UsersFile, authConfig.Users, basicUserParser) users, err := getUsers(authConfig.UsersFile, authConfig.Users, basicUserParser)
if err != nil { if err != nil {
return nil, err return nil, err
@ -58,7 +59,7 @@ func (b *basicAuth) GetTracingInformation() (string, ext.SpanKindEnum) {
} }
func (b *basicAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (b *basicAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), b.name, basicTypeName) logger := log.FromContext(middlewares.GetLoggerCtx(req.Context(), b.name, basicTypeName))
if username := b.auth.CheckAuth(req); username == "" { if username := b.auth.CheckAuth(req); username == "" {
logger.Debug("Authentication failed") logger.Debug("Authentication failed")

View file

@ -210,9 +210,6 @@ func TestBasicAuthUsersFromFile(t *testing.T) {
} }
for _, test := range testCases { for _, test := range testCases {
if test.desc != "Should skip comments" {
continue
}
test := test test := test
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()

View file

@ -9,6 +9,7 @@ import (
goauth "github.com/abbot/go-http-auth" goauth "github.com/abbot/go-http-auth"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/middlewares/accesslog" "github.com/containous/traefik/v2/pkg/middlewares/accesslog"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
@ -30,7 +31,7 @@ type digestAuth struct {
// NewDigest creates a digest auth middleware. // NewDigest creates a digest auth middleware.
func NewDigest(ctx context.Context, next http.Handler, authConfig dynamic.DigestAuth, name string) (http.Handler, error) { func NewDigest(ctx context.Context, next http.Handler, authConfig dynamic.DigestAuth, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, digestTypeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, digestTypeName)).Debug("Creating middleware")
users, err := getUsers(authConfig.UsersFile, authConfig.Users, digestUserParser) users, err := getUsers(authConfig.UsersFile, authConfig.Users, digestUserParser)
if err != nil { if err != nil {
return nil, err return nil, err
@ -58,7 +59,7 @@ func (d *digestAuth) GetTracingInformation() (string, ext.SpanKindEnum) {
} }
func (d *digestAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (d *digestAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), d.name, digestTypeName) logger := log.FromContext(middlewares.GetLoggerCtx(req.Context(), d.name, digestTypeName))
if username, _ := d.auth.CheckAuth(req); username == "" { if username, _ := d.auth.CheckAuth(req); username == "" {
logger.Debug("Digest authentication failed") logger.Debug("Digest authentication failed")

View file

@ -10,6 +10,7 @@ import (
"strings" "strings"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/ext"
@ -34,7 +35,7 @@ type forwardAuth struct {
// NewForward creates a forward auth middleware. // NewForward creates a forward auth middleware.
func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAuth, name string) (http.Handler, error) { func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAuth, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, forwardedTypeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, forwardedTypeName)).Debug("Creating middleware")
fa := &forwardAuth{ fa := &forwardAuth{
address: config.Address, address: config.Address,
@ -61,7 +62,7 @@ func (fa *forwardAuth) GetTracingInformation() (string, ext.SpanKindEnum) {
} }
func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), fa.name, forwardedTypeName) logger := log.FromContext(middlewares.GetLoggerCtx(req.Context(), fa.name, forwardedTypeName))
// Ensure our request client does not follow redirects // Ensure our request client does not follow redirects
httpClient := http.Client{ httpClient := http.Client{

View file

@ -5,6 +5,7 @@ import (
"net/http" "net/http"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/ext"
@ -22,7 +23,7 @@ type buffer struct {
// New creates a buffering middleware. // New creates a buffering middleware.
func New(ctx context.Context, next http.Handler, config dynamic.Buffering, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.Buffering, name string) (http.Handler, error) {
logger := middlewares.GetLogger(ctx, name, typeName) logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName))
logger.Debug("Creating middleware") logger.Debug("Creating middleware")
logger.Debugf("Setting up buffering: request limits: %d (mem), %d (max), response limits: %d (mem), %d (max) with retry: '%s'", logger.Debugf("Setting up buffering: request limits: %d (mem), %d (max), response limits: %d (mem), %d (max) with retry: '%s'",
config.MemRequestBodyBytes, config.MaxRequestBodyBytes, config.MemResponseBodyBytes, config.MaxResponseBodyBytes, config.RetryExpression) config.MemRequestBodyBytes, config.MaxRequestBodyBytes, config.MemResponseBodyBytes, config.MaxResponseBodyBytes, config.RetryExpression)

View file

@ -6,6 +6,7 @@ import (
"github.com/containous/alice" "github.com/containous/alice"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
) )
@ -19,7 +20,7 @@ type chainBuilder interface {
// New creates a chain middleware // New creates a chain middleware
func New(ctx context.Context, next http.Handler, config dynamic.Chain, builder chainBuilder, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.Chain, builder chainBuilder, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
middlewareChain := builder.BuildChain(ctx, config.Middlewares) middlewareChain := builder.BuildChain(ctx, config.Middlewares)
return middlewareChain.Then(next) return middlewareChain.Then(next)

View file

@ -25,7 +25,7 @@ type circuitBreaker struct {
func New(ctx context.Context, next http.Handler, confCircuitBreaker dynamic.CircuitBreaker, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, confCircuitBreaker dynamic.CircuitBreaker, name string) (http.Handler, error) {
expression := confCircuitBreaker.Expression expression := confCircuitBreaker.Expression
logger := middlewares.GetLogger(ctx, name, typeName) logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName))
logger.Debug("Creating middleware") logger.Debug("Creating middleware")
logger.Debug("Setting up with expression: %s", expression) logger.Debug("Setting up with expression: %s", expression)
@ -56,6 +56,5 @@ func (c *circuitBreaker) GetTracingInformation() (string, ext.SpanKindEnum) {
} }
func (c *circuitBreaker) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (c *circuitBreaker) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
middlewares.GetLogger(req.Context(), c.name, typeName).Debug("Entering middleware")
c.circuitBreaker.ServeHTTP(rw, req) c.circuitBreaker.ServeHTTP(rw, req)
} }

View file

@ -7,10 +7,10 @@ import (
"strings" "strings"
"github.com/NYTimes/gziphandler" "github.com/NYTimes/gziphandler"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/ext"
"github.com/sirupsen/logrus"
) )
const ( const (
@ -25,7 +25,7 @@ type compress struct {
// New creates a new compress middleware. // New creates a new compress middleware.
func New(ctx context.Context, next http.Handler, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
return &compress{ return &compress{
next: next, next: next,
@ -38,7 +38,8 @@ func (c *compress) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if strings.HasPrefix(contentType, "application/grpc") { if strings.HasPrefix(contentType, "application/grpc") {
c.next.ServeHTTP(rw, req) c.next.ServeHTTP(rw, req)
} else { } else {
gzipHandler(c.next, middlewares.GetLogger(req.Context(), c.name, typeName)).ServeHTTP(rw, req) ctx := middlewares.GetLoggerCtx(req.Context(), c.name, typeName)
gzipHandler(ctx, c.next).ServeHTTP(rw, req)
} }
} }
@ -46,12 +47,12 @@ func (c *compress) GetTracingInformation() (string, ext.SpanKindEnum) {
return c.name, tracing.SpanKindNoneEnum return c.name, tracing.SpanKindNoneEnum
} }
func gzipHandler(h http.Handler, logger logrus.FieldLogger) http.Handler { func gzipHandler(ctx context.Context, h http.Handler) http.Handler {
wrapper, err := gziphandler.GzipHandlerWithOpts( wrapper, err := gziphandler.GzipHandlerWithOpts(
gziphandler.CompressionLevel(gzip.DefaultCompression), gziphandler.CompressionLevel(gzip.DefaultCompression),
gziphandler.MinSize(gziphandler.DefaultMinSize)) gziphandler.MinSize(gziphandler.DefaultMinSize))
if err != nil { if err != nil {
logger.Error(err) log.FromContext(ctx).Error(err)
} }
return wrapper(h) return wrapper(h)

View file

@ -12,6 +12,7 @@ import (
"strings" "strings"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/containous/traefik/v2/pkg/types" "github.com/containous/traefik/v2/pkg/types"
@ -43,7 +44,7 @@ type customErrors struct {
// New creates a new custom error pages middleware. // New creates a new custom error pages middleware.
func New(ctx context.Context, next http.Handler, config dynamic.ErrorPage, serviceBuilder serviceBuilder, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.ErrorPage, serviceBuilder serviceBuilder, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
httpCodeRanges, err := types.NewHTTPCodeRanges(config.Status) httpCodeRanges, err := types.NewHTTPCodeRanges(config.Status)
if err != nil { if err != nil {
@ -69,7 +70,8 @@ func (c *customErrors) GetTracingInformation() (string, ext.SpanKindEnum) {
} }
func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), c.name, typeName) ctx := middlewares.GetLoggerCtx(req.Context(), c.name, typeName)
logger := log.FromContext(ctx)
if c.backendHandler == nil { if c.backendHandler == nil {
logger.Error("Error pages: no backend handler.") logger.Error("Error pages: no backend handler.")
@ -78,7 +80,7 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return return
} }
recorder := newResponseRecorder(rw, middlewares.GetLogger(context.Background(), "test", typeName)) recorder := newResponseRecorder(ctx, rw)
c.next.ServeHTTP(recorder, req) c.next.ServeHTTP(recorder, req)
// check the recorder code against the configured http status code ranges // check the recorder code against the configured http status code ranges
@ -103,7 +105,7 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return return
} }
recorderErrorPage := newResponseRecorder(rw, middlewares.GetLogger(context.Background(), "test", typeName)) recorderErrorPage := newResponseRecorder(ctx, rw)
utils.CopyHeaders(pageReq.Header, req.Header) utils.CopyHeaders(pageReq.Header, req.Header)
c.backendHandler.ServeHTTP(recorderErrorPage, pageReq.WithContext(req.Context())) c.backendHandler.ServeHTTP(recorderErrorPage, pageReq.WithContext(req.Context()))
@ -151,13 +153,13 @@ type responseRecorder interface {
} }
// newResponseRecorder returns an initialized responseRecorder. // newResponseRecorder returns an initialized responseRecorder.
func newResponseRecorder(rw http.ResponseWriter, logger logrus.FieldLogger) responseRecorder { func newResponseRecorder(ctx context.Context, rw http.ResponseWriter) responseRecorder {
recorder := &responseRecorderWithoutCloseNotify{ recorder := &responseRecorderWithoutCloseNotify{
HeaderMap: make(http.Header), HeaderMap: make(http.Header),
Body: new(bytes.Buffer), Body: new(bytes.Buffer),
Code: http.StatusOK, Code: http.StatusOK,
responseWriter: rw, responseWriter: rw,
logger: logger, logger: log.FromContext(ctx),
} }
if _, ok := rw.(http.CloseNotifier); ok { if _, ok := rw.(http.CloseNotifier); ok {
return &responseRecorderWithCloseNotify{recorder} return &responseRecorderWithCloseNotify{recorder}

View file

@ -8,7 +8,6 @@ import (
"testing" "testing"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/testhelpers" "github.com/containous/traefik/v2/pkg/testhelpers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -151,7 +150,7 @@ func TestNewResponseRecorder(t *testing.T) {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()
rec := newResponseRecorder(test.rw, middlewares.GetLogger(context.Background(), "test", typeName)) rec := newResponseRecorder(context.Background(), test.rw)
assert.IsType(t, rec, test.expected) assert.IsType(t, rec, test.expected)
}) })
} }

View file

@ -9,6 +9,7 @@ import (
"strings" "strings"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/ext"
@ -27,8 +28,9 @@ type headers struct {
// New creates a Headers middleware. // New creates a Headers middleware.
func New(ctx context.Context, next http.Handler, config dynamic.Headers, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.Headers, name string) (http.Handler, error) {
// HeaderMiddleware -> SecureMiddleWare -> next // HeaderMiddleware -> SecureMiddleWare -> next
logger := middlewares.GetLogger(ctx, name, typeName) logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName))
logger.Debug("Creating middleware") logger.Debug("Creating middleware")
hasSecureHeaders := config.HasSecureHeadersDefined() hasSecureHeaders := config.HasSecureHeadersDefined()
hasCustomHeaders := config.HasCustomHeadersDefined() hasCustomHeaders := config.HasCustomHeadersDefined()
hasCorsHeaders := config.HasCorsHeadersDefined() hasCorsHeaders := config.HasCorsHeadersDefined()

View file

@ -8,10 +8,10 @@ import (
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/ip" "github.com/containous/traefik/v2/pkg/ip"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/ext"
"github.com/sirupsen/logrus"
) )
const ( const (
@ -28,7 +28,7 @@ type ipWhiteLister struct {
// New builds a new IPWhiteLister given a list of CIDR-Strings to whitelist // New builds a new IPWhiteLister given a list of CIDR-Strings to whitelist
func New(ctx context.Context, next http.Handler, config dynamic.IPWhiteList, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.IPWhiteList, name string) (http.Handler, error) {
logger := middlewares.GetLogger(ctx, name, typeName) logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName))
logger.Debug("Creating middleware") logger.Debug("Creating middleware")
if len(config.SourceRange) == 0 { if len(config.SourceRange) == 0 {
@ -46,6 +46,7 @@ func New(ctx context.Context, next http.Handler, config dynamic.IPWhiteList, nam
} }
logger.Debugf("Setting up IPWhiteLister with sourceRange: %s", config.SourceRange) logger.Debugf("Setting up IPWhiteLister with sourceRange: %s", config.SourceRange)
return &ipWhiteLister{ return &ipWhiteLister{
strategy: strategy, strategy: strategy,
whiteLister: checker, whiteLister: checker,
@ -59,14 +60,15 @@ func (wl *ipWhiteLister) GetTracingInformation() (string, ext.SpanKindEnum) {
} }
func (wl *ipWhiteLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (wl *ipWhiteLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), wl.name, typeName) ctx := middlewares.GetLoggerCtx(req.Context(), wl.name, typeName)
logger := log.FromContext(ctx)
err := wl.whiteLister.IsAuthorized(wl.strategy.GetIP(req)) err := wl.whiteLister.IsAuthorized(wl.strategy.GetIP(req))
if err != nil { if err != nil {
logMessage := fmt.Sprintf("rejecting request %+v: %v", req, err) logMessage := fmt.Sprintf("rejecting request %+v: %v", req, err)
logger.Debug(logMessage) logger.Debug(logMessage)
tracing.SetErrorWithEvent(req, logMessage) tracing.SetErrorWithEvent(req, logMessage)
reject(logger, rw) reject(ctx, rw)
return return
} }
logger.Debugf("Accept %s: %+v", wl.strategy.GetIP(req), req) logger.Debugf("Accept %s: %+v", wl.strategy.GetIP(req), req)
@ -74,12 +76,12 @@ func (wl *ipWhiteLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
wl.next.ServeHTTP(rw, req) wl.next.ServeHTTP(rw, req)
} }
func reject(logger logrus.FieldLogger, rw http.ResponseWriter) { func reject(ctx context.Context, rw http.ResponseWriter) {
statusCode := http.StatusForbidden statusCode := http.StatusForbidden
rw.WriteHeader(statusCode) rw.WriteHeader(statusCode)
_, err := rw.Write([]byte(http.StatusText(statusCode))) _, err := rw.Write([]byte(http.StatusText(statusCode)))
if err != nil { if err != nil {
logger.Error(err) log.FromContext(ctx).Error(err)
} }
} }

View file

@ -39,7 +39,7 @@ type metricsMiddleware struct {
// NewEntryPointMiddleware creates a new metrics middleware for an Entrypoint. // NewEntryPointMiddleware creates a new metrics middleware for an Entrypoint.
func NewEntryPointMiddleware(ctx context.Context, next http.Handler, registry metrics.Registry, entryPointName string) http.Handler { func NewEntryPointMiddleware(ctx context.Context, next http.Handler, registry metrics.Registry, entryPointName string) http.Handler {
middlewares.GetLogger(ctx, nameEntrypoint, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, nameEntrypoint, typeName)).Debug("Creating middleware")
return &metricsMiddleware{ return &metricsMiddleware{
next: next, next: next,
@ -52,7 +52,7 @@ func NewEntryPointMiddleware(ctx context.Context, next http.Handler, registry me
// NewServiceMiddleware creates a new metrics middleware for a Service. // NewServiceMiddleware creates a new metrics middleware for a Service.
func NewServiceMiddleware(ctx context.Context, next http.Handler, registry metrics.Registry, serviceName string) http.Handler { func NewServiceMiddleware(ctx context.Context, next http.Handler, registry metrics.Registry, serviceName string) http.Handler {
middlewares.GetLogger(ctx, nameService, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, nameService, typeName)).Debug("Creating middleware")
return &metricsMiddleware{ return &metricsMiddleware{
next: next, next: next,

View file

@ -4,10 +4,9 @@ import (
"context" "context"
"github.com/containous/traefik/v2/pkg/log" "github.com/containous/traefik/v2/pkg/log"
"github.com/sirupsen/logrus"
) )
// GetLogger creates a logger configured with the middleware fields. // GetLoggerCtx creates a logger context with the middleware fields.
func GetLogger(ctx context.Context, middleware string, middlewareType string) logrus.FieldLogger { func GetLoggerCtx(ctx context.Context, middleware string, middlewareType string) context.Context {
return log.FromContext(ctx).WithField(log.MiddlewareName, middleware).WithField(log.MiddlewareType, middlewareType) return log.With(ctx, log.Str(log.MiddlewareName, middleware), log.Str(log.MiddlewareType, middlewareType))
} }

View file

@ -16,7 +16,6 @@ import (
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/ext"
"github.com/sirupsen/logrus"
) )
const ( const (
@ -66,7 +65,7 @@ type passTLSClientCert struct {
// New constructs a new PassTLSClientCert instance from supplied frontend header struct. // New constructs a new PassTLSClientCert instance from supplied frontend header struct.
func New(ctx context.Context, next http.Handler, config dynamic.PassTLSClientCert, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.PassTLSClientCert, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
return &passTLSClientCert{ return &passTLSClientCert{
next: next, next: next,
@ -104,11 +103,13 @@ func (p *passTLSClientCert) GetTracingInformation() (string, ext.SpanKindEnum) {
} }
func (p *passTLSClientCert) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (p *passTLSClientCert) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), p.name, typeName) ctx := middlewares.GetLoggerCtx(req.Context(), p.name, typeName)
p.modifyRequestHeaders(logger, req)
p.modifyRequestHeaders(ctx, req)
p.next.ServeHTTP(rw, req) p.next.ServeHTTP(rw, req)
} }
func getDNInfo(prefix string, options *DistinguishedNameOptions, cs *pkix.Name) string {
func getDNInfo(ctx context.Context, prefix string, options *DistinguishedNameOptions, cs *pkix.Name) string {
if options == nil { if options == nil {
return "" return ""
} }
@ -124,27 +125,27 @@ func getDNInfo(prefix string, options *DistinguishedNameOptions, cs *pkix.Name)
} }
if options.CountryName { if options.CountryName {
writeParts(content, cs.Country, "C") writeParts(ctx, content, cs.Country, "C")
} }
if options.StateOrProvinceName { if options.StateOrProvinceName {
writeParts(content, cs.Province, "ST") writeParts(ctx, content, cs.Province, "ST")
} }
if options.LocalityName { if options.LocalityName {
writeParts(content, cs.Locality, "L") writeParts(ctx, content, cs.Locality, "L")
} }
if options.OrganizationName { if options.OrganizationName {
writeParts(content, cs.Organization, "O") writeParts(ctx, content, cs.Organization, "O")
} }
if options.SerialNumber { if options.SerialNumber {
writePart(content, cs.SerialNumber, "SN") writePart(ctx, content, cs.SerialNumber, "SN")
} }
if options.CommonName { if options.CommonName {
writePart(content, cs.CommonName, "CN") writePart(ctx, content, cs.CommonName, "CN")
} }
if content.Len() > 0 { if content.Len() > 0 {
@ -154,24 +155,24 @@ func getDNInfo(prefix string, options *DistinguishedNameOptions, cs *pkix.Name)
return "" return ""
} }
func writeParts(content io.StringWriter, entries []string, prefix string) { func writeParts(ctx context.Context, content io.StringWriter, entries []string, prefix string) {
for _, entry := range entries { for _, entry := range entries {
writePart(content, entry, prefix) writePart(ctx, content, entry, prefix)
} }
} }
func writePart(content io.StringWriter, entry string, prefix string) { func writePart(ctx context.Context, content io.StringWriter, entry string, prefix string) {
if len(entry) > 0 { if len(entry) > 0 {
_, err := content.WriteString(fmt.Sprintf("%s=%s,", prefix, entry)) _, err := content.WriteString(fmt.Sprintf("%s=%s,", prefix, entry))
if err != nil { if err != nil {
log.Error(err) log.FromContext(ctx).Error(err)
} }
} }
} }
// getXForwardedTLSClientCertInfo Build a string with the wanted client certificates information // getXForwardedTLSClientCertInfo Build a string with the wanted client certificates information
// like Subject="C=%s,ST=%s,L=%s,O=%s,CN=%s",NB=%d,NA=%d,SAN=%s; // like Subject="C=%s,ST=%s,L=%s,O=%s,CN=%s",NB=%d,NA=%d,SAN=%s;
func (p *passTLSClientCert) getXForwardedTLSClientCertInfo(certs []*x509.Certificate) string { func (p *passTLSClientCert) getXForwardedTLSClientCertInfo(ctx context.Context, certs []*x509.Certificate) string {
var headerValues []string var headerValues []string
for _, peerCert := range certs { for _, peerCert := range certs {
@ -181,12 +182,12 @@ func (p *passTLSClientCert) getXForwardedTLSClientCertInfo(certs []*x509.Certifi
var na string var na string
if p.info != nil { if p.info != nil {
subject := getDNInfo("Subject", p.info.subject, &peerCert.Subject) subject := getDNInfo(ctx, "Subject", p.info.subject, &peerCert.Subject)
if len(subject) > 0 { if len(subject) > 0 {
values = append(values, subject) values = append(values, subject)
} }
issuer := getDNInfo("Issuer", p.info.issuer, &peerCert.Issuer) issuer := getDNInfo(ctx, "Issuer", p.info.issuer, &peerCert.Issuer)
if len(issuer) > 0 { if len(issuer) > 0 {
values = append(values, issuer) values = append(values, issuer)
} }
@ -217,10 +218,12 @@ func (p *passTLSClientCert) getXForwardedTLSClientCertInfo(certs []*x509.Certifi
} }
// modifyRequestHeaders set the wanted headers with the certificates information. // modifyRequestHeaders set the wanted headers with the certificates information.
func (p *passTLSClientCert) modifyRequestHeaders(logger logrus.FieldLogger, r *http.Request) { func (p *passTLSClientCert) modifyRequestHeaders(ctx context.Context, r *http.Request) {
logger := log.FromContext(ctx)
if p.pem { if p.pem {
if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 { if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
r.Header.Set(xForwardedTLSClientCert, getXForwardedTLSClientCert(logger, r.TLS.PeerCertificates)) r.Header.Set(xForwardedTLSClientCert, getXForwardedTLSClientCert(ctx, r.TLS.PeerCertificates))
} else { } else {
logger.Warn("Tried to extract a certificate on a request without mutual TLS") logger.Warn("Tried to extract a certificate on a request without mutual TLS")
} }
@ -228,7 +231,7 @@ func (p *passTLSClientCert) modifyRequestHeaders(logger logrus.FieldLogger, r *h
if p.info != nil { if p.info != nil {
if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 { if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
headerContent := p.getXForwardedTLSClientCertInfo(r.TLS.PeerCertificates) headerContent := p.getXForwardedTLSClientCertInfo(ctx, r.TLS.PeerCertificates)
r.Header.Set(xForwardedTLSClientCertInfo, url.QueryEscape(headerContent)) r.Header.Set(xForwardedTLSClientCertInfo, url.QueryEscape(headerContent))
} else { } else {
logger.Warn("Tried to extract a certificate on a request without mutual TLS") logger.Warn("Tried to extract a certificate on a request without mutual TLS")
@ -248,22 +251,22 @@ func sanitize(cert []byte) string {
} }
// extractCertificate extract the certificate from the request. // extractCertificate extract the certificate from the request.
func extractCertificate(logger logrus.FieldLogger, cert *x509.Certificate) string { func extractCertificate(ctx context.Context, cert *x509.Certificate) string {
b := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw} b := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}
certPEM := pem.EncodeToMemory(&b) certPEM := pem.EncodeToMemory(&b)
if certPEM == nil { if certPEM == nil {
logger.Error("Cannot extract the certificate content") log.FromContext(ctx).Error("Cannot extract the certificate content")
return "" return ""
} }
return sanitize(certPEM) return sanitize(certPEM)
} }
// getXForwardedTLSClientCert Build a string with the client certificates. // getXForwardedTLSClientCert Build a string with the client certificates.
func getXForwardedTLSClientCert(logger logrus.FieldLogger, certs []*x509.Certificate) string { func getXForwardedTLSClientCert(ctx context.Context, certs []*x509.Certificate) string {
var headerValues []string var headerValues []string
for _, peerCert := range certs { for _, peerCert := range certs {
headerValues = append(headerValues, extractCertificate(logger, peerCert)) headerValues = append(headerValues, extractCertificate(ctx, peerCert))
} }
return strings.Join(headerValues, ",") return strings.Join(headerValues, ",")

View file

@ -6,6 +6,7 @@ import (
"net" "net"
"net/http" "net/http"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
) )
@ -20,7 +21,7 @@ type pipelining struct {
// New returns a new pipelining instance // New returns a new pipelining instance
func New(ctx context.Context, next http.Handler, name string) http.Handler { func New(ctx context.Context, next http.Handler, name string) http.Handler {
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
return &pipelining{ return &pipelining{
next: next, next: next,

View file

@ -90,7 +90,8 @@ func (rl *rateLimiter) GetTracingInformation() (string, ext.SpanKindEnum) {
} }
func (rl *rateLimiter) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (rl *rateLimiter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
logger := middlewares.GetLogger(r.Context(), rl.name, typeName) ctx := middlewares.GetLoggerCtx(r.Context(), rl.name, typeName)
logger := log.FromContext(ctx)
source, amount, err := rl.sourceMatcher.Extract(r) source, amount, err := rl.sourceMatcher.Extract(r)
if err != nil { if err != nil {
@ -127,7 +128,7 @@ func (rl *rateLimiter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
delay := res.Delay() delay := res.Delay()
if delay > rl.maxDelay { if delay > rl.maxDelay {
res.Cancel() res.Cancel()
rl.serveDelayError(w, r, delay) rl.serveDelayError(ctx, w, r, delay)
return return
} }
@ -135,12 +136,12 @@ func (rl *rateLimiter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rl.next.ServeHTTP(w, r) rl.next.ServeHTTP(w, r)
} }
func (rl *rateLimiter) serveDelayError(w http.ResponseWriter, r *http.Request, delay time.Duration) { func (rl *rateLimiter) serveDelayError(ctx context.Context, w http.ResponseWriter, r *http.Request, delay time.Duration) {
w.Header().Set("Retry-After", fmt.Sprintf("%.0f", delay.Seconds())) w.Header().Set("Retry-After", fmt.Sprintf("%.0f", delay.Seconds()))
w.Header().Set("X-Retry-In", delay.String()) w.Header().Set("X-Retry-In", delay.String())
w.WriteHeader(http.StatusTooManyRequests) w.WriteHeader(http.StatusTooManyRequests)
if _, err := w.Write([]byte(http.StatusText(http.StatusTooManyRequests))); err != nil { if _, err := w.Write([]byte(http.StatusText(http.StatusTooManyRequests))); err != nil {
middlewares.GetLogger(r.Context(), rl.name, typeName).Errorf("could not serve 429: %v", err) log.FromContext(ctx).Errorf("could not serve 429: %v", err)
} }
} }

View file

@ -127,15 +127,16 @@ func TestRateLimit(t *testing.T) {
incomingLoad: 200, incomingLoad: 200,
burst: 300, burst: 300,
}, },
{ // TODO Try to disambiguate when it fails if it is because of too high a load.
desc: "Zero average ==> no rate limiting", // {
config: dynamic.RateLimit{ // desc: "Zero average ==> no rate limiting",
Average: 0, // config: dynamic.RateLimit{
Burst: 1, // Average: 0,
}, // Burst: 1,
incomingLoad: 1000, // },
loadDuration: time.Second, // incomingLoad: 1000,
}, // loadDuration: time.Second,
// },
} }
for _, test := range testCases { for _, test := range testCases {

View file

@ -4,8 +4,8 @@ import (
"context" "context"
"net/http" "net/http"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/sirupsen/logrus"
) )
const ( const (
@ -19,7 +19,7 @@ type recovery struct {
// New creates recovery middleware. // New creates recovery middleware.
func New(ctx context.Context, next http.Handler, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
return &recovery{ return &recovery{
next: next, next: next,
@ -28,13 +28,13 @@ func New(ctx context.Context, next http.Handler, name string) (http.Handler, err
} }
func (re *recovery) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (re *recovery) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
defer recoverFunc(middlewares.GetLogger(req.Context(), re.name, typeName), rw) defer recoverFunc(middlewares.GetLoggerCtx(req.Context(), re.name, typeName), rw)
re.next.ServeHTTP(rw, req) re.next.ServeHTTP(rw, req)
} }
func recoverFunc(logger logrus.FieldLogger, rw http.ResponseWriter) { func recoverFunc(ctx context.Context, rw http.ResponseWriter) {
if err := recover(); err != nil { if err := recover(); err != nil {
logger.Errorf("Recovered from panic in http handler: %+v", err) log.FromContext(ctx).Errorf("Recovered from panic in http handler: %+v", err)
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
} }
} }

View file

@ -2,7 +2,6 @@ package redirect
import ( import (
"bytes" "bytes"
"context"
"html/template" "html/template"
"io" "io"
"net/http" "net/http"
@ -25,7 +24,7 @@ type redirect struct {
} }
// New creates a Redirect middleware. // New creates a Redirect middleware.
func newRedirect(_ context.Context, next http.Handler, regex string, replacement string, permanent bool, name string) (http.Handler, error) { func newRedirect(next http.Handler, regex string, replacement string, permanent bool, name string) (http.Handler, error) {
re, err := regexp.Compile(regex) re, err := regexp.Compile(regex)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -5,6 +5,7 @@ import (
"net/http" "net/http"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
) )
@ -14,9 +15,9 @@ const (
// NewRedirectRegex creates a redirect middleware. // NewRedirectRegex creates a redirect middleware.
func NewRedirectRegex(ctx context.Context, next http.Handler, conf dynamic.RedirectRegex, name string) (http.Handler, error) { func NewRedirectRegex(ctx context.Context, next http.Handler, conf dynamic.RedirectRegex, name string) (http.Handler, error) {
logger := middlewares.GetLogger(ctx, name, typeRegexName) logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeRegexName))
logger.Debug("Creating middleware") logger.Debug("Creating middleware")
logger.Debugf("Setting up redirection from %s to %s", conf.Regex, conf.Replacement) logger.Debugf("Setting up redirection from %s to %s", conf.Regex, conf.Replacement)
return newRedirect(ctx, next, conf.Regex, conf.Replacement, conf.Permanent, name) return newRedirect(next, conf.Regex, conf.Replacement, conf.Permanent, name)
} }

View file

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
) )
@ -16,7 +17,7 @@ const (
// NewRedirectScheme creates a new RedirectScheme middleware. // NewRedirectScheme creates a new RedirectScheme middleware.
func NewRedirectScheme(ctx context.Context, next http.Handler, conf dynamic.RedirectScheme, name string) (http.Handler, error) { func NewRedirectScheme(ctx context.Context, next http.Handler, conf dynamic.RedirectScheme, name string) (http.Handler, error) {
logger := middlewares.GetLogger(ctx, name, typeSchemeName) logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeSchemeName))
logger.Debug("Creating middleware") logger.Debug("Creating middleware")
logger.Debugf("Setting up redirection to %s %s", conf.Scheme, conf.Port) logger.Debugf("Setting up redirection to %s %s", conf.Scheme, conf.Port)
@ -29,5 +30,5 @@ func NewRedirectScheme(ctx context.Context, next http.Handler, conf dynamic.Redi
port = ":" + conf.Port port = ":" + conf.Port
} }
return newRedirect(ctx, next, schemeRedirectRegex, conf.Scheme+"://${2}"+port+"${4}", conf.Permanent, name) return newRedirect(next, schemeRedirectRegex, conf.Scheme+"://${2}"+port+"${4}", conf.Permanent, name)
} }

View file

@ -5,6 +5,7 @@ import (
"net/http" "net/http"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/ext"
@ -25,7 +26,7 @@ type replacePath struct {
// New creates a new replace path middleware. // New creates a new replace path middleware.
func New(ctx context.Context, next http.Handler, config dynamic.ReplacePath, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.ReplacePath, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
return &replacePath{ return &replacePath{
next: next, next: next,
@ -42,5 +43,6 @@ func (r *replacePath) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
req.Header.Add(ReplacedPathHeader, req.URL.Path) req.Header.Add(ReplacedPathHeader, req.URL.Path)
req.URL.Path = r.path req.URL.Path = r.path
req.RequestURI = req.URL.RequestURI() req.RequestURI = req.URL.RequestURI()
r.next.ServeHTTP(rw, req) r.next.ServeHTTP(rw, req)
} }

View file

@ -8,6 +8,7 @@ import (
"strings" "strings"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/middlewares/replacepath" "github.com/containous/traefik/v2/pkg/middlewares/replacepath"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
@ -28,7 +29,7 @@ type replacePathRegex struct {
// New creates a new replace path regex middleware. // New creates a new replace path regex middleware.
func New(ctx context.Context, next http.Handler, config dynamic.ReplacePathRegex, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.ReplacePathRegex, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
exp, err := regexp.Compile(strings.TrimSpace(config.Regex)) exp, err := regexp.Compile(strings.TrimSpace(config.Regex))
if err != nil { if err != nil {

View file

@ -10,6 +10,7 @@ import (
"net/http/httptrace" "net/http/httptrace"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/ext"
@ -43,8 +44,7 @@ type retry struct {
// New returns a new retry middleware. // New returns a new retry middleware.
func New(ctx context.Context, next http.Handler, config dynamic.Retry, listener Listener, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.Retry, listener Listener, name string) (http.Handler, error) {
logger := middlewares.GetLogger(ctx, name, typeName) log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
logger.Debug("Creating middleware")
if config.Attempts <= 0 { if config.Attempts <= 0 {
return nil, fmt.Errorf("incorrect (or empty) value for attempt (%d)", config.Attempts) return nil, fmt.Errorf("incorrect (or empty) value for attempt (%d)", config.Attempts)
@ -94,8 +94,10 @@ func (r *retry) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
} }
attempts++ attempts++
logger := middlewares.GetLogger(req.Context(), r.name, typeName)
logger.Debugf("New attempt %d for request: %v", attempts, req.URL) log.FromContext(middlewares.GetLoggerCtx(req.Context(), r.name, typeName)).
Debugf("New attempt %d for request: %v", attempts, req.URL)
r.listener.Retried(req, attempts) r.listener.Retried(req, attempts)
} }
} }

View file

@ -6,6 +6,7 @@ import (
"strings" "strings"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/ext"
@ -26,7 +27,7 @@ type stripPrefix struct {
// New creates a new strip prefix middleware. // New creates a new strip prefix middleware.
func New(ctx context.Context, next http.Handler, config dynamic.StripPrefix, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.StripPrefix, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
return &stripPrefix{ return &stripPrefix{
prefixes: config.Prefixes, prefixes: config.Prefixes,
next: next, next: next,

View file

@ -7,6 +7,7 @@ import (
"strings" "strings"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/middlewares/stripprefix" "github.com/containous/traefik/v2/pkg/middlewares/stripprefix"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
@ -26,7 +27,7 @@ type stripPrefixRegex struct {
// New builds a new StripPrefixRegex middleware. // New builds a new StripPrefixRegex middleware.
func New(ctx context.Context, next http.Handler, config dynamic.StripPrefixRegex, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.StripPrefixRegex, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
stripPrefix := stripPrefixRegex{ stripPrefix := stripPrefixRegex{
next: next, next: next,

View file

@ -5,6 +5,7 @@ import (
"net/http" "net/http"
"github.com/containous/alice" "github.com/containous/alice"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go"
@ -17,7 +18,7 @@ const (
// NewEntryPoint creates a new middleware that the incoming request. // NewEntryPoint creates a new middleware that the incoming request.
func NewEntryPoint(ctx context.Context, t *tracing.Tracing, entryPointName string, next http.Handler) http.Handler { func NewEntryPoint(ctx context.Context, t *tracing.Tracing, entryPointName string, next http.Handler) http.Handler {
middlewares.GetLogger(ctx, "tracing", entryPointTypeName).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, "tracing", entryPointTypeName)).Debug("Creating middleware")
return &entryPointMiddleware{ return &entryPointMiddleware{
entryPoint: entryPointName, entryPoint: entryPointName,

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"net/http" "net/http"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares" "github.com/containous/traefik/v2/pkg/middlewares"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go/ext"
@ -21,7 +22,7 @@ type forwarderMiddleware struct {
// NewForwarder creates a new forwarder middleware that traces the outgoing request. // NewForwarder creates a new forwarder middleware that traces the outgoing request.
func NewForwarder(ctx context.Context, router, service string, next http.Handler) http.Handler { func NewForwarder(ctx context.Context, router, service string, next http.Handler) http.Handler {
middlewares.GetLogger(ctx, "tracing", forwarderTypeName). log.FromContext(middlewares.GetLoggerCtx(ctx, "tracing", forwarderTypeName)).
Debugf("Added outgoing tracing middleware %s", service) Debugf("Added outgoing tracing middleware %s", service)
return &forwarderMiddleware{ return &forwarderMiddleware{

View file

@ -350,17 +350,19 @@ func (p *Provider) watchNewDomains(ctx context.Context) {
if route.TLS == nil || route.TLS.CertResolver != p.ResolverName { if route.TLS == nil || route.TLS.CertResolver != p.ResolverName {
continue continue
} }
ctxRouter := log.With(ctx, log.Str(log.RouterName, routerName), log.Str(log.Rule, route.Rule)) ctxRouter := log.With(ctx, log.Str(log.RouterName, routerName), log.Str(log.Rule, route.Rule))
logger := log.FromContext(ctxRouter)
tlsStore := "default" tlsStore := "default"
if len(route.TLS.Domains) > 0 { if len(route.TLS.Domains) > 0 {
for _, domain := range route.TLS.Domains { for _, domain := range route.TLS.Domains {
if domain.Main != dns01.UnFqdn(domain.Main) { if domain.Main != dns01.UnFqdn(domain.Main) {
log.Warnf("FQDN detected, please remove the trailing dot: %s", domain.Main) logger.Warnf("FQDN detected, please remove the trailing dot: %s", domain.Main)
} }
for _, san := range domain.SANs { for _, san := range domain.SANs {
if san != dns01.UnFqdn(san) { if san != dns01.UnFqdn(san) {
log.Warnf("FQDN detected, please remove the trailing dot: %s", san) logger.Warnf("FQDN detected, please remove the trailing dot: %s", san)
} }
} }
} }
@ -378,7 +380,7 @@ func (p *Provider) watchNewDomains(ctx context.Context) {
} else { } else {
domains, err := rules.ParseHostSNI(route.Rule) domains, err := rules.ParseHostSNI(route.Rule)
if err != nil { if err != nil {
log.FromContext(ctxRouter).Errorf("Error parsing domains in provider ACME: %v", err) logger.Errorf("Error parsing domains in provider ACME: %v", err)
continue continue
} }
p.resolveDomains(ctxRouter, domains, tlsStore) p.resolveDomains(ctxRouter, domains, tlsStore)

View file

@ -78,14 +78,16 @@ func (p *Provider) buildTCPServiceConfiguration(ctx context.Context, container d
if len(configuration.Services) == 0 { if len(configuration.Services) == 0 {
configuration.Services = make(map[string]*dynamic.TCPService) configuration.Services = make(map[string]*dynamic.TCPService)
lb := &dynamic.TCPLoadBalancerService{} lb := &dynamic.TCPServersLoadBalancer{}
lb.SetDefaults()
configuration.Services[serviceName] = &dynamic.TCPService{ configuration.Services[serviceName] = &dynamic.TCPService{
LoadBalancer: lb, LoadBalancer: lb,
} }
} }
for _, service := range configuration.Services { for name, service := range configuration.Services {
err := p.addServerTCP(ctx, container, service.LoadBalancer) ctxSvc := log.With(ctx, log.Str(log.ServiceName, name))
err := p.addServerTCP(ctxSvc, container, service.LoadBalancer)
if err != nil { if err != nil {
return err return err
} }
@ -106,8 +108,9 @@ func (p *Provider) buildServiceConfiguration(ctx context.Context, container dock
} }
} }
for _, service := range configuration.Services { for name, service := range configuration.Services {
err := p.addServer(ctx, container, service.LoadBalancer) ctxSvc := log.With(ctx, log.Str(log.ServiceName, name))
err := p.addServer(ctxSvc, container, service.LoadBalancer)
if err != nil { if err != nil {
return err return err
} }
@ -142,7 +145,7 @@ func (p *Provider) keepContainer(ctx context.Context, container dockerData) bool
return true return true
} }
func (p *Provider) addServerTCP(ctx context.Context, container dockerData, loadBalancer *dynamic.TCPLoadBalancerService) error { func (p *Provider) addServerTCP(ctx context.Context, container dockerData, loadBalancer *dynamic.TCPServersLoadBalancer) error {
serverPort := "" serverPort := ""
if loadBalancer != nil && len(loadBalancer.Servers) > 0 { if loadBalancer != nil && len(loadBalancer.Servers) > 0 {
serverPort = loadBalancer.Servers[0].Port serverPort = loadBalancer.Servers[0].Port

View file

@ -13,6 +13,8 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func Int(v int) *int { return &v }
func TestDefaultRule(t *testing.T) { func TestDefaultRule(t *testing.T) {
testCases := []struct { testCases := []struct {
desc string desc string
@ -2086,12 +2088,13 @@ func Test_buildConfiguration(t *testing.T) {
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"Test": { "Test": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1:80", Address: "127.0.0.1:80",
}, },
}, },
TerminationDelay: Int(100),
}, },
}, },
}, },
@ -2130,12 +2133,13 @@ func Test_buildConfiguration(t *testing.T) {
Routers: map[string]*dynamic.TCPRouter{}, Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"Test": { "Test": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1:80", Address: "127.0.0.1:80",
}, },
}, },
TerminationDelay: Int(100),
}, },
}, },
}, },
@ -2184,12 +2188,13 @@ func Test_buildConfiguration(t *testing.T) {
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"foo": { "foo": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1:8080", Address: "127.0.0.1:8080",
}, },
}, },
TerminationDelay: Int(100),
}, },
}, },
}, },
@ -2259,7 +2264,7 @@ func Test_buildConfiguration(t *testing.T) {
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"foo": { "foo": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1:8080", Address: "127.0.0.1:8080",
@ -2268,6 +2273,7 @@ func Test_buildConfiguration(t *testing.T) {
Address: "127.0.0.2:8080", Address: "127.0.0.2:8080",
}, },
}, },
TerminationDelay: Int(100),
}, },
}, },
}, },
@ -2325,12 +2331,59 @@ func Test_buildConfiguration(t *testing.T) {
Routers: map[string]*dynamic.TCPRouter{}, Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"foo": { "foo": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "127.0.0.1:8080", Address: "127.0.0.1:8080",
}, },
}, },
TerminationDelay: Int(100),
},
},
},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
},
},
{
desc: "tcp with label for tcp service, with termination delay",
containers: []dockerData{
{
ServiceName: "Test",
Name: "Test",
Labels: map[string]string{
"traefik.tcp.services.foo.loadbalancer.server.port": "8080",
"traefik.tcp.services.foo.loadbalancer.terminationdelay": "200",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
Name: "bridge",
Addr: "127.0.0.1",
},
},
},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{
"foo": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "127.0.0.1:8080",
},
},
TerminationDelay: Int(200),
}, },
}, },
}, },

View file

@ -85,7 +85,7 @@ func (p *Provider) BuildConfiguration() (*dynamic.Configuration, error) {
} }
if len(p.Filename) > 0 { if len(p.Filename) > 0 {
return p.loadFileConfig(p.Filename, true) return p.loadFileConfig(ctx, p.Filename, true)
} }
return nil, errors.New("error using file configuration provider, neither filename or directory defined") return nil, errors.New("error using file configuration provider, neither filename or directory defined")
@ -156,11 +156,11 @@ func sendConfigToChannel(configurationChan chan<- dynamic.Message, configuration
} }
} }
func (p *Provider) loadFileConfig(filename string, parseTemplate bool) (*dynamic.Configuration, error) { func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTemplate bool) (*dynamic.Configuration, error) {
var err error var err error
var configuration *dynamic.Configuration var configuration *dynamic.Configuration
if parseTemplate { if parseTemplate {
configuration, err = p.CreateConfiguration(filename, template.FuncMap{}, false) configuration, err = p.CreateConfiguration(ctx, filename, template.FuncMap{}, false)
} else { } else {
configuration, err = p.DecodeConfiguration(filename) configuration, err = p.DecodeConfiguration(filename)
} }
@ -169,25 +169,25 @@ func (p *Provider) loadFileConfig(filename string, parseTemplate bool) (*dynamic
} }
if configuration.TLS != nil { if configuration.TLS != nil {
configuration.TLS.Certificates = flattenCertificates(configuration.TLS) configuration.TLS.Certificates = flattenCertificates(ctx, configuration.TLS)
} }
return configuration, nil return configuration, nil
} }
func flattenCertificates(tlsConfig *dynamic.TLSConfiguration) []*tls.CertAndStores { func flattenCertificates(ctx context.Context, tlsConfig *dynamic.TLSConfiguration) []*tls.CertAndStores {
var certs []*tls.CertAndStores var certs []*tls.CertAndStores
for _, cert := range tlsConfig.Certificates { for _, cert := range tlsConfig.Certificates {
content, err := cert.Certificate.CertFile.Read() content, err := cert.Certificate.CertFile.Read()
if err != nil { if err != nil {
log.Error(err) log.FromContext(ctx).Error(err)
continue continue
} }
cert.Certificate.CertFile = tls.FileOrContent(string(content)) cert.Certificate.CertFile = tls.FileOrContent(string(content))
content, err = cert.Certificate.KeyFile.Read() content, err = cert.Certificate.KeyFile.Read()
if err != nil { if err != nil {
log.Error(err) log.FromContext(ctx).Error(err)
continue continue
} }
cert.Certificate.KeyFile = tls.FileOrContent(string(content)) cert.Certificate.KeyFile = tls.FileOrContent(string(content))
@ -243,7 +243,7 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
} }
var c *dynamic.Configuration var c *dynamic.Configuration
c, err = p.loadFileConfig(filepath.Join(directory, item.Name()), true) c, err = p.loadFileConfig(ctx, filepath.Join(directory, item.Name()), true)
if err != nil { if err != nil {
return configuration, err return configuration, err
} }
@ -331,7 +331,7 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
} }
// CreateConfiguration creates a provider configuration from content using templating. // CreateConfiguration creates a provider configuration from content using templating.
func (p *Provider) CreateConfiguration(filename string, funcMap template.FuncMap, templateObjects interface{}) (*dynamic.Configuration, error) { func (p *Provider) CreateConfiguration(ctx context.Context, filename string, funcMap template.FuncMap, templateObjects interface{}) (*dynamic.Configuration, error) {
tmplContent, err := readFile(filename) tmplContent, err := readFile(filename)
if err != nil { if err != nil {
return nil, fmt.Errorf("error reading configuration file: %s - %s", filename, err) return nil, fmt.Errorf("error reading configuration file: %s - %s", filename, err)
@ -359,7 +359,7 @@ func (p *Provider) CreateConfiguration(filename string, funcMap template.FuncMap
var renderedTemplate = buffer.String() var renderedTemplate = buffer.String()
if p.DebugLogGeneratedTemplate { if p.DebugLogGeneratedTemplate {
logger := log.WithoutContext().WithField(log.ProviderName, providerName) logger := log.FromContext(ctx)
logger.Debugf("Template content: %s", tmplContent) logger.Debugf("Template content: %s", tmplContent)
logger.Debugf("Rendering results: %s", renderedTemplate) logger.Debugf("Rendering results: %s", renderedTemplate)
} }

View file

@ -46,7 +46,7 @@ func TestTLSContent(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
provider := &Provider{} provider := &Provider{}
configuration, err := provider.loadFileConfig(fileConfig.Name(), true) configuration, err := provider.loadFileConfig(context.Background(), fileConfig.Name(), true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "CONTENT", configuration.TLS.Certificates[0].Certificate.CertFile.String()) require.Equal(t, "CONTENT", configuration.TLS.Certificates[0].Certificate.CertFile.String())

View file

@ -0,0 +1,16 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: HostSNI(`foo.com`)
services:
- name: whoamitcp
port: 8000
terminationDelay: 500

View file

@ -13,6 +13,7 @@ spec:
services: services:
- name: whoamitcp - name: whoamitcp
port: 8000 port: 8000
weight: 2
- name: whoamitcp2 - name: whoamitcp2
port: 8080 port: 8080
weight: 3

View file

@ -0,0 +1,20 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: Host(`foo.com`) && PathPrefix(`/bar`)
kind: Rule
priority: 12
services:
- name: whoami
port: 80
passHostHeader: false
responseForwarding:
flushInterval: 10s

View file

@ -511,7 +511,7 @@ func makeID(namespace, name string) string {
return name return name
} }
return namespace + "/" + name return namespace + "-" + name
} }
func shouldProcessIngress(ingressClass string, ingressClassAnnotation string) bool { func shouldProcessIngress(ingressClass string, ingressClassAnnotation string) bool {

View file

@ -73,6 +73,8 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
continue continue
} }
// If there is only one service defined, we skip the creation of the load balancer of services,
// i.e. the service on top is directly a load balancer of servers.
if len(route.Services) == 1 { if len(route.Services) == 1 {
conf.Services[serviceName] = balancerServerHTTP conf.Services[serviceName] = balancerServerHTTP
break break
@ -157,12 +159,18 @@ func createLoadBalancerServerHTTP(client Client, namespace string, service v1alp
return nil, err return nil, err
} }
// TODO: support other strategies.
lb := &dynamic.ServersLoadBalancer{}
lb.SetDefaults()
lb.Servers = servers
if service.PassHostHeader != nil {
lb.PassHostHeader = *service.PassHostHeader
}
lb.ResponseForwarding = service.ResponseForwarding
return &dynamic.Service{ return &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: lb,
Servers: servers,
// TODO: support other strategies.
PassHostHeader: true,
},
}, nil }, nil
} }

View file

@ -49,9 +49,16 @@ func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client
continue continue
} }
var allServers []dynamic.TCPServer key, err := makeServiceKey(route.Match, ingressName)
if err != nil {
logger.Error(err)
continue
}
serviceName := makeID(ingressRouteTCP.Namespace, key)
for _, service := range route.Services { for _, service := range route.Services {
servers, err := loadTCPServers(client, ingressRouteTCP.Namespace, service) balancerServerTCP, err := createLoadBalancerServerTCP(client, ingressRouteTCP.Namespace, service)
if err != nil { if err != nil {
logger. logger.
WithField("serviceName", service.Name). WithField("serviceName", service.Name).
@ -60,16 +67,28 @@ func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client
continue continue
} }
allServers = append(allServers, servers...) // If there is only one service defined, we skip the creation of the load balancer of services,
// i.e. the service on top is directly a load balancer of servers.
if len(route.Services) == 1 {
conf.Services[serviceName] = balancerServerTCP
break
}
serviceKey := fmt.Sprintf("%s-%s-%d", serviceName, service.Name, service.Port)
conf.Services[serviceKey] = balancerServerTCP
srv := dynamic.TCPWRRService{Name: serviceKey}
srv.SetDefaults()
if service.Weight != nil {
srv.Weight = service.Weight
}
if conf.Services[serviceName] == nil {
conf.Services[serviceName] = &dynamic.TCPService{Weighted: &dynamic.TCPWeightedRoundRobin{}}
}
conf.Services[serviceName].Weighted.Services = append(conf.Services[serviceName].Weighted.Services, srv)
} }
key, e := makeServiceKey(route.Match, ingressName)
if e != nil {
logger.Error(e)
continue
}
serviceName := makeID(ingressRouteTCP.Namespace, key)
conf.Routers[serviceName] = &dynamic.TCPRouter{ conf.Routers[serviceName] = &dynamic.TCPRouter{
EntryPoints: ingressRouteTCP.Spec.EntryPoints, EntryPoints: ingressRouteTCP.Spec.EntryPoints,
Rule: route.Match, Rule: route.Match,
@ -83,37 +102,53 @@ func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client
Domains: ingressRouteTCP.Spec.TLS.Domains, Domains: ingressRouteTCP.Spec.TLS.Domains,
} }
if ingressRouteTCP.Spec.TLS.Options != nil && len(ingressRouteTCP.Spec.TLS.Options.Name) > 0 { if ingressRouteTCP.Spec.TLS.Options == nil || len(ingressRouteTCP.Spec.TLS.Options.Name) == 0 {
tlsOptionsName := ingressRouteTCP.Spec.TLS.Options.Name continue
// Is a Kubernetes CRD reference (i.e. not a cross-provider reference)
ns := ingressRouteTCP.Spec.TLS.Options.Namespace
if !strings.Contains(tlsOptionsName, "@") {
if len(ns) == 0 {
ns = ingressRouteTCP.Namespace
}
tlsOptionsName = makeID(ns, tlsOptionsName)
} else if len(ns) > 0 {
logger.
WithField("TLSoptions", ingressRouteTCP.Spec.TLS.Options.Name).
Warnf("namespace %q is ignored in cross-provider context", ns)
}
conf.Routers[serviceName].TLS.Options = tlsOptionsName
} }
tlsOptionsName := ingressRouteTCP.Spec.TLS.Options.Name
// Is a Kubernetes CRD reference (i.e. not a cross-provider reference)
ns := ingressRouteTCP.Spec.TLS.Options.Namespace
if !strings.Contains(tlsOptionsName, "@") {
if len(ns) == 0 {
ns = ingressRouteTCP.Namespace
}
tlsOptionsName = makeID(ns, tlsOptionsName)
} else if len(ns) > 0 {
logger.
WithField("TLSoptions", ingressRouteTCP.Spec.TLS.Options.Name).
Warnf("namespace %q is ignored in cross-provider context", ns)
}
conf.Routers[serviceName].TLS.Options = tlsOptionsName
} }
conf.Services[serviceName] = &dynamic.TCPService{
LoadBalancer: &dynamic.TCPLoadBalancerService{
Servers: allServers,
},
}
} }
} }
return conf return conf
} }
func createLoadBalancerServerTCP(client Client, namespace string, service v1alpha1.ServiceTCP) (*dynamic.TCPService, error) {
servers, err := loadTCPServers(client, namespace, service)
if err != nil {
return nil, err
}
tcpService := &dynamic.TCPService{
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: servers,
},
}
if service.TerminationDelay != nil {
tcpService.LoadBalancer.TerminationDelay = service.TerminationDelay
}
return tcpService, nil
}
func loadTCPServers(client Client, namespace string, svc v1alpha1.ServiceTCP) ([]dynamic.TCPServer, error) { func loadTCPServers(client Client, namespace string, svc v1alpha1.ServiceTCP) ([]dynamic.TCPServer, error) {
service, exists, err := client.GetService(namespace, svc.Name) service, exists, err := client.GetService(namespace, svc.Name)
if err != nil { if err != nil {

View file

@ -47,15 +47,15 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
}, },
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{ Routers: map[string]*dynamic.TCPRouter{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-fdd3e9338e47a45efefc", Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)", Rule: "HostSNI(`foo.com`)",
}, },
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "10.10.0.1:8000", Address: "10.10.0.1:8000",
@ -79,20 +79,20 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{ Routers: map[string]*dynamic.TCPRouter{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-fdd3e9338e47a45efefc", Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)", Rule: "HostSNI(`foo.com`)",
}, },
"default/test.route-f44ce589164e656d231c": { "default-test.route-f44ce589164e656d231c": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-f44ce589164e656d231c", Service: "default-test.route-f44ce589164e656d231c",
Rule: "HostSNI(`bar.com`)", Rule: "HostSNI(`bar.com`)",
}, },
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "10.10.0.1:8000", Address: "10.10.0.1:8000",
@ -105,8 +105,8 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
}, },
}, },
}, },
"default/test.route-f44ce589164e656d231c": { "default-test.route-f44ce589164e656d231c": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "10.10.0.1:8000", Address: "10.10.0.1:8000",
@ -130,40 +130,57 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
}, },
}, },
{ {
desc: "One ingress Route with two different services, their servers will merge", desc: "One ingress Route with two different services",
paths: []string{"tcp/services.yml", "tcp/with_two_services.yml"}, paths: []string{"tcp/services.yml", "tcp/with_two_services.yml"},
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{ Routers: map[string]*dynamic.TCPRouter{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-fdd3e9338e47a45efefc", Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)", Rule: "HostSNI(`foo.com`)",
}, },
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ Weighted: &dynamic.TCPWeightedRoundRobin{
Servers: []dynamic.TCPServer{ Services: []dynamic.TCPWRRService{
{ {
Address: "10.10.0.1:8000", Name: "default-test.route-fdd3e9338e47a45efefc-whoamitcp-8000",
Port: "", Weight: func(i int) *int { return &i }(2),
}, },
{ {
Address: "10.10.0.2:8000", Name: "default-test.route-fdd3e9338e47a45efefc-whoamitcp2-8080",
Port: "", Weight: func(i int) *int { return &i }(3),
},
{
Address: "10.10.0.3:8080",
Port: "",
},
{
Address: "10.10.0.4:8080",
Port: "",
}, },
}, },
}, },
}}, },
"default-test.route-fdd3e9338e47a45efefc-whoamitcp-8000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.1:8000",
},
{
Address: "10.10.0.2:8000",
},
},
},
},
"default-test.route-fdd3e9338e47a45efefc-whoamitcp2-8080": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.3:8080",
},
{
Address: "10.10.0.4:8080",
},
},
},
},
},
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{}, Routers: map[string]*dynamic.Router{},
@ -238,16 +255,16 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
}, },
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{ Routers: map[string]*dynamic.TCPRouter{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-fdd3e9338e47a45efefc", Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)", Rule: "HostSNI(`foo.com`)",
TLS: &dynamic.RouterTCPTLSConfig{}, TLS: &dynamic.RouterTCPTLSConfig{},
}, },
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "10.10.0.1:8000", Address: "10.10.0.1:8000",
@ -275,9 +292,9 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{ Routers: map[string]*dynamic.TCPRouter{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-fdd3e9338e47a45efefc", Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)", Rule: "HostSNI(`foo.com`)",
TLS: &dynamic.RouterTCPTLSConfig{ TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true, Passthrough: true,
@ -285,8 +302,8 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
}, },
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "10.10.0.1:8000", Address: "10.10.0.1:8000",
@ -315,7 +332,7 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{ TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{ Options: map[string]tls.Options{
"default/foo": { "default-foo": {
MinVersion: "VersionTLS12", MinVersion: "VersionTLS12",
CipherSuites: []string{ CipherSuites: []string{
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
@ -334,18 +351,18 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
}, },
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{ Routers: map[string]*dynamic.TCPRouter{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-fdd3e9338e47a45efefc", Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)", Rule: "HostSNI(`foo.com`)",
TLS: &dynamic.RouterTCPTLSConfig{ TLS: &dynamic.RouterTCPTLSConfig{
Options: "default/foo", Options: "default-foo",
}, },
}, },
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "10.10.0.1:8000", Address: "10.10.0.1:8000",
@ -373,7 +390,7 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{ TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{ Options: map[string]tls.Options{
"myns/foo": { "myns-foo": {
MinVersion: "VersionTLS12", MinVersion: "VersionTLS12",
CipherSuites: []string{ CipherSuites: []string{
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
@ -392,18 +409,18 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
}, },
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{ Routers: map[string]*dynamic.TCPRouter{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-fdd3e9338e47a45efefc", Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)", Rule: "HostSNI(`foo.com`)",
TLS: &dynamic.RouterTCPTLSConfig{ TLS: &dynamic.RouterTCPTLSConfig{
Options: "myns/foo", Options: "myns-foo",
}, },
}, },
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "10.10.0.1:8000", Address: "10.10.0.1:8000",
@ -431,7 +448,7 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{ TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{ Options: map[string]tls.Options{
"default/foo": { "default-foo": {
MinVersion: "VersionTLS12", MinVersion: "VersionTLS12",
CipherSuites: []string{ CipherSuites: []string{
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
@ -449,18 +466,18 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
}, },
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{ Routers: map[string]*dynamic.TCPRouter{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-fdd3e9338e47a45efefc", Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)", Rule: "HostSNI(`foo.com`)",
TLS: &dynamic.RouterTCPTLSConfig{ TLS: &dynamic.RouterTCPTLSConfig{
Options: "default/foo", Options: "default-foo",
}, },
}, },
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "10.10.0.1:8000", Address: "10.10.0.1:8000",
@ -488,25 +505,25 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{ TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{ Options: map[string]tls.Options{
"default/foo": { "default-foo": {
MinVersion: "VersionTLS12", MinVersion: "VersionTLS12",
}, },
}, },
}, },
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{ Routers: map[string]*dynamic.TCPRouter{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-fdd3e9338e47a45efefc", Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)", Rule: "HostSNI(`foo.com`)",
TLS: &dynamic.RouterTCPTLSConfig{ TLS: &dynamic.RouterTCPTLSConfig{
Options: "default/unknown", Options: "default-unknown",
}, },
}, },
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "10.10.0.1:8000", Address: "10.10.0.1:8000",
@ -534,25 +551,25 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{ TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{ Options: map[string]tls.Options{
"default/foo": { "default-foo": {
MinVersion: "VersionTLS12", MinVersion: "VersionTLS12",
}, },
}, },
}, },
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{ Routers: map[string]*dynamic.TCPRouter{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-fdd3e9338e47a45efefc", Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)", Rule: "HostSNI(`foo.com`)",
TLS: &dynamic.RouterTCPTLSConfig{ TLS: &dynamic.RouterTCPTLSConfig{
Options: "unknown/foo", Options: "unknown-foo",
}, },
}, },
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "10.10.0.1:8000", Address: "10.10.0.1:8000",
@ -580,16 +597,16 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{ Routers: map[string]*dynamic.TCPRouter{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-fdd3e9338e47a45efefc", Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)", Rule: "HostSNI(`foo.com`)",
TLS: &dynamic.RouterTCPTLSConfig{}, TLS: &dynamic.RouterTCPTLSConfig{},
}, },
}, },
Services: map[string]*dynamic.TCPService{ Services: map[string]*dynamic.TCPService{
"default/test.route-fdd3e9338e47a45efefc": { "default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPLoadBalancerService{ LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{ Servers: []dynamic.TCPServer{
{ {
Address: "10.10.0.1:8000", Address: "10.10.0.1:8000",
@ -612,6 +629,44 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
TLS: &dynamic.TLSConfiguration{}, TLS: &dynamic.TLSConfiguration{},
}, },
}, },
{
desc: "TCP with terminationDelay",
paths: []string{"tcp/services.yml", "tcp/with_termination_delay.yml"},
expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"},
Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)",
},
},
Services: map[string]*dynamic.TCPService{
"default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.1:8000",
Port: "",
},
{
Address: "10.10.0.2:8000",
Port: "",
},
},
TerminationDelay: Int(500),
},
},
},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
},
},
} }
for _, test := range testCases { for _, test := range testCases {
@ -663,16 +718,16 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-6b204d94623b3df4370c", Service: "default-test.route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12, Priority: 12,
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -700,28 +755,28 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test2.route-23c7f4c450289ee29016": { "default-test2.route-23c7f4c450289ee29016": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test2.route-23c7f4c450289ee29016", Service: "default-test2.route-23c7f4c450289ee29016",
Rule: "Host(`foo.com`) && PathPrefix(`/tobestripped`)", Rule: "Host(`foo.com`) && PathPrefix(`/tobestripped`)",
Priority: 12, Priority: 12,
Middlewares: []string{"default/stripprefix", "foo/addprefix"}, Middlewares: []string{"default-stripprefix", "foo-addprefix"},
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{ Middlewares: map[string]*dynamic.Middleware{
"default/stripprefix": { "default-stripprefix": {
StripPrefix: &dynamic.StripPrefix{ StripPrefix: &dynamic.StripPrefix{
Prefixes: []string{"/tobestripped"}, Prefixes: []string{"/tobestripped"},
}, },
}, },
"foo/addprefix": { "foo-addprefix": {
AddPrefix: &dynamic.AddPrefix{ AddPrefix: &dynamic.AddPrefix{
Prefix: "/tobeadded", Prefix: "/tobeadded",
}, },
}, },
}, },
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test2.route-23c7f4c450289ee29016": { "default-test2.route-23c7f4c450289ee29016": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -750,28 +805,28 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test2.route-23c7f4c450289ee29016": { "default-test2.route-23c7f4c450289ee29016": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test2.route-23c7f4c450289ee29016", Service: "default-test2.route-23c7f4c450289ee29016",
Rule: "Host(`foo.com`) && PathPrefix(`/tobestripped`)", Rule: "Host(`foo.com`) && PathPrefix(`/tobestripped`)",
Priority: 12, Priority: 12,
Middlewares: []string{"default/stripprefix", "foo/addprefix", "basicauth@file", "redirect@file"}, Middlewares: []string{"default-stripprefix", "foo-addprefix", "basicauth@file", "redirect@file"},
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{ Middlewares: map[string]*dynamic.Middleware{
"default/stripprefix": { "default-stripprefix": {
StripPrefix: &dynamic.StripPrefix{ StripPrefix: &dynamic.StripPrefix{
Prefixes: []string{"/tobestripped"}, Prefixes: []string{"/tobestripped"},
}, },
}, },
"foo/addprefix": { "foo-addprefix": {
AddPrefix: &dynamic.AddPrefix{ AddPrefix: &dynamic.AddPrefix{
Prefix: "/tobeadded", Prefix: "/tobeadded",
}, },
}, },
}, },
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test2.route-23c7f4c450289ee29016": { "default-test2.route-23c7f4c450289ee29016": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -798,22 +853,22 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Service: "default/test.route-6b204d94623b3df4370c", Service: "default-test.route-6b204d94623b3df4370c",
Priority: 14, Priority: 14,
}, },
"default/test.route-77c62dfe9517144aeeaa": { "default-test.route-77c62dfe9517144aeeaa": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test.route-77c62dfe9517144aeeaa", Service: "default-test.route-77c62dfe9517144aeeaa",
Rule: "Host(`foo.com`) && PathPrefix(`/foo`)", Rule: "Host(`foo.com`) && PathPrefix(`/foo`)",
Priority: 12, Priority: 12,
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -826,7 +881,7 @@ func TestLoadIngressRoutes(t *testing.T) {
PassHostHeader: true, PassHostHeader: true,
}, },
}, },
"default/test.route-77c62dfe9517144aeeaa": { "default-test.route-77c62dfe9517144aeeaa": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -855,30 +910,30 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-77c62dfe9517144aeeaa": { "default-test.route-77c62dfe9517144aeeaa": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test.route-77c62dfe9517144aeeaa", Service: "default-test.route-77c62dfe9517144aeeaa",
Rule: "Host(`foo.com`) && PathPrefix(`/foo`)", Rule: "Host(`foo.com`) && PathPrefix(`/foo`)",
Priority: 12, Priority: 12,
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-77c62dfe9517144aeeaa": { "default-test.route-77c62dfe9517144aeeaa": {
Weighted: &dynamic.WeightedRoundRobin{ Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{ Services: []dynamic.WRRService{
{ {
Name: "default/test.route-77c62dfe9517144aeeaa-whoami-80", Name: "default-test.route-77c62dfe9517144aeeaa-whoami-80",
Weight: func(i int) *int { return &i }(1), Weight: func(i int) *int { return &i }(1),
}, },
{ {
Name: "default/test.route-77c62dfe9517144aeeaa-whoami2-8080", Name: "default-test.route-77c62dfe9517144aeeaa-whoami2-8080",
Weight: func(i int) *int { return &i }(1), Weight: func(i int) *int { return &i }(1),
}, },
}, },
}, },
}, },
"default/test.route-77c62dfe9517144aeeaa-whoami-80": { "default-test.route-77c62dfe9517144aeeaa-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -891,7 +946,7 @@ func TestLoadIngressRoutes(t *testing.T) {
PassHostHeader: true, PassHostHeader: true,
}, },
}, },
"default/test.route-77c62dfe9517144aeeaa-whoami2-8080": { "default-test.route-77c62dfe9517144aeeaa-whoami2-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -919,30 +974,30 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-77c62dfe9517144aeeaa": { "default-test.route-77c62dfe9517144aeeaa": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test.route-77c62dfe9517144aeeaa", Service: "default-test.route-77c62dfe9517144aeeaa",
Rule: "Host(`foo.com`) && PathPrefix(`/foo`)", Rule: "Host(`foo.com`) && PathPrefix(`/foo`)",
Priority: 12, Priority: 12,
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-77c62dfe9517144aeeaa": { "default-test.route-77c62dfe9517144aeeaa": {
Weighted: &dynamic.WeightedRoundRobin{ Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{ Services: []dynamic.WRRService{
{ {
Name: "default/test.route-77c62dfe9517144aeeaa-whoami-80", Name: "default-test.route-77c62dfe9517144aeeaa-whoami-80",
Weight: Int(10), Weight: Int(10),
}, },
{ {
Name: "default/test.route-77c62dfe9517144aeeaa-whoami2-8080", Name: "default-test.route-77c62dfe9517144aeeaa-whoami2-8080",
Weight: Int(0), Weight: Int(0),
}, },
}, },
}, },
}, },
"default/test.route-77c62dfe9517144aeeaa-whoami-80": { "default-test.route-77c62dfe9517144aeeaa-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -955,7 +1010,7 @@ func TestLoadIngressRoutes(t *testing.T) {
PassHostHeader: true, PassHostHeader: true,
}, },
}, },
"default/test.route-77c62dfe9517144aeeaa-whoami2-8080": { "default-test.route-77c62dfe9517144aeeaa-whoami2-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -1057,9 +1112,9 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test.route-6b204d94623b3df4370c", Service: "default-test.route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12, Priority: 12,
TLS: &dynamic.RouterTLSConfig{}, TLS: &dynamic.RouterTLSConfig{},
@ -1067,7 +1122,7 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -1090,7 +1145,7 @@ func TestLoadIngressRoutes(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{ TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{ Options: map[string]tls.Options{
"default/foo": { "default-foo": {
MinVersion: "VersionTLS12", MinVersion: "VersionTLS12",
CipherSuites: []string{ CipherSuites: []string{
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
@ -1113,19 +1168,19 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test.route-6b204d94623b3df4370c", Service: "default-test.route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12, Priority: 12,
TLS: &dynamic.RouterTLSConfig{ TLS: &dynamic.RouterTLSConfig{
Options: "default/foo", Options: "default-foo",
}, },
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -1148,7 +1203,7 @@ func TestLoadIngressRoutes(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{ TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{ Options: map[string]tls.Options{
"myns/foo": { "myns-foo": {
MinVersion: "VersionTLS12", MinVersion: "VersionTLS12",
CipherSuites: []string{ CipherSuites: []string{
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
@ -1171,19 +1226,19 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test.route-6b204d94623b3df4370c", Service: "default-test.route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12, Priority: 12,
TLS: &dynamic.RouterTLSConfig{ TLS: &dynamic.RouterTLSConfig{
Options: "myns/foo", Options: "myns-foo",
}, },
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -1206,7 +1261,7 @@ func TestLoadIngressRoutes(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{ TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{ Options: map[string]tls.Options{
"default/foo": { "default-foo": {
MinVersion: "VersionTLS12", MinVersion: "VersionTLS12",
CipherSuites: []string{ CipherSuites: []string{
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
@ -1228,19 +1283,19 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test.route-6b204d94623b3df4370c", Service: "default-test.route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12, Priority: 12,
TLS: &dynamic.RouterTLSConfig{ TLS: &dynamic.RouterTLSConfig{
Options: "default/foo", Options: "default-foo",
}, },
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -1263,7 +1318,7 @@ func TestLoadIngressRoutes(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{ TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{ Options: map[string]tls.Options{
"default/foo": { "default-foo": {
MinVersion: "VersionTLS12", MinVersion: "VersionTLS12",
}, },
}, },
@ -1274,19 +1329,19 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test.route-6b204d94623b3df4370c", Service: "default-test.route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12, Priority: 12,
TLS: &dynamic.RouterTLSConfig{ TLS: &dynamic.RouterTLSConfig{
Options: "default/unknown", Options: "default-unknown",
}, },
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -1309,7 +1364,7 @@ func TestLoadIngressRoutes(t *testing.T) {
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{ TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{ Options: map[string]tls.Options{
"default/foo": { "default-foo": {
MinVersion: "VersionTLS12", MinVersion: "VersionTLS12",
}, },
}, },
@ -1320,19 +1375,19 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test.route-6b204d94623b3df4370c", Service: "default-test.route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12, Priority: 12,
TLS: &dynamic.RouterTLSConfig{ TLS: &dynamic.RouterTLSConfig{
Options: "unknown/foo", Options: "unknown-foo",
}, },
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -1360,9 +1415,9 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default/test.route-6b204d94623b3df4370c", Service: "default-test.route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12, Priority: 12,
TLS: &dynamic.RouterTLSConfig{}, TLS: &dynamic.RouterTLSConfig{},
@ -1370,7 +1425,7 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -1398,16 +1453,16 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-6b204d94623b3df4370c", Service: "default-test.route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12, Priority: 12,
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -1435,16 +1490,16 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{ Routers: map[string]*dynamic.Router{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"foo"}, EntryPoints: []string{"foo"},
Service: "default/test.route-6b204d94623b3df4370c", Service: "default-test.route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12, Priority: 12,
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/test.route-6b204d94623b3df4370c": { "default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -1473,17 +1528,17 @@ func TestLoadIngressRoutes(t *testing.T) {
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{}, Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{ Middlewares: map[string]*dynamic.Middleware{
"default/basicauth": { "default-basicauth": {
BasicAuth: &dynamic.BasicAuth{ BasicAuth: &dynamic.BasicAuth{
Users: dynamic.Users{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"}, Users: dynamic.Users{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
}, },
}, },
"default/digestauth": { "default-digestauth": {
DigestAuth: &dynamic.DigestAuth{ DigestAuth: &dynamic.DigestAuth{
Users: dynamic.Users{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"}, Users: dynamic.Users{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
}, },
}, },
"default/forwardauth": { "default-forwardauth": {
ForwardAuth: &dynamic.ForwardAuth{ ForwardAuth: &dynamic.ForwardAuth{
Address: "test.com", Address: "test.com",
TLS: &dynamic.ClientTLS{ TLS: &dynamic.ClientTLS{
@ -1510,16 +1565,16 @@ func TestLoadIngressRoutes(t *testing.T) {
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{}, Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{ Middlewares: map[string]*dynamic.Middleware{
"default/errorpage": { "default-errorpage": {
Errors: &dynamic.ErrorPage{ Errors: &dynamic.ErrorPage{
Status: []string{"404", "500"}, Status: []string{"404", "500"},
Service: "default/errorpage-errorpage-service", Service: "default-errorpage-errorpage-service",
Query: "query", Query: "query",
}, },
}, },
}, },
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default/errorpage-errorpage-service": { "default-errorpage-errorpage-service": {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
@ -1536,6 +1591,44 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
}, },
}, },
{
desc: "Simple Ingress Route, with options",
paths: []string{"services.yml", "with_options.yml"},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-test.route-6b204d94623b3df4370c": {
EntryPoints: []string{"foo"},
Service: "default-test.route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test.route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: false,
ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: "10s"},
},
},
},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{ {
desc: "port selected by name (TODO)", desc: "port selected by name (TODO)",
}, },
@ -1544,9 +1637,6 @@ func TestLoadIngressRoutes(t *testing.T) {
for _, test := range testCases { for _, test := range testCases {
test := test test := test
if test.desc != "Simple Ingress Route, with error page middleware" {
continue
}
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()

View file

@ -1,6 +1,7 @@
package v1alpha1 package v1alpha1
import ( import (
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/types" "github.com/containous/traefik/v2/pkg/types"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
@ -46,12 +47,14 @@ type TLSOptionRef struct {
// Service defines an upstream to proxy traffic. // Service defines an upstream to proxy traffic.
type Service struct { type Service struct {
Name string `json:"name"` Name string `json:"name"`
Port int32 `json:"port"` Port int32 `json:"port"`
Scheme string `json:"scheme,omitempty"` Scheme string `json:"scheme,omitempty"`
HealthCheck *HealthCheck `json:"healthCheck,omitempty"` HealthCheck *HealthCheck `json:"healthCheck,omitempty"`
Strategy string `json:"strategy,omitempty"` Strategy string `json:"strategy,omitempty"`
Weight *int `json:"weight,omitempty"` PassHostHeader *bool `json:"passHostHeader,omitempty"`
ResponseForwarding *dynamic.ResponseForwarding `json:"responseForwarding,omitempty"`
Weight *int `json:"weight,omitempty"`
} }
// MiddlewareRef is a ref to the Middleware resources. // MiddlewareRef is a ref to the Middleware resources.

Some files were not shown because too many files have changed in this diff Show more