forked from Ivasoft/traefik
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b8b1427f6 | ||
|
|
e2d971f20e | ||
|
|
9d17e8826b | ||
|
|
531c581cd5 | ||
|
|
f790b9aa54 | ||
|
|
8f000423ed | ||
|
|
4990f6c22d | ||
|
|
d447a50b73 | ||
|
|
cbecfad4df | ||
|
|
770a7f11a7 | ||
|
|
27a65f8745 | ||
|
|
5cd06c03f0 | ||
|
|
43e5092c46 | ||
|
|
a239e3fba6 | ||
|
|
743d772a80 | ||
|
|
1f734630b9 | ||
|
|
355fe6195e | ||
|
|
d22bd5b42d | ||
|
|
5327ce543b | ||
|
|
3747eb59ea | ||
|
|
2b00ab3432 | ||
|
|
a6cdd701e2 | ||
|
|
c8984e6a6a | ||
|
|
9179aa52cf | ||
|
|
2042fdf3bd | ||
|
|
d1c3372dc4 | ||
|
|
3884a68889 | ||
|
|
0ec84ec597 | ||
|
|
6a9d21e9aa | ||
|
|
a829d44b51 | ||
|
|
554e3e9e6e | ||
|
|
904b3b5b0b | ||
|
|
02bdc1dcb9 | ||
|
|
b586ae2f25 | ||
|
|
8492a702b2 | ||
|
|
0048156379 | ||
|
|
cb3328dca3 | ||
|
|
e7b7ae94b0 | ||
|
|
17ce295c30 | ||
|
|
d5e3bb1b6d | ||
|
|
7e4e5ec6e4 | ||
|
|
f2656e62dc | ||
|
|
83de97e547 | ||
|
|
b552efe770 | ||
|
|
1663c7c8e7 | ||
|
|
1a6bef1a7e | ||
|
|
ff31e75ccc | ||
|
|
c87a37f804 | ||
|
|
76ead096aa | ||
|
|
668ff71470 | ||
|
|
538d5e8be4 | ||
|
|
b2b142a037 | ||
|
|
3ebed4ff40 | ||
|
|
a2cd69b654 | ||
|
|
cfc14671ed | ||
|
|
ed4b2f74ff | ||
|
|
dd53be7a1b | ||
|
|
c83d7916c9 | ||
|
|
0865962f8d | ||
|
|
9691085bc2 | ||
|
|
b243d1c599 | ||
|
|
db6e404bda | ||
|
|
6f63e24dbb | ||
|
|
0082fe8173 | ||
|
|
06d37b2a94 | ||
|
|
48f11900d3 | ||
|
|
230cd28ac9 | ||
|
|
86261f2b0a | ||
|
|
30ad00fa65 | ||
|
|
33a1499bdd | ||
|
|
211fa18ac2 | ||
|
|
4c5250e850 | ||
|
|
788024685f | ||
|
|
b5f07d2995 |
29
.github/ISSUE_TEMPLATE.md
vendored
29
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,3 +1,7 @@
|
||||
<!-- PLEASE FOLLOW THE ISSUE TEMPLATE TO HELP TRIAGE AND SUPPORT! -->
|
||||
|
||||
### Do you want to request a *feature* or report a *bug*?
|
||||
|
||||
<!--
|
||||
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
|
||||
|
||||
@@ -8,21 +12,12 @@ For end-user related support questions, please refer to one of the following:
|
||||
|
||||
-->
|
||||
|
||||
|
||||
### Do you want to request a *feature* or report a *bug*?
|
||||
|
||||
<!--
|
||||
If you intend to ask a support question: DO NOT FILE AN ISSUE.
|
||||
-->
|
||||
|
||||
### Did you try using a 1.7.x configuration for the version 2.0?
|
||||
|
||||
- [ ] Yes
|
||||
- [ ] No
|
||||
Bug
|
||||
|
||||
<!--
|
||||
|
||||
If you just checked the "Yes" box, be aware that this is probably not a bug. The configurations between 1.X and 2.X are NOT compatible. Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
|
||||
The configurations between 1.X and 2.X are NOT compatible.
|
||||
Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
|
||||
|
||||
-->
|
||||
|
||||
@@ -30,7 +25,7 @@ If you just checked the "Yes" box, be aware that this is probably not a bug. The
|
||||
|
||||
<!--
|
||||
|
||||
HOW TO WRITE A GOOD ISSUE?
|
||||
HOW TO WRITE A GOOD BUG REPORT?
|
||||
|
||||
- Respect the issue template as much as possible.
|
||||
- The title should be short and descriptive.
|
||||
@@ -52,13 +47,12 @@ HOW TO WRITE A GOOD ISSUE?
|
||||
### Output of `traefik version`: (_What version of Traefik are you using?_)
|
||||
|
||||
<!--
|
||||
`latest` is not considered as a valid version.
|
||||
|
||||
For the Traefik Docker image:
|
||||
docker run [IMAGE] version
|
||||
ex: docker run traefik version
|
||||
|
||||
For the alpine Traefik Docker image:
|
||||
docker run [IMAGE] traefik version
|
||||
ex: docker run traefik traefik version
|
||||
-->
|
||||
|
||||
```
|
||||
@@ -70,12 +64,13 @@ For the alpine Traefik Docker image:
|
||||
```toml
|
||||
# (paste your configuration here)
|
||||
```
|
||||
|
||||
<!--
|
||||
Add more configuration information here.
|
||||
-->
|
||||
|
||||
|
||||
### If applicable, please paste the log output at DEBUG level (`--log.level=DEBUG` switch)
|
||||
### If applicable, please paste the log output in DEBUG level (`--log.level=DEBUG` switch)
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
|
||||
19
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
19
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -3,6 +3,9 @@ name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
<!-- PLEASE FOLLOW THE ISSUE TEMPLATE TO HELP TRIAGE AND SUPPORT! -->
|
||||
|
||||
### Do you want to request a *feature* or report a *bug*?
|
||||
|
||||
<!--
|
||||
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
|
||||
@@ -14,19 +17,12 @@ For end-user related support questions, please refer to one of the following:
|
||||
|
||||
-->
|
||||
|
||||
|
||||
### Do you want to request a *feature* or report a *bug*?
|
||||
|
||||
Bug
|
||||
|
||||
### Did you try using a 1.7.x configuration for the version 2.0?
|
||||
|
||||
- [ ] Yes
|
||||
- [ ] No
|
||||
|
||||
<!--
|
||||
|
||||
If you just checked the "Yes" box, be aware that this is probably not a bug. The configurations between 1.X and 2.X are NOT compatible. Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
|
||||
The configurations between 1.X and 2.X are NOT compatible.
|
||||
Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
|
||||
|
||||
-->
|
||||
|
||||
@@ -56,13 +52,12 @@ HOW TO WRITE A GOOD BUG REPORT?
|
||||
### Output of `traefik version`: (_What version of Traefik are you using?_)
|
||||
|
||||
<!--
|
||||
`latest` is not considered as a valid version.
|
||||
|
||||
For the Traefik Docker image:
|
||||
docker run [IMAGE] version
|
||||
ex: docker run traefik version
|
||||
|
||||
For the alpine Traefik Docker image:
|
||||
docker run [IMAGE] traefik version
|
||||
ex: docker run traefik traefik version
|
||||
-->
|
||||
|
||||
```
|
||||
|
||||
6
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
6
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
@@ -3,6 +3,9 @@ name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
<!-- PLEASE FOLLOW THE ISSUE TEMPLATE TO HELP TRIAGE AND SUPPORT! -->
|
||||
|
||||
### Do you want to request a *feature* or report a *bug*?
|
||||
|
||||
<!--
|
||||
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
|
||||
@@ -14,9 +17,6 @@ For end-user related support questions, please refer to one of the following:
|
||||
|
||||
-->
|
||||
|
||||
|
||||
### Do you want to request a *feature* or report a *bug*?
|
||||
|
||||
Feature
|
||||
|
||||
### What did you expect to see?
|
||||
|
||||
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,18 +1,19 @@
|
||||
<!--
|
||||
PLEASE READ THIS MESSAGE.
|
||||
|
||||
HOW TO WRITE A GOOD PULL REQUEST?
|
||||
Documentation fixes or enhancements:
|
||||
- for Traefik v1: use branch v1.7
|
||||
- for Traefik v2: use branch v2.0
|
||||
|
||||
- Make it small.
|
||||
- Do only one thing.
|
||||
- Avoid re-formatting.
|
||||
- Make sure the code builds.
|
||||
- Make sure all tests pass.
|
||||
- Add tests.
|
||||
- Write useful descriptions and titles.
|
||||
- Address review comments in terms of additional commits.
|
||||
- Do not amend/squash existing ones unless the PR is trivial.
|
||||
- Read the contributing guide: https://github.com/containous/traefik/blob/master/CONTRIBUTING.md.
|
||||
Bug fixes:
|
||||
- for Traefik v1: use branch v1.7
|
||||
- for Traefik v2: use branch v2.0
|
||||
|
||||
Enhancements:
|
||||
- for Traefik v1: we only accept bug fixes
|
||||
- for Traefik v2: use branch master
|
||||
|
||||
HOW TO WRITE A GOOD PULL REQUEST? https://docs.traefik.io/contributing/submitting-pull-requests/
|
||||
|
||||
-->
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
[run]
|
||||
deadline = "10m"
|
||||
timeout = "10m"
|
||||
skip-files = []
|
||||
skip-dirs = [
|
||||
"pkg/provider/kubernetes/crd/generated/",
|
||||
]
|
||||
|
||||
[linters-settings]
|
||||
|
||||
@@ -40,9 +43,11 @@
|
||||
"scopelint",
|
||||
"gochecknoinits",
|
||||
"gochecknoglobals",
|
||||
# "godox", # manage TODO FIXME ## wait for https://github.com/golangci/golangci-lint/issues/337
|
||||
"godox",
|
||||
"gocognit",
|
||||
"bodyclose", # Too many false-positive and panics.
|
||||
# "stylecheck", # skip because report issues related to some generated files. ## wait for https://github.com/golangci/golangci-lint/issues/337
|
||||
"wsl", # Too strict
|
||||
"stylecheck", # skip because report issues related to some generated files.
|
||||
]
|
||||
|
||||
[issues]
|
||||
|
||||
119
CHANGELOG.md
119
CHANGELOG.md
@@ -1,3 +1,81 @@
|
||||
## [v2.0.4](https://github.com/containous/traefik/tree/v2.0.4) (2019-10-28)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.0.3...v2.0.4)
|
||||
|
||||
Fixes releases system.
|
||||
Same changelog as v2.0.3.
|
||||
|
||||
## [v2.0.3](https://github.com/containous/traefik/tree/v2.0.3) (2019-10-28)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.0.2...v2.0.3)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme,logs]** Use debug for log about skipping addition of cert ([#5641](https://github.com/containous/traefik/pull/5641) by [sylr](https://github.com/sylr))
|
||||
- **[file]** fix: add filename in the file provider logs. ([#5636](https://github.com/containous/traefik/pull/5636) by [ldez](https://github.com/ldez))
|
||||
- **[k8s,k8s/crd,k8s/ingress]** Remove unnecessary reload of the configuration. ([#5707](https://github.com/containous/traefik/pull/5707) by [ldez](https://github.com/ldez))
|
||||
- **[k8s,k8s/crd,k8s/ingress]** Fixing support for HTTPs backends with Kubernetes ExternalName services ([#5660](https://github.com/containous/traefik/pull/5660) by [kpeiruza](https://github.com/kpeiruza))
|
||||
- **[k8s,k8s/ingress]** Normalize service and router names for ingress. ([#5623](https://github.com/containous/traefik/pull/5623) by [ldez](https://github.com/ldez))
|
||||
- **[logs]** Set proxy protocol logger to DEBUG level ([#5712](https://github.com/containous/traefik/pull/5712) by [mmatur](https://github.com/mmatur))
|
||||
- **[middleware]** fix: add stacktrace when recover. ([#5654](https://github.com/containous/traefik/pull/5654) by [ldez](https://github.com/ldez))
|
||||
- **[tracing]** Let instana/go-sensor handle default agent host ([#5658](https://github.com/containous/traefik/pull/5658) by [sylr](https://github.com/sylr))
|
||||
- **[tracing]** fix: default tracing backend. ([#5717](https://github.com/containous/traefik/pull/5717) by [ldez](https://github.com/ldez))
|
||||
- fix: deep copy of passHostHeader on ServersLoadBalancer. ([#5720](https://github.com/containous/traefik/pull/5720) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Documentation:**
|
||||
- **[acme]** Fix acme storage file docker mounting example ([#5633](https://github.com/containous/traefik/pull/5633) by [jansauer](https://github.com/jansauer))
|
||||
- **[acme]** fix incorrect DNS reference ([#5666](https://github.com/containous/traefik/pull/5666) by [oskapt](https://github.com/oskapt))
|
||||
- **[logs]** Clarify unit of duration field in access log ([#5664](https://github.com/containous/traefik/pull/5664) by [Sarke](https://github.com/Sarke))
|
||||
- **[middleware]** Fix Security Headers Doc ([#5706](https://github.com/containous/traefik/pull/5706) by [FlorianPerrot](https://github.com/FlorianPerrot))
|
||||
- **[middleware]** Migration guide: pathprefixstrip migration ([#5600](https://github.com/containous/traefik/pull/5600) by [dduportal](https://github.com/dduportal))
|
||||
- **[middleware]** fix ForwardAuth tls.skipverify examples ([#5683](https://github.com/containous/traefik/pull/5683) by [remche](https://github.com/remche))
|
||||
- **[rules]** Add documentation about backtick for rule definition. ([#5714](https://github.com/containous/traefik/pull/5714) by [ldez](https://github.com/ldez))
|
||||
- **[webui]** Improve documentation of the router rules for API and dashboard ([#5625](https://github.com/containous/traefik/pull/5625) by [dduportal](https://github.com/dduportal))
|
||||
- doc: @ is not authorized in names definition. ([#5734](https://github.com/containous/traefik/pull/5734) by [ldez](https://github.com/ldez))
|
||||
- Remove obsolete v2 remark from README ([#5669](https://github.com/containous/traefik/pull/5669) by [dragetd](https://github.com/dragetd))
|
||||
- Fix spelling mistake: "founded" -> "found" ([#5674](https://github.com/containous/traefik/pull/5674) by [ocanty](https://github.com/ocanty))
|
||||
- fix typo for stripPrefix in tab File (YAML) ([#5694](https://github.com/containous/traefik/pull/5694) by [nalakawula](https://github.com/nalakawula))
|
||||
- Add example for changing the port used by traefik to connect to a service ([#5224](https://github.com/containous/traefik/pull/5224) by [robertbaker](https://github.com/robertbaker))
|
||||
|
||||
**Misc:**
|
||||
- **[logs,middleware]** Cherry pick v1.7 into v2.0 ([#5735](https://github.com/containous/traefik/pull/5735) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
|
||||
## [v2.0.2](https://github.com/containous/traefik/tree/v2.0.2) (2019-10-09)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.0.1...v2.0.2)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme]** fix: ovh client int overflow. ([#5607](https://github.com/containous/traefik/pull/5607) by [ldez](https://github.com/ldez))
|
||||
- **[api,k8s,k8s/ingress]** fix: default router name for k8s ingress. ([#5612](https://github.com/containous/traefik/pull/5612) by [ldez](https://github.com/ldez))
|
||||
- **[file]** fix: default passHostHeader for file provider. ([#5516](https://github.com/containous/traefik/pull/5516) by [ldez](https://github.com/ldez))
|
||||
- **[k8s,k8s/crd]** Fix typo in log ([#5590](https://github.com/containous/traefik/pull/5590) by [XciD](https://github.com/XciD))
|
||||
- **[middleware,metrics]** fix: panic with metrics recorder. ([#5536](https://github.com/containous/traefik/pull/5536) by [ldez](https://github.com/ldez))
|
||||
- **[webui]** Add a service sticky details vue component ([#5579](https://github.com/containous/traefik/pull/5579) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
- fix: return an error instead of panic. ([#5549](https://github.com/containous/traefik/pull/5549) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Documentation:**
|
||||
- **[acme,file]** Fix yaml domains example ([#5569](https://github.com/containous/traefik/pull/5569) by [SuperSandro2000](https://github.com/SuperSandro2000))
|
||||
- **[api,webui]** Clarifies how to configure and access the dashboard in the api & dashboard documentations ([#5523](https://github.com/containous/traefik/pull/5523) by [dduportal](https://github.com/dduportal))
|
||||
- **[api]** Add overview to API documentation ([#5539](https://github.com/containous/traefik/pull/5539) by [lnxbil](https://github.com/lnxbil))
|
||||
- **[cli]** typo in cli command ([#5586](https://github.com/containous/traefik/pull/5586) by [basraven](https://github.com/basraven))
|
||||
- **[cli]** Replace ambiguous cli help message wording ([#5233](https://github.com/containous/traefik/pull/5233) by [jansauer](https://github.com/jansauer))
|
||||
- **[docker]** Fixed typo in routing/providers/docker documentation ([#5520](https://github.com/containous/traefik/pull/5520) by [lyrixx](https://github.com/lyrixx))
|
||||
- **[docker]** $ needs escaping in docker-compose.yml ([#5528](https://github.com/containous/traefik/pull/5528) by [lnxbil](https://github.com/lnxbil))
|
||||
- **[file]** State clearly, that they are mutual exclusive ([#5527](https://github.com/containous/traefik/pull/5527) by [lnxbil](https://github.com/lnxbil))
|
||||
- **[healthcheck]** fix: typo in healthCheck examples ([#5575](https://github.com/containous/traefik/pull/5575) by [serpi90](https://github.com/serpi90))
|
||||
- **[k8s/crd]** Update 04-ingressroutes.yml ([#5585](https://github.com/containous/traefik/pull/5585) by [basraven](https://github.com/basraven))
|
||||
- **[k8s/crd]** Update apiVersion in documentation descriptor ([#5605](https://github.com/containous/traefik/pull/5605) by [pyaillet](https://github.com/pyaillet))
|
||||
- **[metrics]** doc: fix influxDB and statsD case in configuration page. ([#5531](https://github.com/containous/traefik/pull/5531) by [ldez](https://github.com/ldez))
|
||||
- **[middleware]** Update scope of services and middlewares ([#5584](https://github.com/containous/traefik/pull/5584) by [Thoorium](https://github.com/Thoorium))
|
||||
- **[middleware]** Typo in documentation ([#5558](https://github.com/containous/traefik/pull/5558) by [Constans](https://github.com/Constans))
|
||||
- **[middleware]** Fix misleading text ([#5540](https://github.com/containous/traefik/pull/5540) by [joassouza](https://github.com/joassouza))
|
||||
- **[tls]** document serversTransport ([#5529](https://github.com/containous/traefik/pull/5529) by [mpl](https://github.com/mpl))
|
||||
- **[tls]** TLS_RSA_WITH_AES_256_GCM_SHA384 is considered weak ([#5578](https://github.com/containous/traefik/pull/5578) by [Constans](https://github.com/Constans))
|
||||
- **[tls]** Improve ciphersuite examples ([#5594](https://github.com/containous/traefik/pull/5594) by [Constans](https://github.com/Constans))
|
||||
- Remove deprecated videos ([#5570](https://github.com/containous/traefik/pull/5570) by [emilevauge](https://github.com/emilevauge))
|
||||
- fix: remove extra backtick from routers docs ([#5572](https://github.com/containous/traefik/pull/5572) by [serpi90](https://github.com/serpi90))
|
||||
- document providersThrottleDuration ([#5519](https://github.com/containous/traefik/pull/5519) by [mpl](https://github.com/mpl))
|
||||
- Add a response forwarding section to the service documentation ([#5517](https://github.com/containous/traefik/pull/5517) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
- Change instances of "dymanic" to "dynamic" ([#5504](https://github.com/containous/traefik/pull/5504) by [dat-gitto-kid](https://github.com/dat-gitto-kid))
|
||||
- Add the pass host header section to the services documentation ([#5500](https://github.com/containous/traefik/pull/5500) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
- fix misspelling on documentation landing page ([#5613](https://github.com/containous/traefik/pull/5613) by [cthompson527](https://github.com/cthompson527))
|
||||
|
||||
## [v2.0.1](https://github.com/containous/traefik/tree/v2.0.1) (2019-09-26)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.0.0...v2.0.1)
|
||||
|
||||
@@ -31,6 +109,24 @@
|
||||
- Add the router priority documentation ([#5481](https://github.com/containous/traefik/pull/5481) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
- Improve the Migration Guide ([#5391](https://github.com/containous/traefik/pull/5391) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
|
||||
## [v1.7.18](https://github.com/containous/traefik/tree/v1.7.18) (2019-09-23)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.7.17...v1.7.18)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[go,security]** This version is compiled with [Go 1.12.10](https://groups.google.com/d/msg/golang-announce/cszieYyuL9Q/g4Z7pKaqAgAJ), which fixes a vulnerability in previous versions. See the [CVE](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-16276) about it for more details.
|
||||
|
||||
## [v1.7.17](https://github.com/containous/traefik/tree/v1.7.17) (2019-09-23)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.7.16...v1.7.17)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[logs,middleware]** Avoid closing stdout when the accesslog handler is closed ([#5459](https://github.com/containous/traefik/pull/5459) by [nrwiersma](https://github.com/nrwiersma))
|
||||
- **[middleware]** Actually send header and code during WriteHeader, if needed ([#5404](https://github.com/containous/traefik/pull/5404) by [mpl](https://github.com/mpl))
|
||||
|
||||
**Documentation:**
|
||||
- **[k8s]** Add note clarifying client certificate header ([#5362](https://github.com/containous/traefik/pull/5362) by [bradjones1](https://github.com/bradjones1))
|
||||
- **[webui]** Update docs links. ([#5412](https://github.com/containous/traefik/pull/5412) by [ldez](https://github.com/ldez))
|
||||
- Update Traefik image version. ([#5399](https://github.com/containous/traefik/pull/5399) by [ldez](https://github.com/ldez))
|
||||
|
||||
## [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)
|
||||
|
||||
@@ -375,6 +471,29 @@
|
||||
- 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))
|
||||
|
||||
## [v1.7.16](https://github.com/containous/traefik/tree/v1.7.16) (2019-09-13)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.7.15...v1.7.16)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[middleware,websocket]** implement Flusher and Hijacker for codeCatcher ([#5376](https://github.com/containous/traefik/pull/5376) by [mpl](https://github.com/mpl))
|
||||
|
||||
## [v1.7.15](https://github.com/containous/traefik/tree/v1.7.15) (2019-09-12)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.7.14...v1.7.15)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[authentication,k8s/ingress]** Kubernetes support for Auth.HeaderField ([#5235](https://github.com/containous/traefik/pull/5235) by [ErikWegner](https://github.com/ErikWegner))
|
||||
- **[k8s,k8s/ingress]** Finish kubernetes throttling refactoring ([#5269](https://github.com/containous/traefik/pull/5269) by [mpl](https://github.com/mpl))
|
||||
- **[k8s]** Throttle Kubernetes config refresh ([#4716](https://github.com/containous/traefik/pull/4716) by [benweissmann](https://github.com/benweissmann))
|
||||
- **[k8s]** Fix wrong handling of insecure tls auth forward ingress annotation ([#5319](https://github.com/containous/traefik/pull/5319) by [majkrzak](https://github.com/majkrzak))
|
||||
- **[middleware]** error pages: do not buffer response when it's not an error ([#5285](https://github.com/containous/traefik/pull/5285) by [mpl](https://github.com/mpl))
|
||||
- **[tls]** Consider default cert domain in certificate store ([#5353](https://github.com/containous/traefik/pull/5353) by [nrwiersma](https://github.com/nrwiersma))
|
||||
- **[tls]** Add TLS minversion constraint ([#5356](https://github.com/containous/traefik/pull/5356) by [dtomcej](https://github.com/dtomcej))
|
||||
|
||||
**Documentation:**
|
||||
- **[acme]** Update Acme doc - Vultr Wildcard & Root ([#5320](https://github.com/containous/traefik/pull/5320) by [ddymko](https://github.com/ddymko))
|
||||
- **[consulcatalog]** Typo in basic auth usersFile label consul-catalog ([#5230](https://github.com/containous/traefik/pull/5230) by [pitan](https://github.com/pitan))
|
||||
- **[logs]** Improve Access Logs Documentation page ([#5238](https://github.com/containous/traefik/pull/5238) by [dduportal](https://github.com/dduportal))
|
||||
|
||||
## [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)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# Contributing
|
||||
|
||||
See <https://docs.traefik.io/v2.0/contributing/thank-you/>.
|
||||
- https://docs.traefik.io/contributing/submitting-pull-requests/
|
||||
- https://docs.traefik.io/contributing/submitting-issues/
|
||||
|
||||
2
Makefile
2
Makefile
@@ -131,7 +131,7 @@ generate-crd:
|
||||
## Create packages for the release
|
||||
release-packages: generate-webui build-dev-image
|
||||
rm -rf dist
|
||||
$(DOCKER_RUN_TRAEFIK_NOTTY) goreleaser release --skip-publish
|
||||
$(DOCKER_RUN_TRAEFIK_NOTTY) goreleaser release --skip-publish --timeout="60m"
|
||||
$(DOCKER_RUN_TRAEFIK_NOTTY) tar cfz dist/traefik-${VERSION}.src.tar.gz \
|
||||
--exclude-vcs \
|
||||
--exclude .idea \
|
||||
|
||||
21
README.md
21
README.md
@@ -33,7 +33,7 @@ Pointing Traefik at your orchestrator should be the _only_ configuration step yo
|
||||
|
||||
---
|
||||
|
||||
:warning: Please be aware that the old configurations for Traefik v1.X are NOT compatible with the v2.X config as of now. If you're running v2, please ensure you are using a [v2 configuration](https://docs.traefik.io/).
|
||||
:warning: Please be aware that the old configurations for Traefik v1.x are NOT compatible with the v2.x config as of now. If you're running v2, please ensure you are using a [v2 configuration](https://docs.traefik.io/).
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -87,10 +87,11 @@ You can access the simple HTML frontend of Traefik.
|
||||
|
||||
## Documentation
|
||||
|
||||
You can find the complete documentation at [https://docs.traefik.io](https://docs.traefik.io).
|
||||
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
|
||||
You can find the complete documentation of Traefik v2 at [https://docs.traefik.io](https://docs.traefik.io).
|
||||
|
||||
:warning: If you're testing out v2, please ensure you are using the [v2 documentation](https://docs.traefik.io/).
|
||||
If you are using Traefik v1, you can find the complete documentation at [https://docs.traefik.io/v1.7/](https://docs.traefik.io/v1.7/)
|
||||
|
||||
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
|
||||
|
||||
## Support
|
||||
|
||||
@@ -121,17 +122,7 @@ git clone https://github.com/containous/traefik
|
||||
|
||||
## Introductory Videos
|
||||
|
||||
:warning: Please be aware that these videos are for v1.X. The old configurations for Traefik v1.X are NOT compatible with Traefik v2. If you're running v2, please ensure you are using a [v2 configuration](https://docs.traefik.io/).
|
||||
|
||||
Here is a talk given by [Emile Vauge](https://github.com/emilevauge) at GopherCon 2017.
|
||||
You will learn Traefik basics in less than 10 minutes.
|
||||
|
||||
[](https://www.youtube.com/watch?v=RgudiksfL-k)
|
||||
|
||||
Here is a talk given by [Ed Robinson](https://github.com/errm) at [ContainerCamp UK](https://container.camp) conference.
|
||||
You will learn fundamental Traefik features and see some demos with Kubernetes.
|
||||
|
||||
[](https://www.youtube.com/watch?v=aFtpIShV60I)
|
||||
You can find high level and deep dive videos on [videos.containo.us](https://videos.containo.us)
|
||||
|
||||
## Maintainers
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ RUN mkdir -p /usr/local/bin \
|
||||
&& chmod +x /usr/local/bin/go-bindata
|
||||
|
||||
# Download golangci-lint binary to bin folder in $GOPATH
|
||||
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.18.0
|
||||
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.20.0
|
||||
|
||||
# Download golangci-lint and misspell binary to bin folder in $GOPATH
|
||||
RUN GO111MODULE=off go get github.com/client9/misspell/cmd/misspell
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
func NewCmd(traefikConfiguration *static.Configuration, loaders []cli.ResourceLoader) *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "healthcheck",
|
||||
Description: `Calls Traefik /ping to check the health of Traefik (the API must be enabled).`,
|
||||
Description: `Calls Traefik /ping endpoint (disabled by default) to check the health of Traefik.`,
|
||||
Configuration: traefikConfiguration,
|
||||
Run: runCmd(traefikConfiguration),
|
||||
Resources: loaders,
|
||||
|
||||
@@ -16,8 +16,8 @@ The _dynamic configuration_ contains everything that defines how the requests ar
|
||||
This configuration can change and is seamlessly hot-reloaded, without any request interruption or connection loss.
|
||||
|
||||
!!! warning "Incompatible Configuration"
|
||||
Please be aware that the old configurations for Traefik v1.X are NOT compatible with the v2.X config as of now.
|
||||
If you're testing out v2, please ensure you are using a v2 configuration.
|
||||
Please be aware that the old configurations for Traefik v1.x are NOT compatible with the v2.x config as of now.
|
||||
If you are running v2, please ensure you are using a v2 configuration.
|
||||
|
||||
## The Dynamic Configuration
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
|
||||
| [Bindman](https://github.com/labbsr0x/bindman-dns-webhook) | `bindman` | `BINDMAN_MANAGER_ADDRESS` | [Additional configuration](https://go-acme.github.io/lego/dns/bindman) |
|
||||
| [Blue Cat](https://www.bluecatnetworks.com/) | `bluecat` | `BLUECAT_SERVER_URL`, `BLUECAT_USER_NAME`, `BLUECAT_PASSWORD`, `BLUECAT_CONFIG_NAME`, `BLUECAT_DNS_VIEW` | [Additional configuration](https://go-acme.github.io/lego/dns/bluecat) |
|
||||
| [ClouDNS](https://www.cloudns.net/) | `cloudns` | `CLOUDNS_AUTH_ID`, `CLOUDNS_AUTH_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudns) |
|
||||
| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CF_API_EMAIL`, `CF_API_KEY` - The `Global API Key` needs to be used, not the `Origin CA Key` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudflare) |
|
||||
| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CF_API_EMAIL`, `CF_API_KEY` or `CF_DNS_API_TOKEN`, `[CF_ZONE_API_TOKEN]` [^5] | [Additional configuration](https://go-acme.github.io/lego/dns/cloudflare) |
|
||||
| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudxns) |
|
||||
| [ConoHa](https://www.conoha.jp) | `conoha` | `CONOHA_TENANT_ID`, `CONOHA_API_USERNAME`, `CONOHA_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/conoha) |
|
||||
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/digitalocean) |
|
||||
@@ -247,6 +247,7 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
|
||||
| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/lightsail) |
|
||||
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) |
|
||||
| [Linode v4](https://www.linode.com) | `linodev4` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linodev4) |
|
||||
| [Liquid Web](https://www.liquidweb.com/) | `liquidweb` | `LIQUID_WEB_PASSWORD`, `LIQUID_WEB_USERNAME`, `LIQUID_WEB_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/liquidweb) |
|
||||
| manual | - | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press <kbd>Enter</kbd>. | |
|
||||
| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) |
|
||||
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namecheap) |
|
||||
@@ -277,6 +278,7 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
|
||||
[^2]: [providing_credentials_to_your_application](https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application)
|
||||
[^3]: [google/default.go](https://github.com/golang/oauth2/blob/36a7019397c4c86cf59eeab3bc0d188bac444277/google/default.go#L61-L76)
|
||||
[^4]: `docker stack` remark: there is no way to support terminal attached to container when deploying with `docker stack`, so you might need to run container with `docker run -it` to generate certificates using `manual` provider.
|
||||
[^5]: The `Global API Key` needs to be used, not the `Origin CA Key`.
|
||||
|
||||
!!! info "`delayBeforeCheck`"
|
||||
By default, the `provider` verifies the TXT record _before_ letting ACME verify.
|
||||
@@ -380,7 +382,7 @@ ACME certificates can be stored in a JSON file that needs to have a `600` file m
|
||||
In Docker you can mount either the JSON file, or the folder containing it:
|
||||
|
||||
```bash
|
||||
docker run -v "/my/host/acme.json:acme.json" traefik
|
||||
docker run -v "/my/host/acme.json:/acme.json" traefik
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
@@ -191,8 +191,7 @@ See [cipherSuites](https://godoc.org/crypto/tls#pkg-constants) for more informat
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
]
|
||||
```
|
||||
|
||||
@@ -204,7 +203,6 @@ tls:
|
||||
default:
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
@@ -217,7 +215,6 @@ metadata:
|
||||
spec:
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
```
|
||||
|
||||
!!! important "TLS 1.3"
|
||||
|
||||
@@ -20,4 +20,4 @@ Developing Traefik, our main goal is to make it simple to use, and we're sure yo
|
||||
|
||||
!!! info
|
||||
|
||||
If you're a businness running critical services behind Traefik, know that [Containous](https://containo.us), the company that sponsors Traefik's development, can provide [commercial support](https://containo.us/services/#commercial-support) and develops an [Enterprise Edition](https://containo.us/traefikee/) of Traefik.
|
||||
If you're a business running critical services behind Traefik, know that [Containous](https://containo.us), the company that sponsors Traefik's development, can provide [commercial support](https://containo.us/services/#commercial-support) and develops an [Enterprise Edition](https://containo.us/traefikee/) of Traefik.
|
||||
|
||||
@@ -474,7 +474,8 @@ metadata:
|
||||
spec:
|
||||
forwardAuth:
|
||||
address: https://authserver.com/auth
|
||||
insecureSkipVerify: true
|
||||
tls:
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
@@ -492,7 +493,8 @@ labels:
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-auth.forwardAuth]
|
||||
address = "https://authserver.com/auth"
|
||||
insecureSkipVerify: true
|
||||
[http.middlewares.test-auth.forwardAuth.tls]
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
@@ -501,5 +503,6 @@ http:
|
||||
test-auth:
|
||||
forwardAuth:
|
||||
address: "https://authserver.com/auth"
|
||||
insecureSkipVerify: true
|
||||
tls:
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
@@ -162,8 +162,8 @@ labels:
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.testHeader.headers]
|
||||
FrameDeny = true
|
||||
SSLRedirect = true
|
||||
frameDeny = true
|
||||
sslRedirect = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
@@ -171,8 +171,8 @@ http:
|
||||
middlewares:
|
||||
testHeader:
|
||||
headers:
|
||||
FrameDeny: true
|
||||
SSLRedirect: true
|
||||
frameDeny: true
|
||||
sslRedirect: true
|
||||
```
|
||||
|
||||
### CORS Headers
|
||||
@@ -235,7 +235,7 @@ http:
|
||||
middlewares:
|
||||
testHeader:
|
||||
headers:
|
||||
accessControlAllowMethod:
|
||||
accessControlAllowMethods:
|
||||
- GET
|
||||
- OPTIONS
|
||||
- PUT
|
||||
|
||||
@@ -183,14 +183,14 @@ and therefore this specification would be ignored even if present.
|
||||
routes:
|
||||
- match: Host(`bar.com`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
middlewares:
|
||||
- name: add-foo-prefix@file
|
||||
# namespace: bar
|
||||
# A namespace specification such as above is ignored
|
||||
# when the cross-provider syntax is used.
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
middlewares:
|
||||
- name: add-foo-prefix@file
|
||||
# namespace: bar
|
||||
# A namespace specification such as above is ignored
|
||||
# when the cross-provider syntax is used.
|
||||
```
|
||||
|
||||
## Available Middlewares
|
||||
|
||||
@@ -219,7 +219,10 @@ PassTLSClientCert can add two headers to the request:
|
||||
- `X-Forwarded-Tls-Client-Cert-Info` that contains all the selected certificate information in an escaped string.
|
||||
|
||||
!!! info
|
||||
The headers are filled with escaped string so it can be safely placed inside a URL query.
|
||||
|
||||
* The headers are filled with escaped string so it can be safely placed inside a URL query.
|
||||
* These options only work accordingly to the [MutualTLS configuration](../https/tls.md#client-authentication-mtls).
|
||||
That is to say, only the certificates that match the `clientAuth.clientAuthType` policy are passed.
|
||||
|
||||
In the following example, you can see a complete certificate. We will use each part of it to explain the middleware options.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Redirecting the Client to a Different Scheme/Port
|
||||
TODO: add schema
|
||||
-->
|
||||
|
||||
RegexRedirect redirect request from a scheme to another.
|
||||
RedirectScheme redirect request from a scheme to another.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
How to Migrate from Traefik v1 to Traefik v2.
|
||||
{: .subtitle }
|
||||
|
||||
The version 2 of Traefik introduces a number of breaking changes,
|
||||
The version 2 of Traefik introduces a number of breaking changes,
|
||||
which require one to update their configuration when they migrate from v1 to v2.
|
||||
The goal of this page is to recapitulate all of these changes, and in particular to give examples,
|
||||
The goal of this page is to recapitulate all of these changes, and in particular to give examples,
|
||||
feature by feature, of how the configuration looked like in v1, and how it now looks like in v2.
|
||||
|
||||
!!! info "Migration Helper"
|
||||
|
||||
|
||||
We created a tool to help during the migration: [traefik-migration-tool](https://github.com/containous/traefik-migration-tool)
|
||||
|
||||
This tool allows to:
|
||||
@@ -32,11 +32,11 @@ Then any router can refer to an instance of the wanted middleware.
|
||||
!!! example "One frontend with basic auth and one backend, become one router, one service, and one basic auth middleware."
|
||||
|
||||
!!! info "v1"
|
||||
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
- "traefik.frontend.rule=Host:test.localhost;PathPrefix:/test"
|
||||
- "traefik.frontend.auth.basic.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
- "traefik.frontend.auth.basic.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```yaml tab="K8s Ingress"
|
||||
@@ -92,18 +92,18 @@ Then any router can refer to an instance of the wanted middleware.
|
||||
[backends.backend1.loadBalancer]
|
||||
method = "wrr"
|
||||
```
|
||||
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
- "traefik.http.routers.router0.rule=Host(`bar.com`) && PathPrefix(`/test`)"
|
||||
- "traefik.http.routers.router0.middlewares=auth"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```yaml tab="K8s IngressRoute"
|
||||
# The definitions below require the definitions for the Middleware and IngressRoute kinds.
|
||||
# The definitions below require the definitions for the Middleware and IngressRoute kinds.
|
||||
# https://docs.traefik.io/v2.0/providers/kubernetes-crd/#traefik-ingressroute-definition
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
@@ -155,7 +155,7 @@ Then any router can refer to an instance of the wanted middleware.
|
||||
[http.middlewares]
|
||||
[http.middlewares.auth.basicAuth]
|
||||
users = [
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
]
|
||||
```
|
||||
@@ -184,7 +184,7 @@ Then any router can refer to an instance of the wanted middleware.
|
||||
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
## TLS configuration is now dynamic, per router.
|
||||
## TLS Configuration Is Now Dynamic, per Router.
|
||||
|
||||
TLS parameters used to be specified in the static configuration, as an entryPoint field.
|
||||
With Traefik v2, a new dynamic TLS section at the root contains all the desired TLS configurations.
|
||||
@@ -204,19 +204,23 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
|
||||
minVersion = "VersionTLS12"
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
]
|
||||
[[entryPoints.web-secure.tls.certificates]]
|
||||
certFile = "path/to/my.cert"
|
||||
keyFile = "path/to/my.key"
|
||||
```
|
||||
|
||||
|
||||
```bash tab="CLI"
|
||||
--entryPoints='Name:web-secure Address::443 TLS:path/to/my.cert,path/to/my.key TLS.MinVersion:VersionTLS12 TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384'
|
||||
--entryPoints='Name:web-secure Address::443 TLS:path/to/my.cert,path/to/my.key TLS.MinVersion:VersionTLS12 TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
|
||||
```
|
||||
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# dynamic configuration
|
||||
[http.routers]
|
||||
@@ -238,11 +242,15 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
|
||||
[tls.options.myTLSOptions]
|
||||
minVersion = "VersionTLS13"
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
routers:
|
||||
@@ -261,12 +269,15 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
|
||||
myTLSOptions:
|
||||
minVersion: VersionTLS13
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
|
||||
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="K8s IngressRoute"
|
||||
# The definitions below require the definitions for the TLSOption and IngressRoute kinds.
|
||||
# The definitions below require the definitions for the TLSOption and IngressRoute kinds.
|
||||
# https://docs.traefik.io/v2.0/providers/kubernetes-crd/#traefik-ingressroute-definition
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
@@ -277,8 +288,11 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
|
||||
spec:
|
||||
minVersion: VersionTLS13
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
|
||||
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
@@ -296,11 +310,11 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
|
||||
- name: whoami
|
||||
port: 80
|
||||
tls:
|
||||
options:
|
||||
options:
|
||||
name: mytlsoption
|
||||
namespace: default
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
# myTLSOptions must be defined by another provider, in this instance in the File Provider.
|
||||
@@ -308,7 +322,7 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
|
||||
- "traefik.http.routers.router0.tls.options=myTLSOptions@file"
|
||||
```
|
||||
|
||||
## HTTP to HTTPS Redirection is now configured on Routers
|
||||
## HTTP to HTTPS Redirection Is Now Configured on Routers
|
||||
|
||||
Previously on Traefik v1, the redirection was applied on an entry point or on a frontend.
|
||||
With Traefik v2 it is applied on a [Router](../routing/routers/index.md).
|
||||
@@ -336,14 +350,14 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||
certFile = "examples/traefik.crt"
|
||||
keyFile = "examples/traefik.key"
|
||||
```
|
||||
|
||||
|
||||
```bash tab="CLI"
|
||||
--entrypoints=Name:web Address::80 Redirect.EntryPoint:web-secure
|
||||
--entryPoints='Name:web-secure Address::443 TLS:path/to/my.cert,path/to/my.key'
|
||||
```
|
||||
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
- traefik.http.routers.web.rule=Host(`foo.com`)
|
||||
@@ -413,7 +427,7 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||
##---------------------##
|
||||
|
||||
## dynamic configuration
|
||||
# dymanic-conf.toml
|
||||
# dynamic-conf.toml
|
||||
|
||||
[http.routers]
|
||||
[http.routers.router0]
|
||||
@@ -440,9 +454,9 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||
|
||||
[[tls.certificates]]
|
||||
certFile = "/path/to/domain.cert"
|
||||
keyFile = "/path/to/domain.key"
|
||||
keyFile = "/path/to/domain.key"
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## static configuration
|
||||
# traefik.yml
|
||||
@@ -457,7 +471,7 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||
##---------------------##
|
||||
|
||||
## dynamic configuration
|
||||
# dymanic-conf.yml
|
||||
# dynamic-conf.yml
|
||||
|
||||
http:
|
||||
routers:
|
||||
@@ -492,7 +506,139 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||
certificates:
|
||||
- certFile: /app/certs/server/server.pem
|
||||
keyFile: /app/certs/server/server.pem
|
||||
```
|
||||
```
|
||||
|
||||
## Strip and Rewrite Path Prefixes
|
||||
|
||||
With the new core notions of v2 (introduced earlier in the section
|
||||
["Frontends and Backends Are Dead... Long Live Routers, Middlewares, and Services"](#frontends-and-backends-are-dead-long-live-routers-middlewares-and-services)),
|
||||
transforming the URL path prefix of incoming requests is configured with [middlewares](../../middlewares/overview/),
|
||||
after the routing step with [router rule `PathPrefix`](https://docs.traefik.io/v2.0/routing/routers/#rule).
|
||||
|
||||
Use Case: Incoming requests to `http://company.org/admin` are forwarded to the webapplication "admin",
|
||||
with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, you must:
|
||||
|
||||
* First, configure a router named `admin` with a rule matching at least the path prefix with the `PathPrefix` keyword,
|
||||
* Then, define a middlware of type [`stripprefix`](../../middlewares/stripprefix/), which remove the prefix `/admin`, associated to the router `admin`.
|
||||
|
||||
!!! example "Strip Path Prefix When Forwarding to Backend"
|
||||
|
||||
!!! info "v1"
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
- "traefik.frontend.rule=Host:company.org;PathPrefixStrip:/admin"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes Ingress"
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: traefik
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: traefik
|
||||
traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip
|
||||
spec:
|
||||
rules:
|
||||
- host: company.org
|
||||
http:
|
||||
paths:
|
||||
- path: /admin
|
||||
backend:
|
||||
serviceName: admin-svc
|
||||
servicePort: admin
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[frontends.admin]
|
||||
[frontends.admin.routes.admin_1]
|
||||
rule = "Host:company.org;PathPrefixStrip:/admin"
|
||||
```
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
- "traefik.http.routers.admin.rule=Host(`company.org`) && PathPrefix(`/admin`)"
|
||||
- "traefik.http.middlewares.admin-stripprefix.stripprefix.prefixes=/admin"
|
||||
- "traefik.http.routers.web.middlewares=admin-stripprefix@docker"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes IngressRoute"
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: http-redirect-ingressRoute
|
||||
namespace: admin-web
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`company.org`) && PathPrefix(`/admin`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: admin-svc
|
||||
port: admin
|
||||
middlewares:
|
||||
- name: admin-stripprefix
|
||||
---
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: admin-stripprefix
|
||||
spec:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- /admin
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## Dynamic configuration
|
||||
# dynamic-conf.toml
|
||||
|
||||
[http.routers.router1]
|
||||
rule = "Host(`company.org`) && PathPrefix(`/admin`)"
|
||||
service = "admin-svc"
|
||||
entrypoints = ["web"]
|
||||
middlewares = ["admin-stripprefix"]
|
||||
|
||||
[http.middlewares]
|
||||
[http.middlewares.admin-stripprefix.stripPrefix]
|
||||
prefixes = ["/admin"]
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Dynamic Configuration
|
||||
# dynamic-conf.yml
|
||||
|
||||
# As YAML Configuration File
|
||||
http:
|
||||
routers:
|
||||
admin:
|
||||
service: admin-svc
|
||||
middlewares:
|
||||
- "admin-stripprefix"
|
||||
rule: "Host(`company.org`) && PathPrefix(`/admin`)"
|
||||
|
||||
middlewares:
|
||||
admin-stripprefix:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- "/admin"
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
??? question "What About Other Path Transformations?"
|
||||
|
||||
Instead of removing the path prefix with the [`stripprefix` middleware](../../middlewares/stripprefix/), you can also:
|
||||
|
||||
* Add a path prefix with the [`addprefix` middleware](../../middlewares/addprefix/)
|
||||
* Replace the complete path of the request with the [`replacepath` middleware](../../middlewares/replacepath/)
|
||||
* ReplaceRewrite path using Regexp with the [`replacepathregex` middleware](../../middlewares/replacepathregex/)
|
||||
* And a lot more on the [`middlewares` page](../../middlewares/overview/)
|
||||
|
||||
## ACME (LetsEncrypt)
|
||||
|
||||
@@ -522,7 +668,7 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||
[acme.httpChallenge]
|
||||
entryPoint = "web"
|
||||
```
|
||||
|
||||
|
||||
```bash tab="CLI"
|
||||
--defaultentrypoints=web-secure,web
|
||||
--entryPoints=Name:web Address::80 Redirect.EntryPoint:web-secure
|
||||
@@ -533,9 +679,9 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||
--acme.onHostRule=true
|
||||
--acme.httpchallenge.entrypoint=http
|
||||
```
|
||||
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# static configuration
|
||||
[entryPoints]
|
||||
@@ -552,7 +698,7 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||
# used during the challenge
|
||||
entryPoint = "web"
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
entryPoints:
|
||||
web:
|
||||
@@ -569,8 +715,8 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||
httpChallenge:
|
||||
# used during the challenge
|
||||
entryPoint: web
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entryPoints.web.address=":80"
|
||||
--entryPoints.websecure.address=":443"
|
||||
@@ -587,7 +733,7 @@ There is no more log configuration at the root level.
|
||||
!!! example "Simple log configuration"
|
||||
|
||||
!!! info "v1"
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# static configuration
|
||||
logLevel = "DEBUG"
|
||||
@@ -596,15 +742,15 @@ There is no more log configuration at the root level.
|
||||
filePath = "/path/to/traefik.log"
|
||||
format = "json"
|
||||
```
|
||||
|
||||
|
||||
```bash tab="CLI"
|
||||
--logLevel="DEBUG"
|
||||
--traefikLog.filePath="/path/to/traefik.log"
|
||||
--traefikLog.format="json"
|
||||
```
|
||||
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# static configuration
|
||||
[log]
|
||||
@@ -612,15 +758,15 @@ There is no more log configuration at the root level.
|
||||
filePath = "/path/to/log-file.log"
|
||||
format = "json"
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# static configuration
|
||||
log:
|
||||
level: DEBUG
|
||||
filePath: /path/to/log-file.log
|
||||
format: json
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.level="DEBUG"
|
||||
--log.filePath="/path/to/traefik.log"
|
||||
@@ -630,11 +776,11 @@ There is no more log configuration at the root level.
|
||||
## Tracing
|
||||
|
||||
Traefik v2 retains OpenTracing support. The `backend` root option from the v1 is gone, you just have to set your [tracing configuration](../observability/tracing/overview.md).
|
||||
|
||||
|
||||
!!! example "Simple Jaeger tracing configuration"
|
||||
|
||||
!!! info "v1"
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# static configuration
|
||||
[tracing]
|
||||
@@ -646,18 +792,18 @@ Traefik v2 retains OpenTracing support. The `backend` root option from the v1 is
|
||||
samplingType = "const"
|
||||
localAgentHostPort = "12.0.0.1:6831"
|
||||
```
|
||||
|
||||
|
||||
```bash tab="CLI"
|
||||
--tracing.backend="jaeger"
|
||||
--tracing.servicename="tracing"
|
||||
--tracing.jaeger.localagenthostport="12.0.0.1:6831"
|
||||
--tracing.jaeger.samplingparam="1.0"
|
||||
--tracing.jaeger.samplingserverurl="http://12.0.0.1:5778/sampling"
|
||||
--tracing.jaeger.samplingtype="const"
|
||||
--tracing.jaeger.samplingtype="const"
|
||||
```
|
||||
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# static configuration
|
||||
[tracing]
|
||||
@@ -668,7 +814,7 @@ Traefik v2 retains OpenTracing support. The `backend` root option from the v1 is
|
||||
samplingType = "const"
|
||||
localAgentHostPort = "12.0.0.1:6831"
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# static configuration
|
||||
tracing:
|
||||
@@ -678,8 +824,8 @@ Traefik v2 retains OpenTracing support. The `backend` root option from the v1 is
|
||||
samplingServerURL: 'http://12.0.0.1:5778/sampling'
|
||||
samplingType: const
|
||||
localAgentHostPort: '12.0.0.1:6831'
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--tracing.servicename="tracing"
|
||||
--tracing.jaeger.localagenthostport="12.0.0.1:6831"
|
||||
@@ -691,33 +837,33 @@ Traefik v2 retains OpenTracing support. The `backend` root option from the v1 is
|
||||
## Metrics
|
||||
|
||||
The v2 retains metrics tools and allows metrics to be configured for the entrypoints and/or services.
|
||||
For a basic configuration, the [metrics configuration](../observability/metrics/overview.md) remains the same.
|
||||
For a basic configuration, the [metrics configuration](../observability/metrics/overview.md) remains the same.
|
||||
|
||||
!!! example "Simple Prometheus metrics configuration"
|
||||
|
||||
!!! info "v1"
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# static configuration
|
||||
[metrics.prometheus]
|
||||
buckets = [0.1,0.3,1.2,5.0]
|
||||
entryPoint = "traefik"
|
||||
```
|
||||
|
||||
|
||||
```bash tab="CLI"
|
||||
--metrics.prometheus.buckets=[0.1,0.3,1.2,5.0]
|
||||
--metrics.prometheus.entrypoint="traefik"
|
||||
```
|
||||
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# static configuration
|
||||
[metrics.prometheus]
|
||||
buckets = [0.1,0.3,1.2,5.0]
|
||||
entryPoint = "metrics"
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# static configuration
|
||||
metrics:
|
||||
@@ -728,22 +874,22 @@ For a basic configuration, the [metrics configuration](../observability/metrics/
|
||||
- 1.2
|
||||
- 5
|
||||
entryPoint: metrics
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--metrics.prometheus.buckets=[0.1,0.3,1.2,5.0]
|
||||
--metrics.prometheus.entrypoint="metrics"
|
||||
```
|
||||
|
||||
## No more root level key/values
|
||||
## No More Root Level Key/Values
|
||||
|
||||
To avoid any source of confusion, there are no more configuration at the root level.
|
||||
Each root item has been moved to a related section or removed.
|
||||
|
||||
!!! example "From root to dedicated section"
|
||||
|
||||
|
||||
!!! info "v1"
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# static configuration
|
||||
checkNewVersion = false
|
||||
@@ -758,7 +904,7 @@ Each root item has been moved to a related section or removed.
|
||||
defaultEntryPoints = ["web", "web-secure"]
|
||||
keepTrailingSlash = false
|
||||
```
|
||||
|
||||
|
||||
```bash tab="CLI"
|
||||
--checknewversion=false
|
||||
--sendanonymoususage=true
|
||||
@@ -772,9 +918,9 @@ Each root item has been moved to a related section or removed.
|
||||
--defaultentrypoints="web","web-secure"
|
||||
--keeptrailingslash=true
|
||||
```
|
||||
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# static configuration
|
||||
[global]
|
||||
@@ -790,9 +936,9 @@ Each root item has been moved to a related section or removed.
|
||||
maxIdleConnsPerHost = 42
|
||||
|
||||
[providers]
|
||||
providersThrottleDuration = 42
|
||||
providersThrottleDuration = 42
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# static configuration
|
||||
global:
|
||||
@@ -810,8 +956,8 @@ Each root item has been moved to a related section or removed.
|
||||
|
||||
providers:
|
||||
providersThrottleDuration: 42
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--global.checknewversion=true
|
||||
--global.sendanonymoususage=true
|
||||
@@ -821,10 +967,10 @@ Each root item has been moved to a related section or removed.
|
||||
--serverstransport.maxidleconnsperhost=42
|
||||
--providers.providersthrottleduration=42
|
||||
```
|
||||
|
||||
|
||||
## Dashboard
|
||||
|
||||
You need to activate the [API](../operations/dashboard.md#enabling-the-dashboard) to access the dashboard.
|
||||
You need to activate the API to access the [dashboard](../operations/dashboard.md).
|
||||
As the dashboard access is now secured by default you can either:
|
||||
|
||||
* define a [specific router](../operations/api.md#configuration) with the `api@internal` service and one authentication middleware like the following example
|
||||
@@ -833,11 +979,11 @@ As the dashboard access is now secured by default you can either:
|
||||
!!! info "Dashboard with k8s and dedicated router"
|
||||
|
||||
As `api@internal` is not a Kubernetes service, you have to use the file provider or the `insecure` API option.
|
||||
|
||||
|
||||
!!! example "Activate and access the dashboard"
|
||||
|
||||
!!! info "v1"
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## static configuration
|
||||
# traefik.toml
|
||||
@@ -854,14 +1000,14 @@ As the dashboard access is now secured by default you can either:
|
||||
[api]
|
||||
entryPoint = "web-secure"
|
||||
```
|
||||
|
||||
|
||||
```bash tab="CLI"
|
||||
--entryPoints='Name:web-secure Address::443 TLS Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/'
|
||||
--api
|
||||
```
|
||||
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
|
||||
```yaml tab="Docker"
|
||||
# dynamic configuration
|
||||
labels:
|
||||
@@ -870,7 +1016,7 @@ As the dashboard access is now secured by default you can either:
|
||||
- "traefik.http.routers.api.service=api@internal"
|
||||
- "traefik.http.routers.api.middlewares=myAuth"
|
||||
- "traefik.http.routers.api.tls"
|
||||
- "traefik.http.middlewares.myAuth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
- "traefik.http.middlewares.myAuth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -883,12 +1029,12 @@ As the dashboard access is now secured by default you can either:
|
||||
[api]
|
||||
|
||||
[providers.file]
|
||||
filename = "/dymanic-conf.toml"
|
||||
filename = "/dynamic-conf.toml"
|
||||
|
||||
##---------------------##
|
||||
|
||||
## dynamic configuration
|
||||
# dymanic-conf.toml
|
||||
# dynamic-conf.toml
|
||||
|
||||
[http.routers.api]
|
||||
rule = "Host(`traefik.docker.localhost`)"
|
||||
@@ -902,7 +1048,7 @@ As the dashboard access is now secured by default you can either:
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## static configuration
|
||||
# traefik.yaml
|
||||
@@ -915,12 +1061,12 @@ As the dashboard access is now secured by default you can either:
|
||||
|
||||
providers:
|
||||
file:
|
||||
filename: /dymanic-conf.yaml
|
||||
filename: /dynamic-conf.yaml
|
||||
|
||||
##---------------------##
|
||||
|
||||
## dynamic configuration
|
||||
# dymanic-conf.yaml
|
||||
# dynamic-conf.yaml
|
||||
|
||||
http:
|
||||
routers:
|
||||
@@ -938,8 +1084,8 @@ As the dashboard access is now secured by default you can either:
|
||||
basicAuth:
|
||||
users:
|
||||
- 'test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/'
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Providers
|
||||
|
||||
Supported [providers](../providers/overview.md), for now:
|
||||
@@ -962,7 +1108,7 @@ Supported [providers](../providers/overview.md), for now:
|
||||
* [x] Rest
|
||||
* [ ] Zookeeper
|
||||
|
||||
## Some Tips You Should Known
|
||||
## Some Tips You Should Know
|
||||
|
||||
* Different sources of static configuration (file, CLI flags, ...) cannot be [mixed](../getting-started/configuration-overview.md#the-static-configuration).
|
||||
* Now, configuration elements can be referenced between different providers by using the provider namespace notation: `@<provider>`.
|
||||
|
||||
@@ -180,7 +180,7 @@ accessLog:
|
||||
|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `StartUTC` | The time at which request processing started. |
|
||||
| `StartLocal` | The local time at which request processing started. |
|
||||
| `Duration` | The total time taken by processing the response, including the origin server's time but not the log writing time. |
|
||||
| `Duration` | The total time taken (in nanoseconds) by processing the response, including the origin server's time but not the log writing time. |
|
||||
| `FrontendName` | The name of the Traefik frontend. |
|
||||
| `BackendName` | The name of the Traefik backend. |
|
||||
| `BackendURL` | The URL of the Traefik backend. |
|
||||
|
||||
@@ -4,12 +4,12 @@ To enable the InfluxDB:
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.influxdb]
|
||||
[metrics.influxDB]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
influxdb: {}
|
||||
influxDB: {}
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
@@ -24,13 +24,13 @@ Address instructs exporter to send metrics to influxdb at this address.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.influxdb]
|
||||
[metrics.influxDB]
|
||||
address = "localhost:8089"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
influxdb:
|
||||
influxDB:
|
||||
address: localhost:8089
|
||||
```
|
||||
|
||||
@@ -46,13 +46,13 @@ InfluxDB's address protocol (udp or http).
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.influxdb]
|
||||
[metrics.influxDB]
|
||||
protocol = "udp"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
influxdb:
|
||||
influxDB:
|
||||
protocol: udp
|
||||
```
|
||||
|
||||
@@ -68,13 +68,13 @@ InfluxDB database used when protocol is http.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.influxdb]
|
||||
[metrics.influxDB]
|
||||
database = ""
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
influxdb:
|
||||
influxDB:
|
||||
database: ""
|
||||
```
|
||||
|
||||
@@ -90,13 +90,13 @@ InfluxDB retention policy used when protocol is http.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.influxdb]
|
||||
[metrics.influxDB]
|
||||
retentionPolicy = ""
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
influxdb:
|
||||
influxDB:
|
||||
retentionPolicy: ""
|
||||
```
|
||||
|
||||
@@ -112,13 +112,13 @@ InfluxDB username (only with http).
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.influxdb]
|
||||
[metrics.influxDB]
|
||||
username = ""
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
influxdb:
|
||||
influxDB:
|
||||
username: ""
|
||||
```
|
||||
|
||||
@@ -134,13 +134,13 @@ InfluxDB password (only with http).
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.influxdb]
|
||||
[metrics.influxDB]
|
||||
password = ""
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
influxdb:
|
||||
influxDB:
|
||||
password: ""
|
||||
```
|
||||
|
||||
@@ -156,13 +156,13 @@ Enable metrics on entry points.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.influxdb]
|
||||
[metrics.influxDB]
|
||||
addEntryPointsLabels = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
influxdb:
|
||||
influxDB:
|
||||
addEntryPointsLabels: true
|
||||
```
|
||||
|
||||
@@ -178,13 +178,13 @@ Enable metrics on services.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.influxdb]
|
||||
[metrics.influxDB]
|
||||
addServicesLabels = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
influxdb:
|
||||
influxDB:
|
||||
addServicesLabels: true
|
||||
```
|
||||
|
||||
@@ -200,13 +200,13 @@ The interval used by the exporter to push metrics to influxdb.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.influxdb]
|
||||
[metrics.influxDB]
|
||||
pushInterval = 10s
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
influxdb:
|
||||
influxDB:
|
||||
pushInterval: 10s
|
||||
```
|
||||
|
||||
|
||||
@@ -114,5 +114,5 @@ metrics:
|
||||
|
||||
```bash tab="CLI"
|
||||
--entryPoints.metrics.address=":8082"
|
||||
--metrics.prometheus..entryPoint="metrics"
|
||||
--metrics.prometheus.entryPoint="metrics"
|
||||
```
|
||||
|
||||
@@ -4,12 +4,12 @@ To enable the Statsd:
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.statsd]
|
||||
[metrics.statsD]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
statsd: {}
|
||||
statsD: {}
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
@@ -24,13 +24,13 @@ Address instructs exporter to send metrics to statsd at this address.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.statsd]
|
||||
[metrics.statsD]
|
||||
address = "localhost:8125"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
statsd:
|
||||
statsD:
|
||||
address: localhost:8125
|
||||
```
|
||||
|
||||
@@ -46,13 +46,13 @@ Enable metrics on entry points.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.statsd]
|
||||
[metrics.statsD]
|
||||
addEntryPointsLabels = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
statsd:
|
||||
statsD:
|
||||
addEntryPointsLabels: true
|
||||
```
|
||||
|
||||
@@ -68,13 +68,13 @@ Enable metrics on services.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.statsd]
|
||||
[metrics.statsD]
|
||||
addServicesLabels = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
statsd:
|
||||
statsD:
|
||||
addServicesLabels: true
|
||||
```
|
||||
|
||||
@@ -90,13 +90,13 @@ The interval used by the exporter to push metrics to statsD.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.statsd]
|
||||
[metrics.statsD]
|
||||
pushInterval = 10s
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
statsd:
|
||||
statsD:
|
||||
pushInterval: 10s
|
||||
```
|
||||
|
||||
|
||||
4
docs/content/operations/.markdownlint.json
Normal file
4
docs/content/operations/.markdownlint.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../.markdownlint.json",
|
||||
"MD046": false
|
||||
}
|
||||
@@ -14,7 +14,7 @@ In production, it should be at least secured by authentication and authorization
|
||||
A good sane default (non exhaustive) set of recommendations
|
||||
would be to apply the following protection mechanisms:
|
||||
|
||||
* At the transport level:
|
||||
* At the transport level:
|
||||
NOT publicly exposing the API's port,
|
||||
keeping it restricted to internal networks
|
||||
(as in the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), applied to networks).
|
||||
@@ -23,13 +23,16 @@ would be to apply the following protection mechanisms:
|
||||
|
||||
If you enable the API, a new special `service` named `api@internal` is created and can then be referenced in a router.
|
||||
|
||||
To enable the API handler:
|
||||
To enable the API handler, use the following option on the
|
||||
[static configuration](../getting-started/configuration-overview.md#the-static-configuration):
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Static Configuration
|
||||
[api]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Static Configuration
|
||||
api: {}
|
||||
```
|
||||
|
||||
@@ -37,11 +40,13 @@ api: {}
|
||||
--api=true
|
||||
```
|
||||
|
||||
And then you will be able to reference it like this:
|
||||
And then define a routing configuration on Traefik itself with the
|
||||
[dynamic configuration](../getting-started/configuration-overview.md#the-dynamic-configuration):
|
||||
|
||||
```yaml tab="Docker"
|
||||
# Dynamic Configuration
|
||||
labels:
|
||||
- "traefik.http.routers.api.rule=PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
|
||||
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
|
||||
- "traefik.http.routers.api.service=api@internal"
|
||||
- "traefik.http.routers.api.middlewares=auth"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
@@ -49,40 +54,42 @@ labels:
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.routers.api.rule": "PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
|
||||
"traefik.http.routers.api.service": "api@internal"
|
||||
"traefik.http.routers.api.middlewares": "auth"
|
||||
"traefik.http.routers.api.rule": "Host(`traefik.domain.com`)",
|
||||
"traefik.http.routers.api.service": "api@internal",
|
||||
"traefik.http.routers.api.middlewares": "auth",
|
||||
"traefik.http.middlewares.auth.basicauth.users": "test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Declaring the user list
|
||||
# Dynamic Configuration
|
||||
labels:
|
||||
- "traefik.http.routers.api.rule=PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
|
||||
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
|
||||
- "traefik.http.routers.api.service=api@internal"
|
||||
- "traefik.http.routers.api.middlewares=auth"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Dynamic Configuration
|
||||
[http.routers.my-api]
|
||||
rule="PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
|
||||
rule="Host(`traefik.domain.com`)
|
||||
service="api@internal"
|
||||
middlewares=["auth"]
|
||||
|
||||
[http.middlewares.auth.basicAuth]
|
||||
users = [
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Dynamic Configuration
|
||||
http:
|
||||
routers:
|
||||
api:
|
||||
rule: PathPrefix(`/api`) || PathPrefix(`/dashboard`)
|
||||
rule: Host(`traefik.domain.com`)
|
||||
service: api@internal
|
||||
middlewares:
|
||||
- auth
|
||||
@@ -90,10 +97,32 @@ http:
|
||||
auth:
|
||||
basicAuth:
|
||||
users:
|
||||
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
??? warning "The router's [rule](../../routing/routers#rule) must catch requests for the URI path `/api`"
|
||||
Using an "Host" rule is recommended, by catching all the incoming traffic on this host domain to the API.
|
||||
However, you can also use "path prefix" rule or any combination or rules.
|
||||
|
||||
```bash tab="Host Rule"
|
||||
# Matches http://traefik.domain.com, http://traefik.domain.com/api
|
||||
# or http://traefik.domain.com/hello
|
||||
rule = "Host(`traefik.domain.com`)"
|
||||
```
|
||||
|
||||
```bash tab="Path Prefix Rule"
|
||||
# Matches http://api.traefik.domain.com/api or http://domain.com/api
|
||||
# but does not match http://api.traefik.domain.com/hello
|
||||
rule = "PathPrefix(`/api`)"
|
||||
```
|
||||
|
||||
```bash tab="Combination of Rules"
|
||||
# Matches http://traefik.domain.com/api or http://traefik.domain.com/dashboard
|
||||
# but does not match http://traefik.domain.com/hello
|
||||
rule = "Host(`traefik.domain.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
|
||||
```
|
||||
|
||||
### `insecure`
|
||||
|
||||
Enable the API in `insecure` mode, which means that the API will be available directly on the entryPoint named `traefik`.
|
||||
@@ -135,6 +164,9 @@ api:
|
||||
--api.dashboard=true
|
||||
```
|
||||
|
||||
!!! warning "With Dashboard enabled, the router [rule](../../routing/routers#rule) must catch requests for both `/api` and `/dashboard`"
|
||||
Please check the [Dashboard documentation](./dashboard.md#dashboard-router-rule) to learn more about this and to get examples.
|
||||
|
||||
### `debug`
|
||||
|
||||
_Optional, Default=false_
|
||||
@@ -159,24 +191,25 @@ api:
|
||||
|
||||
All the following endpoints must be accessed with a `GET` HTTP request.
|
||||
|
||||
| Path | Description |
|
||||
|--------------------------------|-------------------------------------------------------------------------------------------|
|
||||
| `/api/http/routers` | Lists all the HTTP routers information. |
|
||||
| `/api/http/routers/{name}` | Returns the information of the HTTP router specified by `name`. |
|
||||
| `/api/http/services` | Lists all the HTTP services information. |
|
||||
| `/api/http/services/{name}` | Returns the information of the HTTP service specified by `name`. |
|
||||
| `/api/http/middlewares` | Lists all the HTTP middlewares information. |
|
||||
| `/api/http/middlewares/{name}` | Returns the information of the HTTP middleware specified by `name`. |
|
||||
| `/api/tcp/routers` | Lists all the TCP routers information. |
|
||||
| `/api/tcp/routers/{name}` | Returns the information of the TCP router specified by `name`. |
|
||||
| `/api/tcp/services` | Lists all the TCP services information. |
|
||||
| `/api/tcp/services/{name}` | Returns the information of the TCP service specified by `name`. |
|
||||
| `/api/entrypoints` | Lists all the entry points information. |
|
||||
| `/api/entrypoints/{name}` | Returns the information of the entry point specified by `name`. |
|
||||
| `/api/version` | Returns information about Traefik version. |
|
||||
| `/debug/vars` | See the [expvar](https://golang.org/pkg/expvar/) Go documentation. |
|
||||
| `/debug/pprof/` | See the [pprof Index](https://golang.org/pkg/net/http/pprof/#Index) Go documentation. |
|
||||
| `/debug/pprof/cmdline` | See the [pprof Cmdline](https://golang.org/pkg/net/http/pprof/#Cmdline) Go documentation. |
|
||||
| `/debug/pprof/profile` | See the [pprof Profile](https://golang.org/pkg/net/http/pprof/#Profile) Go documentation. |
|
||||
| `/debug/pprof/symbol` | See the [pprof Symbol](https://golang.org/pkg/net/http/pprof/#Symbol) Go documentation. |
|
||||
| `/debug/pprof/trace` | See the [pprof Trace](https://golang.org/pkg/net/http/pprof/#Trace) Go documentation. |
|
||||
| Path | Description |
|
||||
|--------------------------------|---------------------------------------------------------------------------------------------|
|
||||
| `/api/http/routers` | Lists all the HTTP routers information. |
|
||||
| `/api/http/routers/{name}` | Returns the information of the HTTP router specified by `name`. |
|
||||
| `/api/http/services` | Lists all the HTTP services information. |
|
||||
| `/api/http/services/{name}` | Returns the information of the HTTP service specified by `name`. |
|
||||
| `/api/http/middlewares` | Lists all the HTTP middlewares information. |
|
||||
| `/api/http/middlewares/{name}` | Returns the information of the HTTP middleware specified by `name`. |
|
||||
| `/api/tcp/routers` | Lists all the TCP routers information. |
|
||||
| `/api/tcp/routers/{name}` | Returns the information of the TCP router specified by `name`. |
|
||||
| `/api/tcp/services` | Lists all the TCP services information. |
|
||||
| `/api/tcp/services/{name}` | Returns the information of the TCP service specified by `name`. |
|
||||
| `/api/entrypoints` | Lists all the entry points information. |
|
||||
| `/api/entrypoints/{name}` | Returns the information of the entry point specified by `name`. |
|
||||
| `/api/overview` | Returns statistic information about http and tcp as well as enabled features and providers. |
|
||||
| `/api/version` | Returns information about Traefik version. |
|
||||
| `/debug/vars` | See the [expvar](https://golang.org/pkg/expvar/) Go documentation. |
|
||||
| `/debug/pprof/` | See the [pprof Index](https://golang.org/pkg/net/http/pprof/#Index) Go documentation. |
|
||||
| `/debug/pprof/cmdline` | See the [pprof Cmdline](https://golang.org/pkg/net/http/pprof/#Cmdline) Go documentation. |
|
||||
| `/debug/pprof/profile` | See the [pprof Profile](https://golang.org/pkg/net/http/pprof/#Profile) Go documentation. |
|
||||
| `/debug/pprof/symbol` | See the [pprof Symbol](https://golang.org/pkg/net/http/pprof/#Symbol) Go documentation. |
|
||||
| `/debug/pprof/trace` | See the [pprof Trace](https://golang.org/pkg/net/http/pprof/#Trace) Go documentation. |
|
||||
|
||||
@@ -3,24 +3,33 @@
|
||||
See What's Going On
|
||||
{: .subtitle }
|
||||
|
||||
The dashboard is the central place that shows you the current active routes handled by Traefik.
|
||||
The dashboard is the central place that shows you the current active routes handled by Traefik.
|
||||
|
||||
<figure>
|
||||
<img src="../../assets/img/webui-dashboard.png" alt="Dashboard - Providers" />
|
||||
<figcaption>The dashboard in action</figcaption>
|
||||
</figure>
|
||||
|
||||
By default, the dashboard is available on `/dashboard` on port `:8080`.
|
||||
There is also a redirect of `/` to `/dashboard`, but one should not rely on that property as it is bound to change,
|
||||
and it might make for confusing routing rules anyway.
|
||||
The dashboard is available at the same location as the [API](./api.md) but on the path `/dashboard/` by default.
|
||||
|
||||
!!! info "Did You Know?"
|
||||
It is possible to customize the dashboard endpoint.
|
||||
To learn how, refer to the [API documentation](./api.md)
|
||||
|
||||
## Enabling the Dashboard
|
||||
!!! warning "The trailing slash `/` in `/dashboard/` is mandatory"
|
||||
|
||||
To enable the dashboard, you need to enable [Traefik's API](./api.md).
|
||||
There are 2 ways to configure and access the dashboard:
|
||||
|
||||
- [Secure mode (Recommended)](#secure-mode)
|
||||
- [Insecure mode](#insecure-mode)
|
||||
|
||||
!!! note ""
|
||||
There is also a redirect of the path `/` to the path `/dashboard/`,
|
||||
but one should not rely on that property as it is bound to change,
|
||||
and it might make for confusing routing rules anyway.
|
||||
|
||||
## Secure Mode
|
||||
|
||||
This is the **recommended** method.
|
||||
|
||||
Start by enabling the dashboard by using the following option from [Traefik's API](./api.md)
|
||||
on the [static configuration](../getting-started/configuration-overview.md#the-static-configuration):
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[api]
|
||||
@@ -51,12 +60,125 @@ api:
|
||||
--api.dashboard=true
|
||||
```
|
||||
|
||||
!!! important "API/Dashboard Security"
|
||||
|
||||
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)
|
||||
Then define a routing configuration on Traefik itself,
|
||||
with a router attached to the service `api@internal` in the
|
||||
[dynamic configuration](../getting-started/configuration-overview.md#the-dynamic-configuration),
|
||||
to allow defining:
|
||||
|
||||
!!! info "Did You Know?"
|
||||
The API provides more features than the Dashboard.
|
||||
To learn more about it, refer to the [API documentation](./api.md)
|
||||
- One or more security features through [middlewares](../middlewares/overview.md)
|
||||
like authentication ([basicAuth](../middlewares/basicauth.md) , [digestAuth](../middlewares/digestauth.md),
|
||||
[forwardAuth](../middlewares/forwardauth.md)) or [whitelisting](../middlewares/ipwhitelist.md).
|
||||
|
||||
- A [router rule](#dashboard-router-rule) for accessing the dashboard,
|
||||
through Traefik itself (sometimes referred as "Traefik-ception").
|
||||
|
||||
??? example "Dashboard Dynamic Configuration Examples"
|
||||
|
||||
```yaml tab="Docker"
|
||||
# Dynamic Configuration
|
||||
labels:
|
||||
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
|
||||
- "traefik.http.routers.api.service=api@internal"
|
||||
- "traefik.http.routers.api.middlewares=auth"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.routers.api.rule": "Host(`traefik.domain.com`)",
|
||||
"traefik.http.routers.api.service": "api@internal",
|
||||
"traefik.http.routers.api.middlewares": "auth",
|
||||
"traefik.http.middlewares.auth.basicauth.users": "test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Dynamic Configuration
|
||||
labels:
|
||||
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
|
||||
- "traefik.http.routers.api.service=api@internal"
|
||||
- "traefik.http.routers.api.middlewares=auth"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Dynamic Configuration
|
||||
[http.routers.my-api]
|
||||
rule="Host(`traefik.domain.com`)
|
||||
service="api@internal"
|
||||
middlewares=["auth"]
|
||||
|
||||
[http.middlewares.auth.basicAuth]
|
||||
users = [
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Dynamic Configuration
|
||||
http:
|
||||
routers:
|
||||
api:
|
||||
rule: Host(`traefik.domain.com`)
|
||||
service: api@internal
|
||||
middlewares:
|
||||
- auth
|
||||
middlewares:
|
||||
auth:
|
||||
basicAuth:
|
||||
users:
|
||||
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
### Dashboard Router Rule
|
||||
|
||||
As underlined in the [documentation for the `api.dashboard` option](./api.md#dashboard),
|
||||
the [router rule](../routing/routers/index.md#rule) defined for Traefik must match
|
||||
the path prefixes `/api` and `/dashboard`.
|
||||
|
||||
We recommend to use a "Host Based rule" as ```Host(`traefik.domain.com`)``` to match everything on the host domain,
|
||||
or to make sure that the defined rule captures both prefixes:
|
||||
|
||||
```bash tab="Host Rule"
|
||||
# Matches http://traefik.domain.com/api or http://traefik.domain.com/dashboard
|
||||
rule = "Host(`traefik.domain.com`)"
|
||||
```
|
||||
|
||||
```bash tab="Path Prefix Rule"
|
||||
# Matches http://traefik.domain.com/api , http://domain.com/api or http://traefik.domain.com/dashboard
|
||||
# but does not match http://traefik.domain.com/hello
|
||||
rule = "PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
|
||||
```
|
||||
|
||||
```bash tab="Combination of Rules"
|
||||
# Matches http://traefik.domain.com/api or http://traefik.domain.com/dashboard
|
||||
# but does not match http://traefik.domain.com/hello
|
||||
rule = "Host(`traefik.domain.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
|
||||
```
|
||||
|
||||
## Insecure Mode
|
||||
|
||||
This mode is not recommended because it does not allow the use of security features.
|
||||
|
||||
To enable the "insecure mode", use the following options from [Traefik's API](./api.md#insecure):
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[api]
|
||||
dashboard = true
|
||||
insecure = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
api:
|
||||
dashboard: true
|
||||
insecure: true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--api.dashboard=true --api.insecure=true
|
||||
```
|
||||
|
||||
You can now access the dashboard on the port `8080` of the Traefik instance,
|
||||
at the following URL: `http://<Traefik IP>:8080/dashboard/` (trailing slash is mandatory).
|
||||
|
||||
@@ -29,6 +29,9 @@ You can customize the `entryPoint` where the `/ping` is active with the `entryPo
|
||||
|---------|---------------|-----------------------------------------------------------------------------------------------------|
|
||||
| `/ping` | `GET`, `HEAD` | A simple endpoint to check for Traefik process liveness. Return a code `200` with the content: `OK` |
|
||||
|
||||
!!! note
|
||||
The `cli` comes with a [`healthcheck`](./cli.md#healthcheck) command which can be used for calling this endpoint.
|
||||
|
||||
### `entryPoint`
|
||||
|
||||
Enabling /ping on a dedicated EntryPoint.
|
||||
|
||||
@@ -128,7 +128,7 @@ Traefik requires access to the docker socket to get its dynamic configuration.
|
||||
??? info "Resources about Docker's Security"
|
||||
|
||||
- [KubeCon EU 2018 Keynote, Running with Scissors, from Liz Rice](https://www.youtube.com/watch?v=ltrV-Qmh3oY)
|
||||
- [Don't expose the Docker socket (not even to a container)](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container.html)
|
||||
- [Don't expose the Docker socket (not even to a container)](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container/)
|
||||
- [A thread on Stack Overflow about sharing the `/var/run/docker.sock` file](https://news.ycombinator.com/item?id=17983623)
|
||||
- [To DinD or not to DinD](https://blog.loof.fr/2018/01/to-dind-or-not-do-dind.html)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Good Old Configuration File
|
||||
{: .subtitle }
|
||||
|
||||
The file provider lets you define the [dynamic configuration](./overview.md) in a TOML or YAML file.
|
||||
You can write these configuration elements:
|
||||
You can write one of these mutually exclusive configuration elements:
|
||||
|
||||
* In [a dedicated file](#filename)
|
||||
* In [several dedicated files](#directory)
|
||||
|
||||
@@ -39,6 +39,38 @@ Below is the list of the currently supported providers in Traefik.
|
||||
The current version of Traefik doesn't support (yet) every provider.
|
||||
See the [previous version (v1.7)](https://docs.traefik.io/v1.7/) for more providers.
|
||||
|
||||
### Configuration reload frequency
|
||||
|
||||
In some cases, some providers might undergo a sudden burst of changes,
|
||||
which would generate a lot of configuration change events.
|
||||
If Traefik took them all into account,
|
||||
that would trigger a lot more configuration reloads than what is necessary,
|
||||
or even useful.
|
||||
|
||||
In order to mitigate that, the `providers.providersThrottleDuration` option can be set.
|
||||
It is the duration that Traefik waits for, after a configuration reload,
|
||||
before taking into account any new configuration refresh event.
|
||||
If any event arrives during that duration, only the most recent one is taken into account,
|
||||
and all the previous others are dropped.
|
||||
|
||||
This option cannot be set per provider,
|
||||
but the throttling algorithm applies independently to each of them.
|
||||
It defaults to 2 seconds.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[providers]
|
||||
providers.providersThrottleDuration = 10s
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
providersThrottleDuration: 10s
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--providers.providersThrottleDuration=10s
|
||||
```
|
||||
|
||||
<!--
|
||||
TODO (document TCP VS HTTP dynamic configuration)
|
||||
-->
|
||||
|
||||
@@ -529,7 +529,7 @@ Specifies the header name that will be used to store the trace ID.
|
||||
Settings for Instana. (Default: ```false```)
|
||||
|
||||
`--tracing.instana.localagenthost`:
|
||||
Set instana-agent's host that the reporter will used. (Default: ```localhost```)
|
||||
Set instana-agent's host that the reporter will used.
|
||||
|
||||
`--tracing.instana.localagentport`:
|
||||
Set instana-agent's port that the reporter will used. (Default: ```42699```)
|
||||
|
||||
@@ -529,7 +529,7 @@ Specifies the header name that will be used to store the trace ID.
|
||||
Settings for Instana. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_TRACING_INSTANA_LOCALAGENTHOST`:
|
||||
Set instana-agent's host that the reporter will used. (Default: ```localhost```)
|
||||
Set instana-agent's host that the reporter will used.
|
||||
|
||||
`TRAEFIK_TRACING_INSTANA_LOCALAGENTPORT`:
|
||||
Set instana-agent's port that the reporter will used. (Default: ```42699```)
|
||||
|
||||
@@ -235,3 +235,168 @@ http:
|
||||
servers:
|
||||
- address: xx.xx.xx.xx:xx
|
||||
```
|
||||
|
||||
## Transport configuration
|
||||
|
||||
Most of what happens to the connection between the clients and Traefik,
|
||||
and then between Traefik and the backend servers, is configured through the
|
||||
[entrypoints](../entrypoints) and the [routers](../routers).
|
||||
|
||||
In addition, a few parameters are dedicated to configuring globally
|
||||
what happens with the connections between Traefik and the backends.
|
||||
This is done through the `serversTransport` section of the configuration,
|
||||
which features these options:
|
||||
|
||||
### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
`insecureSkipVerify` disables SSL certificate verification.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## Static configuration
|
||||
[serversTransport]
|
||||
insecureSkipVerify = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Static configuration
|
||||
serversTransport:
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--serversTransport.insecureSkipVerify=true
|
||||
```
|
||||
|
||||
### `rootCAs`
|
||||
|
||||
_Optional_
|
||||
|
||||
`rootCAs` is the list of certificates (as file paths, or data bytes)
|
||||
that will be set as Root Certificate Authorities when using a self-signed TLS certificate.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## Static configuration
|
||||
[serversTransport]
|
||||
rootCAs = ["foo.crt", "bar.crt"]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Static configuration
|
||||
serversTransport:
|
||||
rootCAs:
|
||||
- foo.crt
|
||||
- bar.crt
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--serversTransport.rootCAs=foo.crt,bar.crt
|
||||
```
|
||||
|
||||
### `maxIdleConnsPerHost`
|
||||
|
||||
_Optional, Default=2_
|
||||
|
||||
If non-zero, `maxIdleConnsPerHost` controls the maximum idle (keep-alive) connections to keep per-host.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## Static configuration
|
||||
[serversTransport]
|
||||
maxIdleConnsPerHost = 7
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Static configuration
|
||||
serversTransport:
|
||||
maxIdleConnsPerHost: 7
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--serversTransport.maxIdleConnsPerHost=7
|
||||
```
|
||||
|
||||
### `forwardingTimeouts`
|
||||
|
||||
`forwardingTimeouts` is about a number of timeouts relevant to when forwarding requests to the backend servers.
|
||||
|
||||
#### forwardingTimeouts.dialTimeout`
|
||||
|
||||
_Optional, Default=30s_
|
||||
|
||||
`dialTimeout` is the maximum duration allowed for a connection to a backend server to be established.
|
||||
Zero means no timeout.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## Static configuration
|
||||
[serversTransport.forwardingTimeouts]
|
||||
dialTimeout = "1s"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Static configuration
|
||||
serversTransport:
|
||||
forwardingTimeouts:
|
||||
dialTimeout: 1s
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--serversTransport.forwardingTimeouts.dialTimeout=1s
|
||||
```
|
||||
|
||||
#### forwardingTimeouts.responseHeaderTimeout`
|
||||
|
||||
_Optional, Default=0s_
|
||||
|
||||
`responseHeaderTimeout`, if non-zero, specifies the amount of time to wait for a server's response headers
|
||||
after fully writing the request (including its body, if any).
|
||||
This time does not include the time to read the response body.
|
||||
Zero means no timeout.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## Static configuration
|
||||
[serversTransport.forwardingTimeouts]
|
||||
responseHeaderTimeout = "1s"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Static configuration
|
||||
serversTransport:
|
||||
forwardingTimeouts:
|
||||
responseHeaderTimeout: 1s
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--serversTransport.forwardingTimeouts.responseHeaderTimeout=1s
|
||||
```
|
||||
|
||||
#### forwardingTimeouts.idleConnTimeout`
|
||||
|
||||
_Optional, Default=90s_
|
||||
|
||||
`idleConnTimeout`, is the maximum amount of time an idle (keep-alive) connection
|
||||
will remain idle before closing itself.
|
||||
Zero means no limit.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## Static configuration
|
||||
[serversTransport.forwardingTimeouts]
|
||||
idleConnTimeout = "1s"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Static configuration
|
||||
serversTransport:
|
||||
forwardingTimeouts:
|
||||
idleConnTimeout: 1s
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--serversTransport.forwardingTimeouts.idleConnTimeout=1s
|
||||
```
|
||||
|
||||
@@ -12,16 +12,16 @@ Attach labels to your containers and let Traefik do the rest!
|
||||
??? example "Configuring Docker & Deploying / Exposing Services"
|
||||
|
||||
Enabling the docker provider
|
||||
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[providers.docker]
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
docker: {}
|
||||
```
|
||||
|
||||
|
||||
```bash tab="CLI"
|
||||
--providers.docker=true
|
||||
```
|
||||
@@ -37,6 +37,27 @@ Attach labels to your containers and let Traefik do the rest!
|
||||
- traefik.http.routers.my-container.rule=Host(`mydomain.com`)
|
||||
```
|
||||
|
||||
??? example "Specify a Custom Port for the Container"
|
||||
|
||||
Forward requests for `http://mydomain.com` to `http://<private IP of container>:12345`:
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
labels:
|
||||
- traefik.http.routers.my-container.rule=Host(`mydomain.com`)
|
||||
# Tell Traefik to use the port 12345 to connect to `my-container`
|
||||
- traefik.http.services.my-service.loadbalancer.server.port=12345
|
||||
```
|
||||
|
||||
!!! important "Traefik Connecting to the Wrong Port: `HTTP/502 Gateway Error`"
|
||||
By default, Traefik uses the first exposed port of a container.
|
||||
|
||||
Setting the label `traefik.http.services.xxx.loadbalancer.server.port`
|
||||
overrides that behavior.
|
||||
|
||||
??? example "Configuring Docker Swarm & Deploying / Exposing Services"
|
||||
|
||||
Enabling the docker provider (Swarm Mode)
|
||||
@@ -49,7 +70,7 @@ Attach labels to your containers and let Traefik do the rest!
|
||||
endpoint = "tcp://127.0.0.1:2377"
|
||||
swarmMode = true
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
docker:
|
||||
@@ -59,7 +80,7 @@ Attach labels to your containers and let Traefik do the rest!
|
||||
endpoint: "tcp://127.0.0.1:2375"
|
||||
swarmMode: true
|
||||
```
|
||||
|
||||
|
||||
```bash tab="CLI"
|
||||
--providers.docker.endpoint="tcp://127.0.0.1:2375"
|
||||
--providers.docker.swarmMode=true
|
||||
@@ -85,7 +106,7 @@ Attach labels to your containers and let Traefik do the rest!
|
||||
## Routing Configuration
|
||||
|
||||
!!! info "Labels"
|
||||
|
||||
|
||||
- Labels are case insensitive.
|
||||
- The complete list of labels can be found in [the reference page](../../reference/dynamic-configuration/docker.md).
|
||||
|
||||
@@ -129,82 +150,84 @@ add labels starting with `traefik.http.routers.<name-of-your-choice>.` and follo
|
||||
|
||||
For example, to change the rule, you could add the label ```traefik.http.routers.my-container.rule=Host(`mydomain.com`)```.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../routers/index.md#rule) for more information.
|
||||
|
||||
|
||||
See [rule](../routers/index.md#rule) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.rule=Host(`mydomain.com`)"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../routers/index.md#entrypoints) for more information.
|
||||
|
||||
|
||||
See [entry points](../routers/index.md#entrypoints) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.entrypoints=web,websecure"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.middlewares`"
|
||||
|
||||
See [middlewares](../routers/index.md#middlewares) and [middlewares overview](../../middlewares/overview.md) for more information.
|
||||
|
||||
|
||||
See [middlewares](../routers/index.md#middlewares) and [middlewares overview](../../middlewares/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.middlewares=auth,prefix,cb"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.service`"
|
||||
|
||||
See [rule](../routers/index.md#service) for more information.
|
||||
|
||||
|
||||
See [rule](../routers/index.md#service) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.service=myservice"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls`"
|
||||
|
||||
|
||||
See [tls](../routers/index.md#tls) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter>.tls=true"
|
||||
- "traefik.http.routers.myrouter.tls=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
|
||||
See [certResolver](../routers/index.md#certresolver) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.tls.certresolver=myresolver"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
|
||||
See [domains](../routers/index.md#domains) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.tls.domains[0].main=foobar.com"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
|
||||
See [domains](../routers/index.md#domains) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.tls.domains[0].sans=test.foobar.com,dev.foobar.com"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.options`"
|
||||
|
||||
|
||||
See [options](../routers/index.md#options) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.tls.options=foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.priority`"
|
||||
|
||||
|
||||
See [options](../routers/index.md#priority) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.priority=42"
|
||||
```
|
||||
@@ -217,125 +240,127 @@ add labels starting with `traefik.http.services.<name-of-your-choice>.`, followe
|
||||
For example, to change the `passHostHeader` behavior,
|
||||
you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.passhostheader=false`.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
|
||||
Registers a port.
|
||||
Useful when the container exposes multiples ports.
|
||||
|
||||
|
||||
Mandatory for Docker Swarm.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.server.port=8080"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.scheme`"
|
||||
|
||||
|
||||
Overrides the default scheme.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.server.scheme=http"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
|
||||
<!-- TODO doc passHostHeader in services page -->
|
||||
|
||||
|
||||
See [pass Host header](../services/index.md#pass-host-header) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.passhostheader=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.headers.<header_name>`"
|
||||
|
||||
|
||||
See [health check](../services/index.md#health-check) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.headers.X-Foo=foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.hostname`"
|
||||
|
||||
|
||||
See [health check](../services/index.md#health-check) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.hostname=foobar.com"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.interval`"
|
||||
|
||||
|
||||
See [health check](../services/index.md#health-check) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.interval=10"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.path`"
|
||||
|
||||
|
||||
See [health check](../services/index.md#health-check) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.path=/foo"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
|
||||
|
||||
|
||||
See [health check](../services/index.md#health-check) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.port=42"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.scheme`"
|
||||
|
||||
|
||||
See [health check](../services/index.md#health-check) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.scheme=http"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.timeout`"
|
||||
|
||||
|
||||
See [health check](../services/index.md#health-check) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.timeout=10"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky`"
|
||||
|
||||
|
||||
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.httponly`"
|
||||
|
||||
|
||||
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.httponly=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.name`"
|
||||
|
||||
|
||||
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
|
||||
|
||||
|
||||
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.secure=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||
<!-- TODO doc responseforwarding in services page -->
|
||||
|
||||
FlushInterval specifies the flush interval to flush to the client while copying the response body.
|
||||
|
||||
|
||||
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval=10"
|
||||
```
|
||||
@@ -350,6 +375,8 @@ you'd write `traefik.http.middlewares.my-redirect.redirectscheme.scheme=https`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
|
||||
|
||||
!!! warning "The character `@` is not authorized in the middleware name."
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
@@ -391,73 +418,73 @@ You can declare TCP Routers and/or Services using labels.
|
||||
#### TCP Routers
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.entrypoints`"
|
||||
|
||||
|
||||
See [entry points](../routers/index.md#entrypoints_1) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.entrypoints=ep1,ep2"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.rule`"
|
||||
|
||||
|
||||
See [rule](../routers/index.md#rule_1) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.rule=HostSNI(`myhost.com`)"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.service`"
|
||||
|
||||
|
||||
See [service](../routers/index.md#services) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.service=myservice"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls`"
|
||||
|
||||
|
||||
See [TLS](../routers/index.md#tls_1) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
|
||||
See [certResolver](../routers/index.md#certresolver_1) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls.certresolver=myresolver"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
|
||||
See [domains](../routers/index.md#domains_1) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls.domains[0].main=foobar.com"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
|
||||
See [domains](../routers/index.md#domains_1) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls.domains[0].sans=test.foobar.com,dev.foobar.com"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.options`"
|
||||
|
||||
|
||||
See [options](../routers/index.md#options_1) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls.options=mysoptions"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.passthrough`"
|
||||
|
||||
|
||||
See [TLS](../routers/index.md#tls_1) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls.passthrough=true"
|
||||
```
|
||||
@@ -465,17 +492,17 @@ You can declare TCP Routers and/or Services using labels.
|
||||
#### TCP Services
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
|
||||
Registers a port of the application.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.services.mytcpservice.loadbalancer.server.port=423"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.terminationdelay`"
|
||||
|
||||
|
||||
See [termination delay](../services/index.md#termination-delay) for more information.
|
||||
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.services.mytcpservice.loadbalancer.terminationdelay=100"
|
||||
```
|
||||
|
||||
@@ -52,6 +52,8 @@ add labels starting with `traefik.http.routers.{router-name-of-your-choice}.` an
|
||||
|
||||
For example, to change the routing rule, you could add the label ```"traefik.http.routers.routername.rule": "Host(`mydomain.com`)"```.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../routers/index.md#rule) for more information.
|
||||
@@ -139,6 +141,8 @@ add labels starting with `traefik.http.services.{service-name-of-your-choice}.`,
|
||||
|
||||
For example, to change the passHostHeader behavior, you'd add the label `"traefik.http.services.servicename.loadbalancer.passhostheader": "false"`.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port.
|
||||
@@ -157,7 +161,8 @@ For example, to change the passHostHeader behavior, you'd add the label `"traefi
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
|
||||
<!-- TODO doc passHostHeader in services page -->
|
||||
|
||||
See [pass Host header](../services/index.md#pass-host-header) for more information.
|
||||
|
||||
```json
|
||||
"traefik.http.services.myservice.loadbalancer.passhostheader": "true"
|
||||
@@ -252,10 +257,9 @@ For example, to change the passHostHeader behavior, you'd add the label `"traefi
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||
<!-- TODO doc responseforwarding in services page -->
|
||||
|
||||
FlushInterval specifies the flush interval to flush to the client while copying the response body.
|
||||
|
||||
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
||||
|
||||
```json
|
||||
"traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval": "10"
|
||||
```
|
||||
@@ -268,6 +272,8 @@ For example, to declare a middleware [`redirectscheme`](../../middlewares/redire
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
|
||||
|
||||
!!! warning "The character `@` is not authorized in the middleware name."
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```json
|
||||
|
||||
@@ -57,6 +57,8 @@ To update the configuration of the Router automatically attached to the containe
|
||||
|
||||
For example, to change the rule, you could add the label ```traefik.http.routers.my-container.rule=Host(`mydomain.com`)```.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../routers/index.md#rule) for more information.
|
||||
@@ -145,6 +147,8 @@ add labels starting with `traefik.http.services.{name-of-your-choice}.`, followe
|
||||
For example, to change the `passHostHeader` behavior,
|
||||
you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.passhostheader=false`.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port.
|
||||
@@ -163,7 +167,8 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
|
||||
<!-- TODO doc passHostHeader in services page -->
|
||||
|
||||
See [pass Host header](../services/index.md#pass-host-header) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.passhostheader=true"
|
||||
@@ -258,10 +263,9 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||
<!-- TODO doc responseforwarding in services page -->
|
||||
|
||||
FlushInterval specifies the flush interval to flush to the client while copying the response body.
|
||||
|
||||
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval=10"
|
||||
```
|
||||
@@ -274,6 +278,8 @@ For example, to declare a middleware [`redirectscheme`](../../middlewares/redire
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
|
||||
|
||||
!!! warning "The character `@` is not authorized in the middleware name."
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -7,9 +7,8 @@ There are, however, exceptions when using label-based configurations:
|
||||
and a label defines a service (e.g. implicitly through a loadbalancer server port value),
|
||||
but the router does not specify any service,
|
||||
then that service is automatically assigned to the router.
|
||||
1. If a label defines a router (e.g. through a router Rule)
|
||||
but no service is defined, then a service is automatically created
|
||||
and assigned to the router.
|
||||
1. If a label defines a router (e.g. through a router Rule) but no service is defined,
|
||||
then a service is automatically created and assigned to the router.
|
||||
|
||||
!!! info ""
|
||||
As one would expect, in either of these cases, if in addition a service is specified for the router,
|
||||
|
||||
@@ -84,6 +84,8 @@ In the process, routers may use pieces of [middleware](../../middlewares/overvie
|
||||
|
||||
## Configuring HTTP Routers
|
||||
|
||||
!!! warning "The character `@` is not authorized in the router name"
|
||||
|
||||
### EntryPoints
|
||||
|
||||
If not specified, HTTP routers will accept requests from all defined entry points.
|
||||
@@ -203,9 +205,14 @@ If you want to limit the router scope to a set of entry points, set the `entryPo
|
||||
|
||||
### Rule
|
||||
|
||||
Rules are a set of matchers that determine if a particular request matches specific criteria.
|
||||
Rules are a set of matchers configured with values, that determine if a particular request matches specific criteria.
|
||||
If the rule is verified, the router becomes active, calls middlewares, and then forwards the request to the service.
|
||||
|
||||
??? tip "Backticks or Quotes?"
|
||||
To set the value of a rule, use [backticks](https://en.wiktionary.org/wiki/backtick) ``` ` ``` or escaped double-quotes `\"`.
|
||||
|
||||
Single quotes `'` are not accepted as values are [Golang's String Literals](https://golang.org/ref/spec#String_literals).
|
||||
|
||||
!!! example "Host is traefik.io"
|
||||
|
||||
```toml
|
||||
@@ -229,7 +236,7 @@ The table below lists all the available matchers:
|
||||
| ```Method(`GET`, ...)``` | Check if the request method is one of the given `methods` (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`) |
|
||||
| ```Path(`/path`, `/articles/{category}/{id:[0-9]+}`, ...)``` | Match exact request path. It accepts a sequence of literal and regular expression paths. |
|
||||
| ```PathPrefix(`/products/`, `/articles/{category}/{id:[0-9]+}`)``` | Match request prefix path. It accepts a sequence of literal and regular expression prefix paths. |
|
||||
| ```Query(`foo=bar`, `bar=baz`)``` | Match` Query String parameters. It accepts a sequence of key=value pairs. |
|
||||
| ```Query(`foo=bar`, `bar=baz`)``` | Match Query String parameters. It accepts a sequence of key=value pairs. |
|
||||
|
||||
!!! important "Regexp Syntax"
|
||||
|
||||
@@ -337,6 +344,8 @@ A value of `0` for the priority is ignored: `priority = 0` means that the defaul
|
||||
You can attach a list of [middlewares](../../middlewares/overview.md) to each HTTP router.
|
||||
The middlewares will take effect only if the rule matches, and before forwarding the request to the service.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the middleware name."
|
||||
|
||||
!!! tip "Middlewares order"
|
||||
|
||||
Middlewares are applied in the same order as their declaration in **router**.
|
||||
@@ -376,6 +385,8 @@ but there are exceptions for label-based providers.
|
||||
See the specific [docker](../providers/docker.md#service-definition), [rancher](../providers/rancher.md#service-definition),
|
||||
or [marathon](../providers/marathon.md#service-definition) documentation.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the middleware name."
|
||||
|
||||
!!! important "HTTP routers can only target HTTP services (not TCP services)."
|
||||
|
||||
### TLS
|
||||
@@ -479,8 +490,11 @@ It refers to a [TLS Options](../../https/tls.md#tls-options) and will be applied
|
||||
[tls.options.foo]
|
||||
minVersion = "VersionTLS12"
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||
]
|
||||
```
|
||||
|
||||
@@ -500,8 +514,11 @@ It refers to a [TLS Options](../../https/tls.md#tls-options) and will be applied
|
||||
foo:
|
||||
minVersion: VersionTLS12
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
|
||||
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
```
|
||||
|
||||
!!! important "Conflicting TLS Options"
|
||||
@@ -596,7 +613,8 @@ http:
|
||||
certResolver: "bar"
|
||||
domains:
|
||||
- main: "snitest.com"
|
||||
sans: "*.snitest.com"
|
||||
sans:
|
||||
- "*.snitest.com"
|
||||
```
|
||||
|
||||
[ACME v2](https://community.letsencrypt.org/t/acme-v2-and-wildcard-certificate-support-is-live/55579) supports wildcard certificates.
|
||||
@@ -617,6 +635,8 @@ The [supported `provider` table](../../https/acme.md#providers) indicates if the
|
||||
|
||||
## Configuring TCP Routers
|
||||
|
||||
!!! warning "The character `@` is not authorized in the router name"
|
||||
|
||||
### General
|
||||
|
||||
If both HTTP routers and TCP routers listen to the same entry points, the TCP routers will apply *before* the HTTP routers.
|
||||
@@ -851,8 +871,11 @@ It refers to a [TLS Options](../../https/tls.md#tls-options) and will be applied
|
||||
[tls.options.foo]
|
||||
minVersion = "VersionTLS12"
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||
]
|
||||
```
|
||||
|
||||
@@ -872,8 +895,11 @@ It refers to a [TLS Options](../../https/tls.md#tls-options) and will be applied
|
||||
foo:
|
||||
minVersion: VersionTLS12
|
||||
cipherSuites:
|
||||
- "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
- "TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
|
||||
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
```
|
||||
|
||||
#### `certResolver`
|
||||
@@ -925,5 +951,6 @@ tcp:
|
||||
certResolver: "bar"
|
||||
domains:
|
||||
- main: "snitest.com"
|
||||
sans: "*.snitest.com"
|
||||
sans:
|
||||
- "*.snitest.com"
|
||||
```
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"extends": "../../../.markdownlint.json",
|
||||
"MD024": false
|
||||
"MD024": false,
|
||||
"MD046": false
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ Configuring How to Reach the Services
|
||||
|
||||

|
||||
|
||||
The `Services` are responsible for configuring how to reach the actual services that will eventually handle the incoming requests.
|
||||
The `Services` are responsible for configuring how to reach the actual services that will eventually handle the incoming requests.
|
||||
|
||||
## Configuration Example
|
||||
## Configuration Examples
|
||||
|
||||
??? example "Declaring an HTTP Service with Two Servers -- Using the [File Provider](../../providers/file.md)"
|
||||
|
||||
@@ -17,11 +17,11 @@ The `Services` are responsible for configuring how to reach the actual services
|
||||
[http.services.my-service.loadBalancer]
|
||||
|
||||
[[http.services.my-service.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-1/"
|
||||
url = "http://<private-ip-server-1>:<private-port-server-1>/"
|
||||
[[http.services.my-service.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-2/"
|
||||
url = "http://<private-ip-server-2>:<private-port-server-2>/"
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="YAML"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
@@ -29,8 +29,8 @@ The `Services` are responsible for configuring how to reach the actual services
|
||||
my-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://private-ip-server-1/"
|
||||
- url: "http://private-ip-server-2/"
|
||||
- url: "http://<private-ip-server-1>:<private-port-server-1>/"
|
||||
- url: "http://<private-ip-server-2>:<private-port-server-2>/"
|
||||
```
|
||||
|
||||
??? example "Declaring a TCP Service with Two Servers -- Using the [File Provider](../../providers/file.md)"
|
||||
@@ -40,26 +40,28 @@ The `Services` are responsible for configuring how to reach the actual services
|
||||
[tcp.services]
|
||||
[tcp.services.my-service.loadBalancer]
|
||||
[[tcp.services.my-service.loadBalancer.servers]]
|
||||
address = "xx.xx.xx.xx:xx"
|
||||
address = "<private-ip-server-1>:<private-port-server-1>"
|
||||
[[tcp.services.my-service.loadBalancer.servers]]
|
||||
address = "xx.xx.xx.xx:xx"
|
||||
address = "<private-ip-server-2>:<private-port-server-2>"
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="YAML"
|
||||
tcp:
|
||||
services:
|
||||
my-service:
|
||||
loadBalancer:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "xx.xx.xx.xx:xx"
|
||||
- address: "xx.xx.xx.xx:xx"
|
||||
- address: "<private-ip-server-1>:<private-port-server-1>"
|
||||
- address: "<private-ip-server-2>:<private-port-server-2>"
|
||||
```
|
||||
|
||||
## Configuring HTTP Services
|
||||
|
||||
### Servers Load Balancer
|
||||
|
||||
The load balancers are able to load balance the requests between multiple instances of your programs.
|
||||
The load balancers are able to load balance the requests between multiple instances of your programs.
|
||||
|
||||
Each service has a load-balancer, even if there is only one server to forward traffic to.
|
||||
|
||||
??? example "Declaring a Service with Two Servers (with Load Balancing) -- Using the [File Provider](../../providers/file.md)"
|
||||
|
||||
@@ -87,10 +89,10 @@ The load balancers are able to load balance the requests between multiple instan
|
||||
#### Servers
|
||||
|
||||
Servers declare a single instance of your program.
|
||||
The `url` option point to a specific instance.
|
||||
The `url` option point to a specific instance.
|
||||
|
||||
!!! info ""
|
||||
Paths in the servers' `url` have no effect.
|
||||
Paths in the servers' `url` have no effect.
|
||||
If you want the requests to be sent to a specific path on your servers,
|
||||
configure your [`routers`](../routers/index.md) to use a corresponding [middleware](../../middlewares/overview.md) (e.g. the [AddPrefix](../../middlewares/addprefix.md) or [ReplacePath](../../middlewares/replacepath.md)) middlewares.
|
||||
|
||||
@@ -103,7 +105,7 @@ The `url` option point to a specific instance.
|
||||
[[http.services.my-service.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-1/"
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="YAML"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
@@ -142,21 +144,21 @@ For now, only round robin load balancing is supported:
|
||||
```
|
||||
|
||||
#### Sticky sessions
|
||||
|
||||
|
||||
When sticky sessions are enabled, a cookie is set on the initial request to track which server handles the first response.
|
||||
On subsequent requests, the client is forwarded to the same server.
|
||||
|
||||
!!! info "Stickiness & Unhealthy Servers"
|
||||
|
||||
|
||||
If the server specified in the cookie becomes unhealthy, the request will be forwarded to a new server (and the cookie will keep track of the new server).
|
||||
|
||||
!!! info "Cookie Name"
|
||||
|
||||
!!! info "Cookie Name"
|
||||
|
||||
The default cookie name is an abbreviation of a sha1 (ex: `_1d52e`).
|
||||
|
||||
!!! info "Secure & HTTPOnly flags"
|
||||
|
||||
By default, the affinity cookie is created without those flags. One however can change that through configuration.
|
||||
By default, the affinity cookie is created without those flags. One however can change that through configuration.
|
||||
|
||||
??? example "Adding Stickiness -- Using the [File Provider](../../providers/file.md)"
|
||||
|
||||
@@ -166,7 +168,7 @@ On subsequent requests, the client is forwarded to the same server.
|
||||
[http.services.my-service]
|
||||
[http.services.my-service.loadBalancer.sticky.cookie]
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="YAML"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
@@ -223,8 +225,8 @@ Below are the available options for the health check mechanism:
|
||||
The interval must be greater than the timeout. If configuration doesn't reflect this, the interval will be set to timeout + 1 second.
|
||||
|
||||
!!! info "Recovering Servers"
|
||||
|
||||
Traefik keeps monitoring the health of unhealthy servers.
|
||||
|
||||
Traefik keeps monitoring the health of unhealthy servers.
|
||||
If a server has recovered (returning `2xx` -> `3xx` responses again), it will be added back to the load balacer rotation pool.
|
||||
|
||||
??? example "Custom Interval & Timeout -- Using the [File Provider](../../providers/file.md)"
|
||||
@@ -232,7 +234,7 @@ Below are the available options for the health check mechanism:
|
||||
```toml tab="TOML"
|
||||
## Dynamic configuration
|
||||
[http.services]
|
||||
[http.servicess.Service-1]
|
||||
[http.services.Service-1]
|
||||
[http.services.Service-1.loadBalancer.healthCheck]
|
||||
path = "/health"
|
||||
interval = "10s"
|
||||
@@ -242,7 +244,7 @@ Below are the available options for the health check mechanism:
|
||||
```yaml tab="YAML"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
servicess:
|
||||
services:
|
||||
Service-1:
|
||||
loadBalancer:
|
||||
healthCheck:
|
||||
@@ -261,7 +263,7 @@ Below are the available options for the health check mechanism:
|
||||
path = "/health"
|
||||
port = 8080
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="YAML"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
@@ -283,7 +285,7 @@ Below are the available options for the health check mechanism:
|
||||
path = "/health"
|
||||
scheme = "http"
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="YAML"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
@@ -308,7 +310,7 @@ Below are the available options for the health check mechanism:
|
||||
My-Custom-Header = "foo"
|
||||
My-Header = "bar"
|
||||
```
|
||||
|
||||
|
||||
```yaml tab="YAML"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
@@ -322,6 +324,63 @@ Below are the available options for the health check mechanism:
|
||||
My-Header: bar
|
||||
```
|
||||
|
||||
#### Pass Host Header
|
||||
|
||||
The `passHostHeader` allows to forward client Host header to server.
|
||||
|
||||
By default, `passHostHeader` is true.
|
||||
|
||||
??? example "Don't forward the host header -- Using the [File Provider](../../providers/file.md)"
|
||||
|
||||
```toml tab="TOML"
|
||||
## Dynamic configuration
|
||||
[http.services]
|
||||
[http.services.Service01]
|
||||
[http.services.Service01.loadBalancer]
|
||||
passHostHeader = false
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
services:
|
||||
Service01:
|
||||
loadBalancer:
|
||||
passHostHeader: false
|
||||
```
|
||||
|
||||
#### Response Forwarding
|
||||
|
||||
This section is about configuring how Traefik forwards the response from the backend server to the client.
|
||||
|
||||
Below are the available options for the Response Forwarding mechanism:
|
||||
|
||||
- `FlushInterval` specifies the interval in between flushes to the client while copying the response body.
|
||||
It is a duration in milliseconds, defaulting to 100.
|
||||
A negative value means to flush immediately after each write to the client.
|
||||
The FlushInterval is ignored when ReverseProxy recognizes a response as a streaming response;
|
||||
for such responses, writes are flushed to the client immediately.
|
||||
|
||||
??? example "Using a custom FlushInterval -- Using the [File Provider](../../providers/file.md)"
|
||||
|
||||
```toml tab="TOML"
|
||||
## Dynamic configuration
|
||||
[http.services]
|
||||
[http.services.Service-1]
|
||||
[http.services.Service-1.loadBalancer.responseForwarding]
|
||||
flushInterval = "1s"
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
services:
|
||||
Service-1:
|
||||
loadBalancer:
|
||||
responseForwarding:
|
||||
flushInterval: 1s
|
||||
```
|
||||
|
||||
### Weighted Round Robin (service)
|
||||
|
||||
The WRR is able to load balance the requests between multiple services based on weights.
|
||||
@@ -482,7 +541,7 @@ The `address` option (IP:Port) point to a specific instance.
|
||||
my-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
address: "xx.xx.xx.xx:xx"
|
||||
- address: "xx.xx.xx.xx:xx"
|
||||
```
|
||||
|
||||
#### Termination Delay
|
||||
|
||||
@@ -6,7 +6,7 @@ metadata:
|
||||
|
||||
---
|
||||
kind: Deployment
|
||||
apiVersion: extensions/v1beta1
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
namespace: default
|
||||
name: traefik
|
||||
@@ -49,7 +49,7 @@ spec:
|
||||
|
||||
---
|
||||
kind: Deployment
|
||||
apiVersion: extensions/v1beta1
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
namespace: default
|
||||
name: whoami
|
||||
|
||||
@@ -2,6 +2,7 @@ apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: simpleingressroute
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
@@ -17,6 +18,7 @@ apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: ingressroutetls
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
|
||||
@@ -101,4 +101,4 @@ curl [-k] https://your.domain.com/tls
|
||||
curl [-k] http://your.domain.com:8000/notls
|
||||
```
|
||||
|
||||
Note that you'll have to use `-k` as long as you're using the staging server of Let's Encrypt, since it is not in the root DNS servers.
|
||||
Note that you'll have to use `-k` as long as you're using the staging server of Let's Encrypt, since it is not an authorized certificate authority on systems where it hasn't been manually added.
|
||||
|
||||
@@ -21,7 +21,7 @@ find "${PATH_TO_SITE}" -type f -not -path "/app/site/theme/*" \
|
||||
--check_external_hash \
|
||||
--alt_ignore="/traefik.logo.png/" \
|
||||
--http_status_ignore="0,500,501,503" \
|
||||
--url_ignore="/https://groups.google.com/a/traefik.io/forum/#!forum/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/containous\/traefik\/*edit*/,/github.com\/containous\/traefik\/$/,/docs.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/" \
|
||||
--url_ignore="/https://groups.google.com/a/traefik.io/forum/#!forum/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/containous\/traefik\/*edit*/,/github.com\/containous\/traefik\/$/,/docs.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/,/www.akamai.com/" \
|
||||
'{}' 1>/dev/null
|
||||
## HTML-proofer options at https://github.com/gjtorikian/html-proofer#configuration
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# WEBUI
|
||||
FROM node:8.15.0 as webui
|
||||
FROM node:12.11 as webui
|
||||
|
||||
ENV WEBUI_DIR /src/webui
|
||||
RUN mkdir -p $WEBUI_DIR
|
||||
@@ -7,7 +7,7 @@ RUN mkdir -p $WEBUI_DIR
|
||||
COPY ./webui/ $WEBUI_DIR/
|
||||
|
||||
WORKDIR $WEBUI_DIR
|
||||
RUN yarn install
|
||||
RUN npm install
|
||||
|
||||
RUN npm run build
|
||||
|
||||
|
||||
13
go.mod
13
go.mod
@@ -39,7 +39,7 @@ require (
|
||||
github.com/felixge/httpsnoop v1.0.0 // indirect
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
|
||||
github.com/go-acme/lego/v3 v3.0.2
|
||||
github.com/go-acme/lego/v3 v3.1.0
|
||||
github.com/go-check/check v0.0.0-00010101000000-000000000000
|
||||
github.com/go-kit/kit v0.9.0
|
||||
github.com/golang/protobuf v1.3.2
|
||||
@@ -51,7 +51,6 @@ require (
|
||||
github.com/huandu/xstrings v1.2.0 // indirect
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc
|
||||
github.com/instana/go-sensor v1.4.17-0.20190515112224-78c14625025a
|
||||
github.com/labbsr0x/goh v0.0.0-20190830205702-3d6988c73e10 // indirect
|
||||
github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad
|
||||
github.com/libkermit/docker v0.0.0-20171122101128-e6674d32b807
|
||||
github.com/libkermit/docker-check v0.0.0-20171122104347-1113af38e591
|
||||
@@ -72,13 +71,11 @@ require (
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/philhofer/fwd v1.0.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/prometheus/client_golang v1.0.0
|
||||
github.com/prometheus/client_golang v1.1.0
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90
|
||||
github.com/prometheus/common v0.6.0 // indirect
|
||||
github.com/prometheus/procfs v0.0.3 // indirect
|
||||
github.com/rancher/go-rancher-metadata v0.0.0-00010101000000-000000000000
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/stvp/go-udp-testing v0.0.0-20171104055251-c4434f09ec13
|
||||
github.com/tinylib/msgp v1.0.2 // indirect
|
||||
github.com/transip/gotransip v5.8.2+incompatible // indirect
|
||||
@@ -89,9 +86,9 @@ require (
|
||||
github.com/vdemeester/shakers v0.1.0
|
||||
github.com/vulcand/oxy v1.0.0
|
||||
github.com/vulcand/predicate v1.1.0
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
|
||||
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 // indirect
|
||||
google.golang.org/grpc v1.22.1
|
||||
gopkg.in/DataDog/dd-trace-go.v1 v1.16.1
|
||||
|
||||
41
go.sum
41
go.sum
@@ -78,6 +78,8 @@ github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/c0va23/go-proxyprotocol v0.9.1 h1:5BCkp0fDJOhzzH1lhjUgHhmZz9VvRMMif1U2D31hb34=
|
||||
github.com/c0va23/go-proxyprotocol v0.9.1/go.mod h1:TNjUV+llvk8TvWJxlPYAeAYZgSzT/iicNr3nWBWX320=
|
||||
github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c=
|
||||
@@ -85,8 +87,8 @@ github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4r
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cloudflare-go v0.10.0 h1:wJPNqfrQO0w3fCiQcf/2T4lR2y6Q2fAwRszllljgb8I=
|
||||
github.com/cloudflare/cloudflare-go v0.10.0/go.mod h1:fOESqHl/jzAmCtEyjceLkw3v0rVjzl8V9iehxZPynXY=
|
||||
github.com/cloudflare/cloudflare-go v0.10.2 h1:VBodKICVPnwmDxstcW3biKcDSpFIfS/RELUXsZSBYK4=
|
||||
github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
|
||||
@@ -113,6 +115,7 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/cpu/goacmedns v0.0.1 h1:GeIU5chKys9zmHgOAgP+bstRaLqcGQ6HJh/hLw9hrus=
|
||||
github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -178,8 +181,9 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
||||
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2 h1:df6OFl8WNXk82xxP3R9ZPZ5seOA8XZkwLdbEzZF1/xI=
|
||||
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2/go.mod h1:GLyXJD41gBO/NPKVPGQbhyyC06eugGy15QEZyUkE2/s=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-acme/lego/v3 v3.0.2 h1:cnS+URiPzkt2pd7I2WlZtFyt2ihQ762nouBybY4djjw=
|
||||
github.com/go-acme/lego/v3 v3.0.2/go.mod h1:sMoLjf8BUo4Jexg+6Xw5KeFx98KVZ7Nfczh9tzLyhJU=
|
||||
github.com/go-acme/lego/v3 v3.1.0 h1:yanYFoYW8azFkCvJfIk7edWWfjkYkhDxe45ZsxoW4Xk=
|
||||
github.com/go-acme/lego/v3 v3.1.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE=
|
||||
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-ini/ini v1.44.0 h1:8+SRbfpRFlIunpSum4BEf1ClTtVjOgKzgBv9pHFkI6w=
|
||||
@@ -226,6 +230,8 @@ github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASu
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -287,6 +293,8 @@ github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBv
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
@@ -304,11 +312,10 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
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/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-20190830205702-3d6988c73e10 h1:mrPTy7qNJPGHaUkkN301r8Y+13l2/vsiC8Lvi09e6sI=
|
||||
github.com/labbsr0x/goh v0.0.0-20190830205702-3d6988c73e10/go.mod h1:RBxeaayaaMmp7GxwHiKANjkg9e+rxjOm4mB5vD5rt/I=
|
||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2 h1:I7ITbmQPAVwrDdhd6dHKi+MYJTJqPCK0jE6YNBAevnk=
|
||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
|
||||
github.com/labbsr0x/goh v1.0.1 h1:97aBJkDjpyBZGPbQuOK5/gHcSFbcr5aRsq3RSRJFpPk=
|
||||
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
||||
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/docker v0.0.0-20171122101128-e6674d32b807 h1:/7J1WDQd6Xn1Pr8KtE2I/7/cKw66AV3hBUOyxqyXo84=
|
||||
@@ -317,6 +324,8 @@ github.com/libkermit/docker-check v0.0.0-20171122104347-1113af38e591 h1:+zkZyvOy
|
||||
github.com/libkermit/docker-check v0.0.0-20171122104347-1113af38e591/go.mod h1:EBQ0jeOrBpOTkquwjmJl4W6z5xqlf5oA2LZfTqRNcO0=
|
||||
github.com/linode/linodego v0.10.0 h1:AMdb82HVgY8o3mjBXJcUv9B+fnJjfDMn2rNRGbX+jvM=
|
||||
github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
|
||||
github.com/liquidweb/liquidweb-go v1.6.0 h1:vIj1I/Wf97fUnyirD+bi6Y63c0GiXk9nKI1+sFFl3G0=
|
||||
github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ=
|
||||
github.com/looplab/fsm v0.1.0 h1:Qte7Zdn/5hBNbXzP7yxVU4OIFHWXBovyTT2LaBTyC20=
|
||||
github.com/looplab/fsm v0.1.0/go.mod h1:m2VaOfDHxqXBBMgc26m6yUOwkFn8H2AlJDE+jd/uafI=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
@@ -346,6 +355,7 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
@@ -414,6 +424,8 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||
@@ -432,10 +444,12 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhD
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sacloud/libsacloud v1.26.1 h1:td3Kd7lvpSAxxHEVpnaZ9goHmmhi0D/RfP0Rqqf/kek=
|
||||
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
@@ -454,6 +468,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stvp/go-udp-testing v0.0.0-20171104055251-c4434f09ec13 h1:WYRIgR83bWdH2zjqXalfLuQYtgBG1KKxDRxinx2ygMI=
|
||||
github.com/stvp/go-udp-testing v0.0.0-20171104055251-c4434f09ec13/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
|
||||
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7 h1:CpHxIaZzVy26GqJn8ptRyto8fuoYOd1v0fXm9bG3wQ8=
|
||||
@@ -474,7 +490,7 @@ github.com/unrolled/render v1.0.1 h1:VDDnQQVfBMsOsp3VaCJszSO0nkBIVEYoPWeRThk9spY
|
||||
github.com/unrolled/render v1.0.1/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM=
|
||||
github.com/unrolled/secure v1.0.4 h1:DksfKsRTyXP2R8quDdOOuRpRO45VprFL0X9t9+JX1PU=
|
||||
github.com/unrolled/secure v1.0.4/go.mod h1:R6rugAuzh4TQpbFAq69oqZggyBQxFRFQIewtz5z7Jsc=
|
||||
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/vdemeester/shakers v0.1.0 h1:K+n9sSyUCg2ywmZkv+3c7vsYZfivcfKhMh8kRxCrONM=
|
||||
github.com/vdemeester/shakers v0.1.0/go.mod h1:IZ1HHynUOQt32iQ3rvAeVddXLd19h/6LWiKsh9RZtAQ=
|
||||
github.com/vulcand/oxy v1.0.0 h1:7vL5/pjDFzHGbtBEhmlHITUi6KLH4xXTDF33/wrdRKw=
|
||||
@@ -537,6 +553,8 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA=
|
||||
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -563,6 +581,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -574,6 +593,8 @@ golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w=
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
||||
@@ -18,6 +18,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Bool(v bool) *bool { return &v }
|
||||
|
||||
func TestHandler_HTTP(t *testing.T) {
|
||||
type expected struct {
|
||||
statusCode int
|
||||
@@ -267,6 +269,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
@@ -283,6 +286,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.2",
|
||||
@@ -351,6 +355,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
@@ -367,6 +372,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.2",
|
||||
@@ -383,6 +389,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.3",
|
||||
@@ -412,6 +419,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
@@ -429,6 +437,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.2",
|
||||
@@ -459,6 +468,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
@@ -476,6 +486,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.2",
|
||||
@@ -506,6 +517,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
@@ -534,6 +546,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
||||
@@ -38,6 +38,7 @@ func TestHandler_RawData(t *testing.T) {
|
||||
"foo-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
||||
2
pkg/api/testdata/getrawdata.json
vendored
2
pkg/api/testdata/getrawdata.json
vendored
@@ -65,7 +65,7 @@
|
||||
"url": "http://127.0.0.1"
|
||||
}
|
||||
],
|
||||
"passHostHeader": false
|
||||
"passHostHeader": true
|
||||
},
|
||||
"status": "enabled",
|
||||
"usedBy": [
|
||||
|
||||
2
pkg/api/testdata/service-bar.json
vendored
2
pkg/api/testdata/service-bar.json
vendored
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"loadBalancer": {
|
||||
"passHostHeader": false,
|
||||
"passHostHeader": true,
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://127.0.0.1"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"loadBalancer": {
|
||||
"passHostHeader": false,
|
||||
"passHostHeader": true,
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://127.0.0.2"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"loadBalancer": {
|
||||
"passHostHeader": false,
|
||||
"passHostHeader": true,
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://127.0.0.1"
|
||||
|
||||
2
pkg/api/testdata/services-page2.json
vendored
2
pkg/api/testdata/services-page2.json
vendored
@@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"loadBalancer": {
|
||||
"passHostHeader": false,
|
||||
"passHostHeader": true,
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://127.0.0.2"
|
||||
|
||||
4
pkg/api/testdata/services.json
vendored
4
pkg/api/testdata/services.json
vendored
@@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"loadBalancer": {
|
||||
"passHostHeader": false,
|
||||
"passHostHeader": true,
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://127.0.0.1"
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
{
|
||||
"loadBalancer": {
|
||||
"passHostHeader": false,
|
||||
"passHostHeader": true,
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://127.0.0.2"
|
||||
|
||||
@@ -106,7 +106,7 @@ type ServersLoadBalancer struct {
|
||||
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty" label:"allowEmpty"`
|
||||
Servers []Server `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
|
||||
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty"`
|
||||
PassHostHeader bool `json:"passHostHeader" toml:"passHostHeader" yaml:"passHostHeader"`
|
||||
PassHostHeader *bool `json:"passHostHeader" toml:"passHostHeader" yaml:"passHostHeader"`
|
||||
ResponseForwarding *ResponseForwarding `json:"responseForwarding,omitempty" toml:"responseForwarding,omitempty" yaml:"responseForwarding,omitempty"`
|
||||
}
|
||||
|
||||
@@ -129,7 +129,8 @@ func (l *ServersLoadBalancer) Mergeable(loadBalancer *ServersLoadBalancer) bool
|
||||
|
||||
// SetDefaults Default values for a ServersLoadBalancer.
|
||||
func (l *ServersLoadBalancer) SetDefaults() {
|
||||
l.PassHostHeader = true
|
||||
defaultPassHostHeader := true
|
||||
l.PassHostHeader = &defaultPassHostHeader
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
@@ -973,6 +973,11 @@ func (in *ServersLoadBalancer) DeepCopyInto(out *ServersLoadBalancer) {
|
||||
*out = new(HealthCheck)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.PassHostHeader != nil {
|
||||
in, out := &in.PassHostHeader, &out.PassHostHeader
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.ResponseForwarding != nil {
|
||||
in, out := &in.ResponseForwarding, &out.ResponseForwarding
|
||||
*out = new(ResponseForwarding)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -15,12 +16,15 @@ func decodeRawToNode(data map[string]interface{}, rootName string, filters ...st
|
||||
}
|
||||
|
||||
vData := reflect.ValueOf(data)
|
||||
decodeRaw(root, vData, filters...)
|
||||
err := decodeRaw(root, vData, filters...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) {
|
||||
func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) error {
|
||||
sortedKeys := sortKeys(vData, filters)
|
||||
|
||||
for _, key := range sortedKeys {
|
||||
@@ -38,7 +42,11 @@ func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) {
|
||||
case reflect.Bool:
|
||||
fallthrough
|
||||
case reflect.String:
|
||||
child.Value = getSimpleValue(value)
|
||||
value, err := getSimpleValue(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
child.Value = value
|
||||
case reflect.Slice:
|
||||
var values []string
|
||||
|
||||
@@ -63,40 +71,52 @@ func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) {
|
||||
}
|
||||
|
||||
child.Children = append(child.Children, ch)
|
||||
decodeRaw(ch, sValue)
|
||||
err := decodeRaw(ch, sValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
values = append(values, getSimpleValue(sValue))
|
||||
val, err := getSimpleValue(sValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
values = append(values, val)
|
||||
}
|
||||
default:
|
||||
panic("Unsupported slice type: " + item.Kind().String())
|
||||
return fmt.Errorf("field %s uses unsupported slice type: %s", child.Name, item.Kind().String())
|
||||
}
|
||||
}
|
||||
|
||||
child.Value = strings.Join(values, ",")
|
||||
case reflect.Map:
|
||||
decodeRaw(child, value)
|
||||
err := decodeRaw(child, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
panic("Unsupported type: " + value.Kind().String())
|
||||
return fmt.Errorf("field %s uses unsupported type: %s", child.Name, value.Kind().String())
|
||||
}
|
||||
|
||||
node.Children = append(node.Children, child)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSimpleValue(item reflect.Value) string {
|
||||
func getSimpleValue(item reflect.Value) (string, error) {
|
||||
switch item.Kind() {
|
||||
case reflect.String:
|
||||
return item.String()
|
||||
return item.String(), nil
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(item.Int(), 10)
|
||||
return strconv.FormatInt(item.Int(), 10), nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.FormatUint(item.Uint(), 10)
|
||||
return strconv.FormatUint(item.Uint(), 10), nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return strings.TrimSuffix(strconv.FormatFloat(item.Float(), 'f', 6, 64), ".000000")
|
||||
return strings.TrimSuffix(strconv.FormatFloat(item.Float(), 'f', 6, 64), ".000000"), nil
|
||||
case reflect.Bool:
|
||||
return strconv.FormatBool(item.Bool())
|
||||
return strconv.FormatBool(item.Bool()), nil
|
||||
default:
|
||||
panic("Unsupported Simple value type: " + item.Kind().String())
|
||||
return "", fmt.Errorf("unsupported simple value type: %s", item.Kind().String())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -538,3 +538,27 @@ func Test_decodeRawToNode(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_decodeRawToNode_errors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
data map[string]interface{}
|
||||
}{
|
||||
{
|
||||
desc: "invalid type",
|
||||
data: map[string]interface{}{
|
||||
"foo": struct{}{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := decodeRawToNode(test.data, parser.DefaultRootName)
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,7 +544,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||
"name1": "foobar",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: func(v bool) *bool { return &v }(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: "foobar",
|
||||
},
|
||||
@@ -570,7 +570,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||
"name1": "foobar",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: func(v bool) *bool { return &v }(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: "foobar",
|
||||
},
|
||||
@@ -946,7 +946,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||
"name1": "foobar",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: func(v bool) *bool { return &v }(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: "foobar",
|
||||
},
|
||||
@@ -972,7 +972,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||
"name1": "foobar",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: func(v bool) *bool { return &v }(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: "foobar",
|
||||
},
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
package hostresolver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/patrickmn/go-cache"
|
||||
)
|
||||
|
||||
type cnameResolv struct {
|
||||
TTL time.Duration
|
||||
Record string
|
||||
}
|
||||
|
||||
type byTTL []*cnameResolv
|
||||
|
||||
func (a byTTL) Len() int { return len(a) }
|
||||
func (a byTTL) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a byTTL) Less(i, j int) bool { return a[i].TTL > a[j].TTL }
|
||||
|
||||
// Resolver used for host resolver
|
||||
type Resolver struct {
|
||||
CnameFlattening bool
|
||||
ResolvConfig string
|
||||
ResolvDepth int
|
||||
cache *cache.Cache
|
||||
}
|
||||
|
||||
// CNAMEFlatten check if CNAME record exists, flatten if possible
|
||||
func (hr *Resolver) CNAMEFlatten(host string) (string, string) {
|
||||
if hr.cache == nil {
|
||||
hr.cache = cache.New(30*time.Minute, 5*time.Minute)
|
||||
}
|
||||
|
||||
result := []string{host}
|
||||
request := host
|
||||
|
||||
value, found := hr.cache.Get(host)
|
||||
if found {
|
||||
result = strings.Split(value.(string), ",")
|
||||
} else {
|
||||
var cacheDuration = 0 * time.Second
|
||||
|
||||
for depth := 0; depth < hr.ResolvDepth; depth++ {
|
||||
resolv, err := cnameResolve(request, hr.ResolvConfig)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
break
|
||||
}
|
||||
if resolv == nil {
|
||||
break
|
||||
}
|
||||
|
||||
result = append(result, resolv.Record)
|
||||
if depth == 0 {
|
||||
cacheDuration = resolv.TTL
|
||||
}
|
||||
request = resolv.Record
|
||||
}
|
||||
|
||||
if err := hr.cache.Add(host, strings.Join(result, ","), cacheDuration); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
return result[0], result[len(result)-1]
|
||||
}
|
||||
|
||||
// cnameResolve resolves CNAME if exists, and return with the highest TTL
|
||||
func cnameResolve(host string, resolvPath string) (*cnameResolv, error) {
|
||||
config, err := dns.ClientConfigFromFile(resolvPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid resolver configuration file: %s", resolvPath)
|
||||
}
|
||||
|
||||
client := &dns.Client{Timeout: 30 * time.Second}
|
||||
|
||||
m := &dns.Msg{}
|
||||
m.SetQuestion(dns.Fqdn(host), dns.TypeCNAME)
|
||||
|
||||
var result []*cnameResolv
|
||||
for _, server := range config.Servers {
|
||||
tempRecord, err := getRecord(client, m, server, config.Port)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to resolve host %s: %v", host, err)
|
||||
continue
|
||||
}
|
||||
result = append(result, tempRecord)
|
||||
}
|
||||
|
||||
if len(result) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sort.Sort(byTTL(result))
|
||||
return result[0], nil
|
||||
}
|
||||
|
||||
func getRecord(client *dns.Client, msg *dns.Msg, server string, port string) (*cnameResolv, error) {
|
||||
resp, _, err := client.Exchange(msg, net.JoinHostPort(server, port))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("exchange error for server %s: %v", server, err)
|
||||
}
|
||||
|
||||
if resp == nil || len(resp.Answer) == 0 {
|
||||
return nil, fmt.Errorf("empty answer for server %s", server)
|
||||
}
|
||||
|
||||
rr, ok := resp.Answer[0].(*dns.CNAME)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid response type for server %s", server)
|
||||
}
|
||||
|
||||
return &cnameResolv{
|
||||
TTL: time.Duration(rr.Hdr.Ttl) * time.Second,
|
||||
Record: strings.TrimSuffix(rr.Target, "."),
|
||||
}, nil
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package hostresolver
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCNAMEFlatten(t *testing.T) {
|
||||
testCase := []struct {
|
||||
desc string
|
||||
resolvFile string
|
||||
domain string
|
||||
expectedDomain string
|
||||
isCNAME bool
|
||||
}{
|
||||
{
|
||||
desc: "host request is CNAME record",
|
||||
resolvFile: "/etc/resolv.conf",
|
||||
domain: "www.github.com",
|
||||
expectedDomain: "github.com",
|
||||
isCNAME: true,
|
||||
},
|
||||
{
|
||||
desc: "resolve file not found",
|
||||
resolvFile: "/etc/resolv.oops",
|
||||
domain: "www.github.com",
|
||||
expectedDomain: "www.github.com",
|
||||
isCNAME: false,
|
||||
},
|
||||
{
|
||||
desc: "host request is not CNAME record",
|
||||
resolvFile: "/etc/resolv.conf",
|
||||
domain: "github.com",
|
||||
expectedDomain: "github.com",
|
||||
isCNAME: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCase {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
hostResolver := &Resolver{
|
||||
ResolvConfig: test.resolvFile,
|
||||
ResolvDepth: 5,
|
||||
}
|
||||
|
||||
reqH, flatH := hostResolver.CNAMEFlatten(test.domain)
|
||||
assert.Equal(t, test.domain, reqH)
|
||||
assert.Equal(t, test.expectedDomain, flatH)
|
||||
|
||||
if test.isCNAME {
|
||||
assert.NotEqual(t, test.expectedDomain, reqH)
|
||||
} else {
|
||||
assert.Equal(t, test.expectedDomain, reqH)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -33,13 +33,14 @@ func TestJobBackOff(t *testing.T) {
|
||||
// Assert that the next backoff falls in the expected range.
|
||||
var minInterval = expected - time.Duration(testRandomizationFactor*float64(expected))
|
||||
var maxInterval = expected + time.Duration(testRandomizationFactor*float64(expected))
|
||||
|
||||
if i < 3 || i == 8 {
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
var actualInterval = exp.NextBackOff()
|
||||
if !(minInterval <= actualInterval && actualInterval <= maxInterval) {
|
||||
t.Error("error")
|
||||
}
|
||||
// assertEquals(t, expected, exp.currentInterval)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package accesslog
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -31,6 +32,19 @@ const (
|
||||
JSONFormat string = "json"
|
||||
)
|
||||
|
||||
type noopCloser struct {
|
||||
*os.File
|
||||
}
|
||||
|
||||
func (n noopCloser) Write(p []byte) (int, error) {
|
||||
return n.File.Write(p)
|
||||
}
|
||||
|
||||
func (n noopCloser) Close() error {
|
||||
// noop
|
||||
return nil
|
||||
}
|
||||
|
||||
type handlerParams struct {
|
||||
logDataTable *LogData
|
||||
crr *captureRequestReader
|
||||
@@ -41,7 +55,7 @@ type handlerParams struct {
|
||||
type Handler struct {
|
||||
config *types.AccessLog
|
||||
logger *logrus.Logger
|
||||
file *os.File
|
||||
file io.WriteCloser
|
||||
mu sync.Mutex
|
||||
httpCodeRanges types.HTTPCodeRanges
|
||||
logHandlerChan chan handlerParams
|
||||
@@ -59,7 +73,7 @@ func WrapHandler(handler *Handler) alice.Constructor {
|
||||
|
||||
// NewHandler creates a new Handler.
|
||||
func NewHandler(config *types.AccessLog) (*Handler, error) {
|
||||
file := os.Stdout
|
||||
var file io.WriteCloser = noopCloser{os.Stdout}
|
||||
if len(config.FilePath) > 0 {
|
||||
f, err := openAccessLogFile(config.FilePath)
|
||||
if err != nil {
|
||||
@@ -213,14 +227,15 @@ func (h *Handler) Close() error {
|
||||
|
||||
// Rotate closes and reopens the log file to allow for rotation by an external source.
|
||||
func (h *Handler) Rotate() error {
|
||||
var err error
|
||||
|
||||
if h.file != nil {
|
||||
defer func(f *os.File) {
|
||||
f.Close()
|
||||
}(h.file)
|
||||
if h.config.FilePath == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if h.file != nil {
|
||||
defer func(f io.Closer) { _ = f.Close() }(h.file)
|
||||
}
|
||||
|
||||
var err error
|
||||
h.file, err = os.OpenFile(h.config.FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0664)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -22,7 +22,10 @@ import (
|
||||
)
|
||||
|
||||
// Compile time validation that the response recorder implements http interfaces correctly.
|
||||
var _ middlewares.Stateful = &responseRecorderWithCloseNotify{}
|
||||
var (
|
||||
_ middlewares.Stateful = &responseRecorderWithCloseNotify{}
|
||||
_ middlewares.Stateful = &codeCatcherWithCloseNotify{}
|
||||
)
|
||||
|
||||
const (
|
||||
typeName = "customError"
|
||||
@@ -80,25 +83,29 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
recorder := newResponseRecorder(ctx, rw)
|
||||
c.next.ServeHTTP(recorder, req)
|
||||
catcher := newCodeCatcher(rw, c.httpCodeRanges)
|
||||
c.next.ServeHTTP(catcher, req)
|
||||
if !catcher.isFilteredCode() {
|
||||
return
|
||||
}
|
||||
|
||||
// check the recorder code against the configured http status code ranges
|
||||
code := catcher.getCode()
|
||||
for _, block := range c.httpCodeRanges {
|
||||
if recorder.GetCode() >= block[0] && recorder.GetCode() <= block[1] {
|
||||
logger.Errorf("Caught HTTP Status Code %d, returning error page", recorder.GetCode())
|
||||
if code >= block[0] && code <= block[1] {
|
||||
logger.Errorf("Caught HTTP Status Code %d, returning error page", code)
|
||||
|
||||
var query string
|
||||
if len(c.backendQuery) > 0 {
|
||||
query = "/" + strings.TrimPrefix(c.backendQuery, "/")
|
||||
query = strings.Replace(query, "{status}", strconv.Itoa(recorder.GetCode()), -1)
|
||||
query = strings.Replace(query, "{status}", strconv.Itoa(code), -1)
|
||||
}
|
||||
|
||||
pageReq, err := newRequest(backendURL + query)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
rw.WriteHeader(recorder.GetCode())
|
||||
_, err = fmt.Fprint(rw, http.StatusText(recorder.GetCode()))
|
||||
rw.WriteHeader(code)
|
||||
_, err = fmt.Fprint(rw, http.StatusText(code))
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
@@ -111,7 +118,7 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
c.backendHandler.ServeHTTP(recorderErrorPage, pageReq.WithContext(req.Context()))
|
||||
|
||||
utils.CopyHeaders(rw.Header(), recorderErrorPage.Header())
|
||||
rw.WriteHeader(recorder.GetCode())
|
||||
rw.WriteHeader(code)
|
||||
|
||||
if _, err = rw.Write(recorderErrorPage.GetBody().Bytes()); err != nil {
|
||||
logger.Error(err)
|
||||
@@ -119,14 +126,6 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// did not catch a configured status code so proceed with the request
|
||||
utils.CopyHeaders(rw.Header(), recorder.Header())
|
||||
rw.WriteHeader(recorder.GetCode())
|
||||
_, err := rw.Write(recorder.GetBody().Bytes())
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func newRequest(baseURL string) (*http.Request, error) {
|
||||
@@ -144,6 +143,132 @@ func newRequest(baseURL string) (*http.Request, error) {
|
||||
return req, nil
|
||||
}
|
||||
|
||||
type responseInterceptor interface {
|
||||
http.ResponseWriter
|
||||
http.Flusher
|
||||
getCode() int
|
||||
isFilteredCode() bool
|
||||
}
|
||||
|
||||
// codeCatcher is a response writer that detects as soon as possible whether the
|
||||
// response is a code within the ranges of codes it watches for. If it is, it
|
||||
// simply drops the data from the response. Otherwise, it forwards it directly to
|
||||
// the original client (its responseWriter) without any buffering.
|
||||
type codeCatcher struct {
|
||||
headerMap http.Header
|
||||
code int
|
||||
httpCodeRanges types.HTTPCodeRanges
|
||||
firstWrite bool
|
||||
caughtFilteredCode bool
|
||||
responseWriter http.ResponseWriter
|
||||
headersSent bool
|
||||
}
|
||||
|
||||
type codeCatcherWithCloseNotify struct {
|
||||
*codeCatcher
|
||||
}
|
||||
|
||||
// CloseNotify returns a channel that receives at most a
|
||||
// single value (true) when the client connection has gone away.
|
||||
func (cc *codeCatcherWithCloseNotify) CloseNotify() <-chan bool {
|
||||
return cc.responseWriter.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
|
||||
func newCodeCatcher(rw http.ResponseWriter, httpCodeRanges types.HTTPCodeRanges) responseInterceptor {
|
||||
catcher := &codeCatcher{
|
||||
headerMap: make(http.Header),
|
||||
code: http.StatusOK, // If backend does not call WriteHeader on us, we consider it's a 200.
|
||||
responseWriter: rw,
|
||||
httpCodeRanges: httpCodeRanges,
|
||||
firstWrite: true,
|
||||
}
|
||||
if _, ok := rw.(http.CloseNotifier); ok {
|
||||
return &codeCatcherWithCloseNotify{catcher}
|
||||
}
|
||||
return catcher
|
||||
}
|
||||
|
||||
func (cc *codeCatcher) Header() http.Header {
|
||||
if cc.headerMap == nil {
|
||||
cc.headerMap = make(http.Header)
|
||||
}
|
||||
|
||||
return cc.headerMap
|
||||
}
|
||||
|
||||
func (cc *codeCatcher) getCode() int {
|
||||
return cc.code
|
||||
}
|
||||
|
||||
// isFilteredCode returns whether the codeCatcher received a response code among the ones it is watching,
|
||||
// and for which the response should be deferred to the error handler.
|
||||
func (cc *codeCatcher) isFilteredCode() bool {
|
||||
return cc.caughtFilteredCode
|
||||
}
|
||||
|
||||
func (cc *codeCatcher) Write(buf []byte) (int, error) {
|
||||
if !cc.firstWrite {
|
||||
if cc.caughtFilteredCode {
|
||||
// We don't care about the contents of the response,
|
||||
// since we want to serve the ones from the error page,
|
||||
// so we just drop them.
|
||||
return len(buf), nil
|
||||
}
|
||||
return cc.responseWriter.Write(buf)
|
||||
}
|
||||
cc.firstWrite = false
|
||||
|
||||
// If WriteHeader was already called from the caller, this is a NOOP.
|
||||
// Otherwise, cc.code is actually a 200 here.
|
||||
cc.WriteHeader(cc.code)
|
||||
|
||||
if cc.caughtFilteredCode {
|
||||
return len(buf), nil
|
||||
}
|
||||
return cc.responseWriter.Write(buf)
|
||||
}
|
||||
|
||||
func (cc *codeCatcher) WriteHeader(code int) {
|
||||
if cc.headersSent || cc.caughtFilteredCode {
|
||||
return
|
||||
}
|
||||
|
||||
cc.code = code
|
||||
for _, block := range cc.httpCodeRanges {
|
||||
if cc.code >= block[0] && cc.code <= block[1] {
|
||||
cc.caughtFilteredCode = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// it will be up to the other response recorder to send the headers,
|
||||
// so it is out of our hands now.
|
||||
if cc.caughtFilteredCode {
|
||||
return
|
||||
}
|
||||
utils.CopyHeaders(cc.responseWriter.Header(), cc.Header())
|
||||
cc.responseWriter.WriteHeader(cc.code)
|
||||
cc.headersSent = true
|
||||
}
|
||||
|
||||
// Hijack hijacks the connection
|
||||
func (cc *codeCatcher) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
if hj, ok := cc.responseWriter.(http.Hijacker); ok {
|
||||
return hj.Hijack()
|
||||
}
|
||||
return nil, nil, fmt.Errorf("%T is not a http.Hijacker", cc.responseWriter)
|
||||
}
|
||||
|
||||
// Flush sends any buffered data to the client.
|
||||
func (cc *codeCatcher) Flush() {
|
||||
// If WriteHeader was already called from the caller, this is a NOOP.
|
||||
// Otherwise, cc.code is actually a 200 here.
|
||||
cc.WriteHeader(cc.code)
|
||||
|
||||
if flusher, ok := cc.responseWriter.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
type responseRecorder interface {
|
||||
http.ResponseWriter
|
||||
http.Flusher
|
||||
|
||||
@@ -33,6 +33,30 @@ func TestHandler(t *testing.T) {
|
||||
assert.Contains(t, recorder.Body.String(), http.StatusText(http.StatusOK))
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "no error, but not a 200",
|
||||
errorPage: &dynamic.ErrorPage{Service: "error", Query: "/test", Status: []string{"500-501", "503-599"}},
|
||||
backendCode: http.StatusPartialContent,
|
||||
backendErrorHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "My error page.")
|
||||
}),
|
||||
validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
|
||||
assert.Equal(t, http.StatusPartialContent, recorder.Code, "HTTP status")
|
||||
assert.Contains(t, recorder.Body.String(), http.StatusText(http.StatusPartialContent))
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "a 304, so no Write called",
|
||||
errorPage: &dynamic.ErrorPage{Service: "error", Query: "/test", Status: []string{"500-501", "503-599"}},
|
||||
backendCode: http.StatusNotModified,
|
||||
backendErrorHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "whatever, should not be called")
|
||||
}),
|
||||
validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
|
||||
assert.Equal(t, http.StatusNotModified, recorder.Code, "HTTP status")
|
||||
assert.Contains(t, recorder.Body.String(), "")
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "in the range",
|
||||
errorPage: &dynamic.ErrorPage{Service: "error", Query: "/test", Status: []string{"500-501", "503-599"}},
|
||||
@@ -104,6 +128,9 @@ func TestHandler(t *testing.T) {
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(test.backendCode)
|
||||
if test.backendCode == http.StatusNotModified {
|
||||
return
|
||||
}
|
||||
fmt.Fprintln(w, http.StatusText(test.backendCode))
|
||||
})
|
||||
errorPageHandler, err := New(context.Background(), handler, *test.errorPage, serviceBuilderMock, "test")
|
||||
|
||||
@@ -33,5 +33,7 @@ func (r *responseRecorder) CloseNotify() <-chan bool {
|
||||
|
||||
// Flush sends any buffered data to the client.
|
||||
func (r *responseRecorder) Flush() {
|
||||
r.ResponseWriter.(http.Flusher).Flush()
|
||||
if f, ok := r.ResponseWriter.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package recovery
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"runtime"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
"github.com/containous/traefik/v2/pkg/middlewares"
|
||||
@@ -28,13 +29,30 @@ func New(ctx context.Context, next http.Handler, name string) (http.Handler, err
|
||||
}
|
||||
|
||||
func (re *recovery) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
defer recoverFunc(middlewares.GetLoggerCtx(req.Context(), re.name, typeName), rw)
|
||||
defer recoverFunc(middlewares.GetLoggerCtx(req.Context(), re.name, typeName), rw, req)
|
||||
re.next.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
func recoverFunc(ctx context.Context, rw http.ResponseWriter) {
|
||||
func recoverFunc(ctx context.Context, rw http.ResponseWriter, r *http.Request) {
|
||||
if err := recover(); err != nil {
|
||||
log.FromContext(ctx).Errorf("Recovered from panic in http handler: %+v", err)
|
||||
if !shouldLogPanic(err) {
|
||||
log.FromContext(ctx).Debugf("Request has been aborted [%s - %s]: %v", r.RemoteAddr, r.URL, err)
|
||||
return
|
||||
}
|
||||
|
||||
log.FromContext(ctx).Errorf("Recovered from panic in HTTP handler [%s - %s]: %+v", r.RemoteAddr, r.URL, err)
|
||||
|
||||
const size = 64 << 10
|
||||
buf := make([]byte, size)
|
||||
buf = buf[:runtime.Stack(buf, false)]
|
||||
log.FromContext(ctx).Errorf("Stack: %s", buf)
|
||||
|
||||
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/golang/go/blob/a0d6420d8be2ae7164797051ec74fa2a2df466a1/src/net/http/server.go#L1761-L1775
|
||||
// https://github.com/golang/go/blob/c33153f7b416c03983324b3e8f869ce1116d84bc/src/net/http/httputil/reverseproxy.go#L284
|
||||
func shouldLogPanic(panicValue interface{}) bool {
|
||||
return panicValue != nil && panicValue != http.ErrAbortHandler
|
||||
}
|
||||
|
||||
@@ -323,7 +323,7 @@ func (p *Provider) resolveDomains(ctx context.Context, domains []string, tlsStor
|
||||
return
|
||||
}
|
||||
|
||||
log.FromContext(ctx).Debugf("Try to challenge certificate for domain %v founded in HostSNI rule", domains)
|
||||
log.FromContext(ctx).Debugf("Try to challenge certificate for domain %v found in HostSNI rule", domains)
|
||||
|
||||
var domain types.Domain
|
||||
if len(domains) > 0 {
|
||||
|
||||
@@ -13,7 +13,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Int(v int) *int { return &v }
|
||||
func Int(v int) *int { return &v }
|
||||
func Bool(v bool) *bool { return &v }
|
||||
|
||||
func TestDefaultRule(t *testing.T) {
|
||||
testCases := []struct {
|
||||
@@ -64,7 +65,7 @@ func TestDefaultRule(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -113,7 +114,7 @@ func TestDefaultRule(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -164,7 +165,7 @@ func TestDefaultRule(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -208,7 +209,7 @@ func TestDefaultRule(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -252,7 +253,7 @@ func TestDefaultRule(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -301,7 +302,7 @@ func TestDefaultRule(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -384,7 +385,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -452,7 +453,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"Test2": {
|
||||
@@ -462,7 +463,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -531,7 +532,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -581,7 +582,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -633,7 +634,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -677,7 +678,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -734,7 +735,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -781,7 +782,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"Service2": {
|
||||
@@ -791,7 +792,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -842,7 +843,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1052,7 +1053,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1101,7 +1102,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1193,7 +1194,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1266,7 +1267,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1361,7 +1362,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.3:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1429,7 +1430,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1519,7 +1520,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.3:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1592,7 +1593,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1655,7 +1656,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"Test2": {
|
||||
@@ -1665,7 +1666,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1715,7 +1716,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1766,7 +1767,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "h2c://127.0.0.1:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1812,7 +1813,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"Service2": {
|
||||
@@ -1822,7 +1823,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2037,7 +2038,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2098,7 +2099,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2348,7 +2349,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -199,8 +199,6 @@ func flattenCertificates(ctx context.Context, tlsConfig *dynamic.TLSConfiguratio
|
||||
}
|
||||
|
||||
func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory string, configuration *dynamic.Configuration) (*dynamic.Configuration, error) {
|
||||
logger := log.FromContext(ctx)
|
||||
|
||||
fileList, err := ioutil.ReadDir(directory)
|
||||
if err != nil {
|
||||
return configuration, fmt.Errorf("unable to read directory %s: %v", directory, err)
|
||||
@@ -227,6 +225,8 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
|
||||
configTLSMaps := make(map[*tls.CertAndStores]struct{})
|
||||
|
||||
for _, item := range fileList {
|
||||
logger := log.FromContext(log.With(ctx, log.Str("filename", item.Name())))
|
||||
|
||||
if item.IsDir() {
|
||||
configuration, err = p.loadFileConfigFromDirectory(ctx, filepath.Join(directory, item.Name()), configuration)
|
||||
if err != nil {
|
||||
@@ -245,7 +245,7 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
|
||||
var c *dynamic.Configuration
|
||||
c, err = p.loadFileConfig(ctx, filepath.Join(directory, item.Name()), true)
|
||||
if err != nil {
|
||||
return configuration, err
|
||||
return configuration, fmt.Errorf("%s: %v", filepath.Join(directory, item.Name()), err)
|
||||
}
|
||||
|
||||
for name, conf := range c.HTTP.Routers {
|
||||
|
||||
@@ -233,11 +233,11 @@ func (c *clientWrapper) GetMiddlewares() []*v1alpha1.Middleware {
|
||||
var result []*v1alpha1.Middleware
|
||||
|
||||
for ns, factory := range c.factoriesCrd {
|
||||
ings, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(c.labelSelector)
|
||||
middlewares, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(c.labelSelector)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
||||
log.Errorf("Failed to list middlewares in namespace %s: %s", ns, err)
|
||||
}
|
||||
result = append(result, ings...)
|
||||
result = append(result, middlewares...)
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -21,6 +20,7 @@ import (
|
||||
"github.com/containous/traefik/v2/pkg/safe"
|
||||
"github.com/containous/traefik/v2/pkg/tls"
|
||||
"github.com/containous/traefik/v2/pkg/types"
|
||||
"github.com/mitchellh/hashstructure"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
@@ -127,10 +127,14 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
|
||||
// track more information about the dropped events.
|
||||
conf := p.loadConfigurationFromCRD(ctxLog, k8sClient)
|
||||
|
||||
if reflect.DeepEqual(p.lastConfiguration.Get(), conf) {
|
||||
confHash, err := hashstructure.Hash(conf, nil)
|
||||
switch {
|
||||
case err != nil:
|
||||
logger.Error("Unable to hash the configuration")
|
||||
case p.lastConfiguration.Get() == confHash:
|
||||
logger.Debugf("Skipping Kubernetes event kind %T", event)
|
||||
} else {
|
||||
p.lastConfiguration.Set(conf)
|
||||
default:
|
||||
p.lastConfiguration.Set(confHash)
|
||||
configurationChan <- dynamic.Message{
|
||||
ProviderName: "kubernetescrd",
|
||||
Configuration: conf,
|
||||
|
||||
@@ -164,8 +164,11 @@ func createLoadBalancerServerHTTP(client Client, namespace string, service v1alp
|
||||
lb.SetDefaults()
|
||||
|
||||
lb.Servers = servers
|
||||
if service.PassHostHeader != nil {
|
||||
lb.PassHostHeader = *service.PassHostHeader
|
||||
|
||||
lb.PassHostHeader = service.PassHostHeader
|
||||
if lb.PassHostHeader == nil {
|
||||
passHostHeader := true
|
||||
lb.PassHostHeader = &passHostHeader
|
||||
}
|
||||
lb.ResponseForwarding = service.ResponseForwarding
|
||||
|
||||
@@ -206,8 +209,13 @@ func loadServers(client Client, namespace string, svc v1alpha1.Service) ([]dynam
|
||||
|
||||
var servers []dynamic.Server
|
||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
protocol := "http"
|
||||
if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, "https") {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
servers = append(servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("http://%s:%d", service.Spec.ExternalName, portSpec.Port),
|
||||
URL: fmt.Sprintf("%s://%s:%d", protocol, service.Spec.ExternalName, portSpec.Port),
|
||||
})
|
||||
} else {
|
||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
|
||||
var _ provider.Provider = (*Provider)(nil)
|
||||
|
||||
func Int(v int) *int { return &v }
|
||||
func Int(v int) *int { return &v }
|
||||
func Bool(v bool) *bool { return &v }
|
||||
|
||||
func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
@@ -737,7 +738,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -786,7 +787,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -836,7 +837,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -878,7 +879,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"default-test.route-77c62dfe9517144aeeaa": {
|
||||
@@ -891,7 +892,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -943,7 +944,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"default-test.route-77c62dfe9517144aeeaa-whoami2-8080": {
|
||||
@@ -956,7 +957,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.4:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1007,7 +1008,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"default-test.route-77c62dfe9517144aeeaa-whoami2-8080": {
|
||||
@@ -1020,7 +1021,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.4:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1132,7 +1133,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1190,7 +1191,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1248,7 +1249,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1305,7 +1306,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1351,7 +1352,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1397,7 +1398,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1435,7 +1436,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1472,7 +1473,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "https://10.10.0.6:8443",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1509,7 +1510,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "https://10.10.0.8:8443",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1584,7 +1585,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1620,7 +1621,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: false,
|
||||
PassHostHeader: Bool(false),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: "10s"},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -16,9 +15,11 @@ import (
|
||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/containous/traefik/v2/pkg/job"
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
"github.com/containous/traefik/v2/pkg/provider"
|
||||
"github.com/containous/traefik/v2/pkg/safe"
|
||||
"github.com/containous/traefik/v2/pkg/tls"
|
||||
"github.com/containous/traefik/v2/pkg/types"
|
||||
"github.com/mitchellh/hashstructure"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
@@ -138,10 +139,14 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
|
||||
// track more information about the dropped events.
|
||||
conf := p.loadConfigurationFromIngresses(ctxLog, k8sClient)
|
||||
|
||||
if reflect.DeepEqual(p.lastConfiguration.Get(), conf) {
|
||||
confHash, err := hashstructure.Hash(conf, nil)
|
||||
switch {
|
||||
case err != nil:
|
||||
logger.Error("Unable to hash the configuration")
|
||||
case p.lastConfiguration.Get() == confHash:
|
||||
logger.Debugf("Skipping Kubernetes event kind %T", event)
|
||||
} else {
|
||||
p.lastConfiguration.Set(conf)
|
||||
default:
|
||||
p.lastConfiguration.Set(confHash)
|
||||
configurationChan <- dynamic.Message{
|
||||
ProviderName: "kubernetes",
|
||||
Configuration: conf,
|
||||
@@ -202,8 +207,13 @@ func loadService(client Client, namespace string, backend v1beta1.IngressBackend
|
||||
}
|
||||
|
||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
protocol := "http"
|
||||
if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, "https") {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
servers = append(servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("http://%s:%d", service.Spec.ExternalName, portSpec.Port),
|
||||
URL: fmt.Sprintf("%s://%s:%d", protocol, service.Spec.ExternalName, portSpec.Port),
|
||||
})
|
||||
} else {
|
||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, backend.ServiceName)
|
||||
@@ -248,7 +258,7 @@ func loadService(client Client, namespace string, backend v1beta1.IngressBackend
|
||||
return &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: servers,
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: func(v bool) *bool { return &v }(true),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@@ -294,7 +304,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
|
||||
continue
|
||||
}
|
||||
|
||||
conf.HTTP.Routers["/"] = &dynamic.Router{
|
||||
conf.HTTP.Routers["default-router"] = &dynamic.Router{
|
||||
Rule: "PathPrefix(`/`)",
|
||||
Priority: math.MinInt32,
|
||||
Service: "default-backend",
|
||||
@@ -324,8 +334,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
|
||||
continue
|
||||
}
|
||||
|
||||
serviceName := ingress.Namespace + "-" + p.Backend.ServiceName + "-" + p.Backend.ServicePort.String()
|
||||
serviceName = strings.ReplaceAll(serviceName, ".", "-")
|
||||
serviceName := provider.Normalize(ingress.Namespace + "-" + p.Backend.ServiceName + "-" + p.Backend.ServicePort.String())
|
||||
var rules []string
|
||||
if len(rule.Host) > 0 {
|
||||
rules = []string{"Host(`" + rule.Host + "`)"}
|
||||
@@ -335,10 +344,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
|
||||
rules = append(rules, "PathPrefix(`"+p.Path+"`)")
|
||||
}
|
||||
|
||||
routerKey := strings.Replace(rule.Host, ".", "-", -1) + strings.Replace(p.Path, "/", "-", 1)
|
||||
if strings.HasPrefix(routerKey, "-") {
|
||||
routerKey = strings.Replace(routerKey, "-", "", 1)
|
||||
}
|
||||
routerKey := strings.TrimPrefix(provider.Normalize(rule.Host+p.Path), "-")
|
||||
conf.HTTP.Routers[routerKey] = &dynamic.Router{
|
||||
Rule: strings.Join(rules, " && "),
|
||||
Service: serviceName,
|
||||
|
||||
@@ -19,6 +19,8 @@ import (
|
||||
|
||||
var _ provider.Provider = (*Provider)(nil)
|
||||
|
||||
func Bool(v bool) *bool { return &v }
|
||||
|
||||
func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
@@ -51,7 +53,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
@@ -85,7 +87,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
@@ -119,7 +121,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
@@ -149,7 +151,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
@@ -178,7 +180,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-example-com-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.11.0.1:80",
|
||||
@@ -209,7 +211,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
@@ -243,7 +245,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
@@ -277,7 +279,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
@@ -318,7 +320,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
@@ -363,7 +365,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
@@ -376,7 +378,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
},
|
||||
"testing-service2-8082": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.2:8080",
|
||||
@@ -420,7 +422,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"/": {
|
||||
"default-router": {
|
||||
Rule: "PathPrefix(`/`)",
|
||||
Service: "default-backend",
|
||||
Priority: math.MinInt32,
|
||||
@@ -429,7 +431,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-backend": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
@@ -459,7 +461,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8089",
|
||||
@@ -489,7 +491,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-tchouk": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8089",
|
||||
@@ -519,7 +521,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-tchouk": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8089",
|
||||
@@ -553,7 +555,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-tchouk": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8089",
|
||||
@@ -566,7 +568,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
},
|
||||
"testing-service1-carotte": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8090",
|
||||
@@ -600,7 +602,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-tchouk": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8089",
|
||||
@@ -613,7 +615,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
},
|
||||
"toto-service1-tchouk": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.11.0.1:8089",
|
||||
@@ -665,7 +667,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-8080": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://traefik.wtf:8080",
|
||||
@@ -697,7 +699,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-example-com-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.11.0.1:80",
|
||||
@@ -734,7 +736,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-443": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.1:8443",
|
||||
@@ -764,7 +766,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-8443": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.1:8443",
|
||||
@@ -795,7 +797,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-8443": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.1:8443",
|
||||
@@ -817,7 +819,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"/": {
|
||||
"default-router": {
|
||||
Rule: "PathPrefix(`/`)",
|
||||
Service: "default-backend",
|
||||
Priority: math.MinInt32,
|
||||
@@ -826,7 +828,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-backend": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.30.0.1:8080",
|
||||
@@ -856,7 +858,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing-service1-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
|
||||
@@ -11,7 +11,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Int(v int) *int { return &v }
|
||||
func Int(v int) *int { return &v }
|
||||
func Bool(v bool) *bool { return &v }
|
||||
|
||||
func TestGetConfigurationAPIErrors(t *testing.T) {
|
||||
fakeClient := newFakeClient(true, marathon.Applications{})
|
||||
@@ -64,7 +65,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@@ -118,7 +119,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@@ -164,7 +165,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@@ -211,7 +212,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:8081",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@@ -266,7 +267,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:8083",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@@ -308,7 +309,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
}},
|
||||
"bar": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
@@ -316,7 +317,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:8081",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@@ -354,7 +355,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:81",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -390,7 +391,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@@ -428,7 +429,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -459,7 +460,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -503,7 +504,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -537,7 +538,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"Service2": {
|
||||
@@ -547,7 +548,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -639,7 +640,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"app2": {
|
||||
@@ -649,7 +650,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -696,7 +697,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"app2": {
|
||||
@@ -706,7 +707,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -744,7 +745,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"app2": {
|
||||
@@ -754,7 +755,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -802,7 +803,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -840,7 +841,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"app2": {
|
||||
@@ -850,7 +851,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -887,7 +888,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -925,7 +926,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "h2c://localhost:90",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -958,7 +959,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"Service2": {
|
||||
@@ -968,7 +969,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1133,7 +1134,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1171,7 +1172,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1208,7 +1209,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1417,7 +1418,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||
URL: "http://localhost:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -9,7 +9,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Int(v int) *int { return &v }
|
||||
func Int(v int) *int { return &v }
|
||||
func Bool(v bool) *bool { return &v }
|
||||
|
||||
func Test_buildConfiguration(t *testing.T) {
|
||||
testCases := []struct {
|
||||
@@ -51,7 +52,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -103,7 +104,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"Test2": {
|
||||
@@ -113,7 +114,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -168,7 +169,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
"Test2": {
|
||||
@@ -178,7 +179,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://128.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -222,7 +223,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -310,7 +311,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -380,7 +381,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -433,7 +434,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -475,7 +476,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -667,7 +668,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
URL: "http://127.0.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
func TestNewPoolContext(t *testing.T) {
|
||||
type testKeyType string
|
||||
|
||||
testKey := testKeyType("test")
|
||||
|
||||
ctx := context.WithValue(context.Background(), testKey, "test")
|
||||
|
||||
@@ -94,8 +94,9 @@ func setupTracing(conf *static.Tracing) tracing.Backend {
|
||||
|
||||
if backend == nil {
|
||||
log.WithoutContext().Debug("Could not initialize tracing, use Jaeger by default")
|
||||
backend := &jaeger.Config{}
|
||||
backend.SetDefaults()
|
||||
bcd := &jaeger.Config{}
|
||||
bcd.SetDefaults()
|
||||
backend = bcd
|
||||
}
|
||||
|
||||
return backend
|
||||
|
||||
@@ -254,6 +254,15 @@ func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
|
||||
return tc, nil
|
||||
}
|
||||
|
||||
type proxyProtocolLogger struct {
|
||||
log.Logger
|
||||
}
|
||||
|
||||
// Printf force log level to debug.
|
||||
func (p proxyProtocolLogger) Printf(format string, v ...interface{}) {
|
||||
p.Debugf(format, v...)
|
||||
}
|
||||
|
||||
func buildProxyProtocolListener(ctx context.Context, entryPoint *static.EntryPoint, listener net.Listener) (net.Listener, error) {
|
||||
var sourceCheck func(addr net.Addr) (bool, error)
|
||||
if entryPoint.ProxyProtocol.Insecure {
|
||||
@@ -280,7 +289,7 @@ func buildProxyProtocolListener(ctx context.Context, entryPoint *static.EntryPoi
|
||||
|
||||
return proxyprotocol.NewDefaultListener(listener).
|
||||
WithSourceChecker(sourceCheck).
|
||||
WithLogger(log.FromContext(ctx)), nil
|
||||
WithLogger(proxyProtocolLogger{Logger: log.FromContext(ctx)}), nil
|
||||
}
|
||||
|
||||
func buildListener(ctx context.Context, entryPoint *static.EntryPoint) (net.Listener, error) {
|
||||
|
||||
@@ -21,7 +21,7 @@ const StatusClientClosedRequest = 499
|
||||
// StatusClientClosedRequestText non-standard HTTP status for client disconnection
|
||||
const StatusClientClosedRequestText = "Client Closed Request"
|
||||
|
||||
func buildProxy(passHostHeader bool, responseForwarding *dynamic.ResponseForwarding, defaultRoundTripper http.RoundTripper, bufferPool httputil.BufferPool, responseModifier func(*http.Response) error) (http.Handler, error) {
|
||||
func buildProxy(passHostHeader *bool, responseForwarding *dynamic.ResponseForwarding, defaultRoundTripper http.RoundTripper, bufferPool httputil.BufferPool, responseModifier func(*http.Response) error) (http.Handler, error) {
|
||||
var flushInterval types.Duration
|
||||
if responseForwarding != nil {
|
||||
err := flushInterval.Set(responseForwarding.FlushInterval)
|
||||
@@ -53,7 +53,7 @@ func buildProxy(passHostHeader bool, responseForwarding *dynamic.ResponseForward
|
||||
outReq.ProtoMinor = 1
|
||||
|
||||
// Do not pass client Host header unless optsetter PassHostHeader is set.
|
||||
if !passHostHeader {
|
||||
if passHostHeader != nil && !*passHostHeader {
|
||||
outReq.Host = outReq.URL.Host
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ func BenchmarkProxy(b *testing.B) {
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil)
|
||||
|
||||
pool := newBufferPool()
|
||||
handler, _ := buildProxy(false, nil, &staticTransport{res}, pool, nil)
|
||||
handler, _ := buildProxy(Bool(false), nil, &staticTransport{res}, pool, nil)
|
||||
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
||||
@@ -17,8 +17,10 @@ import (
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
func Bool(v bool) *bool { return &v }
|
||||
|
||||
func TestWebSocketTCPClose(t *testing.T) {
|
||||
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
errChan := make(chan error, 1)
|
||||
@@ -57,7 +59,7 @@ func TestWebSocketTCPClose(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWebSocketPingPong(t *testing.T) {
|
||||
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -123,7 +125,7 @@ func TestWebSocketPingPong(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWebSocketEcho(t *testing.T) {
|
||||
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
@@ -189,7 +191,7 @@ func TestWebSocketPassHost(t *testing.T) {
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
f, err := buildProxy(test.passHost, nil, http.DefaultTransport, nil, nil)
|
||||
f, err := buildProxy(Bool(test.passHost), nil, http.DefaultTransport, nil, nil)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -248,7 +250,7 @@ func TestWebSocketPassHost(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWebSocketServerWithoutCheckOrigin(t *testing.T) {
|
||||
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
upgrader := gorillawebsocket.Upgrader{CheckOrigin: func(r *http.Request) bool {
|
||||
@@ -289,7 +291,7 @@ func TestWebSocketServerWithoutCheckOrigin(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWebSocketRequestWithOrigin(t *testing.T) {
|
||||
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
upgrader := gorillawebsocket.Upgrader{}
|
||||
@@ -335,7 +337,7 @@ func TestWebSocketRequestWithOrigin(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWebSocketRequestWithQueryParams(t *testing.T) {
|
||||
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
upgrader := gorillawebsocket.Upgrader{}
|
||||
@@ -375,7 +377,7 @@ func TestWebSocketRequestWithQueryParams(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWebSocketRequestWithHeadersInResponseWriter(t *testing.T) {
|
||||
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
@@ -407,7 +409,7 @@ func TestWebSocketRequestWithHeadersInResponseWriter(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWebSocketRequestWithEncodedChar(t *testing.T) {
|
||||
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
upgrader := gorillawebsocket.Upgrader{}
|
||||
@@ -447,7 +449,7 @@ func TestWebSocketRequestWithEncodedChar(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWebSocketUpgradeFailed(t *testing.T) {
|
||||
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
@@ -497,7 +499,7 @@ func TestWebSocketUpgradeFailed(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestForwardsWebsocketTraffic(t *testing.T) {
|
||||
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
@@ -553,7 +555,7 @@ func TestWebSocketTransferTLSConfig(t *testing.T) {
|
||||
srv := createTLSWebsocketServer()
|
||||
defer srv.Close()
|
||||
|
||||
forwarderWithoutTLSConfig, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
forwarderWithoutTLSConfig, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
proxyWithoutTLSConfig := createProxyWithForwarder(t, forwarderWithoutTLSConfig, srv.URL)
|
||||
@@ -572,7 +574,7 @@ func TestWebSocketTransferTLSConfig(t *testing.T) {
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
forwarderWithTLSConfig, err := buildProxy(true, nil, transport, nil, nil)
|
||||
forwarderWithTLSConfig, err := buildProxy(Bool(true), nil, transport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
proxyWithTLSConfig := createProxyWithForwarder(t, forwarderWithTLSConfig, srv.URL)
|
||||
@@ -591,7 +593,7 @@ func TestWebSocketTransferTLSConfig(t *testing.T) {
|
||||
|
||||
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
|
||||
forwarderWithTLSConfigFromDefaultTransport, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
|
||||
forwarderWithTLSConfigFromDefaultTransport, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
proxyWithTLSConfigFromDefaultTransport := createProxyWithForwarder(t, forwarderWithTLSConfigFromDefaultTransport, srv.URL)
|
||||
|
||||
@@ -176,6 +176,11 @@ func (m *Manager) getLoadBalancerServiceHandler(
|
||||
service *dynamic.ServersLoadBalancer,
|
||||
responseModifier func(*http.Response) error,
|
||||
) (http.Handler, error) {
|
||||
if service.PassHostHeader == nil {
|
||||
defaultPassHostHeader := true
|
||||
service.PassHostHeader = &defaultPassHostHeader
|
||||
}
|
||||
|
||||
fwd, err := buildProxy(service.PassHostHeader, service.ResponseForwarding, m.defaultRoundTripper, m.bufferPool, responseModifier)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -221,7 +221,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
||||
serviceName: "test",
|
||||
service: &dynamic.ServersLoadBalancer{
|
||||
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
|
||||
PassHostHeader: true,
|
||||
PassHostHeader: func(v bool) *bool { return &v }(true),
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: serverPassHost.URL,
|
||||
@@ -239,7 +239,8 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
||||
desc: "PassHost doesn't passe the host instead of the IP",
|
||||
serviceName: "test",
|
||||
service: &dynamic.ServersLoadBalancer{
|
||||
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
|
||||
PassHostHeader: Bool(false),
|
||||
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: serverPassHostFalse.URL,
|
||||
|
||||
@@ -189,7 +189,7 @@ func (c *Certificate) AppendCertificate(certs map[string]map[string]*tls.Certifi
|
||||
}
|
||||
}
|
||||
if certExists {
|
||||
log.Warnf("Skipping addition of certificate for domain(s) %q, to EntryPoint %s, as it already exists for this Entrypoint.", certKey, ep)
|
||||
log.Debugf("Skipping addition of certificate for domain(s) %q, to EntryPoint %s, as it already exists for this Entrypoint.", certKey, ep)
|
||||
} else {
|
||||
log.Debugf("Adding certificate for domain(s) %s", certKey)
|
||||
certs[ep][certKey] = &tlsCert
|
||||
|
||||
@@ -86,6 +86,7 @@ func derCert(privKey *rsa.PrivateKey, expiration time.Time, domain string) ([]by
|
||||
NotAfter: expiration,
|
||||
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement | x509.KeyUsageDataEncipherment,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
DNSNames: []string{domain},
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ type Config struct {
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
func (c *Config) SetDefaults() {
|
||||
c.LocalAgentHost = "localhost"
|
||||
c.LocalAgentPort = 42699
|
||||
c.LogLevel = "info"
|
||||
}
|
||||
|
||||
@@ -91,10 +91,7 @@ func (t *Tracing) Extract(format interface{}, carrier interface{}) (opentracing.
|
||||
|
||||
// IsEnabled determines if tracing was successfully activated.
|
||||
func (t *Tracing) IsEnabled() bool {
|
||||
if t == nil || t.tracer == nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return t != nil && t.tracer != nil
|
||||
}
|
||||
|
||||
// Close tracer
|
||||
@@ -169,9 +166,7 @@ func StartSpan(r *http.Request, operationName string, spanKind ext.SpanKindEnum,
|
||||
}
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
return span, r, func() {
|
||||
span.Finish()
|
||||
}
|
||||
return span, r, func() { span.Finish() }
|
||||
}
|
||||
|
||||
// SetError flags the span associated with this request as in error.
|
||||
|
||||
@@ -28,7 +28,7 @@ fi
|
||||
# Build binaries
|
||||
# shellcheck disable=SC2086
|
||||
CGO_ENABLED=0 GOGC=off go build ${FLAGS[*]} -ldflags "-s -w \
|
||||
-X github.com/containous/traefik/pkg/v2/version.Version=$VERSION \
|
||||
-X github.com/containous/traefik/pkg/v2/version.Codename=$CODENAME \
|
||||
-X github.com/containous/traefik/pkg/v2/version.BuildDate=$DATE" \
|
||||
-X github.com/containous/traefik/v2/pkg/version.Version=$VERSION \
|
||||
-X github.com/containous/traefik/v2/pkg/version.Codename=$CODENAME \
|
||||
-X github.com/containous/traefik/v2/pkg/version.BuildDate=$DATE" \
|
||||
-a -installsuffix nocgo -o dist/traefik ./cmd/traefik
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${0}" )" && pwd -P)"
|
||||
files=()
|
||||
while IFS='' read -r line; do files+=("$line"); done < <(git ls-files "${SCRIPT_DIR}"/../'docs/*.md' "${SCRIPT_DIR}"/../*.md)
|
||||
|
||||
while IFS='' read -r line; do files+=("$line"); done < <(git ls-files "${SCRIPT_DIR}"/../'docs/*.md' "${SCRIPT_DIR}"/../*.md | grep -v "CHANGELOG.md")
|
||||
|
||||
errors=()
|
||||
for f in "${files[@]}"; do
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:8.15.0
|
||||
FROM node:12.11
|
||||
|
||||
ENV WEBUI_DIR /src/webui
|
||||
RUN mkdir -p $WEBUI_DIR
|
||||
|
||||
@@ -20,7 +20,7 @@ make generate-webui # Generate static contents in `traefik/static/` folder.
|
||||
|
||||
## How to build (only for frontend developer)
|
||||
|
||||
- prerequisite: [Node 6+](https://nodejs.org) [Npm](https://www.npmjs.com/)
|
||||
- prerequisite: [Node 12.11+](https://nodejs.org) [Npm](https://www.npmjs.com/)
|
||||
|
||||
- Go to the directory `webui`
|
||||
|
||||
|
||||
@@ -54,37 +54,8 @@
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-separator v-if="data.weighted && data.weighted.sticky" />
|
||||
<q-card-section v-if="data.weighted && data.weighted.sticky" >
|
||||
<div class="row items-start no-wrap">
|
||||
<div class="text-subtitle1">Sticky: Cookie</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="data.weighted && data.weighted.sticky" >
|
||||
<div class="row items-start no-wrap">
|
||||
<div class="col" v-if="data.weighted.sticky.cookie && data.weighted.sticky.cookie.name">
|
||||
<div class="text-subtitle2">NAME</div>
|
||||
<q-chip
|
||||
dense
|
||||
class="app-chip app-chip-entry-points">
|
||||
{{ data.weighted.sticky.cookie.name }}
|
||||
</q-chip>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="data.weighted && data.weighted.sticky" >
|
||||
<div class="row items-start no-wrap">
|
||||
<div class="col">
|
||||
<div class="text-subtitle2">SECURE</div>
|
||||
<boolean-state :value="data.weighted.sticky.cookie.secure"/>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="text-subtitle2">HTTP Only</div>
|
||||
<boolean-state :value="data.weighted.sticky.cookie.httpOnly"/>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-separator v-if="sticky" />
|
||||
<StickyServiceDetails v-if="sticky" :sticky="sticky" :dense="dense"/>
|
||||
</q-scroll-area>
|
||||
</q-card>
|
||||
</template>
|
||||
@@ -92,17 +63,30 @@
|
||||
<script>
|
||||
import AvatarState from './AvatarState'
|
||||
import BooleanState from './BooleanState'
|
||||
import StickyServiceDetails from './StickyServiceDetails'
|
||||
|
||||
export default {
|
||||
name: 'PanelServiceDetails',
|
||||
props: ['data', 'dense'],
|
||||
components: {
|
||||
BooleanState,
|
||||
AvatarState
|
||||
AvatarState,
|
||||
StickyServiceDetails
|
||||
},
|
||||
computed: {
|
||||
isDense () {
|
||||
return this.dense !== undefined
|
||||
},
|
||||
sticky () {
|
||||
if (this.data.weighted && this.data.weighted.sticky) {
|
||||
return this.data.weighted.sticky
|
||||
}
|
||||
|
||||
if (this.data.loadBalancer && this.data.loadBalancer.sticky) {
|
||||
return this.data.loadBalancer.sticky
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
|
||||
68
webui/src/components/_commons/StickyServiceDetails.vue
Normal file
68
webui/src/components/_commons/StickyServiceDetails.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div>
|
||||
<q-card-section>
|
||||
<div class="row items-start no-wrap">
|
||||
<div class="text-subtitle1">Sticky: Cookie </div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<div class="row items-start no-wrap">
|
||||
<div class="col" v-if="sticky.cookie && sticky.cookie.name">
|
||||
<div class="text-subtitle2">NAME</div>
|
||||
<q-chip
|
||||
dense
|
||||
class="app-chip app-chip-entry-points">
|
||||
{{ sticky.cookie.name }}
|
||||
</q-chip>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<div class="row items-start no-wrap">
|
||||
<div class="col">
|
||||
<div class="text-subtitle2">SECURE</div>
|
||||
<boolean-state :value="sticky.cookie.secure"/>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="text-subtitle2">HTTP Only</div>
|
||||
<boolean-state :value="sticky.cookie.httpOnly"/>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BooleanState from './BooleanState'
|
||||
|
||||
export default {
|
||||
name: 'StickyServiceDetails',
|
||||
components: {
|
||||
BooleanState
|
||||
},
|
||||
props: ['sticky', 'dense']
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import "../../css/sass/variables";
|
||||
|
||||
.q-card__section {
|
||||
padding: 24px;
|
||||
+ .q-card__section {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.text-subtitle2 {
|
||||
font-size: 11px;
|
||||
color: $app-text-grey;
|
||||
line-height: 16px;
|
||||
margin-bottom: 4px;
|
||||
text-align: left;
|
||||
letter-spacing: 2px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user