forked from Ivasoft/traefik
Compare commits
19 Commits
v2.0.0-rc1
...
v2.0.0-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b77bb690de | ||
|
|
f843f260ee | ||
|
|
770b3739e0 | ||
|
|
261e7c1744 | ||
|
|
10acbb8d92 | ||
|
|
a917115a85 | ||
|
|
b8ed6f1588 | ||
|
|
3ed57e01a6 | ||
|
|
cb7c5a8ca1 | ||
|
|
07eb9c5970 | ||
|
|
306e5081d9 | ||
|
|
259c7adc81 | ||
|
|
af9762cf32 | ||
|
|
17554202f6 | ||
|
|
0d9cf697fa | ||
|
|
df0dd2f5e6 | ||
|
|
38508f9a9c | ||
|
|
b113972bcf | ||
|
|
72e67bf4e9 |
@@ -21,7 +21,7 @@ if [ -n "$SHOULD_TEST" ]; then docker version; fi
|
||||
|
||||
export GO_VERSION=1.12
|
||||
if [ -f "./go.mod" ]; then GO_VERSION="$(grep '^go .*' go.mod | awk '{print $2}')"; export GO_VERSION; fi
|
||||
if [ "${GO_VERSION}" == '1.13' ]; then export GO_VERSION=1.13rc1; fi
|
||||
if [ "${GO_VERSION}" == '1.13' ]; then export GO_VERSION=1.13rc2; fi
|
||||
echo "Selected Go version: ${GO_VERSION}"
|
||||
|
||||
if [ -f "./.semaphoreci/golang.sh" ]; then ./.semaphoreci/golang.sh; fi
|
||||
|
||||
49
CHANGELOG.md
49
CHANGELOG.md
@@ -1,5 +1,30 @@
|
||||
# Change Log
|
||||
|
||||
## [v2.0.0-rc2](https://github.com/containous/traefik/tree/v2.0.0-rc2) (2019-09-03)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.0.0-rc1...v2.0.0-rc2)
|
||||
|
||||
**Enhancements:**
|
||||
- **[api]** Improve API for the web UI ([#5267](https://github.com/containous/traefik/pull/5267) by [ldez](https://github.com/ldez))
|
||||
- **[middleware,tracing]** Re enable ratelimit integration tests ([#5288](https://github.com/containous/traefik/pull/5288) by [mmatur](https://github.com/mmatur))
|
||||
- **[tracing]** Update Zipkin OpenTracing driver to latest 0.4.3 release ([#5283](https://github.com/containous/traefik/pull/5283) by [basvanbeek](https://github.com/basvanbeek))
|
||||
|
||||
**Bug fixes:**
|
||||
- **[api]** Add errors about unknown entryPoint in runtime api ([#5265](https://github.com/containous/traefik/pull/5265) by [juliens](https://github.com/juliens))
|
||||
- **[metrics,tracing]** fix: Datadog case. ([#5272](https://github.com/containous/traefik/pull/5272) by [ldez](https://github.com/ldez))
|
||||
- **[middleware,k8s,k8s/crd]** The chain middleware in k8s use middlewareRef ([#5290](https://github.com/containous/traefik/pull/5290) by [juliens](https://github.com/juliens))
|
||||
- **[middleware]** Don't panic with undefined middleware ([#5289](https://github.com/containous/traefik/pull/5289) by [ldez](https://github.com/ldez))
|
||||
- **[middleware]** fix buffering middleware ([#5281](https://github.com/containous/traefik/pull/5281) by [ldez](https://github.com/ldez))
|
||||
- **[middleware]** fix: stripPrefix and stripPrefixRegex. ([#5291](https://github.com/containous/traefik/pull/5291) by [ldez](https://github.com/ldez))
|
||||
- **[service,websocket]** Fix recovered panic when websocket is mirrored ([#5255](https://github.com/containous/traefik/pull/5255) by [juliens](https://github.com/juliens))
|
||||
- **[webui]** Rest provider icon in the webui ([#5261](https://github.com/containous/traefik/pull/5261) by [mmatur](https://github.com/mmatur))
|
||||
- Fix trailing slash with check new version ([#5266](https://github.com/containous/traefik/pull/5266) by [mmatur](https://github.com/mmatur))
|
||||
|
||||
**Documentation:**
|
||||
- **[middleware]** fix: stripPrefixRegex documentation. ([#5273](https://github.com/containous/traefik/pull/5273) by [ldez](https://github.com/ldez))
|
||||
- Fix some documentation issues ([#5286](https://github.com/containous/traefik/pull/5286) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
- Update restrictions in the documentation. ([#5270](https://github.com/containous/traefik/pull/5270) by [ldez](https://github.com/ldez))
|
||||
- Base of the migration guide ([#5263](https://github.com/containous/traefik/pull/5263) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
|
||||
## [v2.0.0-rc1](https://github.com/containous/traefik/tree/v2.0.0-rc1) (2019-08-26)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.0.0-beta1...v2.0.0-rc1)
|
||||
|
||||
@@ -217,7 +242,7 @@
|
||||
- **[api,authentication]** Remove authentication hashes from API ([#4918](https://github.com/containous/traefik/pull/4918) by [ldez](https://github.com/ldez))
|
||||
- **[consul]** Enhance KV logs. ([#4877](https://github.com/containous/traefik/pull/4877) by [ldez](https://github.com/ldez))
|
||||
- **[k8s]** Fix kubernetes template for backend responseforwarding flushinterval setting ([#4901](https://github.com/containous/traefik/pull/4901) by [ravilr](https://github.com/ravilr))
|
||||
- **[metrics]** Upgraded DataDog tracing library to 1.13.0 ([#4878](https://github.com/containous/traefik/pull/4878) by [aantono](https://github.com/aantono))
|
||||
- **[metrics]** Upgraded Datadog tracing library to 1.13.0 ([#4878](https://github.com/containous/traefik/pull/4878) by [aantono](https://github.com/aantono))
|
||||
- **[server]** Add missing callback on close of hijacked connections ([#4900](https://github.com/containous/traefik/pull/4900) by [ravilr](https://github.com/ravilr))
|
||||
|
||||
**Documentation:**
|
||||
@@ -419,7 +444,7 @@
|
||||
- **[k8s/ingress]** Loop through service ports for global backend ([#4486](https://github.com/containous/traefik/pull/4486) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[k8s]** Add entrypoints prefix in kubernetes frontend/backend id ([#4679](https://github.com/containous/traefik/pull/4679) by [juliens](https://github.com/juliens))
|
||||
- **[websocket]** Exclude websocket connections from Average Response Time ([#4313](https://github.com/containous/traefik/pull/4313) by [siyu6974](https://github.com/siyu6974))
|
||||
- **[middleware]** Added support for configuring trace headers for DataDog tracing ([#4516](https://github.com/containous/traefik/pull/4516) by [aantono](https://github.com/aantono))
|
||||
- **[middleware]** Added support for configuring trace headers for Datadog tracing ([#4516](https://github.com/containous/traefik/pull/4516) by [aantono](https://github.com/aantono))
|
||||
|
||||
**Documentation:**
|
||||
- **[acme]** Add _FILE Environment Variable Documentation ([#4643](https://github.com/containous/traefik/pull/4643) by [dargmuesli](https://github.com/dargmuesli))
|
||||
@@ -670,7 +695,7 @@
|
||||
- **[metrics]** Metrics: Add support for InfluxDB Database / RetentionPolicy and HTTP client ([#3391](https://github.com/containous/traefik/pull/3391) by [drewkerrigan](https://github.com/drewkerrigan))
|
||||
- **[middleware,consulcatalog,docker,ecs,kv,marathon,mesos,rancher]** Pass the TLS Cert infos in headers ([#3826](https://github.com/containous/traefik/pull/3826) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
- **[middleware,server]** Extreme Makeover: server refactoring ([#3461](https://github.com/containous/traefik/pull/3461) by [ldez](https://github.com/ldez))
|
||||
- **[middleware,tracing]** Added integration support for DataDog APM Tracing ([#3517](https://github.com/containous/traefik/pull/3517) by [aantono](https://github.com/aantono))
|
||||
- **[middleware,tracing]** Added integration support for Datadog APM Tracing ([#3517](https://github.com/containous/traefik/pull/3517) by [aantono](https://github.com/aantono))
|
||||
- **[middleware,tracing]** Create a custom logger for jaeger ([#3541](https://github.com/containous/traefik/pull/3541) by [mmatur](https://github.com/mmatur))
|
||||
- **[middleware]** Performance enhancements for the rules matchers. ([#3563](https://github.com/containous/traefik/pull/3563) by [ShaneSaww](https://github.com/ShaneSaww))
|
||||
- **[middleware]** Extract internal router creation from server ([#3204](https://github.com/containous/traefik/pull/3204) by [Juliens](https://github.com/Juliens))
|
||||
@@ -731,7 +756,7 @@
|
||||
- **[oxy]** Handle Te header when http2 ([#3824](https://github.com/containous/traefik/pull/3824) by [Juliens](https://github.com/Juliens))
|
||||
- **[server]** Avoid goroutine leak in server ([#3851](https://github.com/containous/traefik/pull/3851) by [nmengin](https://github.com/nmengin))
|
||||
- **[server]** Avoid panic during stop ([#3898](https://github.com/containous/traefik/pull/3898) by [nmengin](https://github.com/nmengin))
|
||||
- **[tracing]** Added default configuration for DataDog APM Tracer ([#3655](https://github.com/containous/traefik/pull/3655) by [aantono](https://github.com/aantono))
|
||||
- **[tracing]** Added default configuration for Datadog APM Tracer ([#3655](https://github.com/containous/traefik/pull/3655) by [aantono](https://github.com/aantono))
|
||||
- **[tracing]** Added support for Trace name truncation for traces ([#3689](https://github.com/containous/traefik/pull/3689) by [aantono](https://github.com/aantono))
|
||||
- **[websocket]** Handle shutdown of Hijacked connections ([#3636](https://github.com/containous/traefik/pull/3636) by [Juliens](https://github.com/Juliens))
|
||||
- **[webui]** Added Dashboard table item for Rate Limits ([#3893](https://github.com/containous/traefik/pull/3893) by [codecyclist](https://github.com/codecyclist))
|
||||
@@ -868,7 +893,7 @@
|
||||
- **[docker]** Uses both binded HostIP and HostPort when useBindPortIP=true ([#3638](https://github.com/containous/traefik/pull/3638) by [geraldcroes](https://github.com/geraldcroes))
|
||||
- **[k8s]** Fix Rewrite-target regex ([#3699](https://github.com/containous/traefik/pull/3699) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[middleware]** Correct Entrypoint Redirect with Stripped or Added Path ([#3631](https://github.com/containous/traefik/pull/3631) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[tracing]** Added default configuration for DataDog APM Tracer ([#3655](https://github.com/containous/traefik/pull/3655) by [aantono](https://github.com/aantono))
|
||||
- **[tracing]** Added default configuration for Datadog APM Tracer ([#3655](https://github.com/containous/traefik/pull/3655) by [aantono](https://github.com/aantono))
|
||||
- **[tracing]** Added support for Trace name truncation for traces ([#3689](https://github.com/containous/traefik/pull/3689) by [aantono](https://github.com/aantono))
|
||||
- **[websocket]** Handle shutdown of Hijacked connections ([#3636](https://github.com/containous/traefik/pull/3636) by [Juliens](https://github.com/Juliens))
|
||||
- H2C: Remove buggy line in init to make verbose switch working ([#3701](https://github.com/containous/traefik/pull/3701) by [dduportal](https://github.com/dduportal))
|
||||
@@ -964,7 +989,7 @@
|
||||
- **[mesos]** Segments Labels: Mesos ([#3383](https://github.com/containous/traefik/pull/3383) by [drewkerrigan](https://github.com/drewkerrigan))
|
||||
- **[metrics]** Metrics: Add support for InfluxDB Database / RetentionPolicy and HTTP client ([#3391](https://github.com/containous/traefik/pull/3391) by [drewkerrigan](https://github.com/drewkerrigan))
|
||||
- **[middleware,server]** Extreme Makeover: server refactoring ([#3461](https://github.com/containous/traefik/pull/3461) by [ldez](https://github.com/ldez))
|
||||
- **[middleware,tracing]** Added integration support for DataDog APM Tracing ([#3517](https://github.com/containous/traefik/pull/3517) by [aantono](https://github.com/aantono))
|
||||
- **[middleware,tracing]** Added integration support for Datadog APM Tracing ([#3517](https://github.com/containous/traefik/pull/3517) by [aantono](https://github.com/aantono))
|
||||
- **[middleware,tracing]** Create a custom logger for jaeger ([#3541](https://github.com/containous/traefik/pull/3541) by [mmatur](https://github.com/mmatur))
|
||||
- **[middleware]** Performance enhancements for the rules matchers. ([#3563](https://github.com/containous/traefik/pull/3563) by [ShaneSaww](https://github.com/ShaneSaww))
|
||||
- **[middleware]** Extract internal router creation from server ([#3204](https://github.com/containous/traefik/pull/3204) by [Juliens](https://github.com/Juliens))
|
||||
@@ -1142,7 +1167,7 @@
|
||||
- **[metrics]** Added entrypoint metrics to influxdb ([#2992](https://github.com/containous/traefik/pull/2992) by [adityacs](https://github.com/adityacs))
|
||||
- **[metrics]** Remove unnecessary conversion ([#2850](https://github.com/containous/traefik/pull/2850) by [ferhatelmas](https://github.com/ferhatelmas))
|
||||
- **[metrics]** Extend metrics and rebuild prometheus exporting logic ([#2567](https://github.com/containous/traefik/pull/2567) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[metrics]** Added missing metrics to registry for DataDog and StatsD ([#2890](https://github.com/containous/traefik/pull/2890) by [aantono](https://github.com/aantono))
|
||||
- **[metrics]** Added missing metrics to registry for Datadog and StatsD ([#2890](https://github.com/containous/traefik/pull/2890) by [aantono](https://github.com/aantono))
|
||||
- **[middleware,consul,consulcatalog,docker,ecs,k8s,marathon,mesos,rancher]** New option in secure middleware ([#2958](https://github.com/containous/traefik/pull/2958) by [mmatur](https://github.com/mmatur))
|
||||
- **[middleware,consulcatalog,docker,ecs,k8s,kv,marathon,mesos,rancher]** Ability to use "X-Forwarded-For" as a source of IP for white list. ([#3070](https://github.com/containous/traefik/pull/3070) by [ldez](https://github.com/ldez))
|
||||
- **[middleware,docker]** Use pointer of error pages ([#2607](https://github.com/containous/traefik/pull/2607) by [ldez](https://github.com/ldez))
|
||||
@@ -1394,7 +1419,7 @@
|
||||
- **[mesos]** Add all available labels to Mesos Backend ([#2687](https://github.com/containous/traefik/pull/2687) by [ldez](https://github.com/ldez))
|
||||
- **[metrics]** Added entrypoint metrics to influxdb ([#2992](https://github.com/containous/traefik/pull/2992) by [adityacs](https://github.com/adityacs))
|
||||
- **[metrics]** Extend metrics and rebuild prometheus exporting logic ([#2567](https://github.com/containous/traefik/pull/2567) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[metrics]** Added missing metrics to registry for DataDog and StatsD ([#2890](https://github.com/containous/traefik/pull/2890) by [aantono](https://github.com/aantono))
|
||||
- **[metrics]** Added missing metrics to registry for Datadog and StatsD ([#2890](https://github.com/containous/traefik/pull/2890) by [aantono](https://github.com/aantono))
|
||||
- **[metrics]** Remove unnecessary conversion ([#2850](https://github.com/containous/traefik/pull/2850) by [ferhatelmas](https://github.com/ferhatelmas))
|
||||
- **[middleware,consul,consulcatalog,docker,ecs,k8s,marathon,mesos,rancher]** New option in secure middleware ([#2958](https://github.com/containous/traefik/pull/2958) by [mmatur](https://github.com/mmatur))
|
||||
- **[middleware,consulcatalog,docker,ecs,k8s,kv,marathon,mesos,rancher]** Ability to use "X-Forwarded-For" as a source of IP for white list. ([#3070](https://github.com/containous/traefik/pull/3070) by [ldez](https://github.com/ldez))
|
||||
@@ -2015,12 +2040,12 @@
|
||||
- **[marathon]** Add support for readiness checks. ([#1883](https://github.com/containous/traefik/pull/1883) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[marathon]** Move marathon mock ([#1732](https://github.com/containous/traefik/pull/1732) by [ldez](https://github.com/ldez))
|
||||
- **[marathon]** Use single API call to fetch Marathon resources. ([#1815](https://github.com/containous/traefik/pull/1815) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[metrics]** Added RetryMetrics to DataDog and StatsD providers ([#1884](https://github.com/containous/traefik/pull/1884) by [aantono](https://github.com/aantono))
|
||||
- **[metrics]** Added RetryMetrics to Datadog and StatsD providers ([#1884](https://github.com/containous/traefik/pull/1884) by [aantono](https://github.com/aantono))
|
||||
- **[metrics]** Extract metrics to own package and refactor implementations ([#1968](https://github.com/containous/traefik/pull/1968) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[metrics]** Add metrics for backend_retries_total ([#1504](https://github.com/containous/traefik/pull/1504) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[metrics]** Add status code to request duration metric ([#1755](https://github.com/containous/traefik/pull/1755) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[middleware]** Add trusted whitelist proxy protocol ([#2234](https://github.com/containous/traefik/pull/2234) by [emilevauge](https://github.com/emilevauge)))
|
||||
- **[metrics]** DataDog and StatsD Metrics Support ([#1701](https://github.com/containous/traefik/pull/1701) by [aantono](https://github.com/aantono))
|
||||
- **[metrics]** Datadog and StatsD Metrics Support ([#1701](https://github.com/containous/traefik/pull/1701) by [aantono](https://github.com/aantono))
|
||||
- **[middleware]** Create Header Middleware ([#1236](https://github.com/containous/traefik/pull/1236) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[middleware]** Add configurable timeouts and curate default timeout settings ([#1873](https://github.com/containous/traefik/pull/1873) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[middleware]** Fix command bug content. ([#2002](https://github.com/containous/traefik/pull/2002) by [ldez](https://github.com/ldez))
|
||||
@@ -2326,11 +2351,11 @@
|
||||
- **[marathon]** Move marathon mock ([#1732](https://github.com/containous/traefik/pull/1732) by [ldez](https://github.com/ldez))
|
||||
- **[marathon]** Support multi-port service routing for containers running on Marathon ([#1742](https://github.com/containous/traefik/pull/1742) by [aantono](https://github.com/aantono))
|
||||
- **[marathon]** Use test builder. ([#1871](https://github.com/containous/traefik/pull/1871) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[metrics]** DataDog and StatsD Metrics Support ([#1701](https://github.com/containous/traefik/pull/1701) by [aantono](https://github.com/aantono))
|
||||
- **[metrics]** Datadog and StatsD Metrics Support ([#1701](https://github.com/containous/traefik/pull/1701) by [aantono](https://github.com/aantono))
|
||||
- **[metrics]** Add status code to request duration metric ([#1755](https://github.com/containous/traefik/pull/1755) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[metrics]** Add metrics for backend_retries_total ([#1504](https://github.com/containous/traefik/pull/1504) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[metrics]** Extract metrics to own package and refactor implementations ([#1968](https://github.com/containous/traefik/pull/1968) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[metrics]** Added RetryMetrics to DataDog and StatsD providers ([#1884](https://github.com/containous/traefik/pull/1884) by [aantono](https://github.com/aantono))
|
||||
- **[metrics]** Added RetryMetrics to Datadog and StatsD providers ([#1884](https://github.com/containous/traefik/pull/1884) by [aantono](https://github.com/aantono))
|
||||
- **[middleware]** Return 503 on empty backend ([#1748](https://github.com/containous/traefik/pull/1748) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[middleware]** Add configurable timeouts and curate default timeout settings ([#1873](https://github.com/containous/traefik/pull/1873) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[middleware]** Custom Error Pages ([#1675](https://github.com/containous/traefik/pull/1675) by [bparli](https://github.com/bparli))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.13rc1-alpine
|
||||
FROM golang:1.13rc2-alpine
|
||||
|
||||
RUN apk --update upgrade \
|
||||
&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar ca-certificates tzdata \
|
||||
|
||||
@@ -299,14 +299,14 @@ You haven't specified the sendAnonymousUsage option, it will be enabled by defau
|
||||
Stats collection is enabled.
|
||||
Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration.
|
||||
Help us improve Traefik by leaving this feature on :)
|
||||
More details on: https://docs.traefik.io/basics/#collected-data
|
||||
More details on: https://docs.traefik.io/v2.0/contributing/data-collection/
|
||||
`)
|
||||
collect(staticConfiguration)
|
||||
} else {
|
||||
log.WithoutContext().Info(`
|
||||
Stats collection is disabled.
|
||||
Help us improve Traefik by turning this feature on :)
|
||||
More details on: https://docs.traefik.io/basics/#collected-data
|
||||
More details on: https://docs.traefik.io/v2.0/contributing/data-collection/
|
||||
`)
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB |
@@ -28,7 +28,7 @@ Successfully tagged traefik-webui:latest
|
||||
[...]
|
||||
docker build -t "traefik-dev:4475--feature-documentation" -f build.Dockerfile .
|
||||
Sending build context to Docker daemon 279MB
|
||||
Step 1/10 : FROM golang:1.13rc1-alpine
|
||||
Step 1/10 : FROM golang:1.13rc2-alpine
|
||||
---> f4bfb3d22bda
|
||||
[...]
|
||||
Successfully built 5c3c1a911277
|
||||
|
||||
@@ -9,7 +9,7 @@ Understanding how you use Traefik is very important to us: it helps us improve t
|
||||
For this very reason, the sendAnonymousUsage option is mandatory: we want you to take time to consider whether or not you wish to share anonymous data with us so we can benefit from your experience and use cases.
|
||||
|
||||
!!! warning
|
||||
During the beta stage only, leaving this option unset will not prevent Traefik from running but will generate an error log indicating that it enables data collection by default.
|
||||
Before the GA, leaving this option unset will not prevent Traefik from running but will generate an error log indicating that it enables data collection by default.
|
||||
|
||||
!!! example "Enabling Data Collection"
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ tls:
|
||||
!!! important "File Provider Only"
|
||||
|
||||
In the above example, we've used the [file provider](../providers/file.md) to handle these definitions.
|
||||
In its current beta version, it is the only available method to configure the certificates (as well as the options and the stores).
|
||||
It is the only available method to configure the certificates (as well as the options and the stores).
|
||||
|
||||
## Certificates Stores
|
||||
|
||||
@@ -52,9 +52,9 @@ tls:
|
||||
default: {}
|
||||
```
|
||||
|
||||
!!! important "Beta restriction"
|
||||
!!! important "Restriction"
|
||||
|
||||
During the beta version, any store definition other than the default one (named `default`) will be ignored,
|
||||
Any store definition other than the default one (named `default`) will be ignored,
|
||||
and there is thefore only one globally available TLS store.
|
||||
|
||||
In the `tls.certificates` section, a list of stores can then be specified to indicate where the certificates should be stored:
|
||||
@@ -85,9 +85,9 @@ tls:
|
||||
keyFile: /path/to/other-domain.key
|
||||
```
|
||||
|
||||
!!! important "Beta restriction"
|
||||
!!! important "Restriction"
|
||||
|
||||
During the beta version, the `stores` list will actually be ignored and automatically set to `["default"]`.
|
||||
The `stores` list will actually be ignored and automatically set to `["default"]`.
|
||||
|
||||
### Default Certificate
|
||||
|
||||
|
||||
@@ -79,10 +79,6 @@ Passwords must be encoded using MD5, SHA1, or BCrypt.
|
||||
|
||||
The `users` option is an array of authorized users. Each user will be declared using the `name:encoded-password` format.
|
||||
|
||||
!!! Note
|
||||
|
||||
If both `users` and `usersFile` are provided, the two are merged. The content of `usersFile` has precedence over `users`.
|
||||
|
||||
### `usersFile`
|
||||
|
||||
The `usersFile` option is the path to an external file that contains the authorized users for the middleware.
|
||||
@@ -106,7 +102,7 @@ You can customize the realm for the authentication with the `realm` option. The
|
||||
|
||||
### `headerField`
|
||||
|
||||
You can customize the header field for the authenticated user using the `headerField`option.
|
||||
You can define a header field to store the authenticated user using the `headerField`option.
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
|
||||
@@ -51,9 +51,9 @@ metadata:
|
||||
spec:
|
||||
chain:
|
||||
middlewares:
|
||||
- https-only
|
||||
- known-ips
|
||||
- auth-users
|
||||
- name: https-only
|
||||
- name: known-ips
|
||||
- name: auth-users
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
|
||||
@@ -132,7 +132,7 @@ For example, the expression `LatencyAtQuantileMS(50.0) > 100` will trigger the c
|
||||
|
||||
!!! Note
|
||||
|
||||
You must provide a float number (with the leading .0) for the quantile value
|
||||
You must provide a float number (with the trailing .0) for the quantile value
|
||||
|
||||
#### Using multiple metrics
|
||||
|
||||
@@ -153,7 +153,6 @@ Here is the list of supported operators:
|
||||
- Greater or equal than (`>=`)
|
||||
- Lesser than (`<`)
|
||||
- Lesser or equal than (`<=`)
|
||||
- Not (`!`)
|
||||
- Equal (`==`)
|
||||
- Not Equal (`!=`)
|
||||
|
||||
|
||||
@@ -55,6 +55,6 @@ http:
|
||||
|
||||
Responses are compressed when:
|
||||
|
||||
* The response body is larger than `512` bytes.
|
||||
* The response body is larger than `1400` bytes.
|
||||
* The `Accept-Encoding` request header contains `gzip`.
|
||||
* The response is not already compressed, i.e. the `Content-Encoding` response header is not already set.
|
||||
|
||||
@@ -77,7 +77,7 @@ http:
|
||||
```
|
||||
|
||||
!!! note
|
||||
In this example, the error page URL is based on the status code (`query=/{status}.html)`.
|
||||
In this example, the error page URL is based on the status code (`query=/{status}.html`).
|
||||
|
||||
## Configuration Options
|
||||
|
||||
|
||||
@@ -70,7 +70,12 @@ http:
|
||||
`X-Script-Name` header added to the proxied request, the `X-Custom-Request-Header` header removed from the request,
|
||||
and the `X-Custom-Response-Header` header removed from the response.
|
||||
|
||||
Please note that is not possible to remove headers through the use of labels (Docker, Rancher, Marathon, ...) for now.
|
||||
Please note that it is not possible to remove headers through the use of labels (Docker, Rancher, Marathon, ...) for now.
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
@@ -86,17 +91,17 @@ spec:
|
||||
X-Custom-Response-Header: "" # Removes
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name": "test",
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.testHeader.headers]
|
||||
@@ -121,7 +126,7 @@ http:
|
||||
|
||||
### Using Security Headers
|
||||
|
||||
Security related headers (HSTS headers, SSL redirection, Browser XSS filter, etc) can be added and configured per frontend in a similar manner to the custom headers above.
|
||||
Security related headers (HSTS headers, SSL redirection, Browser XSS filter, etc) can be added and configured in a manner similar to the custom headers above.
|
||||
This functionality allows for some easy security features to quickly be set.
|
||||
|
||||
```yaml tab="Docker"
|
||||
@@ -141,12 +146,6 @@ spec:
|
||||
sslRedirect: "true"
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.framedeny=true"
|
||||
- "traefik.http.middlewares.testheader.headers.sslredirect=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.testheader.headers.framedeny": "true",
|
||||
@@ -154,6 +153,12 @@ labels:
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.framedeny=true"
|
||||
- "traefik.http.middlewares.testheader.headers.sslredirect=true"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.testHeader.headers]
|
||||
@@ -172,7 +177,7 @@ http:
|
||||
|
||||
### CORS Headers
|
||||
|
||||
CORS (Cross-Origin Resource Sharing) headers can be added and configured per frontend in a similar manner to the custom headers above.
|
||||
CORS (Cross-Origin Resource Sharing) headers can be added and configured in a manner similar to the custom headers above.
|
||||
This functionality allows for more advanced security features to quickly be set.
|
||||
|
||||
```yaml tab="Docker"
|
||||
@@ -199,14 +204,6 @@ spec:
|
||||
addVaryHeader: "true"
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolalloworigin=origin-list-or-null"
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100"
|
||||
- "traefik.http.middlewares.testheader.headers.addvaryheader=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.testheader.headers.accesscontrolallowmethods": "GET,OPTIONS,PUT",
|
||||
@@ -216,6 +213,14 @@ labels:
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolalloworigin=origin-list-or-null"
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100"
|
||||
- "traefik.http.middlewares.testheader.headers.addvaryheader=true"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.testHeader.headers]
|
||||
|
||||
@@ -74,7 +74,7 @@ The `ipStrategy` option defines two parameters that sets how Traefik will determ
|
||||
The `depth` option tells Traefik to use the `X-Forwarded-For` header and take the IP located at the `depth` position (starting from the right).
|
||||
|
||||
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP will be empty.
|
||||
- `depth` is ignored if its value is is lesser than or equal to 0.
|
||||
- `depth` is ignored if its value is lesser than or equal to 0.
|
||||
|
||||
!!! note "Example of Depth & X-Forwarded-For"
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and take th
|
||||
!!! note
|
||||
|
||||
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP will be empty.
|
||||
- `depth` is ignored if its value is is lesser than or equal to 0.
|
||||
- `depth` is ignored if its value is lesser than or equal to 0.
|
||||
|
||||
#### `ipStrategy.excludedIPs`
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ PassTLSClientCert can add two headers to the request:
|
||||
!!! note
|
||||
The headers are filled with escaped string so it can be safely placed inside a URL query.
|
||||
|
||||
In the following example, you can see a complete certificate. We will use each part of it to explains the middleware options.
|
||||
In the following example, you can see a complete certificate. We will use each part of it to explain the middleware options.
|
||||
|
||||
??? example "A complete client tls certificate"
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
To Control the Number of Requests Going to a Service
|
||||
{: .subtitle }
|
||||
|
||||

|
||||
|
||||
The RateLimit middleware ensures that services will receive a _fair_ number of requests, and allows you define what is fair.
|
||||
|
||||
## Configuration Example
|
||||
@@ -173,7 +171,7 @@ The `ipStrategy` option defines two parameters that sets how Traefik will determ
|
||||
The `depth` option tells Traefik to use the `X-Forwarded-For` header and take the IP located at the `depth` position (starting from the right).
|
||||
|
||||
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP will be empty.
|
||||
- `depth` is ignored if its value is is lesser than or equal to 0.
|
||||
- `depth` is ignored if its value is lesser than or equal to 0.
|
||||
|
||||
!!! note "Example of Depth & X-Forwarded-For"
|
||||
|
||||
|
||||
@@ -3,55 +3,50 @@
|
||||
Removing Prefixes From the Path Before Forwarding the Request (Using a Regex)
|
||||
{: .subtitle }
|
||||
|
||||
`TODO: add schema`
|
||||
|
||||
Remove the matching prefixes from the URL path.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
# Replace the path by /foo
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=^/foo/(.*)",
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/",
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Replace the path by /foo
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-stripprefixregex
|
||||
spec:
|
||||
stripPrefixRegex:
|
||||
regex: "^/foo/(.*)"
|
||||
regex:
|
||||
- "/foo/[a-z0-9]+/[0-9]+/"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex": "^/foo/(.*)"
|
||||
"traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex": "/foo/[a-z0-9]+/[0-9]+/"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Replace the path by /foo
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=^/foo/(.*)",
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/",
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Replace the path by /foo
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-stripprefixregex.stripPrefixRegex]
|
||||
regex = "^/foo/(.*)"
|
||||
regex = ["/foo/[a-z0-9]+/[0-9]+/"]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Replace the path by /foo
|
||||
http:
|
||||
middlewares:
|
||||
test-stripprefixregex:
|
||||
stripPrefixRegex:
|
||||
regex: "^/foo/(.*)"
|
||||
regex:
|
||||
- "/foo/[a-z0-9]+/[0-9]+/"
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
344
docs/content/migration/v1-to-v2.md
Normal file
344
docs/content/migration/v1-to-v2.md
Normal file
@@ -0,0 +1,344 @@
|
||||
# Migration Guide: From v1 to v2
|
||||
|
||||
How to Migrate from Traefik v1 to Traefik v2.
|
||||
{: .subtitle }
|
||||
|
||||
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,
|
||||
feature by feature, of how the configuration looked like in v1, and how it now looks like in v2.
|
||||
|
||||
## Frontends and Backends Are Dead... <br/>... Long Live Routers, Middlewares, and Services
|
||||
|
||||
During the transition from v1 to v2, a number of internal pieces and components of Traefik were rewritten and reorganized.
|
||||
As such, the combination of core notions such as frontends and backends has been replaced with the combination of routers, services, and middlewares.
|
||||
|
||||
Typically, a router replaces a frontend, and a service assumes the role of a backend, with each router referring to a service.
|
||||
However, even though a backend was in charge of applying any desired modification on the fly to the incoming request,
|
||||
the router defers that responsibility to another component.
|
||||
Instead, a dedicated middleware is now defined for each kind of such modification.
|
||||
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."
|
||||
|
||||
### 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"
|
||||
```
|
||||
|
||||
```yaml tab="K8s Ingress"
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: traefik
|
||||
namespace: kube-system
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: traefik
|
||||
traefik.ingress.kubernetes.io/rule-type: PathPrefix
|
||||
spec:
|
||||
rules:
|
||||
- host: test.locahost
|
||||
http:
|
||||
paths:
|
||||
- path: /test
|
||||
backend:
|
||||
serviceName: server0
|
||||
servicePort: 80
|
||||
- path: /test
|
||||
backend:
|
||||
serviceName: server1
|
||||
servicePort: 80
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[frontends]
|
||||
[frontends.frontend1]
|
||||
entryPoints = ["http"]
|
||||
backend = "backend1"
|
||||
|
||||
[frontends.frontend1.routes]
|
||||
[frontends.frontend1.routes.route0]
|
||||
rule = "Host:test.localhost"
|
||||
[frontends.frontend1.routes.route0]
|
||||
rule = "PathPrefix:/test"
|
||||
|
||||
[frontends.frontend1.auth]
|
||||
[frontends.frontend1.auth.basic]
|
||||
users = [
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
]
|
||||
|
||||
[backends]
|
||||
[backends.backend1]
|
||||
[backends.backend1.servers.server0]
|
||||
url = "http://10.10.10.1:80"
|
||||
[backends.backend1.servers.server1]
|
||||
url = "http://10.10.10.2:80"
|
||||
|
||||
[backends.backend1.loadBalancer]
|
||||
method = "wrr"
|
||||
```
|
||||
|
||||
### 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"
|
||||
```
|
||||
|
||||
```yaml tab="K8s IngressRoute"
|
||||
# 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
|
||||
metadata:
|
||||
name: basicauth
|
||||
namespace: foo
|
||||
|
||||
spec:
|
||||
basicAuth:
|
||||
users:
|
||||
- test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/
|
||||
- test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: ingressroutebar
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- http
|
||||
routes:
|
||||
- match: Host(`test.localhost`) && PathPrefix(`/test`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: server0
|
||||
port: 80
|
||||
- name: server1
|
||||
port: 80
|
||||
middlewares:
|
||||
- name: basicauth
|
||||
namespace: foo
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.routers]
|
||||
[http.routers.router0]
|
||||
rule = "Host(`test.localhost`) && PathPrefix(`/test`)"
|
||||
middlewares = ["auth"]
|
||||
service = "my-service"
|
||||
|
||||
[http.services]
|
||||
[[http.services.my-service.loadBalancer.servers]]
|
||||
url = "http://10.10.10.1:80"
|
||||
[[http.services.my-service.loadBalancer.servers]]
|
||||
url = "http://10.10.10.2:80"
|
||||
|
||||
[http.middlewares]
|
||||
[http.middlewares.auth.basicAuth]
|
||||
users = [
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
routers:
|
||||
router0:
|
||||
rule: "Host(`test.localhost`) && PathPrefix(`/test`)"
|
||||
service: my-service
|
||||
middlewares:
|
||||
- auth
|
||||
|
||||
services:
|
||||
my-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: http://10.10.10.1:80
|
||||
- url: http://10.10.10.2:80
|
||||
|
||||
middlewares:
|
||||
auth:
|
||||
basicAuth:
|
||||
users:
|
||||
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
## 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.
|
||||
Then, a router's TLS field can refer to one of the TLS configurations defined at the root, hence defining the TLS configuration for that router.
|
||||
|
||||
!!! example "TLS on web-secure entryPoint becomes TLS option on Router-1"
|
||||
|
||||
### v1
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# static configuration
|
||||
[entryPoints]
|
||||
[entryPoints.web-secure]
|
||||
address = ":443"
|
||||
|
||||
[entryPoints.web-secure.tls]
|
||||
minVersion = "VersionTLS12"
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||
]
|
||||
[[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'
|
||||
```
|
||||
|
||||
### v2
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# dynamic configuration
|
||||
[http.routers]
|
||||
[http.routers.Router-1]
|
||||
rule = "Host(`bar.com`)"
|
||||
service = "service-id"
|
||||
# will terminate the TLS request
|
||||
[http.routers.Router-1.tls]
|
||||
options = "myTLSOptions"
|
||||
|
||||
[[tls.certificates]]
|
||||
certFile = "/path/to/domain.cert"
|
||||
keyFile = "/path/to/domain.key"
|
||||
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
minVersion = "VersionTLS12"
|
||||
|
||||
[tls.options.myTLSOptions]
|
||||
minVersion = "VersionTLS13"
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||
]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
routers:
|
||||
Router-1:
|
||||
rule: "Host(`bar.com`)"
|
||||
service: service-id
|
||||
# will terminate the TLS request
|
||||
tls:
|
||||
options: myTLSOptions
|
||||
|
||||
tls:
|
||||
certificates:
|
||||
- certFile: /path/to/domain.cert
|
||||
keyFile: /path/to/domain.key
|
||||
options:
|
||||
myTLSOptions:
|
||||
minVersion: VersionTLS13
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
```
|
||||
|
||||
```yaml tab="K8s IngressRoute"
|
||||
# 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
|
||||
metadata:
|
||||
name: mytlsoption
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minVersion: VersionTLS13
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: ingressroutebar
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`bar.com`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
tls:
|
||||
options:
|
||||
name: mytlsoption
|
||||
namespace: default
|
||||
```
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
# myTLSOptions must be defined by another provider, in this instance in the File Provider.
|
||||
# see the cross provider section
|
||||
- "traefik.http.routers.router0.tls.options=myTLSOptions@file"
|
||||
```
|
||||
|
||||
## HTTP -> HTTPS Redirection
|
||||
|
||||
TODO
|
||||
|
||||
## ACME (let's encrypt)
|
||||
|
||||
TODO
|
||||
|
||||
## Traefik Logs
|
||||
|
||||
TODO
|
||||
|
||||
## Tracing
|
||||
|
||||
TODO
|
||||
|
||||
## Metrics
|
||||
|
||||
TODO
|
||||
|
||||
## No more root level key/values
|
||||
|
||||
TODO
|
||||
|
||||
## Providers
|
||||
|
||||
Supported providers, for now:
|
||||
|
||||
- [ ] Azure Service Fabric
|
||||
- [ ] BoltDB
|
||||
- [ ] Consul
|
||||
- [ ] Consul Catalog
|
||||
- [x] Docker
|
||||
- [ ] DynamoDB
|
||||
- [ ] ECS
|
||||
- [ ] Etcd
|
||||
- [ ] Eureka
|
||||
- [x] File
|
||||
- [x] Kubernetes Ingress (without annotations)
|
||||
- [x] Kubernetes IngressRoute
|
||||
- [x] Marathon
|
||||
- [ ] Mesos
|
||||
- [x] Rest
|
||||
- [ ] Zookeeper
|
||||
@@ -1,15 +1,15 @@
|
||||
# DataDog
|
||||
# Datadog
|
||||
|
||||
To enable the DataDog:
|
||||
To enable the Datadog:
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.dataDog]
|
||||
[metrics.datadog]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
dataDog: {}
|
||||
datadog: {}
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
@@ -24,13 +24,13 @@ Address instructs exporter to send metrics to datadog-agent at this address.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.dataDog]
|
||||
[metrics.datadog]
|
||||
address = "127.0.0.1:8125"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
dataDog:
|
||||
datadog:
|
||||
address: 127.0.0.1:8125
|
||||
```
|
||||
|
||||
@@ -46,13 +46,13 @@ Enable metrics on entry points.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.dataDog]
|
||||
[metrics.datadog]
|
||||
addEntryPointsLabels = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
dataDog:
|
||||
datadog:
|
||||
addEntryPointsLabels: true
|
||||
```
|
||||
|
||||
@@ -68,13 +68,13 @@ Enable metrics on services.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.dataDog]
|
||||
[metrics.datadog]
|
||||
addServicesLabels = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
dataDog:
|
||||
datadog:
|
||||
addServicesLabels: true
|
||||
```
|
||||
|
||||
@@ -90,13 +90,13 @@ The interval used by the exporter to push metrics to datadog-agent.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.dataDog]
|
||||
[metrics.datadog]
|
||||
pushInterval = 10s
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
dataDog:
|
||||
datadog:
|
||||
pushInterval: 10s
|
||||
```
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Metrics system
|
||||
|
||||
Traefik supports 4 metrics backends:
|
||||
|
||||
- [DataDog](./datadog.md)
|
||||
- [Datadog](./datadog.md)
|
||||
- [InfluxDB](./influxdb.md)
|
||||
- [Prometheus](./prometheus.md)
|
||||
- [StatsD](./statsd.md)
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
# DataDog
|
||||
# Datadog
|
||||
|
||||
To enable the DataDog:
|
||||
To enable the Datadog:
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[tracing]
|
||||
[tracing.dataDog]
|
||||
[tracing.datadog]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
tracing:
|
||||
dataDog: {}
|
||||
datadog: {}
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
@@ -24,13 +24,13 @@ Local Agent Host Port instructs reporter to send spans to datadog-tracing-agent
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[tracing]
|
||||
[tracing.dataDog]
|
||||
[tracing.datadog]
|
||||
localAgentHostPort = "127.0.0.1:8126"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
tracing:
|
||||
dataDog:
|
||||
datadog:
|
||||
localAgentHostPort: 127.0.0.1:8126
|
||||
```
|
||||
|
||||
@@ -42,17 +42,17 @@ tracing:
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
Enable DataDog debug.
|
||||
Enable Datadog debug.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[tracing]
|
||||
[tracing.dataDog]
|
||||
[tracing.datadog]
|
||||
debug = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
tracing:
|
||||
dataDog:
|
||||
datadog:
|
||||
debug: true
|
||||
```
|
||||
|
||||
@@ -68,13 +68,13 @@ Apply shared tag in a form of Key:Value to all the traces.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[tracing]
|
||||
[tracing.dataDog]
|
||||
[tracing.datadog]
|
||||
globalTag = "sample"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
tracing:
|
||||
dataDog:
|
||||
datadog:
|
||||
globalTag: sample
|
||||
```
|
||||
|
||||
@@ -91,13 +91,13 @@ this option must be enabled in order to get all the parts of a distributed trace
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[tracing]
|
||||
[tracing.dataDog]
|
||||
[tracing.datadog]
|
||||
prioritySampling = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
tracing:
|
||||
dataDog:
|
||||
datadog:
|
||||
prioritySampling: true
|
||||
```
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ Traefik supports five tracing backends:
|
||||
|
||||
- [Jaeger](./jaeger.md)
|
||||
- [Zipkin](./zipkin.md)
|
||||
- [DataDog](./datadog.md)
|
||||
- [Datadog](./datadog.md)
|
||||
- [Instana](./instana.md)
|
||||
- [Haystack](./haystack.md)
|
||||
|
||||
|
||||
@@ -18,46 +18,24 @@ tracing:
|
||||
|
||||
#### `httpEndpoint`
|
||||
|
||||
_Required, Default="http://localhost:9411/api/v1/spans"_
|
||||
_Required, Default="http://localhost:9411/api/v2/spans"_
|
||||
|
||||
Zipkin HTTP endpoint used to send data.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[tracing]
|
||||
[tracing.zipkin]
|
||||
httpEndpoint = "http://localhost:9411/api/v1/spans"
|
||||
httpEndpoint = "http://localhost:9411/api/v2/spans"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
tracing:
|
||||
zipkin:
|
||||
httpEndpoint: http://localhost:9411/api/v1/spans
|
||||
httpEndpoint: http://localhost:9411/api/v2/spans
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--tracing.zipkin.httpEndpoint="http://localhost:9411/api/v1/spans"
|
||||
```
|
||||
|
||||
#### `debug`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
Enable Zipkin debug.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[tracing]
|
||||
[tracing.zipkin]
|
||||
debug = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
tracing:
|
||||
zipkin:
|
||||
debug: true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--tracing.zipkin.debug=true
|
||||
--tracing.zipkin.httpEndpoint="http://localhost:9411/api/v2/spans"
|
||||
```
|
||||
|
||||
#### `sameSpan`
|
||||
@@ -86,7 +64,7 @@ tracing:
|
||||
|
||||
_Optional, Default=true_
|
||||
|
||||
Use Zipkin 128 bit root span IDs.
|
||||
Use Zipkin 128 bit trace IDs.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[tracing]
|
||||
@@ -124,4 +102,4 @@ tracing:
|
||||
|
||||
```bash tab="CLI"
|
||||
--tracing.zipkin.sampleRate="0.2"
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# API
|
||||
|
||||
!!! important
|
||||
In the beta version, you can't configure middlewares (basic authentication or white listing) anymore, but as security is important, this will change before the RC version.
|
||||
In the RC version, you can't configure middlewares (basic authentication or white listing) anymore, but as security is important, this will change before the GA version.
|
||||
|
||||
Traefik exposes a number of information through an API handler, such as the configuration of all routers, services, middlewares, etc.
|
||||
|
||||
|
||||
@@ -477,7 +477,7 @@ You can declare TCP Routers and/or Services using labels.
|
||||
# ...
|
||||
labels:
|
||||
- traefik.tcp.routers.my-router.rule="HostSNI(`my-host.com`)"
|
||||
- traefik.tcp.routers.my-router.rule.tls="true"
|
||||
- traefik.tcp.routers.my-router.tls="true"
|
||||
- traefik.tcp.services.my-service.loadbalancer.server.port="4123"
|
||||
```
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ You can write these configuration elements:
|
||||
entryPoints = ["web"]
|
||||
middlewares = ["my-basic-auth"]
|
||||
service = "service-foo"
|
||||
rule = "Path(`foo`)"
|
||||
rule = "Path(`/foo`)"
|
||||
|
||||
# Add the middleware
|
||||
[http.middlewares]
|
||||
@@ -75,7 +75,7 @@ You can write these configuration elements:
|
||||
middlewares:
|
||||
- my-basic-auth
|
||||
service: service-foo
|
||||
rule: Path(`foo`)
|
||||
rule: Path(`/foo`)
|
||||
|
||||
# Add the middleware
|
||||
middlewares:
|
||||
|
||||
@@ -45,13 +45,13 @@
|
||||
- "traefik.http.middlewares.middleware09.headers.customrequestheaders.name1=foobar"
|
||||
- "traefik.http.middlewares.middleware09.headers.customresponseheaders.name0=foobar"
|
||||
- "traefik.http.middlewares.middleware09.headers.customresponseheaders.name1=foobar"
|
||||
- "traefik.http.middlewares.middleware09.headers.featurepolicy=foobar"
|
||||
- "traefik.http.middlewares.middleware09.headers.forcestsheader=true"
|
||||
- "traefik.http.middlewares.middleware09.headers.framedeny=true"
|
||||
- "traefik.http.middlewares.middleware09.headers.hostsproxyheaders=foobar, foobar"
|
||||
- "traefik.http.middlewares.middleware09.headers.isdevelopment=true"
|
||||
- "traefik.http.middlewares.middleware09.headers.publickey=foobar"
|
||||
- "traefik.http.middlewares.middleware09.headers.referrerpolicy=foobar"
|
||||
- "traefik.http.middlewares.middleware09.headers.featurepolicy=foobar"
|
||||
- "traefik.http.middlewares.middleware09.headers.sslforcehost=true"
|
||||
- "traefik.http.middlewares.middleware09.headers.sslhost=foobar"
|
||||
- "traefik.http.middlewares.middleware09.headers.sslproxyheaders.name0=foobar"
|
||||
@@ -65,10 +65,9 @@
|
||||
- "traefik.http.middlewares.middleware10.ipwhitelist.ipstrategy.excludedips=foobar, foobar"
|
||||
- "traefik.http.middlewares.middleware10.ipwhitelist.sourcerange=foobar, foobar"
|
||||
- "traefik.http.middlewares.middleware11.inflightreq.amount=42"
|
||||
- "traefik.http.middlewares.middleware11.inflightreq.sourcecriterion.requestheadername=foobar"
|
||||
- "traefik.http.middlewares.middleware11.inflightreq.sourcecriterion.requesthost=true"
|
||||
- "traefik.http.middlewares.middleware11.inflightreq.sourcecriterion.ipstrategy.depth=42"
|
||||
- "traefik.http.middlewares.middleware11.inflightreq.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
|
||||
- "traefik.http.middlewares.middleware11.inflightreq.sourcecriterion.requestheadername=foobar"
|
||||
- "traefik.http.middlewares.middleware11.inflightreq.sourcecriterion.requesthost=true"
|
||||
- "traefik.http.middlewares.middleware12.passtlsclientcert.info.issuer.commonname=true"
|
||||
- "traefik.http.middlewares.middleware12.passtlsclientcert.info.issuer.country=true"
|
||||
@@ -88,18 +87,24 @@
|
||||
- "traefik.http.middlewares.middleware12.passtlsclientcert.info.subject.province=true"
|
||||
- "traefik.http.middlewares.middleware12.passtlsclientcert.info.subject.serialnumber=true"
|
||||
- "traefik.http.middlewares.middleware12.passtlsclientcert.pem=true"
|
||||
- "traefik.http.middlewares.middleware13.redirectregex.permanent=true"
|
||||
- "traefik.http.middlewares.middleware13.redirectregex.regex=foobar"
|
||||
- "traefik.http.middlewares.middleware13.redirectregex.replacement=foobar"
|
||||
- "traefik.http.middlewares.middleware14.redirectscheme.permanent=true"
|
||||
- "traefik.http.middlewares.middleware14.redirectscheme.port=foobar"
|
||||
- "traefik.http.middlewares.middleware14.redirectscheme.scheme=foobar"
|
||||
- "traefik.http.middlewares.middleware15.replacepath.path=foobar"
|
||||
- "traefik.http.middlewares.middleware16.replacepathregex.regex=foobar"
|
||||
- "traefik.http.middlewares.middleware16.replacepathregex.replacement=foobar"
|
||||
- "traefik.http.middlewares.middleware17.retry.attempts=42"
|
||||
- "traefik.http.middlewares.middleware18.stripprefix.prefixes=foobar, foobar"
|
||||
- "traefik.http.middlewares.middleware19.stripprefixregex.regex=foobar, foobar"
|
||||
- "traefik.http.middlewares.middleware13.ratelimit.average=42"
|
||||
- "traefik.http.middlewares.middleware13.ratelimit.burst=42"
|
||||
- "traefik.http.middlewares.middleware13.ratelimit.sourcecriterion.ipstrategy.depth=42"
|
||||
- "traefik.http.middlewares.middleware13.ratelimit.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
|
||||
- "traefik.http.middlewares.middleware13.ratelimit.sourcecriterion.requestheadername=foobar"
|
||||
- "traefik.http.middlewares.middleware13.ratelimit.sourcecriterion.requesthost=true"
|
||||
- "traefik.http.middlewares.middleware14.redirectregex.permanent=true"
|
||||
- "traefik.http.middlewares.middleware14.redirectregex.regex=foobar"
|
||||
- "traefik.http.middlewares.middleware14.redirectregex.replacement=foobar"
|
||||
- "traefik.http.middlewares.middleware15.redirectscheme.permanent=true"
|
||||
- "traefik.http.middlewares.middleware15.redirectscheme.port=foobar"
|
||||
- "traefik.http.middlewares.middleware15.redirectscheme.scheme=foobar"
|
||||
- "traefik.http.middlewares.middleware16.replacepath.path=foobar"
|
||||
- "traefik.http.middlewares.middleware17.replacepathregex.regex=foobar"
|
||||
- "traefik.http.middlewares.middleware17.replacepathregex.replacement=foobar"
|
||||
- "traefik.http.middlewares.middleware18.retry.attempts=42"
|
||||
- "traefik.http.middlewares.middleware19.stripprefix.prefixes=foobar, foobar"
|
||||
- "traefik.http.middlewares.middleware20.stripprefixregex.regex=foobar, foobar"
|
||||
- "traefik.http.routers.router0.entrypoints=foobar, foobar"
|
||||
- "traefik.http.routers.router0.middlewares=foobar, foobar"
|
||||
- "traefik.http.routers.router0.priority=42"
|
||||
@@ -135,8 +140,8 @@
|
||||
- "traefik.http.services.service0.loadbalancer.passhostheader=true"
|
||||
- "traefik.http.services.service0.loadbalancer.responseforwarding.flushinterval=foobar"
|
||||
- "traefik.http.services.service0.loadbalancer.sticky=true"
|
||||
- "traefik.http.services.service0.loadbalancer.sticky.cookie.name=foobar"
|
||||
- "traefik.http.services.service0.loadbalancer.sticky.cookie.httponly=true"
|
||||
- "traefik.http.services.service0.loadbalancer.sticky.cookie.name=foobar"
|
||||
- "traefik.http.services.service0.loadbalancer.sticky.cookie.secure=true"
|
||||
- "traefik.http.services.service0.loadbalancer.server.port=foobar"
|
||||
- "traefik.http.services.service0.loadbalancer.server.scheme=foobar"
|
||||
@@ -151,8 +156,8 @@
|
||||
- "traefik.http.services.service1.loadbalancer.passhostheader=true"
|
||||
- "traefik.http.services.service1.loadbalancer.responseforwarding.flushinterval=foobar"
|
||||
- "traefik.http.services.service1.loadbalancer.sticky=true"
|
||||
- "traefik.http.services.service1.loadbalancer.sticky.cookie.name=foobar"
|
||||
- "traefik.http.services.service1.loadbalancer.sticky.cookie.httponly=true"
|
||||
- "traefik.http.services.service1.loadbalancer.sticky.cookie.name=foobar"
|
||||
- "traefik.http.services.service1.loadbalancer.sticky.cookie.secure=true"
|
||||
- "traefik.http.services.service1.loadbalancer.server.port=foobar"
|
||||
- "traefik.http.services.service1.loadbalancer.server.scheme=foobar"
|
||||
|
||||
@@ -62,17 +62,28 @@
|
||||
[http.services.Service01.loadBalancer.responseForwarding]
|
||||
flushInterval = "foobar"
|
||||
[http.services.Service02]
|
||||
[http.services.Service02.weighted]
|
||||
[http.services.Service02.mirroring]
|
||||
service = "foobar"
|
||||
|
||||
[[http.services.Service02.weighted.services]]
|
||||
[[http.services.Service02.mirroring.mirrors]]
|
||||
name = "foobar"
|
||||
percent = 42
|
||||
|
||||
[[http.services.Service02.mirroring.mirrors]]
|
||||
name = "foobar"
|
||||
percent = 42
|
||||
[http.services.Service03]
|
||||
[http.services.Service03.weighted]
|
||||
|
||||
[[http.services.Service03.weighted.services]]
|
||||
name = "foobar"
|
||||
weight = 42
|
||||
|
||||
[[http.services.Service02.weighted.services]]
|
||||
[[http.services.Service03.weighted.services]]
|
||||
name = "foobar"
|
||||
weight = 42
|
||||
[http.services.Service02.weighted.sticky]
|
||||
[http.services.Service02.weighted.sticky.cookie]
|
||||
[http.services.Service03.weighted.sticky]
|
||||
[http.services.Service03.weighted.sticky.cookie]
|
||||
name = "foobar"
|
||||
secure = true
|
||||
httpOnly = true
|
||||
@@ -202,30 +213,40 @@
|
||||
serialNumber = true
|
||||
domainComponent = true
|
||||
[http.middlewares.Middleware13]
|
||||
[http.middlewares.Middleware13.redirectRegex]
|
||||
[http.middlewares.Middleware13.rateLimit]
|
||||
average = 42
|
||||
burst = 42
|
||||
[http.middlewares.Middleware13.rateLimit.sourceCriterion]
|
||||
requestHeaderName = "foobar"
|
||||
requestHost = true
|
||||
[http.middlewares.Middleware13.rateLimit.sourceCriterion.ipStrategy]
|
||||
depth = 42
|
||||
excludedIPs = ["foobar", "foobar"]
|
||||
[http.middlewares.Middleware14]
|
||||
[http.middlewares.Middleware14.redirectRegex]
|
||||
regex = "foobar"
|
||||
replacement = "foobar"
|
||||
permanent = true
|
||||
[http.middlewares.Middleware14]
|
||||
[http.middlewares.Middleware14.redirectScheme]
|
||||
[http.middlewares.Middleware15]
|
||||
[http.middlewares.Middleware15.redirectScheme]
|
||||
scheme = "foobar"
|
||||
port = "foobar"
|
||||
permanent = true
|
||||
[http.middlewares.Middleware15]
|
||||
[http.middlewares.Middleware15.replacePath]
|
||||
path = "foobar"
|
||||
[http.middlewares.Middleware16]
|
||||
[http.middlewares.Middleware16.replacePathRegex]
|
||||
[http.middlewares.Middleware16.replacePath]
|
||||
path = "foobar"
|
||||
[http.middlewares.Middleware17]
|
||||
[http.middlewares.Middleware17.replacePathRegex]
|
||||
regex = "foobar"
|
||||
replacement = "foobar"
|
||||
[http.middlewares.Middleware17]
|
||||
[http.middlewares.Middleware17.retry]
|
||||
attempts = 42
|
||||
[http.middlewares.Middleware18]
|
||||
[http.middlewares.Middleware18.stripPrefix]
|
||||
prefixes = ["foobar", "foobar"]
|
||||
[http.middlewares.Middleware18.retry]
|
||||
attempts = 42
|
||||
[http.middlewares.Middleware19]
|
||||
[http.middlewares.Middleware19.stripPrefixRegex]
|
||||
[http.middlewares.Middleware19.stripPrefix]
|
||||
prefixes = ["foobar", "foobar"]
|
||||
[http.middlewares.Middleware20]
|
||||
[http.middlewares.Middleware20.stripPrefixRegex]
|
||||
regex = ["foobar", "foobar"]
|
||||
|
||||
[tcp]
|
||||
|
||||
@@ -69,6 +69,14 @@ http:
|
||||
responseForwarding:
|
||||
flushInterval: foobar
|
||||
Service02:
|
||||
mirroring:
|
||||
service: foobar
|
||||
mirrors:
|
||||
- name: foobar
|
||||
percent: 42
|
||||
- name: foobar
|
||||
percent: 42
|
||||
Service03:
|
||||
weighted:
|
||||
services:
|
||||
- name: foobar
|
||||
@@ -201,9 +209,11 @@ http:
|
||||
inFlightReq:
|
||||
amount: 42
|
||||
sourceCriterion:
|
||||
ipStrategy:
|
||||
ipstrategy:
|
||||
depth: 42
|
||||
excludedIPs: [ foobar, foobar ]
|
||||
excludedIPs:
|
||||
- foobar
|
||||
- foobar
|
||||
requestHeaderName: foobar
|
||||
requestHost: true
|
||||
Middleware12:
|
||||
@@ -230,45 +240,47 @@ http:
|
||||
serialNumber: true
|
||||
domainComponent: true
|
||||
Middleware13:
|
||||
redirectRegex:
|
||||
regex: foobar
|
||||
replacement: foobar
|
||||
permanent: true
|
||||
Middleware14:
|
||||
redirectScheme:
|
||||
scheme: foobar
|
||||
port: foobar
|
||||
permanent: true
|
||||
Middleware15:
|
||||
replacePath:
|
||||
path: foobar
|
||||
Middleware16:
|
||||
replacePathRegex:
|
||||
regex: foobar
|
||||
replacement: foobar
|
||||
Middleware17:
|
||||
retry:
|
||||
attempts: 42
|
||||
Middleware18:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- foobar
|
||||
- foobar
|
||||
Middleware19:
|
||||
stripPrefixRegex:
|
||||
regex:
|
||||
- foobar
|
||||
- foobar
|
||||
Middleware20:
|
||||
rateLimit:
|
||||
average: 42
|
||||
burst: 42
|
||||
sourceCriterion:
|
||||
ipStrategy:
|
||||
ipstrategy:
|
||||
depth: 42
|
||||
excludedIPs: [ foobar, foobar ]
|
||||
excludedIPs:
|
||||
- foobar
|
||||
- foobar
|
||||
requestHeaderName: foobar
|
||||
requestHost: true
|
||||
Middleware14:
|
||||
redirectRegex:
|
||||
regex: foobar
|
||||
replacement: foobar
|
||||
permanent: true
|
||||
Middleware15:
|
||||
redirectScheme:
|
||||
scheme: foobar
|
||||
port: foobar
|
||||
permanent: true
|
||||
Middleware16:
|
||||
replacePath:
|
||||
path: foobar
|
||||
Middleware17:
|
||||
replacePathRegex:
|
||||
regex: foobar
|
||||
replacement: foobar
|
||||
Middleware18:
|
||||
retry:
|
||||
attempts: 42
|
||||
Middleware19:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- foobar
|
||||
- foobar
|
||||
Middleware20:
|
||||
stripPrefixRegex:
|
||||
regex:
|
||||
- foobar
|
||||
- foobar
|
||||
tcp:
|
||||
routers:
|
||||
TCPRouter0:
|
||||
|
||||
@@ -45,13 +45,13 @@
|
||||
"traefik.http.middlewares.middleware09.headers.customrequestheaders.name1": "foobar",
|
||||
"traefik.http.middlewares.middleware09.headers.customresponseheaders.name0": "foobar",
|
||||
"traefik.http.middlewares.middleware09.headers.customresponseheaders.name1": "foobar",
|
||||
"traefik.http.middlewares.middleware09.headers.featurepolicy": "foobar",
|
||||
"traefik.http.middlewares.middleware09.headers.forcestsheader": "true",
|
||||
"traefik.http.middlewares.middleware09.headers.framedeny": "true",
|
||||
"traefik.http.middlewares.middleware09.headers.hostsproxyheaders": "foobar, foobar",
|
||||
"traefik.http.middlewares.middleware09.headers.isdevelopment": "true",
|
||||
"traefik.http.middlewares.middleware09.headers.publickey": "foobar",
|
||||
"traefik.http.middlewares.middleware09.headers.referrerpolicy": "foobar",
|
||||
"traefik.http.middlewares.middleware09.headers.featurepolicy": "foobar",
|
||||
"traefik.http.middlewares.middleware09.headers.sslforcehost": "true",
|
||||
"traefik.http.middlewares.middleware09.headers.sslhost": "foobar",
|
||||
"traefik.http.middlewares.middleware09.headers.sslproxyheaders.name0": "foobar",
|
||||
@@ -64,11 +64,11 @@
|
||||
"traefik.http.middlewares.middleware10.ipwhitelist.ipstrategy.depth": "42",
|
||||
"traefik.http.middlewares.middleware10.ipwhitelist.ipstrategy.excludedips": "foobar, foobar",
|
||||
"traefik.http.middlewares.middleware10.ipwhitelist.sourcerange": "foobar, foobar",
|
||||
"traefik.http.middlewares.Middleware11.inflightreq.amount": "42",
|
||||
"traefik.http.middlewares.Middleware11.inflightreq.sourcecriterion.ipstrategy.depth": "42",
|
||||
"traefik.http.middlewares.Middleware11.inflightreq.sourcecriterion.ipstrategy.excludedips": "foobar, fiibar",
|
||||
"traefik.http.middlewares.Middleware11.inflightreq.sourcecriterion.requestheadername": "foobar",
|
||||
"traefik.http.middlewares.Middleware11.inflightreq.sourcecriterion.requesthost": "true",
|
||||
"traefik.http.middlewares.middleware11.inflightreq.amount": "42",
|
||||
"traefik.http.middlewares.middleware11.inflightreq.sourcecriterion.ipstrategy.depth": "42",
|
||||
"traefik.http.middlewares.middleware11.inflightreq.sourcecriterion.ipstrategy.excludedips": "foobar, foobar",
|
||||
"traefik.http.middlewares.middleware11.inflightreq.sourcecriterion.requestheadername": "foobar",
|
||||
"traefik.http.middlewares.middleware11.inflightreq.sourcecriterion.requesthost": "true",
|
||||
"traefik.http.middlewares.middleware12.passtlsclientcert.info.issuer.commonname": "true",
|
||||
"traefik.http.middlewares.middleware12.passtlsclientcert.info.issuer.country": "true",
|
||||
"traefik.http.middlewares.middleware12.passtlsclientcert.info.issuer.domaincomponent": "true",
|
||||
@@ -87,24 +87,24 @@
|
||||
"traefik.http.middlewares.middleware12.passtlsclientcert.info.subject.province": "true",
|
||||
"traefik.http.middlewares.middleware12.passtlsclientcert.info.subject.serialnumber": "true",
|
||||
"traefik.http.middlewares.middleware12.passtlsclientcert.pem": "true",
|
||||
"traefik.http.middlewares.middleware13.redirectregex.permanent": "true",
|
||||
"traefik.http.middlewares.middleware13.redirectregex.regex": "foobar",
|
||||
"traefik.http.middlewares.middleware13.redirectregex.replacement": "foobar",
|
||||
"traefik.http.middlewares.middleware14.redirectscheme.permanent": "true",
|
||||
"traefik.http.middlewares.middleware14.redirectscheme.port": "foobar",
|
||||
"traefik.http.middlewares.middleware14.redirectscheme.scheme": "foobar",
|
||||
"traefik.http.middlewares.middleware15.replacepath.path": "foobar",
|
||||
"traefik.http.middlewares.middleware16.replacepathregex.regex": "foobar",
|
||||
"traefik.http.middlewares.middleware16.replacepathregex.replacement": "foobar",
|
||||
"traefik.http.middlewares.middleware17.retry.attempts": "42",
|
||||
"traefik.http.middlewares.middleware18.stripprefix.prefixes": "foobar, foobar",
|
||||
"traefik.http.middlewares.middleware19.stripprefixregex.regex": "foobar, foobar",
|
||||
"traefik.http.middlewares.Middleware20.ratelimit.average": "42",
|
||||
"traefik.http.middlewares.Middleware20.ratelimit.burst": "42",
|
||||
"traefik.http.middlewares.Middleware20.ratelimit.sourcecriterion.requestheadername": "foobar",
|
||||
"traefik.http.middlewares.Middleware20.ratelimit.sourcecriterion.requesthost": "true",
|
||||
"traefik.http.middlewares.Middleware20.ratelimit.sourcecriterion.ipstrategy.depth": "42",
|
||||
"traefik.http.middlewares.Middleware20.ratelimit.sourcecriterion.ipstrategy.excludedips": "foobar, foobar",
|
||||
"traefik.http.middlewares.middleware13.ratelimit.average": "42",
|
||||
"traefik.http.middlewares.middleware13.ratelimit.burst": "42",
|
||||
"traefik.http.middlewares.middleware13.ratelimit.sourcecriterion.ipstrategy.depth": "42",
|
||||
"traefik.http.middlewares.middleware13.ratelimit.sourcecriterion.ipstrategy.excludedips": "foobar, foobar",
|
||||
"traefik.http.middlewares.middleware13.ratelimit.sourcecriterion.requestheadername": "foobar",
|
||||
"traefik.http.middlewares.middleware13.ratelimit.sourcecriterion.requesthost": "true",
|
||||
"traefik.http.middlewares.middleware14.redirectregex.permanent": "true",
|
||||
"traefik.http.middlewares.middleware14.redirectregex.regex": "foobar",
|
||||
"traefik.http.middlewares.middleware14.redirectregex.replacement": "foobar",
|
||||
"traefik.http.middlewares.middleware15.redirectscheme.permanent": "true",
|
||||
"traefik.http.middlewares.middleware15.redirectscheme.port": "foobar",
|
||||
"traefik.http.middlewares.middleware15.redirectscheme.scheme": "foobar",
|
||||
"traefik.http.middlewares.middleware16.replacepath.path": "foobar",
|
||||
"traefik.http.middlewares.middleware17.replacepathregex.regex": "foobar",
|
||||
"traefik.http.middlewares.middleware17.replacepathregex.replacement": "foobar",
|
||||
"traefik.http.middlewares.middleware18.retry.attempts": "42",
|
||||
"traefik.http.middlewares.middleware19.stripprefix.prefixes": "foobar, foobar",
|
||||
"traefik.http.middlewares.middleware20.stripprefixregex.regex": "foobar, foobar",
|
||||
"traefik.http.routers.router0.entrypoints": "foobar, foobar",
|
||||
"traefik.http.routers.router0.middlewares": "foobar, foobar",
|
||||
"traefik.http.routers.router0.priority": "42",
|
||||
@@ -140,8 +140,8 @@
|
||||
"traefik.http.services.service0.loadbalancer.passhostheader": "true",
|
||||
"traefik.http.services.service0.loadbalancer.responseforwarding.flushinterval": "foobar",
|
||||
"traefik.http.services.service0.loadbalancer.sticky": "true",
|
||||
"traefik.http.services.service0.loadbalancer.sticky.cookie.name": "foobar",
|
||||
"traefik.http.services.service0.loadbalancer.sticky.cookie.httponly": "true",
|
||||
"traefik.http.services.service0.loadbalancer.sticky.cookie.name": "foobar",
|
||||
"traefik.http.services.service0.loadbalancer.sticky.cookie.secure": "true",
|
||||
"traefik.http.services.service0.loadbalancer.server.port": "foobar",
|
||||
"traefik.http.services.service0.loadbalancer.server.scheme": "foobar",
|
||||
@@ -156,9 +156,9 @@
|
||||
"traefik.http.services.service1.loadbalancer.passhostheader": "true",
|
||||
"traefik.http.services.service1.loadbalancer.responseforwarding.flushinterval": "foobar",
|
||||
"traefik.http.services.service1.loadbalancer.sticky": "true",
|
||||
"traefik.http.services.service1.loadbalancer.sticky.cookie.httponly": "true",
|
||||
"traefik.http.services.service1.loadbalancer.sticky.cookie.name": "foobar",
|
||||
"traefik.http.services.service1.loadbalancer.sticky.cookie.secure": "true",
|
||||
"traefik.http.services.service1.loadbalancer.sticky.cookie.httponly": "true",
|
||||
"traefik.http.services.service1.loadbalancer.server.port": "foobar",
|
||||
"traefik.http.services.service1.loadbalancer.server.scheme": "foobar",
|
||||
"traefik.tcp.routers.tcprouter0.entrypoints": "foobar, foobar",
|
||||
|
||||
@@ -151,19 +151,19 @@ Traefik log format: json | common (Default: ```common```)
|
||||
Log level set to traefik logs. (Default: ```ERROR```)
|
||||
|
||||
`--metrics.datadog`:
|
||||
DataDog metrics exporter type. (Default: ```false```)
|
||||
Datadog metrics exporter type. (Default: ```false```)
|
||||
|
||||
`--metrics.datadog.addentrypointslabels`:
|
||||
Enable metrics on entry points. (Default: ```true```)
|
||||
|
||||
`--metrics.datadog.address`:
|
||||
DataDog's address. (Default: ```localhost:8125```)
|
||||
Datadog's address. (Default: ```localhost:8125```)
|
||||
|
||||
`--metrics.datadog.addserviceslabels`:
|
||||
Enable metrics on services. (Default: ```true```)
|
||||
|
||||
`--metrics.datadog.pushinterval`:
|
||||
DataDog push interval. (Default: ```10```)
|
||||
Datadog push interval. (Default: ```10```)
|
||||
|
||||
`--metrics.influxdb`:
|
||||
InfluxDB metrics exporter type. (Default: ```false```)
|
||||
@@ -457,13 +457,13 @@ Add cert file for self-signed certificate.
|
||||
OpenTracing configuration. (Default: ```false```)
|
||||
|
||||
`--tracing.datadog`:
|
||||
Settings for DataDog. (Default: ```false```)
|
||||
Settings for Datadog. (Default: ```false```)
|
||||
|
||||
`--tracing.datadog.bagageprefixheadername`:
|
||||
Specifies the header name prefix that will be used to store baggage items in a map.
|
||||
|
||||
`--tracing.datadog.debug`:
|
||||
Enable DataDog debug. (Default: ```false```)
|
||||
Enable Datadog debug. (Default: ```false```)
|
||||
|
||||
`--tracing.datadog.globaltag`:
|
||||
Key:Value tag to be set on all the spans.
|
||||
@@ -561,11 +561,8 @@ Set the maximum character limit for Span names (default 0 = no limit). (Default:
|
||||
`--tracing.zipkin`:
|
||||
Settings for Zipkin. (Default: ```false```)
|
||||
|
||||
`--tracing.zipkin.debug`:
|
||||
Enable Zipkin debug. (Default: ```false```)
|
||||
|
||||
`--tracing.zipkin.httpendpoint`:
|
||||
HTTP Endpoint to report traces to. (Default: ```http://localhost:9411/api/v1/spans```)
|
||||
HTTP Endpoint to report traces to. (Default: ```http://localhost:9411/api/v2/spans```)
|
||||
|
||||
`--tracing.zipkin.id128bit`:
|
||||
Use Zipkin 128 bit root span IDs. (Default: ```true```)
|
||||
|
||||
@@ -151,19 +151,19 @@ Traefik log format: json | common (Default: ```common```)
|
||||
Log level set to traefik logs. (Default: ```ERROR```)
|
||||
|
||||
`TRAEFIK_METRICS_DATADOG`:
|
||||
DataDog metrics exporter type. (Default: ```false```)
|
||||
Datadog metrics exporter type. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_METRICS_DATADOG_ADDENTRYPOINTSLABELS`:
|
||||
Enable metrics on entry points. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_METRICS_DATADOG_ADDRESS`:
|
||||
DataDog's address. (Default: ```localhost:8125```)
|
||||
Datadog's address. (Default: ```localhost:8125```)
|
||||
|
||||
`TRAEFIK_METRICS_DATADOG_ADDSERVICESLABELS`:
|
||||
Enable metrics on services. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_METRICS_DATADOG_PUSHINTERVAL`:
|
||||
DataDog push interval. (Default: ```10```)
|
||||
Datadog push interval. (Default: ```10```)
|
||||
|
||||
`TRAEFIK_METRICS_INFLUXDB`:
|
||||
InfluxDB metrics exporter type. (Default: ```false```)
|
||||
@@ -457,13 +457,13 @@ Add cert file for self-signed certificate.
|
||||
OpenTracing configuration. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_TRACING_DATADOG`:
|
||||
Settings for DataDog. (Default: ```false```)
|
||||
Settings for Datadog. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_TRACING_DATADOG_BAGAGEPREFIXHEADERNAME`:
|
||||
Specifies the header name prefix that will be used to store baggage items in a map.
|
||||
|
||||
`TRAEFIK_TRACING_DATADOG_DEBUG`:
|
||||
Enable DataDog debug. (Default: ```false```)
|
||||
Enable Datadog debug. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_TRACING_DATADOG_GLOBALTAG`:
|
||||
Key:Value tag to be set on all the spans.
|
||||
@@ -561,11 +561,8 @@ Set the maximum character limit for Span names (default 0 = no limit). (Default:
|
||||
`TRAEFIK_TRACING_ZIPKIN`:
|
||||
Settings for Zipkin. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_TRACING_ZIPKIN_DEBUG`:
|
||||
Enable Zipkin debug. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_TRACING_ZIPKIN_HTTPENDPOINT`:
|
||||
HTTP Endpoint to report traces to. (Default: ```http://localhost:9411/api/v1/spans```)
|
||||
HTTP Endpoint to report traces to. (Default: ```http://localhost:9411/api/v2/spans```)
|
||||
|
||||
`TRAEFIK_TRACING_ZIPKIN_ID128BIT`:
|
||||
Use Zipkin 128 bit root span IDs. (Default: ```true```)
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
buckets = [42.0, 42.0]
|
||||
addEntryPointsLabels = true
|
||||
addServicesLabels = true
|
||||
[metrics.dataDog]
|
||||
[metrics.datadog]
|
||||
address = "foobar"
|
||||
pushInterval = "10s"
|
||||
addEntryPointsLabels = true
|
||||
@@ -181,9 +181,8 @@
|
||||
httpEndpoint = "foobar"
|
||||
sameSpan = true
|
||||
id128Bit = true
|
||||
debug = true
|
||||
sampleRate = 42.0
|
||||
[tracing.dataDog]
|
||||
[tracing.datadog]
|
||||
localAgentHostPort = "foobar"
|
||||
globalTag = "foobar"
|
||||
debug = true
|
||||
|
||||
@@ -122,7 +122,7 @@ metrics:
|
||||
- 42
|
||||
addEntryPointsLabels: true
|
||||
addServicesLabels: true
|
||||
dataDog:
|
||||
datadog:
|
||||
address: foobar
|
||||
pushInterval: 42
|
||||
addEntryPointsLabels: true
|
||||
@@ -186,9 +186,8 @@ tracing:
|
||||
httpEndpoint: foobar
|
||||
sameSpan: true
|
||||
id128Bit: true
|
||||
debug: true
|
||||
sampleRate: 42
|
||||
dataDog:
|
||||
datadog:
|
||||
localAgentHostPort: foobar
|
||||
globalTag: foobar
|
||||
debug: true
|
||||
|
||||
@@ -216,7 +216,7 @@ The table below lists all the available matchers:
|
||||
| ```Host(`domain-1`, ...)``` | Check if the request domain targets one of the given `domains`. |
|
||||
| ```HostRegexp(`traefik.io`, `{subdomain:[a-z]+}.traefik.io`, ...)``` | Check if the request domain matches the given `regexp`. |
|
||||
| ```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. |
|
||||
| ```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. |
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ The remaining section is going to explore them along with a benefit/cost trade-o
|
||||
|
||||
It may seem obvious to reuse the Marathon health checks as a signal to Traefik whether an application should be taken into load-balancing rotation or not.
|
||||
|
||||
Apart from the increased latency a failing health check may have, a major problem with this is is that Marathon does not persist the health check results.
|
||||
Apart from the increased latency a failing health check may have, a major problem with this is that Marathon does not persist the health check results.
|
||||
Consequently, if a master re-election occurs in the Marathon clusters, all health check results will revert to the _unknown_ state, effectively causing all applications inside the cluster to become unavailable and leading to a complete cluster failure.
|
||||
Re-elections do not only happen during regular maintenance work (often requiring rolling upgrades of the Marathon nodes) but also when the Marathon leader fails spontaneously.
|
||||
As such, there is no way to handle this situation deterministically.
|
||||
|
||||
@@ -122,7 +122,7 @@ nav:
|
||||
- 'Access Logs': 'observability/access-logs.md'
|
||||
- 'Metrics':
|
||||
- 'Overview': 'observability/metrics/overview.md'
|
||||
- 'DataDog': 'observability/metrics/datadog.md'
|
||||
- 'Datadog': 'observability/metrics/datadog.md'
|
||||
- 'InfluxDB': 'observability/metrics/influxdb.md'
|
||||
- 'Prometheus': 'observability/metrics/prometheus.md'
|
||||
- 'StatsD': 'observability/metrics/statsd.md'
|
||||
@@ -130,7 +130,7 @@ nav:
|
||||
- 'Overview': 'observability/tracing/overview.md'
|
||||
- 'Jaeger': 'observability/tracing/jaeger.md'
|
||||
- 'Zipkin': 'observability/tracing/zipkin.md'
|
||||
- 'DataDog': 'observability/tracing/datadog.md'
|
||||
- 'Datadog': 'observability/tracing/datadog.md'
|
||||
- 'Instana': 'observability/tracing/instana.md'
|
||||
- 'Haystack': 'observability/tracing/haystack.md'
|
||||
- 'User Guides':
|
||||
@@ -143,6 +143,8 @@ nav:
|
||||
- 'TLS Challenge': 'user-guides/docker-compose/acme-tls/index.md'
|
||||
- 'HTTP Challenge': 'user-guides/docker-compose/acme-http/index.md'
|
||||
- 'DNS Challenge': 'user-guides/docker-compose/acme-dns/index.md'
|
||||
- 'Migration':
|
||||
- 'Traefik v1 to v2': 'migration/v1-to-v2.md'
|
||||
- 'Contributing':
|
||||
- 'Thank You!': 'contributing/thank-you.md'
|
||||
- 'Submitting Issues': 'contributing/submitting-issues.md'
|
||||
|
||||
@@ -12,7 +12,7 @@ RUN yarn install
|
||||
RUN npm run build
|
||||
|
||||
# BUILD
|
||||
FROM golang:1.13rc1-alpine as gobuild
|
||||
FROM golang:1.13rc2-alpine as gobuild
|
||||
|
||||
RUN apk --update upgrade \
|
||||
&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar ca-certificates tzdata \
|
||||
|
||||
8
go.mod
8
go.mod
@@ -43,9 +43,9 @@ require (
|
||||
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
|
||||
github.com/google/go-github/v27 v27.0.4
|
||||
github.com/google/go-github/v28 v28.0.0
|
||||
github.com/googleapis/gnostic v0.1.0 // indirect
|
||||
github.com/gorilla/mux v1.6.2
|
||||
github.com/gorilla/mux v1.7.3
|
||||
github.com/gorilla/websocket v1.4.0
|
||||
github.com/hashicorp/go-version v1.2.0
|
||||
github.com/huandu/xstrings v1.2.0 // indirect
|
||||
@@ -65,10 +65,10 @@ require (
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/opencontainers/runc v1.0.0-rc8 // indirect
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect
|
||||
github.com/opentracing/basictracer-go v1.0.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.1.0
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.3.5
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.3
|
||||
github.com/openzipkin/zipkin-go v0.2.1
|
||||
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
|
||||
|
||||
16
go.sum
16
go.sum
@@ -161,6 +161,7 @@ github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZi
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
@@ -193,6 +194,7 @@ github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
|
||||
@@ -218,8 +220,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-github/v27 v27.0.4 h1:N/EEqsvJLgqTbepTiMBz+12KhwLovv6YvwpRezd+4Fg=
|
||||
github.com/google/go-github/v27 v27.0.4/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0=
|
||||
github.com/google/go-github/v28 v28.0.0 h1:+UjHI4+1W/vsXR4jJBWt0ZA74XHbvt5yBAvsf1M3bgM=
|
||||
github.com/google/go-github/v28 v28.0.0/go.mod h1:+5GboIspo7F0NG2qsvfYh7en6F3EK37uyqv+c35AR3s=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
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=
|
||||
@@ -317,6 +319,7 @@ github.com/linode/linodego v0.10.0 h1:AMdb82HVgY8o3mjBXJcUv9B+fnJjfDMn2rNRGbX+jv
|
||||
github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
|
||||
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=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 h1:Kg/NPZLLC3aAFr1YToMs98dbCdhootQ1hZIvZU28hAQ=
|
||||
@@ -383,9 +386,11 @@ github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7l
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.3.5 h1:82Tnq9OJpn+h5xgGpss5/mOv3KXdjtkdorFSOUusjM8=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.3.5/go.mod h1:uVHyebswE1cCXr2A73cRM2frx5ld1RJUCJkFNZ90ZiI=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.3 h1:XudIMByQMXJ6oDHy4SipNyo35LxjA69Z7v1nL0aAZvA=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.3/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/openzipkin/zipkin-go v0.2.1 h1:noL5/5Uf1HpVl3wNsfkZhIKbSWCVi5jgqkONNx8PXcA=
|
||||
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/oracle/oci-go-sdk v7.0.0+incompatible h1:oj5ESjXwwkFRdhZSnPlShvLWYdt/IZ65RQxveYM3maA=
|
||||
github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 h1:37VE5TYj2m/FLA9SNr4z0+A0JefvTmR60Zwf8XSEV7c=
|
||||
@@ -396,6 +401,7 @@ github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR
|
||||
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -441,6 +447,7 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -604,6 +611,7 @@ google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3
|
||||
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM=
|
||||
|
||||
@@ -309,8 +309,6 @@ func (s *AccessLogSuite) TestAccessLogFrontendRedirect(c *check.C) {
|
||||
}
|
||||
|
||||
func (s *AccessLogSuite) TestAccessLogRateLimit(c *check.C) {
|
||||
c.Skip("RateLimit is disable for now")
|
||||
|
||||
ensureWorkingDirectoryIsClean()
|
||||
|
||||
expected := []accessLogValue{
|
||||
|
||||
@@ -150,9 +150,9 @@
|
||||
[http.middlewares.foo-slash-add-prefix.addPrefix]
|
||||
prefix = "/foo/"
|
||||
[http.middlewares.id-strip-regex-prefix.stripPrefixRegex]
|
||||
regex = ["/{id:[a-z]+}"]
|
||||
regex = ["/[a-z]+"]
|
||||
[http.middlewares.id-slash-strip-regex-prefix.stripPrefixRegex]
|
||||
regex = ["/{id:[a-z]+}/"]
|
||||
regex = ["/[a-z]+/"]
|
||||
[http.middlewares.api-regex-replace.replacePathRegex]
|
||||
regex = "/api"
|
||||
replacement = "/"
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: mychain
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
chain:
|
||||
middlewares:
|
||||
- name: stripprefix
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: stripprefix
|
||||
namespace: default
|
||||
@@ -26,4 +38,4 @@ spec:
|
||||
- name: whoami
|
||||
port: 80
|
||||
middlewares:
|
||||
- name: stripprefix
|
||||
- name: mychain
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
## dynamic configuration ##
|
||||
|
||||
[http.routers]
|
||||
[http.routers.router3]
|
||||
entrypoints=["unknown-entrypoint"]
|
||||
service = "service1"
|
||||
rule = "Host(`mydomain.com`)"
|
||||
|
||||
[http.routers.router4]
|
||||
service = "service1"
|
||||
rule = "Host(`snitest.net`)"
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
[http.routers]
|
||||
[http.routers.router1]
|
||||
Service = "service1"
|
||||
Middlewares = ["retry", "ratelimit"]
|
||||
Middlewares = ["retry", "ratelimit-1"]
|
||||
Rule = "Path(`/ratelimit`)"
|
||||
[http.routers.router2]
|
||||
Service = "service2"
|
||||
@@ -44,16 +44,9 @@
|
||||
attempts = 3
|
||||
[http.middlewares.basic-auth.basicAuth]
|
||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
||||
[http.middlewares.ratelimit.rateLimit]
|
||||
extractorfunc = "client.ip"
|
||||
[http.middlewares.ratelimit.rateLimit.rateSet.rateset1]
|
||||
period = "60s"
|
||||
average = 4
|
||||
burst = 5
|
||||
[http.middlewares.ratelimit.rateLimit.rateSet.rateset2]
|
||||
period = "3s"
|
||||
average = 1
|
||||
burst = 2
|
||||
[http.middlewares.ratelimit-1.rateLimit]
|
||||
average = 1
|
||||
burst = 2
|
||||
|
||||
|
||||
[http.services]
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
[http.routers]
|
||||
[http.routers.router1]
|
||||
Service = "service1"
|
||||
Middlewares = ["retry", "ratelimit"]
|
||||
Middlewares = ["retry", "ratelimit-1"]
|
||||
Rule = "Path(`/ratelimit`)"
|
||||
[http.routers.router2]
|
||||
Service = "service2"
|
||||
@@ -43,17 +43,9 @@
|
||||
attempts = 3
|
||||
[http.middlewares.basic-auth.basicAuth]
|
||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
||||
[http.middlewares.ratelimit.rateLimit]
|
||||
extractorfunc = "client.ip"
|
||||
[http.middlewares.ratelimit.rateLimit.rateSet.rateset1]
|
||||
period = "60s"
|
||||
average = 4
|
||||
burst = 5
|
||||
[http.middlewares.ratelimit.rateLimit.rateSet.rateset2]
|
||||
period = "3s"
|
||||
average = 1
|
||||
burst = 2
|
||||
|
||||
[http.middlewares.ratelimit-1.rateLimit]
|
||||
average = 1
|
||||
burst = 2
|
||||
|
||||
[http.services]
|
||||
[http.services.service1]
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
[tracing]
|
||||
servicename = "tracing"
|
||||
[tracing.zipkin]
|
||||
httpEndpoint = "http://{{.IP}}:9411/api/v1/spans"
|
||||
debug = true
|
||||
httpEndpoint = "http://{{.IP}}:9411/api/v2/spans"
|
||||
|
||||
[providers.file]
|
||||
filename = "{{ .SelfFilename }}"
|
||||
@@ -25,7 +24,7 @@
|
||||
[http.routers]
|
||||
[http.routers.router1]
|
||||
service = "service1"
|
||||
middlewares = ["retry", "ratelimit"]
|
||||
middlewares = ["retry", "ratelimit-1"]
|
||||
rule = "Path(`/ratelimit`)"
|
||||
[http.routers.router2]
|
||||
service = "service2"
|
||||
@@ -41,16 +40,9 @@
|
||||
attempts = 3
|
||||
[http.middlewares.basic-auth.basicAuth]
|
||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
||||
[http.middlewares.ratelimit.rateLimit]
|
||||
extractorfunc = "client.ip"
|
||||
[http.middlewares.ratelimit.rateLimit.rateSet.rateset1]
|
||||
period = "60s"
|
||||
average = 4
|
||||
burst = 5
|
||||
[http.middlewares.ratelimit.rateLimit.rateSet.rateset2]
|
||||
period = "3s"
|
||||
average = 1
|
||||
burst = 2
|
||||
[http.middlewares.ratelimit-1.rateLimit]
|
||||
average = 1
|
||||
burst = 2
|
||||
|
||||
[http.services]
|
||||
[http.services.service1]
|
||||
|
||||
@@ -55,19 +55,17 @@ frontendRedirect:
|
||||
- traefik.http.middlewares.redirecthttp.redirectScheme.scheme=http
|
||||
- traefik.http.middlewares.redirecthttp.redirectScheme.port=8000
|
||||
- traefik.http.services.service3.loadbalancer.server.port=80
|
||||
# TODO: disable temporarily (rateLimit)
|
||||
#rateLimit:
|
||||
# image: containous/whoami
|
||||
# labels:
|
||||
# - traefik.enable=true
|
||||
# - traefik.http.routers.rt-rateLimit.entryPoints=httpRateLimit
|
||||
# - traefik.http.routers.rt-rateLimit.rule=Host("ratelimit.docker.local")
|
||||
# - traefik.http.routers.rt-rateLimit.middlewares=rate
|
||||
# - traefik.http.middlewares.rate.ratelimit.extractorfunc=client.ip
|
||||
# - traefik.http.middlewares.rate.ratelimit.rateset.Rate0.average=1
|
||||
# - traefik.http.middlewares.rate.ratelimit.rateset.Rate0.burst=2
|
||||
# - traefik.http.middlewares.rate.ratelimit.rateset.Rate0.period=10s
|
||||
# - traefik.http.services.service3.loadbalancer.server.port=80
|
||||
rateLimit:
|
||||
image: containous/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt-rateLimit.entryPoints=httpRateLimit
|
||||
- traefik.http.routers.rt-rateLimit.rule=Host("ratelimit.docker.local")
|
||||
- traefik.http.routers.rt-rateLimit.middlewares=rate
|
||||
- traefik.http.middlewares.rate.ratelimit
|
||||
- traefik.http.middlewares.rate.ratelimit.average=1
|
||||
- traefik.http.middlewares.rate.ratelimit.burst=2
|
||||
- traefik.http.services.service3.loadbalancer.server.port=80
|
||||
frontendWhitelist:
|
||||
image: containous/whoami
|
||||
labels:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
zipkin:
|
||||
image: openzipkin/zipkin:2.12.6
|
||||
image: openzipkin/zipkin:2.16.2
|
||||
environment:
|
||||
STORAGE_TYPE: mem
|
||||
JAVA_OPTS: -Dlogging.level.zipkin=DEBUG
|
||||
|
||||
@@ -546,6 +546,10 @@ func (s *SimpleSuite) TestRouterConfigErrors(c *check.C) {
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers", 1000*time.Millisecond, try.BodyContains(`["middleware \"unknown@file\" does not exist","found different TLS options for routers on the same host snitest.net, so using the default TLS options instead"]`))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// router3 has an error because it uses an unknown entrypoint
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router3@file", 1000*time.Millisecond, try.BodyContains(`entryPoint \"unknown-entrypoint\" doesn't exist`, "no valid entryPoint for this router"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// router4 is enabled, but in warning state because its tls options conf was messed up
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router4@file", 1000*time.Millisecond, try.BodyContains(`"status":"warning"`))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
45
integration/testdata/rawdata-crd.json
vendored
45
integration/testdata/rawdata-crd.json
vendored
@@ -10,31 +10,45 @@
|
||||
"tls": {
|
||||
"options": "default/mytlsoption"
|
||||
},
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
},
|
||||
"default/test2.route-23c7f4c450289ee29016@kubernetescrd": {
|
||||
"entryPoints": [
|
||||
"web"
|
||||
],
|
||||
"middlewares": [
|
||||
"default/stripprefix"
|
||||
"default/mychain"
|
||||
],
|
||||
"service": "default/test2.route-23c7f4c450289ee29016",
|
||||
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/tobestripped`)",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
},
|
||||
"middlewares": {
|
||||
"default/stripprefix@kubernetescrd": {
|
||||
"stripPrefix": {
|
||||
"prefixes": [
|
||||
"/tobestripped"
|
||||
"default/mychain@kubernetescrd": {
|
||||
"chain": {
|
||||
"middlewares": [
|
||||
"default/stripprefix"
|
||||
]
|
||||
},
|
||||
"status": "enabled",
|
||||
"usedBy": [
|
||||
"default/test2.route-23c7f4c450289ee29016@kubernetescrd"
|
||||
]
|
||||
},
|
||||
"default/stripprefix@kubernetescrd": {
|
||||
"stripPrefix": {
|
||||
"prefixes": [
|
||||
"/tobestripped"
|
||||
]
|
||||
},
|
||||
"status": "enabled"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
@@ -42,7 +56,7 @@
|
||||
"loadBalancer": {
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://10.42.0.4:80"
|
||||
"url": "http://10.42.0.3:80"
|
||||
},
|
||||
{
|
||||
"url": "http://10.42.0.5:80"
|
||||
@@ -55,7 +69,7 @@
|
||||
"default/test.route-6b204d94623b3df4370c@kubernetescrd"
|
||||
],
|
||||
"serverStatus": {
|
||||
"http://10.42.0.4:80": "UP",
|
||||
"http://10.42.0.3:80": "UP",
|
||||
"http://10.42.0.5:80": "UP"
|
||||
}
|
||||
},
|
||||
@@ -63,7 +77,7 @@
|
||||
"loadBalancer": {
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://10.42.0.4:80"
|
||||
"url": "http://10.42.0.3:80"
|
||||
},
|
||||
{
|
||||
"url": "http://10.42.0.5:80"
|
||||
@@ -76,7 +90,7 @@
|
||||
"default/test2.route-23c7f4c450289ee29016@kubernetescrd"
|
||||
],
|
||||
"serverStatus": {
|
||||
"http://10.42.0.4:80": "UP",
|
||||
"http://10.42.0.3:80": "UP",
|
||||
"http://10.42.0.5:80": "UP"
|
||||
}
|
||||
}
|
||||
@@ -92,7 +106,10 @@
|
||||
"passthrough": false,
|
||||
"options": "default/mytlsoption"
|
||||
},
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"footcp"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tcpServices": {
|
||||
@@ -100,10 +117,10 @@
|
||||
"loadBalancer": {
|
||||
"servers": [
|
||||
{
|
||||
"address": "10.42.0.3:8080"
|
||||
"address": "10.42.0.6:8080"
|
||||
},
|
||||
{
|
||||
"address": "10.42.0.6:8080"
|
||||
"address": "10.42.0.7:8080"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
26
integration/testdata/rawdata-ingress.json
vendored
26
integration/testdata/rawdata-ingress.json
vendored
@@ -4,17 +4,29 @@
|
||||
"service": "default/whoami/http",
|
||||
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||
"tls": {},
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"traefik",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
"whoami-test-https/whoami@kubernetes": {
|
||||
"service": "default/whoami/http",
|
||||
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"traefik",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
"whoami-test/whoami@kubernetes": {
|
||||
"service": "default/whoami/http",
|
||||
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"traefik",
|
||||
"web"
|
||||
]
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
@@ -22,10 +34,10 @@
|
||||
"loadBalancer": {
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://10.42.0.4:80"
|
||||
"url": "http://10.42.0.2:80"
|
||||
},
|
||||
{
|
||||
"url": "http://10.42.0.5:80"
|
||||
"url": "http://10.42.0.4:80"
|
||||
}
|
||||
],
|
||||
"passHostHeader": true
|
||||
@@ -37,8 +49,8 @@
|
||||
"whoami-test/whoami@kubernetes"
|
||||
],
|
||||
"serverStatus": {
|
||||
"http://10.42.0.4:80": "UP",
|
||||
"http://10.42.0.5:80": "UP"
|
||||
"http://10.42.0.2:80": "UP",
|
||||
"http://10.42.0.4:80": "UP"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,6 @@ func (s *TracingSuite) startZipkin(c *check.C) {
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestZipkinRateLimit(c *check.C) {
|
||||
c.Skip("RateLimit is disable for now")
|
||||
|
||||
s.startZipkin(c)
|
||||
defer s.composeProject.Stop(c, "zipkin")
|
||||
file := s.adaptFile(c, "fixtures/tracing/simple-zipkin.toml", TracingTemplate{
|
||||
@@ -88,7 +86,7 @@ func (s *TracingSuite) TestZipkinRateLimit(c *check.C) {
|
||||
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://"+s.IP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit@file"))
|
||||
err = try.GetRequest("http://"+s.IP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
}
|
||||
@@ -157,8 +155,6 @@ func (s *TracingSuite) startJaeger(c *check.C) {
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestJaegerRateLimit(c *check.C) {
|
||||
c.Skip("RateLimit is disable for now")
|
||||
|
||||
s.startJaeger(c)
|
||||
defer s.composeProject.Stop(c, "jaeger")
|
||||
file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{
|
||||
@@ -200,13 +196,11 @@ func (s *TracingSuite) TestJaegerRateLimit(c *check.C) {
|
||||
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://"+s.IP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit@file"))
|
||||
err = try.GetRequest("http://"+s.IP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestJaegerRetry(c *check.C) {
|
||||
|
||||
@@ -186,7 +186,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||
Prometheus: &types.Prometheus{
|
||||
Buckets: []float64{0.1, 0.3, 1.2, 5},
|
||||
},
|
||||
DataDog: &types.DataDog{
|
||||
Datadog: &types.Datadog{
|
||||
Address: "localhost:8181",
|
||||
PushInterval: 12,
|
||||
},
|
||||
@@ -223,10 +223,9 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||
HTTPEndpoint: "fff",
|
||||
SameSpan: true,
|
||||
ID128Bit: true,
|
||||
Debug: true,
|
||||
SampleRate: 53,
|
||||
},
|
||||
DataDog: &datadog.Config{
|
||||
Datadog: &datadog.Config{
|
||||
LocalAgentHostPort: "ggg",
|
||||
GlobalTag: "eee",
|
||||
Debug: true,
|
||||
|
||||
102
pkg/api/criterion.go
Normal file
102
pkg/api/criterion.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultPerPage = 100
|
||||
defaultPage = 1
|
||||
)
|
||||
|
||||
const nextPageHeader = "X-Next-Page"
|
||||
|
||||
type pageInfo struct {
|
||||
startIndex int
|
||||
endIndex int
|
||||
nextPage int
|
||||
}
|
||||
|
||||
type searchCriterion struct {
|
||||
Search string `url:"search"`
|
||||
Status string `url:"status"`
|
||||
}
|
||||
|
||||
func newSearchCriterion(query url.Values) *searchCriterion {
|
||||
if len(query) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
search := query.Get("search")
|
||||
status := query.Get("status")
|
||||
|
||||
if status == "" && search == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &searchCriterion{Search: search, Status: status}
|
||||
}
|
||||
|
||||
func (c *searchCriterion) withStatus(name string) bool {
|
||||
return c.Status == "" || strings.EqualFold(name, c.Status)
|
||||
}
|
||||
|
||||
func (c *searchCriterion) searchIn(values ...string) bool {
|
||||
if c.Search == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, v := range values {
|
||||
if strings.Contains(strings.ToLower(v), strings.ToLower(c.Search)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func pagination(request *http.Request, max int) (pageInfo, error) {
|
||||
perPage, err := getIntParam(request, "per_page", defaultPerPage)
|
||||
if err != nil {
|
||||
return pageInfo{}, err
|
||||
}
|
||||
|
||||
page, err := getIntParam(request, "page", defaultPage)
|
||||
if err != nil {
|
||||
return pageInfo{}, err
|
||||
}
|
||||
|
||||
startIndex := (page - 1) * perPage
|
||||
if startIndex != 0 && startIndex >= max {
|
||||
return pageInfo{}, fmt.Errorf("invalid request: page: %d, per_page: %d", page, perPage)
|
||||
}
|
||||
|
||||
endIndex := startIndex + perPage
|
||||
if endIndex >= max {
|
||||
endIndex = max
|
||||
}
|
||||
|
||||
nextPage := 1
|
||||
if page*perPage < max {
|
||||
nextPage = page + 1
|
||||
}
|
||||
|
||||
return pageInfo{startIndex: startIndex, endIndex: endIndex, nextPage: nextPage}, nil
|
||||
}
|
||||
|
||||
func getIntParam(request *http.Request, key string, defaultValue int) (int, error) {
|
||||
raw := request.URL.Query().Get(key)
|
||||
if raw == "" {
|
||||
return defaultValue, nil
|
||||
}
|
||||
|
||||
value, err := strconv.Atoi(raw)
|
||||
if err != nil || value <= 0 {
|
||||
return 0, fmt.Errorf("invalid request: %s: %d", key, value)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
@@ -2,9 +2,8 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/config/runtime"
|
||||
@@ -15,12 +14,19 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultPerPage = 100
|
||||
defaultPage = 1
|
||||
)
|
||||
type apiError struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
const nextPageHeader = "X-Next-Page"
|
||||
func writeError(rw http.ResponseWriter, msg string, code int) {
|
||||
data, err := json.Marshal(apiError{Message: msg})
|
||||
if err != nil {
|
||||
http.Error(rw, msg, code)
|
||||
return
|
||||
}
|
||||
|
||||
http.Error(rw, string(data), code)
|
||||
}
|
||||
|
||||
type serviceInfoRepresentation struct {
|
||||
*runtime.ServiceInfo
|
||||
@@ -36,12 +42,6 @@ type RunTimeRepresentation struct {
|
||||
TCPServices map[string]*runtime.TCPServiceInfo `json:"tcpServices,omitempty"`
|
||||
}
|
||||
|
||||
type pageInfo struct {
|
||||
startIndex int
|
||||
endIndex int
|
||||
nextPage int
|
||||
}
|
||||
|
||||
// Handler serves the configuration and status of Traefik on API endpoints.
|
||||
type Handler struct {
|
||||
dashboard bool
|
||||
@@ -136,48 +136,19 @@ func (h Handler) getRuntimeConfiguration(rw http.ResponseWriter, request *http.R
|
||||
}
|
||||
}
|
||||
|
||||
func pagination(request *http.Request, max int) (pageInfo, error) {
|
||||
perPage, err := getIntParam(request, "per_page", defaultPerPage)
|
||||
if err != nil {
|
||||
return pageInfo{}, err
|
||||
}
|
||||
|
||||
page, err := getIntParam(request, "page", defaultPage)
|
||||
if err != nil {
|
||||
return pageInfo{}, err
|
||||
}
|
||||
|
||||
startIndex := (page - 1) * perPage
|
||||
if startIndex != 0 && startIndex >= max {
|
||||
return pageInfo{}, fmt.Errorf("invalid request: page: %d, per_page: %d", page, perPage)
|
||||
}
|
||||
|
||||
endIndex := startIndex + perPage
|
||||
if endIndex >= max {
|
||||
endIndex = max
|
||||
}
|
||||
|
||||
nextPage := 1
|
||||
if page*perPage < max {
|
||||
nextPage = page + 1
|
||||
}
|
||||
|
||||
return pageInfo{startIndex: startIndex, endIndex: endIndex, nextPage: nextPage}, nil
|
||||
}
|
||||
|
||||
func getIntParam(request *http.Request, key string, defaultValue int) (int, error) {
|
||||
raw := request.URL.Query().Get(key)
|
||||
if raw == "" {
|
||||
return defaultValue, nil
|
||||
}
|
||||
|
||||
value, err := strconv.Atoi(raw)
|
||||
if err != nil || value <= 0 {
|
||||
return 0, fmt.Errorf("invalid request: %s: %d", key, value)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func getProviderName(id string) string {
|
||||
return strings.SplitN(id, "@", 2)[1]
|
||||
}
|
||||
|
||||
func extractType(element interface{}) string {
|
||||
v := reflect.ValueOf(element).Elem()
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
field := v.Field(i)
|
||||
if field.Kind() == reflect.Ptr && field.Elem().Kind() == reflect.Struct {
|
||||
if !field.IsNil() {
|
||||
return v.Type().Field(i).Name
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -30,28 +31,31 @@ func (h Handler) getEntryPoints(rw http.ResponseWriter, request *http.Request) {
|
||||
return results[i].Name < results[j].Name
|
||||
})
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
pageInfo, err := pagination(request, len(results))
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||
|
||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getEntryPoint(rw http.ResponseWriter, request *http.Request) {
|
||||
entryPointID := mux.Vars(request)["entryPointID"]
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
ep, ok := h.staticConfig.EntryPoints[entryPointID]
|
||||
if !ok {
|
||||
http.NotFound(rw, request)
|
||||
writeError(rw, fmt.Sprintf("entry point not found: %s", entryPointID), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -60,11 +64,9 @@ func (h Handler) getEntryPoint(rw http.ResponseWriter, request *http.Request) {
|
||||
Name: entryPointID,
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
err := json.NewEncoder(rw).Encode(result)
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/config/runtime"
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
@@ -17,182 +19,224 @@ type routerRepresentation struct {
|
||||
Provider string `json:"provider,omitempty"`
|
||||
}
|
||||
|
||||
func newRouterRepresentation(name string, rt *runtime.RouterInfo) routerRepresentation {
|
||||
return routerRepresentation{
|
||||
RouterInfo: rt,
|
||||
Name: name,
|
||||
Provider: getProviderName(name),
|
||||
}
|
||||
}
|
||||
|
||||
type serviceRepresentation struct {
|
||||
*runtime.ServiceInfo
|
||||
ServerStatus map[string]string `json:"serverStatus,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
func newServiceRepresentation(name string, si *runtime.ServiceInfo) serviceRepresentation {
|
||||
return serviceRepresentation{
|
||||
ServiceInfo: si,
|
||||
Name: name,
|
||||
Provider: getProviderName(name),
|
||||
ServerStatus: si.GetAllStatus(),
|
||||
Type: strings.ToLower(extractType(si.Service)),
|
||||
}
|
||||
}
|
||||
|
||||
type middlewareRepresentation struct {
|
||||
*runtime.MiddlewareInfo
|
||||
Name string `json:"name,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
func newMiddlewareRepresentation(name string, mi *runtime.MiddlewareInfo) middlewareRepresentation {
|
||||
return middlewareRepresentation{
|
||||
MiddlewareInfo: mi,
|
||||
Name: name,
|
||||
Provider: getProviderName(name),
|
||||
Type: strings.ToLower(extractType(mi.Middleware)),
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getRouters(rw http.ResponseWriter, request *http.Request) {
|
||||
results := make([]routerRepresentation, 0, len(h.runtimeConfiguration.Routers))
|
||||
|
||||
criterion := newSearchCriterion(request.URL.Query())
|
||||
|
||||
for name, rt := range h.runtimeConfiguration.Routers {
|
||||
results = append(results, routerRepresentation{
|
||||
RouterInfo: rt,
|
||||
Name: name,
|
||||
Provider: getProviderName(name),
|
||||
})
|
||||
if keepRouter(name, rt, criterion) {
|
||||
results = append(results, newRouterRepresentation(name, rt))
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].Name < results[j].Name
|
||||
})
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
pageInfo, err := pagination(request, len(results))
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||
|
||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getRouter(rw http.ResponseWriter, request *http.Request) {
|
||||
routerID := mux.Vars(request)["routerID"]
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
router, ok := h.runtimeConfiguration.Routers[routerID]
|
||||
if !ok {
|
||||
http.NotFound(rw, request)
|
||||
writeError(rw, fmt.Sprintf("router not found: %s", routerID), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
result := routerRepresentation{
|
||||
RouterInfo: router,
|
||||
Name: routerID,
|
||||
Provider: getProviderName(routerID),
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
result := newRouterRepresentation(routerID, router)
|
||||
|
||||
err := json.NewEncoder(rw).Encode(result)
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getServices(rw http.ResponseWriter, request *http.Request) {
|
||||
results := make([]serviceRepresentation, 0, len(h.runtimeConfiguration.Services))
|
||||
|
||||
criterion := newSearchCriterion(request.URL.Query())
|
||||
|
||||
for name, si := range h.runtimeConfiguration.Services {
|
||||
results = append(results, serviceRepresentation{
|
||||
ServiceInfo: si,
|
||||
Name: name,
|
||||
Provider: getProviderName(name),
|
||||
ServerStatus: si.GetAllStatus(),
|
||||
})
|
||||
if keepService(name, si, criterion) {
|
||||
results = append(results, newServiceRepresentation(name, si))
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].Name < results[j].Name
|
||||
})
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
pageInfo, err := pagination(request, len(results))
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||
|
||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getService(rw http.ResponseWriter, request *http.Request) {
|
||||
serviceID := mux.Vars(request)["serviceID"]
|
||||
|
||||
rw.Header().Add("Content-Type", "application/json")
|
||||
|
||||
service, ok := h.runtimeConfiguration.Services[serviceID]
|
||||
if !ok {
|
||||
http.NotFound(rw, request)
|
||||
writeError(rw, fmt.Sprintf("service not found: %s", serviceID), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
result := serviceRepresentation{
|
||||
ServiceInfo: service,
|
||||
Name: serviceID,
|
||||
Provider: getProviderName(serviceID),
|
||||
ServerStatus: service.GetAllStatus(),
|
||||
}
|
||||
|
||||
rw.Header().Add("Content-Type", "application/json")
|
||||
result := newServiceRepresentation(serviceID, service)
|
||||
|
||||
err := json.NewEncoder(rw).Encode(result)
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getMiddlewares(rw http.ResponseWriter, request *http.Request) {
|
||||
results := make([]middlewareRepresentation, 0, len(h.runtimeConfiguration.Middlewares))
|
||||
|
||||
criterion := newSearchCriterion(request.URL.Query())
|
||||
|
||||
for name, mi := range h.runtimeConfiguration.Middlewares {
|
||||
results = append(results, middlewareRepresentation{
|
||||
MiddlewareInfo: mi,
|
||||
Name: name,
|
||||
Provider: getProviderName(name),
|
||||
})
|
||||
if keepMiddleware(name, mi, criterion) {
|
||||
results = append(results, newMiddlewareRepresentation(name, mi))
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].Name < results[j].Name
|
||||
})
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
pageInfo, err := pagination(request, len(results))
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||
|
||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getMiddleware(rw http.ResponseWriter, request *http.Request) {
|
||||
middlewareID := mux.Vars(request)["middlewareID"]
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
middleware, ok := h.runtimeConfiguration.Middlewares[middlewareID]
|
||||
if !ok {
|
||||
http.NotFound(rw, request)
|
||||
writeError(rw, fmt.Sprintf("middleware not found: %s", middlewareID), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
result := middlewareRepresentation{
|
||||
MiddlewareInfo: middleware,
|
||||
Name: middlewareID,
|
||||
Provider: getProviderName(middlewareID),
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
result := newMiddlewareRepresentation(middlewareID, middleware)
|
||||
|
||||
err := json.NewEncoder(rw).Encode(result)
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func keepRouter(name string, item *runtime.RouterInfo, criterion *searchCriterion) bool {
|
||||
if criterion == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return criterion.withStatus(item.Status) && criterion.searchIn(item.Rule, name)
|
||||
}
|
||||
|
||||
func keepService(name string, item *runtime.ServiceInfo, criterion *searchCriterion) bool {
|
||||
if criterion == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return criterion.withStatus(item.Status) && criterion.searchIn(name)
|
||||
}
|
||||
|
||||
func keepMiddleware(name string, item *runtime.MiddlewareInfo, criterion *searchCriterion) bool {
|
||||
if criterion == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return criterion.withStatus(item.Status) && criterion.searchIn(name)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -137,6 +138,68 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
statusCode: http.StatusBadRequest,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "routers filtered by status",
|
||||
path: "/api/http/routers?status=enabled",
|
||||
conf: runtime.Configuration{
|
||||
Routers: map[string]*runtime.RouterInfo{
|
||||
"test@myprovider": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service@myprovider",
|
||||
Rule: "Host(`foo.bar.other`)",
|
||||
Middlewares: []string{"addPrefixTest", "auth"},
|
||||
},
|
||||
Status: runtime.StatusEnabled,
|
||||
},
|
||||
"bar@myprovider": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service@myprovider",
|
||||
Rule: "Host(`foo.bar`)",
|
||||
Middlewares: []string{"auth", "addPrefixTest@anotherprovider"},
|
||||
},
|
||||
Status: runtime.StatusDisabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: expected{
|
||||
statusCode: http.StatusOK,
|
||||
nextPage: "1",
|
||||
jsonFile: "testdata/routers-filtered-status.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "routers filtered by search",
|
||||
path: "/api/http/routers?search=fii",
|
||||
conf: runtime.Configuration{
|
||||
Routers: map[string]*runtime.RouterInfo{
|
||||
"test@myprovider": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "fii-service@myprovider",
|
||||
Rule: "Host(`fii.bar.other`)",
|
||||
Middlewares: []string{"addPrefixTest", "auth"},
|
||||
},
|
||||
Status: runtime.StatusEnabled,
|
||||
},
|
||||
"bar@myprovider": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service@myprovider",
|
||||
Rule: "Host(`foo.bar`)",
|
||||
Middlewares: []string{"auth", "addPrefixTest@anotherprovider"},
|
||||
},
|
||||
Status: runtime.StatusDisabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: expected{
|
||||
statusCode: http.StatusOK,
|
||||
nextPage: "1",
|
||||
jsonFile: "testdata/routers-filtered-search.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "one router by id",
|
||||
path: "/api/http/routers/bar@myprovider",
|
||||
@@ -232,6 +295,45 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
si.UpdateServerStatus("http://127.0.0.2", "UP")
|
||||
return si
|
||||
}(),
|
||||
"canary@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: nil,
|
||||
Sticky: &dynamic.Sticky{
|
||||
Cookie: &dynamic.Cookie{
|
||||
Name: "chocolat",
|
||||
Secure: true,
|
||||
HTTPOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: runtime.StatusEnabled,
|
||||
UsedBy: []string{"foo@myprovider"},
|
||||
},
|
||||
"mirror@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
Mirroring: &dynamic.Mirroring{
|
||||
Service: "one@myprovider",
|
||||
Mirrors: []dynamic.MirrorService{
|
||||
{
|
||||
Name: "two@myprovider",
|
||||
Percent: 10,
|
||||
},
|
||||
{
|
||||
Name: "three@myprovider",
|
||||
Percent: 15,
|
||||
},
|
||||
{
|
||||
Name: "four@myprovider",
|
||||
Percent: 80,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: runtime.StatusEnabled,
|
||||
UsedBy: []string{"foo@myprovider"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: expected{
|
||||
@@ -301,6 +403,100 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
jsonFile: "testdata/services-page2.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "services filtered by status",
|
||||
path: "/api/http/services?status=enabled",
|
||||
conf: runtime.Configuration{
|
||||
Services: map[string]*runtime.ServiceInfo{
|
||||
"bar@myprovider": func() *runtime.ServiceInfo {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"foo@myprovider", "test@myprovider"},
|
||||
Status: runtime.StatusEnabled,
|
||||
}
|
||||
si.UpdateServerStatus("http://127.0.0.1", "UP")
|
||||
return si
|
||||
}(),
|
||||
"baz@myprovider": func() *runtime.ServiceInfo {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"foo@myprovider"},
|
||||
Status: runtime.StatusDisabled,
|
||||
}
|
||||
si.UpdateServerStatus("http://127.0.0.2", "UP")
|
||||
return si
|
||||
}(),
|
||||
},
|
||||
},
|
||||
expected: expected{
|
||||
statusCode: http.StatusOK,
|
||||
nextPage: "1",
|
||||
jsonFile: "testdata/services-filtered-status.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "services filtered by search",
|
||||
path: "/api/http/services?search=baz",
|
||||
conf: runtime.Configuration{
|
||||
Services: map[string]*runtime.ServiceInfo{
|
||||
"bar@myprovider": func() *runtime.ServiceInfo {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"foo@myprovider", "test@myprovider"},
|
||||
Status: runtime.StatusEnabled,
|
||||
}
|
||||
si.UpdateServerStatus("http://127.0.0.1", "UP")
|
||||
return si
|
||||
}(),
|
||||
"baz@myprovider": func() *runtime.ServiceInfo {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"foo@myprovider"},
|
||||
Status: runtime.StatusDisabled,
|
||||
}
|
||||
si.UpdateServerStatus("http://127.0.0.2", "UP")
|
||||
return si
|
||||
}(),
|
||||
},
|
||||
},
|
||||
expected: expected{
|
||||
statusCode: http.StatusOK,
|
||||
nextPage: "1",
|
||||
jsonFile: "testdata/services-filtered-search.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "one service by id",
|
||||
path: "/api/http/services/bar@myprovider",
|
||||
@@ -411,6 +607,86 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
jsonFile: "testdata/middlewares.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "middlewares filtered by status",
|
||||
path: "/api/http/middlewares?status=enabled",
|
||||
conf: runtime.Configuration{
|
||||
Middlewares: map[string]*runtime.MiddlewareInfo{
|
||||
"auth@myprovider": {
|
||||
Middleware: &dynamic.Middleware{
|
||||
BasicAuth: &dynamic.BasicAuth{
|
||||
Users: []string{"admin:admin"},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"bar@myprovider", "test@myprovider"},
|
||||
Status: runtime.StatusEnabled,
|
||||
},
|
||||
"addPrefixTest@myprovider": {
|
||||
Middleware: &dynamic.Middleware{
|
||||
AddPrefix: &dynamic.AddPrefix{
|
||||
Prefix: "/titi",
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"test@myprovider"},
|
||||
Status: runtime.StatusDisabled,
|
||||
},
|
||||
"addPrefixTest@anotherprovider": {
|
||||
Middleware: &dynamic.Middleware{
|
||||
AddPrefix: &dynamic.AddPrefix{
|
||||
Prefix: "/toto",
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"bar@myprovider"},
|
||||
Status: runtime.StatusEnabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: expected{
|
||||
statusCode: http.StatusOK,
|
||||
nextPage: "1",
|
||||
jsonFile: "testdata/middlewares-filtered-status.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "middlewares filtered by search",
|
||||
path: "/api/http/middlewares?search=addprefixtest",
|
||||
conf: runtime.Configuration{
|
||||
Middlewares: map[string]*runtime.MiddlewareInfo{
|
||||
"auth@myprovider": {
|
||||
Middleware: &dynamic.Middleware{
|
||||
BasicAuth: &dynamic.BasicAuth{
|
||||
Users: []string{"admin:admin"},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"bar@myprovider", "test@myprovider"},
|
||||
Status: runtime.StatusEnabled,
|
||||
},
|
||||
"addPrefixTest@myprovider": {
|
||||
Middleware: &dynamic.Middleware{
|
||||
AddPrefix: &dynamic.AddPrefix{
|
||||
Prefix: "/titi",
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"test@myprovider"},
|
||||
Status: runtime.StatusDisabled,
|
||||
},
|
||||
"addPrefixTest@anotherprovider": {
|
||||
Middleware: &dynamic.Middleware{
|
||||
AddPrefix: &dynamic.AddPrefix{
|
||||
Prefix: "/toto",
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"bar@myprovider"},
|
||||
Status: runtime.StatusEnabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: expected{
|
||||
statusCode: http.StatusOK,
|
||||
nextPage: "1",
|
||||
jsonFile: "testdata/middlewares-filtered-search.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "all middlewares, 1 res per page, want page 2",
|
||||
path: "/api/http/middlewares?page=2&per_page=1",
|
||||
@@ -521,6 +797,8 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
rtConf := &test.conf
|
||||
// To lazily initialize the Statuses.
|
||||
rtConf.PopulateUsedBy()
|
||||
rtConf.GetRoutersByEntryPoints(context.Background(), []string{"web"}, false)
|
||||
|
||||
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
|
||||
router := mux.NewRouter()
|
||||
handler.Append(router)
|
||||
|
||||
@@ -56,7 +56,7 @@ func (h Handler) getOverview(rw http.ResponseWriter, request *http.Request) {
|
||||
err := json.NewEncoder(rw).Encode(result)
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/config/runtime"
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
@@ -17,118 +19,146 @@ type tcpRouterRepresentation struct {
|
||||
Provider string `json:"provider,omitempty"`
|
||||
}
|
||||
|
||||
func newTCPRouterRepresentation(name string, rt *runtime.TCPRouterInfo) tcpRouterRepresentation {
|
||||
return tcpRouterRepresentation{
|
||||
TCPRouterInfo: rt,
|
||||
Name: name,
|
||||
Provider: getProviderName(name),
|
||||
}
|
||||
}
|
||||
|
||||
type tcpServiceRepresentation struct {
|
||||
*runtime.TCPServiceInfo
|
||||
Name string `json:"name,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
func newTCPServiceRepresentation(name string, si *runtime.TCPServiceInfo) tcpServiceRepresentation {
|
||||
return tcpServiceRepresentation{
|
||||
TCPServiceInfo: si,
|
||||
Name: name,
|
||||
Provider: getProviderName(name),
|
||||
Type: strings.ToLower(extractType(si.TCPService)),
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getTCPRouters(rw http.ResponseWriter, request *http.Request) {
|
||||
results := make([]tcpRouterRepresentation, 0, len(h.runtimeConfiguration.TCPRouters))
|
||||
|
||||
criterion := newSearchCriterion(request.URL.Query())
|
||||
|
||||
for name, rt := range h.runtimeConfiguration.TCPRouters {
|
||||
results = append(results, tcpRouterRepresentation{
|
||||
TCPRouterInfo: rt,
|
||||
Name: name,
|
||||
Provider: getProviderName(name),
|
||||
})
|
||||
if keepTCPRouter(name, rt, criterion) {
|
||||
results = append(results, newTCPRouterRepresentation(name, rt))
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].Name < results[j].Name
|
||||
})
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
pageInfo, err := pagination(request, len(results))
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||
|
||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getTCPRouter(rw http.ResponseWriter, request *http.Request) {
|
||||
routerID := mux.Vars(request)["routerID"]
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
router, ok := h.runtimeConfiguration.TCPRouters[routerID]
|
||||
if !ok {
|
||||
http.NotFound(rw, request)
|
||||
writeError(rw, fmt.Sprintf("router not found: %s", routerID), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
result := tcpRouterRepresentation{
|
||||
TCPRouterInfo: router,
|
||||
Name: routerID,
|
||||
Provider: getProviderName(routerID),
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
result := newTCPRouterRepresentation(routerID, router)
|
||||
|
||||
err := json.NewEncoder(rw).Encode(result)
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getTCPServices(rw http.ResponseWriter, request *http.Request) {
|
||||
results := make([]tcpServiceRepresentation, 0, len(h.runtimeConfiguration.TCPServices))
|
||||
|
||||
criterion := newSearchCriterion(request.URL.Query())
|
||||
|
||||
for name, si := range h.runtimeConfiguration.TCPServices {
|
||||
results = append(results, tcpServiceRepresentation{
|
||||
TCPServiceInfo: si,
|
||||
Name: name,
|
||||
Provider: getProviderName(name),
|
||||
})
|
||||
if keepTCPService(name, si, criterion) {
|
||||
results = append(results, newTCPServiceRepresentation(name, si))
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].Name < results[j].Name
|
||||
})
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
pageInfo, err := pagination(request, len(results))
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||
writeError(rw, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
|
||||
|
||||
err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getTCPService(rw http.ResponseWriter, request *http.Request) {
|
||||
serviceID := mux.Vars(request)["serviceID"]
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
service, ok := h.runtimeConfiguration.TCPServices[serviceID]
|
||||
if !ok {
|
||||
http.NotFound(rw, request)
|
||||
writeError(rw, fmt.Sprintf("service not found: %s", serviceID), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
result := tcpServiceRepresentation{
|
||||
TCPServiceInfo: service,
|
||||
Name: serviceID,
|
||||
Provider: getProviderName(serviceID),
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
result := newTCPServiceRepresentation(serviceID, service)
|
||||
|
||||
err := json.NewEncoder(rw).Encode(result)
|
||||
if err != nil {
|
||||
log.FromContext(request.Context()).Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func keepTCPRouter(name string, item *runtime.TCPRouterInfo, criterion *searchCriterion) bool {
|
||||
if criterion == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return criterion.withStatus(item.Status) && criterion.searchIn(item.Rule, name)
|
||||
}
|
||||
|
||||
func keepTCPService(name string, item *runtime.TCPServiceInfo, criterion *searchCriterion) bool {
|
||||
if criterion == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return criterion.withStatus(item.Status) && criterion.searchIn(name)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@@ -112,6 +113,86 @@ func TestHandler_TCP(t *testing.T) {
|
||||
jsonFile: "testdata/tcprouters-page2.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TCP routers filtered by status",
|
||||
path: "/api/tcp/routers?status=enabled",
|
||||
conf: runtime.Configuration{
|
||||
TCPRouters: map[string]*runtime.TCPRouterInfo{
|
||||
"test@myprovider": {
|
||||
TCPRouter: &dynamic.TCPRouter{
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service@myprovider",
|
||||
Rule: "Host(`foo.bar.other`)",
|
||||
TLS: &dynamic.RouterTCPTLSConfig{
|
||||
Passthrough: false,
|
||||
},
|
||||
},
|
||||
Status: runtime.StatusEnabled,
|
||||
},
|
||||
"bar@myprovider": {
|
||||
TCPRouter: &dynamic.TCPRouter{
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service@myprovider",
|
||||
Rule: "Host(`foo.bar`)",
|
||||
},
|
||||
Status: runtime.StatusWarning,
|
||||
},
|
||||
"foo@myprovider": {
|
||||
TCPRouter: &dynamic.TCPRouter{
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service@myprovider",
|
||||
Rule: "Host(`foo.bar`)",
|
||||
},
|
||||
Status: runtime.StatusDisabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: expected{
|
||||
statusCode: http.StatusOK,
|
||||
nextPage: "1",
|
||||
jsonFile: "testdata/tcprouters-filtered-status.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TCP routers filtered by search",
|
||||
path: "/api/tcp/routers?search=bar@my",
|
||||
conf: runtime.Configuration{
|
||||
TCPRouters: map[string]*runtime.TCPRouterInfo{
|
||||
"test@myprovider": {
|
||||
TCPRouter: &dynamic.TCPRouter{
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service@myprovider",
|
||||
Rule: "Host(`foo.bar.other`)",
|
||||
TLS: &dynamic.RouterTCPTLSConfig{
|
||||
Passthrough: false,
|
||||
},
|
||||
},
|
||||
Status: runtime.StatusEnabled,
|
||||
},
|
||||
"bar@myprovider": {
|
||||
TCPRouter: &dynamic.TCPRouter{
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service@myprovider",
|
||||
Rule: "Host(`foo.bar`)",
|
||||
},
|
||||
Status: runtime.StatusWarning,
|
||||
},
|
||||
"foo@myprovider": {
|
||||
TCPRouter: &dynamic.TCPRouter{
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service@myprovider",
|
||||
Rule: "Host(`foo.bar`)",
|
||||
},
|
||||
Status: runtime.StatusDisabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: expected{
|
||||
statusCode: http.StatusOK,
|
||||
nextPage: "1",
|
||||
jsonFile: "testdata/tcprouters-filtered-search.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "one TCP router by id",
|
||||
path: "/api/tcp/routers/bar@myprovider",
|
||||
@@ -219,6 +300,110 @@ func TestHandler_TCP(t *testing.T) {
|
||||
jsonFile: "testdata/tcpservices.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "tcp services filtered by status",
|
||||
path: "/api/tcp/services?status=enabled",
|
||||
conf: runtime.Configuration{
|
||||
TCPServices: map[string]*runtime.TCPServiceInfo{
|
||||
"bar@myprovider": {
|
||||
TCPService: &dynamic.TCPService{
|
||||
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||
Servers: []dynamic.TCPServer{
|
||||
{
|
||||
Address: "127.0.0.1:2345",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"foo@myprovider", "test@myprovider"},
|
||||
Status: runtime.StatusEnabled,
|
||||
},
|
||||
"baz@myprovider": {
|
||||
TCPService: &dynamic.TCPService{
|
||||
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||
Servers: []dynamic.TCPServer{
|
||||
{
|
||||
Address: "127.0.0.2:2345",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"foo@myprovider"},
|
||||
Status: runtime.StatusWarning,
|
||||
},
|
||||
"foz@myprovider": {
|
||||
TCPService: &dynamic.TCPService{
|
||||
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||
Servers: []dynamic.TCPServer{
|
||||
{
|
||||
Address: "127.0.0.2:2345",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"foo@myprovider"},
|
||||
Status: runtime.StatusDisabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: expected{
|
||||
statusCode: http.StatusOK,
|
||||
nextPage: "1",
|
||||
jsonFile: "testdata/tcpservices-filtered-status.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "tcp services filtered by search",
|
||||
path: "/api/tcp/services?search=baz@my",
|
||||
conf: runtime.Configuration{
|
||||
TCPServices: map[string]*runtime.TCPServiceInfo{
|
||||
"bar@myprovider": {
|
||||
TCPService: &dynamic.TCPService{
|
||||
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||
Servers: []dynamic.TCPServer{
|
||||
{
|
||||
Address: "127.0.0.1:2345",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"foo@myprovider", "test@myprovider"},
|
||||
Status: runtime.StatusEnabled,
|
||||
},
|
||||
"baz@myprovider": {
|
||||
TCPService: &dynamic.TCPService{
|
||||
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||
Servers: []dynamic.TCPServer{
|
||||
{
|
||||
Address: "127.0.0.2:2345",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"foo@myprovider"},
|
||||
Status: runtime.StatusWarning,
|
||||
},
|
||||
"foz@myprovider": {
|
||||
TCPService: &dynamic.TCPService{
|
||||
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||
Servers: []dynamic.TCPServer{
|
||||
{
|
||||
Address: "127.0.0.2:2345",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UsedBy: []string{"foo@myprovider"},
|
||||
Status: runtime.StatusDisabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: expected{
|
||||
statusCode: http.StatusOK,
|
||||
nextPage: "1",
|
||||
jsonFile: "testdata/tcpservices-filtered-search.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "all tcp services, 1 res per page, want page 2",
|
||||
path: "/api/tcp/services?page=2&per_page=1",
|
||||
@@ -330,6 +515,10 @@ func TestHandler_TCP(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rtConf := &test.conf
|
||||
// To lazily initialize the Statuses.
|
||||
rtConf.PopulateUsedBy()
|
||||
rtConf.GetTCPRoutersByEntryPoints(context.Background(), []string{"web"})
|
||||
|
||||
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
|
||||
router := mux.NewRouter()
|
||||
handler.Append(router)
|
||||
|
||||
1
pkg/api/testdata/middleware-auth.json
vendored
1
pkg/api/testdata/middleware-auth.json
vendored
@@ -7,6 +7,7 @@
|
||||
"name": "auth@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "enabled",
|
||||
"type": "basicauth",
|
||||
"usedBy": [
|
||||
"bar@myprovider",
|
||||
"test@myprovider"
|
||||
|
||||
26
pkg/api/testdata/middlewares-filtered-search.json
vendored
Normal file
26
pkg/api/testdata/middlewares-filtered-search.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
[
|
||||
{
|
||||
"addPrefix": {
|
||||
"prefix": "/toto"
|
||||
},
|
||||
"name": "addPrefixTest@anotherprovider",
|
||||
"provider": "anotherprovider",
|
||||
"status": "enabled",
|
||||
"type": "addprefix",
|
||||
"usedBy": [
|
||||
"bar@myprovider"
|
||||
]
|
||||
},
|
||||
{
|
||||
"addPrefix": {
|
||||
"prefix": "/titi"
|
||||
},
|
||||
"name": "addPrefixTest@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "disabled",
|
||||
"type": "addprefix",
|
||||
"usedBy": [
|
||||
"test@myprovider"
|
||||
]
|
||||
}
|
||||
]
|
||||
29
pkg/api/testdata/middlewares-filtered-status.json
vendored
Normal file
29
pkg/api/testdata/middlewares-filtered-status.json
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
[
|
||||
{
|
||||
"addPrefix": {
|
||||
"prefix": "/toto"
|
||||
},
|
||||
"name": "addPrefixTest@anotherprovider",
|
||||
"provider": "anotherprovider",
|
||||
"status": "enabled",
|
||||
"type": "addprefix",
|
||||
"usedBy": [
|
||||
"bar@myprovider"
|
||||
]
|
||||
},
|
||||
{
|
||||
"basicAuth": {
|
||||
"users": [
|
||||
"admin:admin"
|
||||
]
|
||||
},
|
||||
"name": "auth@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "enabled",
|
||||
"type": "basicauth",
|
||||
"usedBy": [
|
||||
"bar@myprovider",
|
||||
"test@myprovider"
|
||||
]
|
||||
}
|
||||
]
|
||||
1
pkg/api/testdata/middlewares-page2.json
vendored
1
pkg/api/testdata/middlewares-page2.json
vendored
@@ -6,6 +6,7 @@
|
||||
"name": "addPrefixTest@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "enabled",
|
||||
"type": "addprefix",
|
||||
"usedBy": [
|
||||
"test@myprovider"
|
||||
]
|
||||
|
||||
3
pkg/api/testdata/middlewares.json
vendored
3
pkg/api/testdata/middlewares.json
vendored
@@ -6,6 +6,7 @@
|
||||
"name": "addPrefixTest@anotherprovider",
|
||||
"provider": "anotherprovider",
|
||||
"status": "enabled",
|
||||
"type": "addprefix",
|
||||
"usedBy": [
|
||||
"bar@myprovider"
|
||||
]
|
||||
@@ -17,6 +18,7 @@
|
||||
"name": "addPrefixTest@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "enabled",
|
||||
"type": "addprefix",
|
||||
"usedBy": [
|
||||
"test@myprovider"
|
||||
]
|
||||
@@ -30,6 +32,7 @@
|
||||
"name": "auth@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "enabled",
|
||||
"type": "basicauth",
|
||||
"usedBy": [
|
||||
"bar@myprovider",
|
||||
"test@myprovider"
|
||||
|
||||
5
pkg/api/testdata/router-bar.json
vendored
5
pkg/api/testdata/router-bar.json
vendored
@@ -10,5 +10,8 @@
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
19
pkg/api/testdata/routers-filtered-search.json
vendored
Normal file
19
pkg/api/testdata/routers-filtered-search.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
[
|
||||
{
|
||||
"entryPoints": [
|
||||
"web"
|
||||
],
|
||||
"middlewares": [
|
||||
"addPrefixTest",
|
||||
"auth"
|
||||
],
|
||||
"name": "test@myprovider",
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`fii.bar.other`)",
|
||||
"service": "fii-service@myprovider",
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
]
|
||||
19
pkg/api/testdata/routers-filtered-status.json
vendored
Normal file
19
pkg/api/testdata/routers-filtered-status.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
[
|
||||
{
|
||||
"entryPoints": [
|
||||
"web"
|
||||
],
|
||||
"middlewares": [
|
||||
"addPrefixTest",
|
||||
"auth"
|
||||
],
|
||||
"name": "test@myprovider",
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar.other`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
]
|
||||
25
pkg/api/testdata/routers-many-lastpage.json
vendored
25
pkg/api/testdata/routers-many-lastpage.json
vendored
@@ -7,7 +7,10 @@
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar14`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entryPoints": [
|
||||
@@ -17,7 +20,10 @@
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar15`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entryPoints": [
|
||||
@@ -27,7 +33,10 @@
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar16`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entryPoints": [
|
||||
@@ -37,7 +46,10 @@
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar17`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entryPoints": [
|
||||
@@ -47,6 +59,9 @@
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar18`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
]
|
||||
5
pkg/api/testdata/routers-page2.json
vendored
5
pkg/api/testdata/routers-page2.json
vendored
@@ -7,6 +7,9 @@
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`toto.bar`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
]
|
||||
10
pkg/api/testdata/routers.json
vendored
10
pkg/api/testdata/routers.json
vendored
@@ -11,7 +11,10 @@
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entryPoints": [
|
||||
@@ -25,6 +28,9 @@
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar.other`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled"
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
]
|
||||
1
pkg/api/testdata/service-bar.json
vendored
1
pkg/api/testdata/service-bar.json
vendored
@@ -13,6 +13,7 @@
|
||||
"http://127.0.0.1": "UP"
|
||||
},
|
||||
"status": "enabled",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider",
|
||||
"test@myprovider"
|
||||
|
||||
22
pkg/api/testdata/services-filtered-search.json
vendored
Normal file
22
pkg/api/testdata/services-filtered-search.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"loadBalancer": {
|
||||
"passHostHeader": false,
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://127.0.0.2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "baz@myprovider",
|
||||
"provider": "myprovider",
|
||||
"serverStatus": {
|
||||
"http://127.0.0.2": "UP"
|
||||
},
|
||||
"status": "disabled",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider"
|
||||
]
|
||||
}
|
||||
]
|
||||
23
pkg/api/testdata/services-filtered-status.json
vendored
Normal file
23
pkg/api/testdata/services-filtered-status.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
[
|
||||
{
|
||||
"loadBalancer": {
|
||||
"passHostHeader": false,
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://127.0.0.1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "bar@myprovider",
|
||||
"provider": "myprovider",
|
||||
"serverStatus": {
|
||||
"http://127.0.0.1": "UP"
|
||||
},
|
||||
"status": "enabled",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider",
|
||||
"test@myprovider"
|
||||
]
|
||||
}
|
||||
]
|
||||
1
pkg/api/testdata/services-page2.json
vendored
1
pkg/api/testdata/services-page2.json
vendored
@@ -14,6 +14,7 @@
|
||||
"http://127.0.0.2": "UP"
|
||||
},
|
||||
"status": "enabled",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider"
|
||||
]
|
||||
|
||||
46
pkg/api/testdata/services.json
vendored
46
pkg/api/testdata/services.json
vendored
@@ -14,6 +14,7 @@
|
||||
"http://127.0.0.1": "UP"
|
||||
},
|
||||
"status": "enabled",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider",
|
||||
"test@myprovider"
|
||||
@@ -34,6 +35,51 @@
|
||||
"http://127.0.0.2": "UP"
|
||||
},
|
||||
"status": "enabled",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "canary@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "enabled",
|
||||
"type": "weighted",
|
||||
"usedBy": [
|
||||
"foo@myprovider"
|
||||
],
|
||||
"weighted": {
|
||||
"sticky": {
|
||||
"cookie": {
|
||||
"httpOnly": true,
|
||||
"name": "chocolat",
|
||||
"secure": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"mirroring": {
|
||||
"mirrors": [
|
||||
{
|
||||
"name": "two@myprovider",
|
||||
"percent": 10
|
||||
},
|
||||
{
|
||||
"name": "three@myprovider",
|
||||
"percent": 15
|
||||
},
|
||||
{
|
||||
"name": "four@myprovider",
|
||||
"percent": 80
|
||||
}
|
||||
],
|
||||
"service": "one@myprovider"
|
||||
},
|
||||
"name": "mirror@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "enabled",
|
||||
"type": "mirroring",
|
||||
"usedBy": [
|
||||
"foo@myprovider"
|
||||
]
|
||||
|
||||
6
pkg/api/testdata/tcprouter-bar.json
vendored
6
pkg/api/testdata/tcprouter-bar.json
vendored
@@ -5,5 +5,9 @@
|
||||
"name": "bar@myprovider",
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar`)",
|
||||
"service": "foo-service@myprovider"
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
15
pkg/api/testdata/tcprouters-filtered-search.json
vendored
Normal file
15
pkg/api/testdata/tcprouters-filtered-search.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
[
|
||||
{
|
||||
"entryPoints": [
|
||||
"web"
|
||||
],
|
||||
"name": "bar@myprovider",
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "warning",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
]
|
||||
18
pkg/api/testdata/tcprouters-filtered-status.json
vendored
Normal file
18
pkg/api/testdata/tcprouters-filtered-status.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"entryPoints": [
|
||||
"web"
|
||||
],
|
||||
"name": "test@myprovider",
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar.other`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled",
|
||||
"tls": {
|
||||
"passthrough": false
|
||||
},
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
]
|
||||
6
pkg/api/testdata/tcprouters-page2.json
vendored
6
pkg/api/testdata/tcprouters-page2.json
vendored
@@ -6,6 +6,10 @@
|
||||
"name": "baz@myprovider",
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`toto.bar`)",
|
||||
"service": "foo-service@myprovider"
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
]
|
||||
15
pkg/api/testdata/tcprouters.json
vendored
15
pkg/api/testdata/tcprouters.json
vendored
@@ -7,7 +7,10 @@
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "warning"
|
||||
"status": "warning",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entryPoints": [
|
||||
@@ -17,7 +20,10 @@
|
||||
"provider": "myprovider",
|
||||
"rule": "Host(`foo.bar`)",
|
||||
"service": "foo-service@myprovider",
|
||||
"status": "disabled"
|
||||
"status": "disabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entryPoints": [
|
||||
@@ -30,6 +36,9 @@
|
||||
"status": "enabled",
|
||||
"tls": {
|
||||
"passthrough": false
|
||||
}
|
||||
},
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
]
|
||||
2
pkg/api/testdata/tcpservice-bar.json
vendored
2
pkg/api/testdata/tcpservice-bar.json
vendored
@@ -8,6 +8,8 @@
|
||||
},
|
||||
"name": "bar@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "enabled",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider",
|
||||
"test@myprovider"
|
||||
|
||||
18
pkg/api/testdata/tcpservices-filtered-search.json
vendored
Normal file
18
pkg/api/testdata/tcpservices-filtered-search.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"loadBalancer": {
|
||||
"servers": [
|
||||
{
|
||||
"address": "127.0.0.2:2345"
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "baz@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "warning",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider"
|
||||
]
|
||||
}
|
||||
]
|
||||
19
pkg/api/testdata/tcpservices-filtered-status.json
vendored
Normal file
19
pkg/api/testdata/tcpservices-filtered-status.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
[
|
||||
{
|
||||
"loadBalancer": {
|
||||
"servers": [
|
||||
{
|
||||
"address": "127.0.0.1:2345"
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "bar@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "enabled",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider",
|
||||
"test@myprovider"
|
||||
]
|
||||
}
|
||||
]
|
||||
2
pkg/api/testdata/tcpservices-page2.json
vendored
2
pkg/api/testdata/tcpservices-page2.json
vendored
@@ -9,6 +9,8 @@
|
||||
},
|
||||
"name": "baz@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "enabled",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider"
|
||||
]
|
||||
|
||||
3
pkg/api/testdata/tcpservices.json
vendored
3
pkg/api/testdata/tcpservices.json
vendored
@@ -10,6 +10,7 @@
|
||||
"name": "bar@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "enabled",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider",
|
||||
"test@myprovider"
|
||||
@@ -26,6 +27,7 @@
|
||||
"name": "baz@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "warning",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider"
|
||||
]
|
||||
@@ -41,6 +43,7 @@
|
||||
"name": "foz@myprovider",
|
||||
"provider": "myprovider",
|
||||
"status": "disabled",
|
||||
"type": "loadbalancer",
|
||||
"usedBy": [
|
||||
"foo@myprovider"
|
||||
]
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
buckets = [42.0, 42.0]
|
||||
entryPoint = "foobar"
|
||||
middlewares = ["foobar", "foobar"]
|
||||
[metrics.dataDog]
|
||||
[metrics.datadog]
|
||||
address = "foobar"
|
||||
pushInterval = "10s"
|
||||
[metrics.statsD]
|
||||
@@ -179,7 +179,7 @@
|
||||
id128Bit = true
|
||||
debug = true
|
||||
sampleRate = 42.0
|
||||
[tracing.dataDog]
|
||||
[tracing.datadog]
|
||||
localAgentHostPort = "foobar"
|
||||
globalTag = "foobar"
|
||||
debug = true
|
||||
@@ -249,16 +249,14 @@
|
||||
prefixes = ["foobar", "foobar"]
|
||||
[http.middlewares.Middleware10]
|
||||
[http.middlewares.Middleware10.rateLimit]
|
||||
extractorFunc = "foobar"
|
||||
[http.middlewares.Middleware10.rateLimit.rateSet]
|
||||
[http.middlewares.Middleware10.rateLimit.rateSet.Rate0]
|
||||
period = 42000000000
|
||||
average = 42
|
||||
burst = 42
|
||||
[http.middlewares.Middleware10.rateLimit.rateSet.Rate1]
|
||||
period = 42000000000
|
||||
average = 42
|
||||
burst = 42
|
||||
average = 42
|
||||
burst = 42
|
||||
[http.middlewares.Middleware10.rateLimit.sourceCriterion]
|
||||
requestHeaderName = "foobar"
|
||||
requestHost = true
|
||||
[http.middlewares.Middleware10.rateLimit.sourceCriterion.ipStrategy]
|
||||
depth = 42
|
||||
excludedIPs = ["foobar", "foobar"]
|
||||
[http.middlewares.Middleware11]
|
||||
[http.middlewares.Middleware11.redirectRegex]
|
||||
regex = "foobar"
|
||||
|
||||
@@ -687,6 +687,43 @@ func (in *Middleware) DeepCopy() *Middleware {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MirrorService) DeepCopyInto(out *MirrorService) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MirrorService.
|
||||
func (in *MirrorService) DeepCopy() *MirrorService {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MirrorService)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Mirroring) DeepCopyInto(out *Mirroring) {
|
||||
*out = *in
|
||||
if in.Mirrors != nil {
|
||||
in, out := &in.Mirrors, &out.Mirrors
|
||||
*out = make([]MirrorService, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mirroring.
|
||||
func (in *Mirroring) DeepCopy() *Mirroring {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Mirroring)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PassTLSClientCert) DeepCopyInto(out *PassTLSClientCert) {
|
||||
*out = *in
|
||||
@@ -967,6 +1004,11 @@ func (in *Service) DeepCopyInto(out *Service) {
|
||||
*out = new(WeightedRoundRobin)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Mirroring != nil {
|
||||
in, out := &in.Mirroring, &out.Mirroring
|
||||
*out = new(Mirroring)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
|
||||
{Name: "format", Value: "foobar"},
|
||||
{Name: "level", Value: "foobar"}}},
|
||||
{Name: "metrics", Children: []*parser.Node{
|
||||
{Name: "dataDog", Children: []*parser.Node{
|
||||
{Name: "datadog", Children: []*parser.Node{
|
||||
{Name: "address", Value: "foobar"},
|
||||
{Name: "pushInterval", Value: "10s"}}},
|
||||
{Name: "influxDB", Children: []*parser.Node{
|
||||
@@ -251,7 +251,7 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
|
||||
{Name: "maxIdleConnsPerHost", Value: "42"},
|
||||
{Name: "rootCAs", Value: "foobar,foobar"}}},
|
||||
{Name: "tracing", Children: []*parser.Node{
|
||||
{Name: "dataDog", Children: []*parser.Node{
|
||||
{Name: "datadog", Children: []*parser.Node{
|
||||
{Name: "bagagePrefixHeaderName", Value: "foobar"},
|
||||
{Name: "debug", Value: "true"},
|
||||
{Name: "globalTag", Value: "foobar"},
|
||||
@@ -282,7 +282,6 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
|
||||
{Name: "serviceName", Value: "foobar"},
|
||||
{Name: "spanNameLimit", Value: "42"},
|
||||
{Name: "zipkin", Children: []*parser.Node{
|
||||
{Name: "debug", Value: "true"},
|
||||
{Name: "httpEndpoint", Value: "foobar"},
|
||||
{Name: "id128Bit", Value: "true"},
|
||||
{Name: "sameSpan", Value: "true"},
|
||||
@@ -378,7 +377,7 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
|
||||
{Name: "format", Value: "foobar"},
|
||||
{Name: "level", Value: "foobar"}}},
|
||||
{Name: "metrics", Children: []*parser.Node{
|
||||
{Name: "dataDog", Children: []*parser.Node{
|
||||
{Name: "datadog", Children: []*parser.Node{
|
||||
{Name: "address", Value: "foobar"},
|
||||
{Name: "pushInterval", Value: "10s"}}},
|
||||
{Name: "influxDB", Children: []*parser.Node{
|
||||
@@ -486,7 +485,7 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
|
||||
{Name: "maxIdleConnsPerHost", Value: "42"},
|
||||
{Name: "rootCAs", Value: "foobar,foobar"}}},
|
||||
{Name: "tracing", Children: []*parser.Node{
|
||||
{Name: "dataDog", Children: []*parser.Node{
|
||||
{Name: "datadog", Children: []*parser.Node{
|
||||
{Name: "bagagePrefixHeaderName", Value: "foobar"},
|
||||
{Name: "debug", Value: "true"},
|
||||
{Name: "globalTag", Value: "foobar"},
|
||||
@@ -517,7 +516,6 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
|
||||
{Name: "serviceName", Value: "foobar"},
|
||||
{Name: "spanNameLimit", Value: "42"},
|
||||
{Name: "zipkin", Children: []*parser.Node{
|
||||
{Name: "debug", Value: "true"},
|
||||
{Name: "httpEndpoint", Value: "foobar"},
|
||||
{Name: "id128Bit", Value: "true"},
|
||||
{Name: "sameSpan", Value: "true"},
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
buckets = [42.0, 42.0]
|
||||
entryPoint = "foobar"
|
||||
middlewares = ["foobar", "foobar"]
|
||||
[metrics.dataDog]
|
||||
[metrics.datadog]
|
||||
address = "foobar"
|
||||
pushInterval = "10s"
|
||||
[metrics.statsD]
|
||||
@@ -177,9 +177,8 @@
|
||||
httpEndpoint = "foobar"
|
||||
sameSpan = true
|
||||
id128Bit = true
|
||||
debug = true
|
||||
sampleRate = 42.0
|
||||
[tracing.dataDog]
|
||||
[tracing.datadog]
|
||||
localAgentHostPort = "foobar"
|
||||
globalTag = "foobar"
|
||||
debug = true
|
||||
@@ -241,16 +240,14 @@
|
||||
prefixes = ["foobar", "foobar"]
|
||||
[http.middlewares.Middleware10]
|
||||
[http.middlewares.Middleware10.rateLimit]
|
||||
extractorFunc = "foobar"
|
||||
[http.middlewares.Middleware10.rateLimit.rateSet]
|
||||
[http.middlewares.Middleware10.rateLimit.rateSet.Rate0]
|
||||
period = 42000000000
|
||||
average = 42
|
||||
burst = 42
|
||||
[http.middlewares.Middleware10.rateLimit.rateSet.Rate1]
|
||||
period = 42000000000
|
||||
average = 42
|
||||
burst = 42
|
||||
average = 42
|
||||
burst = 42
|
||||
[http.middlewares.Middleware10.rateLimit.sourceCriterion]
|
||||
requestHeaderName = "foobar"
|
||||
requestHost = true
|
||||
[http.middlewares.Middleware10.rateLimit.sourceCriterion.ipStrategy]
|
||||
depth = 42
|
||||
excludedIPs = ["foobar", "foobar"]
|
||||
[http.middlewares.Middleware11]
|
||||
[http.middlewares.Middleware11.redirectRegex]
|
||||
regex = "foobar"
|
||||
|
||||
@@ -130,7 +130,7 @@ metrics:
|
||||
middlewares:
|
||||
- foobar
|
||||
- foobar
|
||||
dataDog:
|
||||
datadog:
|
||||
address: foobar
|
||||
pushInterval: 10s
|
||||
statsD:
|
||||
@@ -188,9 +188,8 @@ tracing:
|
||||
httpEndpoint: foobar
|
||||
sameSpan: true
|
||||
id128Bit: true
|
||||
debug: true
|
||||
sampleRate: 42
|
||||
dataDog:
|
||||
datadog:
|
||||
localAgentHostPort: foobar
|
||||
globalTag: foobar
|
||||
debug: true
|
||||
|
||||
@@ -2,13 +2,15 @@ package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
)
|
||||
|
||||
// GetRoutersByEntryPoints returns all the http routers by entry points name and routers name
|
||||
// GetRoutersByEntryPoints returns all the http routers by entry points name and routers name.
|
||||
func (c *Configuration) GetRoutersByEntryPoints(ctx context.Context, entryPoints []string, tls bool) map[string]map[string]*RouterInfo {
|
||||
entryPointsRouters := make(map[string]map[string]*RouterInfo)
|
||||
|
||||
@@ -17,13 +19,19 @@ func (c *Configuration) GetRoutersByEntryPoints(ctx context.Context, entryPoints
|
||||
continue
|
||||
}
|
||||
|
||||
logger := log.FromContext(log.With(ctx, log.Str(log.RouterName, rtName)))
|
||||
|
||||
eps := rt.EntryPoints
|
||||
if len(eps) == 0 {
|
||||
logger.Debugf("No entryPoint defined for this router, using the default one(s) instead: %+v", entryPoints)
|
||||
eps = entryPoints
|
||||
}
|
||||
|
||||
entryPointsCount := 0
|
||||
for _, entryPointName := range eps {
|
||||
if !contains(entryPoints, entryPointName) {
|
||||
log.FromContext(log.With(ctx, log.Str(log.EntryPointName, entryPointName))).
|
||||
rt.AddError(fmt.Errorf("entryPoint %q doesn't exist", entryPointName), false)
|
||||
logger.WithField(log.EntryPointName, entryPointName).
|
||||
Errorf("entryPoint %q doesn't exist", entryPointName)
|
||||
continue
|
||||
}
|
||||
@@ -32,14 +40,40 @@ func (c *Configuration) GetRoutersByEntryPoints(ctx context.Context, entryPoints
|
||||
entryPointsRouters[entryPointName] = make(map[string]*RouterInfo)
|
||||
}
|
||||
|
||||
entryPointsCount++
|
||||
rt.Using = append(rt.Using, entryPointName)
|
||||
|
||||
entryPointsRouters[entryPointName][rtName] = rt
|
||||
}
|
||||
|
||||
if entryPointsCount == 0 {
|
||||
rt.AddError(fmt.Errorf("no valid entryPoint for this router"), true)
|
||||
logger.Error("no valid entryPoint for this router")
|
||||
}
|
||||
|
||||
rt.Using = unique(rt.Using)
|
||||
}
|
||||
|
||||
return entryPointsRouters
|
||||
}
|
||||
|
||||
// RouterInfo holds information about a currently running HTTP router
|
||||
func unique(src []string) []string {
|
||||
var uniq []string
|
||||
|
||||
set := make(map[string]struct{})
|
||||
for _, v := range src {
|
||||
if _, exist := set[v]; !exist {
|
||||
set[v] = struct{}{}
|
||||
uniq = append(uniq, v)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(uniq)
|
||||
|
||||
return uniq
|
||||
}
|
||||
|
||||
// RouterInfo holds information about a currently running HTTP router.
|
||||
type RouterInfo struct {
|
||||
*dynamic.Router // dynamic configuration
|
||||
// Err contains all the errors that occurred during router's creation.
|
||||
@@ -47,7 +81,8 @@ type RouterInfo struct {
|
||||
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
||||
// If not in "enabled" state, the reason for it should be in the list of Err.
|
||||
// It is the caller's responsibility to set the initial status.
|
||||
Status string `json:"status,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Using []string `json:"using,omitempty"` // Effective entry points used by that router.
|
||||
}
|
||||
|
||||
// AddError adds err to r.Err, if it does not already exist.
|
||||
@@ -71,13 +106,13 @@ func (r *RouterInfo) AddError(err error, critical bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// MiddlewareInfo holds information about a currently running middleware
|
||||
// MiddlewareInfo holds information about a currently running middleware.
|
||||
type MiddlewareInfo struct {
|
||||
*dynamic.Middleware // dynamic configuration
|
||||
// Err contains all the errors that occurred during service creation.
|
||||
Err []string `json:"error,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
UsedBy []string `json:"usedBy,omitempty"` // list of routers and services using that middleware
|
||||
UsedBy []string `json:"usedBy,omitempty"` // list of routers and services using that middleware.
|
||||
}
|
||||
|
||||
// AddError adds err to s.Err, if it does not already exist.
|
||||
@@ -101,7 +136,7 @@ func (m *MiddlewareInfo) AddError(err error, critical bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceInfo holds information about a currently running service
|
||||
// ServiceInfo holds information about a currently running service.
|
||||
type ServiceInfo struct {
|
||||
*dynamic.Service // dynamic configuration
|
||||
// Err contains all the errors that occurred during service creation.
|
||||
|
||||
@@ -104,6 +104,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||
Rule: "Host(`bar.foo`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"web"},
|
||||
},
|
||||
"foobar": {
|
||||
Router: &dynamic.Router{
|
||||
@@ -111,7 +112,9 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||
Service: "foobar-service@myprovider",
|
||||
Rule: "Host(`bar.foobar`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Status: "warning",
|
||||
Err: []string{`entryPoint "webs" doesn't exist`},
|
||||
Using: []string{"web"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -168,6 +171,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||
Rule: "Host(`bar.foo`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"web"},
|
||||
},
|
||||
"foobar": {
|
||||
Router: &dynamic.Router{
|
||||
@@ -176,6 +180,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||
Rule: "Host(`bar.foobar`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"web", "webs"},
|
||||
},
|
||||
},
|
||||
"webs": {
|
||||
@@ -187,6 +192,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||
Rule: "Host(`foo.bar`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"webs"},
|
||||
},
|
||||
"foobar": {
|
||||
Router: &dynamic.Router{
|
||||
@@ -195,6 +201,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
||||
Rule: "Host(`bar.foobar`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"web", "webs"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -2,24 +2,30 @@ package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
)
|
||||
|
||||
// GetTCPRoutersByEntryPoints returns all the tcp routers by entry points name and routers name
|
||||
// GetTCPRoutersByEntryPoints returns all the tcp routers by entry points name and routers name.
|
||||
func (c *Configuration) GetTCPRoutersByEntryPoints(ctx context.Context, entryPoints []string) map[string]map[string]*TCPRouterInfo {
|
||||
entryPointsRouters := make(map[string]map[string]*TCPRouterInfo)
|
||||
|
||||
for rtName, rt := range c.TCPRouters {
|
||||
logger := log.FromContext(log.With(ctx, log.Str(log.RouterName, rtName)))
|
||||
|
||||
eps := rt.EntryPoints
|
||||
if len(eps) == 0 {
|
||||
logger.Debugf("No entryPoint defined for this router, using the default one(s) instead: %+v", entryPoints)
|
||||
eps = entryPoints
|
||||
}
|
||||
|
||||
entryPointsCount := 0
|
||||
for _, entryPointName := range eps {
|
||||
if !contains(entryPoints, entryPointName) {
|
||||
log.FromContext(log.With(ctx, log.Str(log.EntryPointName, entryPointName))).
|
||||
rt.AddError(fmt.Errorf("entryPoint %q doesn't exist", entryPointName), false)
|
||||
logger.WithField(log.EntryPointName, entryPointName).
|
||||
Errorf("entryPoint %q doesn't exist", entryPointName)
|
||||
continue
|
||||
}
|
||||
@@ -28,21 +34,30 @@ func (c *Configuration) GetTCPRoutersByEntryPoints(ctx context.Context, entryPoi
|
||||
entryPointsRouters[entryPointName] = make(map[string]*TCPRouterInfo)
|
||||
}
|
||||
|
||||
entryPointsCount++
|
||||
rt.Using = append(rt.Using, entryPointName)
|
||||
|
||||
entryPointsRouters[entryPointName][rtName] = rt
|
||||
}
|
||||
|
||||
if entryPointsCount == 0 {
|
||||
rt.AddError(fmt.Errorf("no valid entryPoint for this router"), true)
|
||||
logger.Error("no valid entryPoint for this router")
|
||||
}
|
||||
}
|
||||
|
||||
return entryPointsRouters
|
||||
}
|
||||
|
||||
// TCPRouterInfo holds information about a currently running TCP router
|
||||
// TCPRouterInfo holds information about a currently running TCP router.
|
||||
type TCPRouterInfo struct {
|
||||
*dynamic.TCPRouter // dynamic configuration
|
||||
Err []string `json:"error,omitempty"` // initialization error
|
||||
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
||||
// If not in "enabled" state, the reason for it should be in the list of Err.
|
||||
// It is the caller's responsibility to set the initial status.
|
||||
Status string `json:"status,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Using []string `json:"using,omitempty"` // Effective entry points used by that router.
|
||||
}
|
||||
|
||||
// AddError adds err to r.Err, if it does not already exist.
|
||||
@@ -66,7 +81,7 @@ func (r *TCPRouterInfo) AddError(err error, critical bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// TCPServiceInfo holds information about a currently running TCP service
|
||||
// TCPServiceInfo holds information about a currently running TCP service.
|
||||
type TCPServiceInfo struct {
|
||||
*dynamic.TCPService // dynamic configuration
|
||||
Err []string `json:"error,omitempty"` // initialization error
|
||||
|
||||
@@ -104,6 +104,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||
Rule: "HostSNI(`bar.foo`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"web"},
|
||||
},
|
||||
"foobar": {
|
||||
TCPRouter: &dynamic.TCPRouter{
|
||||
@@ -111,7 +112,9 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||
Service: "foobar-service@myprovider",
|
||||
Rule: "HostSNI(`bar.foobar`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Status: "warning",
|
||||
Err: []string{`entryPoint "webs" doesn't exist`},
|
||||
Using: []string{"web"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -168,6 +171,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||
Rule: "HostSNI(`bar.foo`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"web"},
|
||||
},
|
||||
"foobar": {
|
||||
TCPRouter: &dynamic.TCPRouter{
|
||||
@@ -176,6 +180,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||
Rule: "HostSNI(`bar.foobar`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"web", "webs"},
|
||||
},
|
||||
},
|
||||
"webs": {
|
||||
@@ -187,6 +192,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||
Rule: "HostSNI(`foo.bar`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"webs"},
|
||||
},
|
||||
"foobar": {
|
||||
TCPRouter: &dynamic.TCPRouter{
|
||||
@@ -195,6 +201,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
||||
Rule: "HostSNI(`bar.foobar`)",
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"web", "webs"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -139,7 +139,7 @@ type Tracing struct {
|
||||
SpanNameLimit int `description:"Set the maximum character limit for Span names (default 0 = no limit)." json:"spanNameLimit,omitempty" toml:"spanNameLimit,omitempty" yaml:"spanNameLimit,omitempty" export:"true"`
|
||||
Jaeger *jaeger.Config `description:"Settings for Jaeger." json:"jaeger,omitempty" toml:"jaeger,omitempty" yaml:"jaeger,omitempty" export:"true" label:"allowEmpty"`
|
||||
Zipkin *zipkin.Config `description:"Settings for Zipkin." json:"zipkin,omitempty" toml:"zipkin,omitempty" yaml:"zipkin,omitempty" export:"true" label:"allowEmpty"`
|
||||
DataDog *datadog.Config `description:"Settings for DataDog." json:"dataDog,omitempty" toml:"dataDog,omitempty" yaml:"dataDog,omitempty" export:"true" label:"allowEmpty"`
|
||||
Datadog *datadog.Config `description:"Settings for Datadog." json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" export:"true" label:"allowEmpty"`
|
||||
Instana *instana.Config `description:"Settings for Instana." json:"instana,omitempty" toml:"instana,omitempty" yaml:"instana,omitempty" export:"true" label:"allowEmpty"`
|
||||
Haystack *haystack.Config `description:"Settings for Haystack." json:"haystack,omitempty" toml:"haystack,omitempty" yaml:"haystack,omitempty" export:"true" label:"allowEmpty"`
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user