Merge current v2.7 into master
This commit is contained in:
commit
521109d3f2
60 changed files with 2136 additions and 529 deletions
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -3,11 +3,11 @@ PLEASE READ THIS MESSAGE.
|
||||||
|
|
||||||
Documentation fixes or enhancements:
|
Documentation fixes or enhancements:
|
||||||
- for Traefik v1: use branch v1.7
|
- for Traefik v1: use branch v1.7
|
||||||
- for Traefik v2: use branch v2.6
|
- for Traefik v2: use branch v2.7
|
||||||
|
|
||||||
Bug fixes:
|
Bug fixes:
|
||||||
- for Traefik v1: use branch v1.7
|
- for Traefik v1: use branch v1.7
|
||||||
- for Traefik v2: use branch v2.6
|
- for Traefik v2: use branch v2.7
|
||||||
|
|
||||||
Enhancements:
|
Enhancements:
|
||||||
- for Traefik v1: we only accept bug fixes
|
- for Traefik v1: we only accept bug fixes
|
||||||
|
|
2
.github/workflows/validate.yaml
vendored
2
.github/workflows/validate.yaml
vendored
|
@ -7,7 +7,7 @@ on:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: 1.17
|
GO_VERSION: 1.17
|
||||||
GOLANGCI_LINT_VERSION: v1.45.0
|
GOLANGCI_LINT_VERSION: v1.46.2
|
||||||
MISSSPELL_VERSION: v0.3.4
|
MISSSPELL_VERSION: v0.3.4
|
||||||
IN_DOCKER: ""
|
IN_DOCKER: ""
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,7 @@
|
||||||
"interfacer", # Deprecated
|
"interfacer", # Deprecated
|
||||||
"maligned", # Deprecated
|
"maligned", # Deprecated
|
||||||
"golint", # Deprecated
|
"golint", # Deprecated
|
||||||
|
"execinquery", # Not relevant (SQL)
|
||||||
"sqlclosecheck", # Not relevant (SQL)
|
"sqlclosecheck", # Not relevant (SQL)
|
||||||
"rowserrcheck", # Not relevant (SQL)
|
"rowserrcheck", # Not relevant (SQL)
|
||||||
"lll", # Not relevant
|
"lll", # Not relevant
|
||||||
|
@ -142,6 +143,7 @@
|
||||||
"paralleltest", # Not relevant
|
"paralleltest", # Not relevant
|
||||||
"exhaustive", # Not relevant
|
"exhaustive", # Not relevant
|
||||||
"exhaustivestruct", # Not relevant
|
"exhaustivestruct", # Not relevant
|
||||||
|
"exhaustruct", # duplicate of exhaustivestruct
|
||||||
"goerr113", # Too strict
|
"goerr113", # Too strict
|
||||||
"wrapcheck", # Too strict
|
"wrapcheck", # Too strict
|
||||||
"noctx", # Too strict
|
"noctx", # Too strict
|
||||||
|
@ -156,6 +158,7 @@
|
||||||
"contextcheck", # too many false-positive
|
"contextcheck", # too many false-positive
|
||||||
"containedctx", # too many false-positive
|
"containedctx", # too many false-positive
|
||||||
"maintidx", # kind of duplicate of gocyclo
|
"maintidx", # kind of duplicate of gocyclo
|
||||||
|
"nonamedreturns", # not relevant
|
||||||
]
|
]
|
||||||
|
|
||||||
[issues]
|
[issues]
|
||||||
|
|
|
@ -25,7 +25,7 @@ global_job_config:
|
||||||
- export "PATH=${GOPATH}/bin:${PATH}"
|
- export "PATH=${GOPATH}/bin:${PATH}"
|
||||||
- mkdir -vp "${SEMAPHORE_GIT_DIR}" "${GOPATH}/bin"
|
- mkdir -vp "${SEMAPHORE_GIT_DIR}" "${GOPATH}/bin"
|
||||||
- export GOPROXY=https://proxy.golang.org,direct
|
- export GOPROXY=https://proxy.golang.org,direct
|
||||||
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin" v1.45.0
|
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin" v1.46.2
|
||||||
- curl -sSfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | bash -s -- -b "${GOPATH}/bin"
|
- curl -sSfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | bash -s -- -b "${GOPATH}/bin"
|
||||||
- checkout
|
- checkout
|
||||||
- cache restore traefik-$(checksum go.sum)
|
- cache restore traefik-$(checksum go.sum)
|
||||||
|
|
90
CHANGELOG.md
90
CHANGELOG.md
|
@ -1,3 +1,93 @@
|
||||||
|
## [v2.7.0](https://github.com/traefik/traefik/tree/v2.7.0) (2022-05-24)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v2.7.0-rc1...v2.7.0)
|
||||||
|
|
||||||
|
**Enhancements:**
|
||||||
|
- **[consulcatalog]** Watch for Consul events to rebuild the dynamic configuration ([#8476](https://github.com/traefik/traefik/pull/8476) by [JasonWangA](https://github.com/JasonWangA))
|
||||||
|
- **[healthcheck]** Add Failover service ([#8825](https://github.com/traefik/traefik/pull/8825) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- **[http3]** Configure advertised port using h3 server option ([#8778](https://github.com/traefik/traefik/pull/8778) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- **[http3]** Upgrade quic-go to v0.25.0 ([#8760](https://github.com/traefik/traefik/pull/8760) by [sylr](https://github.com/sylr))
|
||||||
|
- **[hub]** Add Traefik Hub Integration (Experimental Feature) ([#8837](https://github.com/traefik/traefik/pull/8837) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||||
|
- **[k8s/crd,k8s]** Allow empty services in Kubernetes CRD ([#8802](https://github.com/traefik/traefik/pull/8802) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- **[metrics]** Support InfluxDB v2 metrics backend ([#8250](https://github.com/traefik/traefik/pull/8250) by [sh7dm](https://github.com/sh7dm))
|
||||||
|
- **[plugins]** Remove Pilot token setup constraint to use plugins ([#8869](https://github.com/traefik/traefik/pull/8869) by [ldez](https://github.com/ldez))
|
||||||
|
- **[provider]** Refactor configuration reload/throttling ([#6633](https://github.com/traefik/traefik/pull/6633) by [rkojedzinszky](https://github.com/rkojedzinszky))
|
||||||
|
- **[rules,tcp]** Add HostSNIRegexp rule matcher for TCP ([#8849](https://github.com/traefik/traefik/pull/8849) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- **[tcp]** Add muxer for TCP Routers ([#8182](https://github.com/traefik/traefik/pull/8182) by [dtomcej](https://github.com/dtomcej))
|
||||||
|
- **[webui,pilot]** Add Traefik Hub access and remove Pilot access ([#8848](https://github.com/traefik/traefik/pull/8848) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- **[webui]** Add a link to service on router detail view ([#8821](https://github.com/traefik/traefik/pull/8821) by [Tchoupinax](https://github.com/Tchoupinax))
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[hub]** Skip Provide when TLS is nil ([#9031](https://github.com/traefik/traefik/pull/9031) by [ldez](https://github.com/ldez))
|
||||||
|
- **[tcp]** Fix TCP-TLS/HTTPS routing precedence ([#9024](https://github.com/traefik/traefik/pull/9024) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- **[webui,hub]** Use dedicated entrypoint for the tunnels ([#9023](https://github.com/traefik/traefik/pull/9023) by [youkoulayley](https://github.com/youkoulayley))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- **[hub]** Fix Traefik Hub TLS documentation ([#8883](https://github.com/traefik/traefik/pull/8883) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||||
|
- Add a Feature Deprecation page ([#8868](https://github.com/traefik/traefik/pull/8868) by [ddtmachado](https://github.com/ddtmachado))
|
||||||
|
- Prepare release v2.7.0-rc1 ([#8879](https://github.com/traefik/traefik/pull/8879) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- Prepare release v2.7.0-rc2 ([#8900](https://github.com/traefik/traefik/pull/8900) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
|
||||||
|
**Misc:**
|
||||||
|
- Merge current v2.6 into v2.7 ([#8984](https://github.com/traefik/traefik/pull/8984) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- Merge current v2.6 into v2.7 ([#8958](https://github.com/traefik/traefik/pull/8958) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- Merge current v2.6 into v2.7 ([#8899](https://github.com/traefik/traefik/pull/8899) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- Merge current v2.6 into master ([#8877](https://github.com/traefik/traefik/pull/8877) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- Merge current v2.6 into master ([#8865](https://github.com/traefik/traefik/pull/8865) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- Merge current v2.6 into master ([#8832](https://github.com/traefik/traefik/pull/8832) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- Merge current v2.6 into master ([#8793](https://github.com/traefik/traefik/pull/8793) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- Merge current v2.6 into master ([#8777](https://github.com/traefik/traefik/pull/8777) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- Merge current v2.6 into master ([#8757](https://github.com/traefik/traefik/pull/8757) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- Merge current v2.6 into master ([#8754](https://github.com/traefik/traefik/pull/8754) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- Merge current v2.6 into master ([#8736](https://github.com/traefik/traefik/pull/8736) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- Merge current v2.6 into master ([#8689](https://github.com/traefik/traefik/pull/8689) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- Merge current v2.6 into master ([#8666](https://github.com/traefik/traefik/pull/8666) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
|
||||||
|
## [v2.6.7](https://github.com/traefik/traefik/tree/v2.6.7) (2022-05-23)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v2.6.6...v2.6.7)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[logs,k8s/crd]** Fix log statement for ExternalName misconfig ([#9014](https://github.com/traefik/traefik/pull/9014) by [kruton](https://github.com/kruton))
|
||||||
|
- **[plugins]** Update Yaegi to v0.12.0 ([#9039](https://github.com/traefik/traefik/pull/9039) by [mpl](https://github.com/mpl))
|
||||||
|
- **[tcp,service]** Fix initial tcp lookup when address is not available ([#9021](https://github.com/traefik/traefik/pull/9021) by [ddtmachado](https://github.com/ddtmachado))
|
||||||
|
- **[tls]** Fix panic when getting certificates with non-existing store ([#9019](https://github.com/traefik/traefik/pull/9019) by [moutoum](https://github.com/moutoum))
|
||||||
|
- **[tracing]** Update jaeger-client-go to v2.30.0 ([#9000](https://github.com/traefik/traefik/pull/9000) by [moutoum](https://github.com/moutoum))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- **[middleware]** Updated browserXssFilter key to camel case ([#9038](https://github.com/traefik/traefik/pull/9038) by [karlosmunjos](https://github.com/karlosmunjos))
|
||||||
|
- Fix the default priority for the entrypoint redirection ([#9028](https://github.com/traefik/traefik/pull/9028) by [ldez](https://github.com/ldez))
|
||||||
|
- Fix typo in maintainers guidelines ([#9011](https://github.com/traefik/traefik/pull/9011) by [eltociear](https://github.com/eltociear))
|
||||||
|
|
||||||
|
## [v2.6.6](https://github.com/traefik/traefik/tree/v2.6.6) (2022-05-03)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v2.6.3...v2.6.6)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[acme]** Fix RenewInterval computation in ACME provider ([#8969](https://github.com/traefik/traefik/pull/8969) by [smasset-orange](https://github.com/smasset-orange))
|
||||||
|
- **[ecs,logs]** Remove duplicate error logs ([#8916](https://github.com/traefik/traefik/pull/8916) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- **[ecs]** Filter out ECS anywhere instance IDs ([#8973](https://github.com/traefik/traefik/pull/8973) by [JohnPreston](https://github.com/JohnPreston))
|
||||||
|
- **[middleware]** Re-add missing writeheader call in flush ([#8957](https://github.com/traefik/traefik/pull/8957) by [mpl](https://github.com/mpl))
|
||||||
|
- **[middleware]** Fix bug for when custom page is large enough ([#8932](https://github.com/traefik/traefik/pull/8932) by [mpl](https://github.com/mpl))
|
||||||
|
- **[middleware]** Fix regexp handling in redirect middleware ([#8920](https://github.com/traefik/traefik/pull/8920) by [tomMoulard](https://github.com/tomMoulard))
|
||||||
|
- **[plugins]** Update Yaegi to v0.11.3 ([#8954](https://github.com/traefik/traefik/pull/8954) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- **[k8s/gatewayapi]** Fix certificateRefs in dynamic configuration ([#8940](https://github.com/traefik/traefik/pull/8940) by [kahirokunn](https://github.com/kahirokunn))
|
||||||
|
- **[logs]** Move accessLog.fields example to TOML section ([#8944](https://github.com/traefik/traefik/pull/8944) by [major](https://github.com/major))
|
||||||
|
- **[logs]** Add default mode for fields.names to access log ([#8933](https://github.com/traefik/traefik/pull/8933) by [aleksvujic](https://github.com/aleksvujic))
|
||||||
|
- **[middleware]** Fix default for buffering middleware ([#8945](https://github.com/traefik/traefik/pull/8945) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- **[middleware]** Preflight requests are not forwarded to services ([#8923](https://github.com/traefik/traefik/pull/8923) by [sizief](https://github.com/sizief))
|
||||||
|
- Add title and description metadata to documentation pages ([#8941](https://github.com/traefik/traefik/pull/8941) by [ldez](https://github.com/ldez))
|
||||||
|
- Update dynamic and static configuration references ([#8918](https://github.com/traefik/traefik/pull/8918) by [ldez](https://github.com/ldez))
|
||||||
|
|
||||||
|
## [v2.6.5](https://github.com/traefik/traefik/tree/v2.6.5) (2022-05-03)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v2.6.3...v2.6.5)
|
||||||
|
|
||||||
|
Release canceled.
|
||||||
|
|
||||||
|
## [v2.6.4](https://github.com/traefik/traefik/tree/v2.6.4) (2022-05-03)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v2.6.3...v2.6.4)
|
||||||
|
|
||||||
|
Release canceled.
|
||||||
|
|
||||||
## [v2.7.0-rc2](https://github.com/traefik/traefik/tree/v2.7.0-rc2) (2022-03-29)
|
## [v2.7.0-rc2](https://github.com/traefik/traefik/tree/v2.7.0-rc2) (2022-03-29)
|
||||||
[All Commits](https://github.com/traefik/traefik/compare/v2.7.0-rc1...v2.7.0-rc2)
|
[All Commits](https://github.com/traefik/traefik/compare/v2.7.0-rc1...v2.7.0-rc2)
|
||||||
|
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -65,7 +65,7 @@ build-webui-image:
|
||||||
clean-webui:
|
clean-webui:
|
||||||
rm -r webui/static
|
rm -r webui/static
|
||||||
mkdir -p webui/static
|
mkdir -p webui/static
|
||||||
echo 'For more information show `webui/readme.md`' > webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md
|
printf 'For more information see `webui/readme.md`' > webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md
|
||||||
|
|
||||||
## Generate WebUI
|
## Generate WebUI
|
||||||
webui/static/index.html:
|
webui/static/index.html:
|
||||||
|
|
|
@ -13,7 +13,7 @@ RUN mkdir -p /usr/local/bin \
|
||||||
| tar -xzC /usr/local/bin --transform 's#^.+/##x'
|
| tar -xzC /usr/local/bin --transform 's#^.+/##x'
|
||||||
|
|
||||||
# Download golangci-lint binary to bin folder in $GOPATH
|
# Download golangci-lint binary to bin folder in $GOPATH
|
||||||
RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b $GOPATH/bin v1.45.0
|
RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b $GOPATH/bin v1.46.2
|
||||||
|
|
||||||
# Download misspell binary to bin folder in $GOPATH
|
# Download misspell binary to bin folder in $GOPATH
|
||||||
RUN curl -sfL https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.3.4
|
RUN curl -sfL https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.3.4
|
||||||
|
|
|
@ -34,6 +34,7 @@ import (
|
||||||
"github.com/traefik/traefik/v2/pkg/pilot"
|
"github.com/traefik/traefik/v2/pkg/pilot"
|
||||||
"github.com/traefik/traefik/v2/pkg/provider/acme"
|
"github.com/traefik/traefik/v2/pkg/provider/acme"
|
||||||
"github.com/traefik/traefik/v2/pkg/provider/aggregator"
|
"github.com/traefik/traefik/v2/pkg/provider/aggregator"
|
||||||
|
"github.com/traefik/traefik/v2/pkg/provider/hub"
|
||||||
"github.com/traefik/traefik/v2/pkg/provider/traefik"
|
"github.com/traefik/traefik/v2/pkg/provider/traefik"
|
||||||
"github.com/traefik/traefik/v2/pkg/safe"
|
"github.com/traefik/traefik/v2/pkg/safe"
|
||||||
"github.com/traefik/traefik/v2/pkg/server"
|
"github.com/traefik/traefik/v2/pkg/server"
|
||||||
|
@ -215,8 +216,6 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if staticConfiguration.Pilot != nil {
|
if staticConfiguration.Pilot != nil {
|
||||||
log.WithoutContext().Warn("Traefik Pilot is deprecated and will be removed soon. Please check our Blog for migration instructions later this year")
|
|
||||||
|
|
||||||
version.PilotEnabled = staticConfiguration.Pilot.Dashboard
|
version.PilotEnabled = staticConfiguration.Pilot.Dashboard
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +362,7 @@ func getDefaultsEntrypoints(staticConfiguration *static.Configuration) []string
|
||||||
var defaultEntryPoints []string
|
var defaultEntryPoints []string
|
||||||
for name, cfg := range staticConfiguration.EntryPoints {
|
for name, cfg := range staticConfiguration.EntryPoints {
|
||||||
// Traefik Hub entryPoint should not be part of the set of default entryPoints.
|
// Traefik Hub entryPoint should not be part of the set of default entryPoints.
|
||||||
if staticConfiguration.Hub != nil && staticConfiguration.Hub.EntryPoint == name {
|
if hub.APIEntrypoint == name || hub.TunnelEntrypoint == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ but we can suggest you start with activities such as:
|
||||||
The ability to set up a testing environment in a few minutes,
|
The ability to set up a testing environment in a few minutes,
|
||||||
using the official documentation,
|
using the official documentation,
|
||||||
is a game changer.
|
is a game changer.
|
||||||
- You will be listed on our Maintainers Github page
|
- You will be listed on our Maintainers GitHub page
|
||||||
as well as on our website in the section [maintainers](maintainers.md).
|
as well as on our website in the section [maintainers](maintainers.md).
|
||||||
- We will be promoting you on social channels (mostly on Twitter).
|
- We will be promoting you on social channels (mostly on Twitter).
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ You can install Traefik with the following flavors:
|
||||||
|
|
||||||
Choose one of the [official Docker images](https://hub.docker.com/_/traefik) and run it with one sample configuration file:
|
Choose one of the [official Docker images](https://hub.docker.com/_/traefik) and run it with one sample configuration file:
|
||||||
|
|
||||||
* [YAML](https://raw.githubusercontent.com/traefik/traefik/v2.6/traefik.sample.yml)
|
* [YAML](https://raw.githubusercontent.com/traefik/traefik/v2.7/traefik.sample.yml)
|
||||||
* [TOML](https://raw.githubusercontent.com/traefik/traefik/v2.6/traefik.sample.toml)
|
* [TOML](https://raw.githubusercontent.com/traefik/traefik/v2.7/traefik.sample.toml)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d -p 8080:8080 -p 80:80 \
|
docker run -d -p 8080:8080 -p 80:80 \
|
||||||
|
|
|
@ -165,7 +165,7 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
headers:
|
headers:
|
||||||
frameDeny: true
|
frameDeny: true
|
||||||
browserxssfilter: true
|
browserXssFilter: true
|
||||||
```
|
```
|
||||||
|
|
||||||
```yaml tab="Consul Catalog"
|
```yaml tab="Consul Catalog"
|
||||||
|
@ -192,14 +192,14 @@ http:
|
||||||
testHeader:
|
testHeader:
|
||||||
headers:
|
headers:
|
||||||
frameDeny: true
|
frameDeny: true
|
||||||
browserxssfilter: true
|
browserXssFilter: true
|
||||||
```
|
```
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
```toml tab="File (TOML)"
|
||||||
[http.middlewares]
|
[http.middlewares]
|
||||||
[http.middlewares.testHeader.headers]
|
[http.middlewares.testHeader.headers]
|
||||||
frameDeny = true
|
frameDeny = true
|
||||||
browserxssfilter = true
|
browserXssFilter = true
|
||||||
```
|
```
|
||||||
|
|
||||||
### CORS Headers
|
### CORS Headers
|
||||||
|
|
|
@ -109,7 +109,7 @@ Then any router can refer to an instance of the wanted middleware.
|
||||||
|
|
||||||
```yaml tab="K8s IngressRoute"
|
```yaml tab="K8s IngressRoute"
|
||||||
# The definitions below require the definitions for the Middleware and IngressRoute kinds.
|
# The definitions below require the definitions for the Middleware and IngressRoute kinds.
|
||||||
# https://doc.traefik.io/traefik/v2.6/reference/dynamic-configuration/kubernetes-crd/#definitions
|
# https://doc.traefik.io/traefik/v2.7/reference/dynamic-configuration/kubernetes-crd/#definitions
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
kind: Middleware
|
kind: Middleware
|
||||||
metadata:
|
metadata:
|
||||||
|
|
|
@ -458,14 +458,9 @@ the value for the method label becomes `EXTENSION_METHOD`, instead of the reques
|
||||||
|
|
||||||
In `v2.6.1`, the Datadog tags added to a span changed from `service.name` to `traefik.service.name` and from `router.name` to `traefik.router.name`.
|
In `v2.6.1`, the Datadog tags added to a span changed from `service.name` to `traefik.service.name` and from `router.name` to `traefik.router.name`.
|
||||||
|
|
||||||
## v2.7
|
|
||||||
|
|
||||||
### Traefik Pilot
|
|
||||||
|
|
||||||
In `v2.7`, the `pilot.token` and `pilot.dashboard` options are deprecated.
|
|
||||||
Please check the [feature deprecation page](../deprecation/features.md) and our Blog for migration instructions later this year.
|
|
||||||
|
|
||||||
## v2.8
|
## v2.8
|
||||||
|
|
||||||
|
### TLS client authentication
|
||||||
|
|
||||||
In `v2.8`, the `caOptional` option is deprecated as TLS client authentication is a server side option.
|
In `v2.8`, the `caOptional` option is deprecated as TLS client authentication is a server side option.
|
||||||
This option available in the ForwardAuth middleware, as well as in the HTTP, Consul, Etcd, Redis, ZooKeeper, Marathon, Consul Catalog, and Docker providers has no effect and must not be used anymore.
|
This option available in the ForwardAuth middleware, as well as in the HTTP, Consul, Etcd, Redis, ZooKeeper, Marathon, Consul Catalog, and Docker providers has no effect and must not be used anymore.
|
||||||
|
|
|
@ -5,11 +5,6 @@ description: "Learn how to connect Traefik Proxy with Pilot, a SaaS platform tha
|
||||||
|
|
||||||
# Plugins and Traefik Pilot
|
# Plugins and Traefik Pilot
|
||||||
|
|
||||||
!!! warning "Traefik Pilot Deprecation"
|
|
||||||
|
|
||||||
Traefik Pilot is deprecated and will be removed soon.
|
|
||||||
Please check our Blog for migration instructions later this year.
|
|
||||||
|
|
||||||
Traefik Pilot is a software-as-a-service (SaaS) platform that connects to Traefik to extend its capabilities.
|
Traefik Pilot is a software-as-a-service (SaaS) platform that connects to Traefik to extend its capabilities.
|
||||||
It offers a number of features to enhance observability and control of Traefik through a global control plane and dashboard, including:
|
It offers a number of features to enhance observability and control of Traefik through a global control plane and dashboard, including:
|
||||||
|
|
||||||
|
|
|
@ -500,4 +500,4 @@ providers:
|
||||||
### Further
|
### Further
|
||||||
|
|
||||||
To learn more about the various aspects of the Ingress specification that Traefik supports,
|
To learn more about the various aspects of the Ingress specification that Traefik supports,
|
||||||
many examples of Ingresses definitions are located in the test [examples](https://github.com/traefik/traefik/tree/v2.6/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository.
|
many examples of Ingresses definitions are located in the test [examples](https://github.com/traefik/traefik/tree/v2.7/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository.
|
||||||
|
|
|
@ -225,9 +225,6 @@ The maximal depth of DNS recursive resolving (Default: ```5```)
|
||||||
`--hub`:
|
`--hub`:
|
||||||
Traefik Hub configuration. (Default: ```false```)
|
Traefik Hub configuration. (Default: ```false```)
|
||||||
|
|
||||||
`--hub.entrypoint`:
|
|
||||||
Entrypoint that exposes data for Traefik Hub. It should be a dedicated one, and not used by any router. (Default: ```traefik-hub```)
|
|
||||||
|
|
||||||
`--hub.tls.ca`:
|
`--hub.tls.ca`:
|
||||||
The certificate authority authenticates the Traefik Hub Agent certificate.
|
The certificate authority authenticates the Traefik Hub Agent certificate.
|
||||||
|
|
||||||
|
|
|
@ -225,9 +225,6 @@ The maximal depth of DNS recursive resolving (Default: ```5```)
|
||||||
`TRAEFIK_HUB`:
|
`TRAEFIK_HUB`:
|
||||||
Traefik Hub configuration. (Default: ```false```)
|
Traefik Hub configuration. (Default: ```false```)
|
||||||
|
|
||||||
`TRAEFIK_HUB_ENTRYPOINT`:
|
|
||||||
Entrypoint that exposes data for Traefik Hub. It should be a dedicated one, and not used by any router. (Default: ```traefik-hub```)
|
|
||||||
|
|
||||||
`TRAEFIK_HUB_TLS_CA`:
|
`TRAEFIK_HUB_TLS_CA`:
|
||||||
The certificate authority authenticates the Traefik Hub Agent certificate.
|
The certificate authority authenticates the Traefik Hub Agent certificate.
|
||||||
|
|
||||||
|
|
|
@ -432,7 +432,6 @@
|
||||||
dashboard = true
|
dashboard = true
|
||||||
|
|
||||||
[hub]
|
[hub]
|
||||||
entrypoint = "foobar"
|
|
||||||
[hub.tls]
|
[hub.tls]
|
||||||
insecure = true
|
insecure = true
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
|
|
|
@ -453,7 +453,6 @@ pilot:
|
||||||
token: foobar
|
token: foobar
|
||||||
dashboard: true
|
dashboard: true
|
||||||
hub:
|
hub:
|
||||||
entrypoint: foobar
|
|
||||||
tls:
|
tls:
|
||||||
insecure: true
|
insecure: true
|
||||||
ca: foobar
|
ca: foobar
|
||||||
|
|
|
@ -805,7 +805,7 @@ This section is a convenience to enable (permanent) redirecting of all incoming
|
||||||
|
|
||||||
??? info "`entryPoint.priority`"
|
??? info "`entryPoint.priority`"
|
||||||
|
|
||||||
_Optional, Default=1_
|
_Optional, Default=MaxInt32-1 (2147483646)_
|
||||||
|
|
||||||
Priority of the generated router.
|
Priority of the generated router.
|
||||||
|
|
||||||
|
|
|
@ -1,295 +0,0 @@
|
||||||
# Traefik Hub (Experimental)
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Once the Traefik Hub Experimental feature is enabled in Traefik,
|
|
||||||
Traefik and its local agent communicate together.
|
|
||||||
This agent can:
|
|
||||||
|
|
||||||
* get the Traefik metrics to display them in the Traefik Hub UI
|
|
||||||
* secure the Traefik routers
|
|
||||||
* provide ACME certificates to Traefik
|
|
||||||
* transfer requests from the SaaS Platform to Traefik (and then avoid the users to expose directly their infrastructure on the internet)
|
|
||||||
|
|
||||||
!!! warning "Traefik Hub EntryPoint"
|
|
||||||
|
|
||||||
When the Traefik Hub feature is enabled, Traefik exposes some services meant for the Traefik Hub Agent on a dedicated entryPoint (on port `9900` by default).
|
|
||||||
Given their sensitive nature, those services should not be publicly exposed.
|
|
||||||
Also this dedicated entryPoint, regardless of how it is created (default, or user-defined), should not be used by anything other than the Hub Agent.
|
|
||||||
|
|
||||||
!!! important "Learn More About Traefik Hub"
|
|
||||||
|
|
||||||
This section is intended only as a brief overview for Traefik users who are not familiar with Traefik Hub.
|
|
||||||
To explore all that Traefik Hub has to offer, please consult the [Traefik Hub Documentation](https://doc.traefik.io/traefik-hub).
|
|
||||||
|
|
||||||
!!! Note "Prerequisites"
|
|
||||||
|
|
||||||
* Traefik Hub is compatible with Traefik Proxy 2.7 or later.
|
|
||||||
* The Traefik Hub Agent must be installed to connect to the Traefik Hub platform.
|
|
||||||
* Activate this feature in the experimental section of the static configuration.
|
|
||||||
|
|
||||||
!!! example "Minimal Static Configuration to Activate Traefik Hub"
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
experimental:
|
|
||||||
hub: true
|
|
||||||
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
insecure: true
|
|
||||||
|
|
||||||
metrics:
|
|
||||||
prometheus: {}
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[experimental]
|
|
||||||
hub = true
|
|
||||||
|
|
||||||
[hub]
|
|
||||||
[hub.tls]
|
|
||||||
insecure = true
|
|
||||||
|
|
||||||
[metrics]
|
|
||||||
[metrics.prometheus]
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--experimental.hub
|
|
||||||
--hub.tls.insecure=true
|
|
||||||
--metrics.prometheus=true
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### `entryPoint`
|
|
||||||
|
|
||||||
_Optional, Default="traefik-hub"_
|
|
||||||
|
|
||||||
Defines the entryPoint that exposes data for Traefik Hub Agent.
|
|
||||||
|
|
||||||
!!! info
|
|
||||||
|
|
||||||
* If no entryPoint is defined, a default `traefik-hub` entryPoint is created (on port `9900`).
|
|
||||||
* If defined, the value must match an existing entryPoint name.
|
|
||||||
* This dedicated Traefik Hub entryPoint should not be used by anything other than Traefik Hub.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
entryPoints:
|
|
||||||
hub-ep: ":8000"
|
|
||||||
|
|
||||||
hub:
|
|
||||||
entryPoint: "hub-ep"
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[entryPoints.hub-ep]
|
|
||||||
address = ":8000"
|
|
||||||
|
|
||||||
[hub]
|
|
||||||
entryPoint = "hub-ep"
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--entrypoints.hub-ep.address=:8000
|
|
||||||
--hub.entrypoint=hub-ep
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tls`
|
|
||||||
|
|
||||||
_Required, Default=None_
|
|
||||||
|
|
||||||
This section allows configuring mutual TLS connection between Traefik Proxy and the Traefik Hub Agent.
|
|
||||||
The key and the certificate are the credentials for Traefik Proxy as a TLS client.
|
|
||||||
The certificate authority authenticates the Traefik Hub Agent certificate.
|
|
||||||
|
|
||||||
!!! note "Certificate Domain"
|
|
||||||
|
|
||||||
The certificate must be valid for the `proxy.traefik` domain.
|
|
||||||
|
|
||||||
!!! note "Certificates Definition"
|
|
||||||
|
|
||||||
Certificates can be defined either by their content or their path.
|
|
||||||
|
|
||||||
!!! note "Insecure Mode"
|
|
||||||
|
|
||||||
The `insecure` option is mutually exclusive with any other option.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
ca: /path/to/ca.pem
|
|
||||||
cert: /path/to/cert.pem
|
|
||||||
key: /path/to/key.pem
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[hub.tls]
|
|
||||||
ca= "/path/to/ca.pem"
|
|
||||||
cert= "/path/to/cert.pem"
|
|
||||||
key= "/path/to/key.pem"
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--hub.tls.ca=/path/to/ca.pem
|
|
||||||
--hub.tls.cert=/path/to/cert.pem
|
|
||||||
--hub.tls.key=/path/to/key.pem
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tls.ca`
|
|
||||||
|
|
||||||
The certificate authority authenticates the Traefik Hub Agent certificate.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
ca: |-
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[hub.tls]
|
|
||||||
ca = """-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----"""
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--hub.tls.ca=-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tls.cert`
|
|
||||||
|
|
||||||
The TLS certificate for Traefik Proxy as a TLS client.
|
|
||||||
|
|
||||||
!!! note "Certificate Domain"
|
|
||||||
|
|
||||||
The certificate must be valid for the `proxy.traefik` domain.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
cert: |-
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[hub.tls]
|
|
||||||
cert = """-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----"""
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--hub.tls.cert=-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tls.key`
|
|
||||||
|
|
||||||
The TLS key for Traefik Proxy as a TLS client.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
key: |-
|
|
||||||
-----BEGIN PRIVATE KEY-----
|
|
||||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgm+XJ3LVrTbbirJea
|
|
||||||
O+Crj2ADVsVHjMuiyd72VE3lgxihRANCAARlopg+PYbweeaO7qNse3684PAqo0NV
|
|
||||||
AwfmfGG0CBJRlLrWYtbBm+9SEhgs0/AfPxrHwLv5y6KEQLpPO+fwN4Z4
|
|
||||||
-----END PRIVATE KEY-----
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[hub.tls]
|
|
||||||
key = """-----BEGIN PRIVATE KEY-----
|
|
||||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgm+XJ3LVrTbbirJea
|
|
||||||
O+Crj2ADVsVHjMuiyd72VE3lgxihRANCAARlopg+PYbweeaO7qNse3684PAqo0NV
|
|
||||||
AwfmfGG0CBJRlLrWYtbBm+9SEhgs0/AfPxrHwLv5y6KEQLpPO+fwN4Z4
|
|
||||||
-----END PRIVATE KEY-----"""
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--hub.tls.key=-----BEGIN PRIVATE KEY-----
|
|
||||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgm+XJ3LVrTbbirJea
|
|
||||||
O+Crj2ADVsVHjMuiyd72VE3lgxihRANCAARlopg+PYbweeaO7qNse3684PAqo0NV
|
|
||||||
AwfmfGG0CBJRlLrWYtbBm+9SEhgs0/AfPxrHwLv5y6KEQLpPO+fwN4Z4
|
|
||||||
-----END PRIVATE KEY-----
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tls.insecure`
|
|
||||||
|
|
||||||
_Optional, Default=false_
|
|
||||||
|
|
||||||
Enables an insecure TLS connection that uses default credentials,
|
|
||||||
and which has no peer authentication between Traefik Proxy and the Traefik Hub Agent.
|
|
||||||
The `insecure` option is mutually exclusive with any other option.
|
|
||||||
|
|
||||||
!!! warning "Security Consideration"
|
|
||||||
|
|
||||||
Do not use this setup in production.
|
|
||||||
This option implies sensitive data can be exposed to potential malicious third-party programs.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
insecure: true
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[hub.tls]
|
|
||||||
insecure = true
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--hub.tls.insecure=true
|
|
||||||
```
|
|
|
@ -136,7 +136,6 @@ nav:
|
||||||
- 'InFlightConn': 'middlewares/tcp/inflightconn.md'
|
- 'InFlightConn': 'middlewares/tcp/inflightconn.md'
|
||||||
- 'IpWhitelist': 'middlewares/tcp/ipwhitelist.md'
|
- 'IpWhitelist': 'middlewares/tcp/ipwhitelist.md'
|
||||||
- 'Plugins & Traefik Pilot': 'plugins/index.md'
|
- 'Plugins & Traefik Pilot': 'plugins/index.md'
|
||||||
- 'Traefik Hub': 'traefik-hub/index.md'
|
|
||||||
- 'Operations':
|
- 'Operations':
|
||||||
- 'CLI': 'operations/cli.md'
|
- 'CLI': 'operations/cli.md'
|
||||||
- 'Dashboard' : 'operations/dashboard.md'
|
- 'Dashboard' : 'operations/dashboard.md'
|
||||||
|
|
|
@ -22,7 +22,7 @@ find "${PATH_TO_SITE}" -type f -not -path "/app/site/theme/*" \
|
||||||
--alt_ignore="/traefikproxy-vertical-logo-color.svg/" \
|
--alt_ignore="/traefikproxy-vertical-logo-color.svg/" \
|
||||||
--http_status_ignore="0,500,501,503" \
|
--http_status_ignore="0,500,501,503" \
|
||||||
--file_ignore="/404.html/" \
|
--file_ignore="/404.html/" \
|
||||||
--url_ignore="/https://groups.google.com/a/traefik.io/forum/#!forum/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/traefik\/traefik\/*edit*/,/github.com\/traefik\/traefik/,/doc.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/,/www.akamai.com/,/pilot.traefik.io\/profile/,/traefik.io/,/doc.traefik.io\/traefik-mesh/,/www.mkdocs.org/,/squidfunk.github.io/,/ietf.org/,/www.namesilo.com/,/www.youtube.com/,/www.linode.com/,/www.alibabacloud.com/,/www.cloudxns.net/,/www.vultr.com/,/vscale.io/,/hetzner.com/,/docs.github.com/,/njal.la/" \
|
--url_ignore="/https://groups.google.com/a/traefik.io/forum/#!forum/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/traefik\/traefik\/*edit*/,/github.com\/traefik\/traefik/,/doc.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/,/www.akamai.com/,/pilot.traefik.io\/profile/,/traefik.io/,/doc.traefik.io\/traefik-mesh/,/www.mkdocs.org/,/squidfunk.github.io/,/ietf.org/,/www.namesilo.com/,/www.youtube.com/,/www.linode.com/,/www.alibabacloud.com/,/www.cloudxns.net/,/www.vultr.com/,/vscale.io/,/hetzner.com/,/docs.github.com/,/njal.la/,/www.wedos.com/" \
|
||||||
'{}' 1>/dev/null
|
'{}' 1>/dev/null
|
||||||
## HTML-proofer options at https://github.com/gjtorikian/html-proofer#configuration
|
## HTML-proofer options at https://github.com/gjtorikian/html-proofer#configuration
|
||||||
|
|
||||||
|
|
264
go.mod
264
go.mod
|
@ -1,18 +1,15 @@
|
||||||
module github.com/traefik/traefik/v2
|
module github.com/traefik/traefik/v2
|
||||||
|
|
||||||
go 1.16
|
go 1.17
|
||||||
|
|
||||||
// github.com/docker/docker v17.12.0-ce-rc1.0.20200204220554-5f6d6f3f2203+incompatible => v19.03.6
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.0.0
|
github.com/BurntSushi/toml v1.0.0
|
||||||
github.com/ExpediaDotCom/haystack-client-go v0.0.0-20190315171017-e7edbdf53a61
|
github.com/ExpediaDotCom/haystack-client-go v0.0.0-20190315171017-e7edbdf53a61
|
||||||
github.com/Masterminds/sprig/v3 v3.2.2
|
github.com/Masterminds/sprig/v3 v3.2.2
|
||||||
github.com/Shopify/sarama v1.23.1 // indirect
|
|
||||||
github.com/abbot/go-http-auth v0.0.0-00010101000000-000000000000
|
github.com/abbot/go-http-auth v0.0.0-00010101000000-000000000000
|
||||||
github.com/aws/aws-sdk-go v1.39.0
|
github.com/aws/aws-sdk-go v1.39.0
|
||||||
github.com/cenkalti/backoff/v4 v4.1.1
|
github.com/cenkalti/backoff/v4 v4.1.1
|
||||||
github.com/compose-spec/compose-go v1.0.3
|
github.com/compose-spec/compose-go v1.0.3
|
||||||
github.com/containerd/containerd v1.5.9 // indirect
|
|
||||||
github.com/containous/alice v0.0.0-20181107144136-d83ebdd94cbd
|
github.com/containous/alice v0.0.0-20181107144136-d83ebdd94cbd
|
||||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
|
@ -20,7 +17,6 @@ require (
|
||||||
github.com/docker/compose/v2 v2.0.1
|
github.com/docker/compose/v2 v2.0.1
|
||||||
github.com/docker/docker v20.10.7+incompatible
|
github.com/docker/docker v20.10.7+incompatible
|
||||||
github.com/docker/go-connections v0.4.0
|
github.com/docker/go-connections v0.4.0
|
||||||
github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e // indirect
|
|
||||||
github.com/fatih/structs v1.1.0
|
github.com/fatih/structs v1.1.0
|
||||||
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
|
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
|
||||||
github.com/go-acme/lego/v4 v4.6.0
|
github.com/go-acme/lego/v4 v4.6.0
|
||||||
|
@ -29,7 +25,7 @@ require (
|
||||||
github.com/golang/protobuf v1.5.2
|
github.com/golang/protobuf v1.5.2
|
||||||
github.com/google/go-github/v28 v28.1.1
|
github.com/google/go-github/v28 v28.1.1
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.5.0
|
||||||
github.com/hashicorp/consul v1.10.4
|
github.com/hashicorp/consul v1.10.4
|
||||||
github.com/hashicorp/consul/api v1.12.0
|
github.com/hashicorp/consul/api v1.12.0
|
||||||
github.com/hashicorp/go-hclog v0.16.1
|
github.com/hashicorp/go-hclog v0.16.1
|
||||||
|
@ -50,30 +46,27 @@ require (
|
||||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5
|
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5
|
||||||
github.com/openzipkin/zipkin-go v0.2.2
|
github.com/openzipkin/zipkin-go v0.2.2
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/philhofer/fwd v1.0.0 // indirect
|
|
||||||
github.com/pires/go-proxyproto v0.6.1
|
github.com/pires/go-proxyproto v0.6.1
|
||||||
github.com/pmezard/go-difflib v1.0.0
|
github.com/pmezard/go-difflib v1.0.0
|
||||||
github.com/prometheus/client_golang v1.11.0
|
github.com/prometheus/client_golang v1.11.0
|
||||||
github.com/prometheus/client_model v0.2.0
|
github.com/prometheus/client_model v0.2.0
|
||||||
github.com/rancher/go-rancher-metadata v0.0.0-20200311180630-7f4c936a06ac
|
github.com/rancher/go-rancher-metadata v0.0.0-20200311180630-7f4c936a06ac
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.1
|
||||||
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
|
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
|
||||||
github.com/tinylib/msgp v1.0.2 // indirect
|
|
||||||
github.com/traefik/paerser v0.1.5
|
github.com/traefik/paerser v0.1.5
|
||||||
github.com/traefik/yaegi v0.11.3
|
github.com/traefik/yaegi v0.12.0
|
||||||
github.com/uber/jaeger-client-go v2.29.1+incompatible
|
github.com/uber/jaeger-client-go v2.30.0+incompatible
|
||||||
github.com/uber/jaeger-lib v2.2.0+incompatible
|
github.com/uber/jaeger-lib v2.2.0+incompatible
|
||||||
github.com/unrolled/render v1.0.2
|
github.com/unrolled/render v1.0.2
|
||||||
github.com/unrolled/secure v1.0.9
|
github.com/unrolled/secure v1.0.9
|
||||||
github.com/vdemeester/shakers v0.1.0
|
github.com/vdemeester/shakers v0.1.0
|
||||||
github.com/vulcand/oxy v1.3.0
|
github.com/vulcand/oxy v1.4.1
|
||||||
github.com/vulcand/predicate v1.1.0
|
github.com/vulcand/predicate v1.2.0
|
||||||
go.elastic.co/apm v1.13.1
|
go.elastic.co/apm v1.13.1
|
||||||
go.elastic.co/apm/module/apmot v1.13.1
|
go.elastic.co/apm/module/apmot v1.13.1
|
||||||
golang.org/x/mod v0.4.2
|
golang.org/x/mod v0.4.2
|
||||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
|
||||||
golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect
|
|
||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2
|
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2
|
||||||
google.golang.org/grpc v1.38.0
|
google.golang.org/grpc v1.38.0
|
||||||
|
@ -89,13 +82,252 @@ require (
|
||||||
sigs.k8s.io/gateway-api v0.4.0
|
sigs.k8s.io/gateway-api v0.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
cloud.google.com/go v0.81.0 // indirect
|
||||||
|
github.com/AlecAivazis/survey/v2 v2.2.3 // indirect
|
||||||
|
github.com/Azure/azure-sdk-for-go v40.3.0+incompatible // indirect
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||||
|
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest v0.11.19 // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/auth v0.5.8 // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||||
|
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||||
|
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||||
|
github.com/DataDog/datadog-go v3.2.0+incompatible // indirect
|
||||||
|
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
|
||||||
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
|
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||||
|
github.com/Microsoft/go-winio v0.4.17 // indirect
|
||||||
|
github.com/Microsoft/hcsshim v0.8.23 // indirect
|
||||||
|
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
|
||||||
|
github.com/Shopify/sarama v1.23.1 // indirect
|
||||||
|
github.com/VividCortex/gohistogram v1.0.0 // indirect
|
||||||
|
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
|
||||||
|
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1 // indirect
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1183 // indirect
|
||||||
|
github.com/armon/go-metrics v0.3.10 // indirect
|
||||||
|
github.com/armon/go-radix v1.0.0 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||||
|
github.com/buger/goterm v1.0.0 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||||
|
github.com/cheekybits/genny v1.0.0 // indirect
|
||||||
|
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible // indirect
|
||||||
|
github.com/circonus-labs/circonusllhist v0.1.3 // indirect
|
||||||
|
github.com/cloudflare/cloudflare-go v0.20.0 // indirect
|
||||||
|
github.com/compose-spec/godotenv v1.0.0 // indirect
|
||||||
|
github.com/containerd/cgroups v1.0.1 // indirect
|
||||||
|
github.com/containerd/console v1.0.2 // indirect
|
||||||
|
github.com/containerd/containerd v1.5.9 // indirect
|
||||||
|
github.com/containerd/continuity v0.1.0 // indirect
|
||||||
|
github.com/containerd/typeurl v1.0.2 // indirect
|
||||||
|
github.com/coreos/go-semver v0.3.0 // indirect
|
||||||
|
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||||
|
github.com/cpu/goacmedns v0.1.1 // indirect
|
||||||
|
github.com/deepmap/oapi-codegen v1.8.2 // indirect
|
||||||
|
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||||
|
github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e // indirect
|
||||||
|
github.com/dnsimple/dnsimple-go v0.70.1 // indirect
|
||||||
|
github.com/docker/buildx v0.5.2-0.20210422185057-908a856079fc // indirect
|
||||||
|
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||||
|
github.com/docker/docker-credential-helpers v0.6.4-0.20210125172408-38bea2ce277a // indirect
|
||||||
|
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||||
|
github.com/docker/go-metrics v0.0.1 // indirect
|
||||||
|
github.com/docker/go-units v0.4.0 // indirect
|
||||||
|
github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e // indirect
|
||||||
|
github.com/elastic/go-licenser v0.3.1 // indirect
|
||||||
|
github.com/elastic/go-sysinfo v1.1.1 // indirect
|
||||||
|
github.com/elastic/go-windows v1.0.0 // indirect
|
||||||
|
github.com/evanphx/json-patch v4.11.0+incompatible // indirect
|
||||||
|
github.com/exoscale/egoscale v0.67.0 // indirect
|
||||||
|
github.com/fatih/color v1.12.0 // indirect
|
||||||
|
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
|
github.com/fvbommel/sortorder v1.0.1 // indirect
|
||||||
|
github.com/go-errors/errors v1.0.1 // indirect
|
||||||
|
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||||
|
github.com/go-logr/logr v0.4.0 // indirect
|
||||||
|
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 // indirect
|
||||||
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||||
|
github.com/go-zookeeper/zk v1.0.2 // indirect
|
||||||
|
github.com/gofrs/flock v0.8.0 // indirect
|
||||||
|
github.com/gofrs/uuid v3.3.0+incompatible // indirect
|
||||||
|
github.com/gogo/googleapis v1.4.0 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
|
github.com/golang/snappy v0.0.3 // indirect
|
||||||
|
github.com/google/btree v1.0.1 // indirect
|
||||||
|
github.com/google/go-cmp v0.5.6 // indirect
|
||||||
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
|
github.com/google/uuid v1.2.0 // indirect
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
|
||||||
|
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||||
|
github.com/gophercloud/gophercloud v0.16.0 // indirect
|
||||||
|
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae // indirect
|
||||||
|
github.com/gorilla/context v1.1.1 // indirect
|
||||||
|
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf // indirect
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 // indirect
|
||||||
|
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
|
||||||
|
github.com/hashicorp/consul/sdk v0.8.0 // indirect
|
||||||
|
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
|
||||||
|
github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
|
||||||
|
github.com/hashicorp/go-msgpack v0.5.5 // indirect
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2 // indirect
|
||||||
|
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/hashicorp/memberlist v0.3.0 // indirect
|
||||||
|
github.com/hashicorp/raft v1.3.2 // indirect
|
||||||
|
github.com/hashicorp/raft-autopilot v0.1.5 // indirect
|
||||||
|
github.com/hashicorp/serf v0.9.6 // indirect
|
||||||
|
github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493 // indirect
|
||||||
|
github.com/huandu/xstrings v1.3.1 // indirect
|
||||||
|
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
|
||||||
|
github.com/imdario/mergo v0.3.12 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
|
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
|
||||||
|
github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect
|
||||||
|
github.com/jaguilar/vt100 v0.0.0-20150826170717-2703a27b14ea // indirect
|
||||||
|
github.com/jarcoal/httpmock v1.0.6 // indirect
|
||||||
|
github.com/jcchavezs/porto v0.1.0 // indirect
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect
|
||||||
|
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.11 // indirect
|
||||||
|
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect
|
||||||
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
|
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b // indirect
|
||||||
|
github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect
|
||||||
|
github.com/labbsr0x/goh v1.0.1 // indirect
|
||||||
|
github.com/linode/linodego v0.31.1 // indirect
|
||||||
|
github.com/liquidweb/go-lwApi v0.0.5 // indirect
|
||||||
|
github.com/liquidweb/liquidweb-cli v0.6.9 // indirect
|
||||||
|
github.com/liquidweb/liquidweb-go v1.6.3 // indirect
|
||||||
|
github.com/looplab/fsm v0.1.0 // indirect
|
||||||
|
github.com/mailgun/minheap v0.0.0-20170619185613-3dbe6c6bf55f // indirect
|
||||||
|
github.com/mailgun/multibuf v0.1.2 // indirect
|
||||||
|
github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 // indirect
|
||||||
|
github.com/marten-seemann/qpack v0.2.1 // indirect
|
||||||
|
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||||
|
github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect
|
||||||
|
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||||
|
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||||
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||||
|
github.com/miekg/pkcs11 v1.0.3 // indirect
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
|
github.com/mitchellh/go-testing-interface v1.14.0 // indirect
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.1 // indirect
|
||||||
|
github.com/moby/buildkit v0.8.2-0.20210401015549-df49b648c8bf // indirect
|
||||||
|
github.com/moby/locker v1.0.1 // indirect
|
||||||
|
github.com/moby/sys/mount v0.2.0 // indirect
|
||||||
|
github.com/moby/sys/mountinfo v0.4.1 // indirect
|
||||||
|
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
|
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
|
||||||
|
github.com/nrdcg/auroradns v1.0.1 // indirect
|
||||||
|
github.com/nrdcg/desec v0.6.0 // indirect
|
||||||
|
github.com/nrdcg/dnspod-go v0.4.0 // indirect
|
||||||
|
github.com/nrdcg/freemyip v0.2.0 // indirect
|
||||||
|
github.com/nrdcg/goinwx v0.8.1 // indirect
|
||||||
|
github.com/nrdcg/namesilo v0.2.1 // indirect
|
||||||
|
github.com/nrdcg/porkbun v0.1.1 // indirect
|
||||||
|
github.com/nxadm/tail v1.4.8 // indirect
|
||||||
|
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||||
|
github.com/opencontainers/runc v1.0.2 // indirect
|
||||||
|
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect
|
||||||
|
github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect
|
||||||
|
github.com/ovh/go-ovh v1.1.0 // indirect
|
||||||
|
github.com/philhofer/fwd v1.0.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pquerna/otp v1.3.0 // indirect
|
||||||
|
github.com/prometheus/common v0.26.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.6.0 // indirect
|
||||||
|
github.com/sacloud/libsacloud v1.36.2 // indirect
|
||||||
|
github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b // indirect
|
||||||
|
github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect
|
||||||
|
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f // indirect
|
||||||
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
|
||||||
|
github.com/segmentio/fasthash v1.0.3 // indirect
|
||||||
|
github.com/shopspring/decimal v1.2.0 // indirect
|
||||||
|
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
|
||||||
|
github.com/softlayer/softlayer-go v1.0.3 // indirect
|
||||||
|
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
|
||||||
|
github.com/spf13/cast v1.3.1 // indirect
|
||||||
|
github.com/spf13/cobra v1.2.1 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/stretchr/objx v0.3.0 // indirect
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.287 // indirect
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.287 // indirect
|
||||||
|
github.com/theupdateframework/notary v0.6.1 // indirect
|
||||||
|
github.com/tinylib/msgp v1.0.2 // indirect
|
||||||
|
github.com/tonistiigi/fsutil v0.0.0-20201103201449-0834f99b7b85 // indirect
|
||||||
|
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||||
|
github.com/transip/gotransip/v6 v6.6.1 // indirect
|
||||||
|
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 // indirect
|
||||||
|
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
|
||||||
|
github.com/vultr/govultr/v2 v2.7.1 // indirect
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
|
go.elastic.co/apm/module/apmhttp v1.13.1 // indirect
|
||||||
|
go.elastic.co/fastjson v1.1.0 // indirect
|
||||||
|
go.etcd.io/etcd/api/v3 v3.5.0 // indirect
|
||||||
|
go.etcd.io/etcd/client/pkg/v3 v3.5.0 // indirect
|
||||||
|
go.etcd.io/etcd/client/v3 v3.5.0 // indirect
|
||||||
|
go.opencensus.io v0.23.0 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277 // indirect
|
||||||
|
go.uber.org/zap v1.18.1 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect
|
||||||
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 // indirect
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 // indirect
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
|
golang.org/x/text v0.3.7 // indirect
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
|
google.golang.org/api v0.44.0 // indirect
|
||||||
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
|
||||||
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||||
|
gopkg.in/ns1/ns1-go.v2 v2.6.2 // indirect
|
||||||
|
gopkg.in/redis.v5 v5.2.9 // indirect
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect
|
||||||
|
k8s.io/klog/v2 v2.10.0 // indirect
|
||||||
|
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
|
||||||
|
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
// Containous forks
|
// Containous forks
|
||||||
replace (
|
replace (
|
||||||
github.com/abbot/go-http-auth => github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e
|
github.com/abbot/go-http-auth => github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e
|
||||||
github.com/go-check/check => github.com/containous/check v0.0.0-20170915194414-ca0bf163426a
|
github.com/go-check/check => github.com/containous/check v0.0.0-20170915194414-ca0bf163426a
|
||||||
github.com/gorilla/mux => github.com/containous/mux v0.0.0-20220113180107-8ffa4f6d063c
|
github.com/gorilla/mux => github.com/containous/mux v0.0.0-20220113180107-8ffa4f6d063c
|
||||||
github.com/mailgun/minheap => github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595
|
github.com/mailgun/minheap => github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595
|
||||||
github.com/mailgun/multibuf => github.com/containous/multibuf v0.0.0-20220419123348-2d0b12e116c6
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://github.com/docker/compose/blob/e44222664abd07ce1d1fe6796d84d93cbc7468c3/go.mod#L131
|
// https://github.com/docker/compose/blob/e44222664abd07ce1d1fe6796d84d93cbc7468c3/go.mod#L131
|
||||||
|
|
71
go.sum
71
go.sum
|
@ -125,6 +125,8 @@ github.com/ExpediaDotCom/haystack-client-go v0.0.0-20190315171017-e7edbdf53a61 h
|
||||||
github.com/ExpediaDotCom/haystack-client-go v0.0.0-20190315171017-e7edbdf53a61/go.mod h1:62qWSDaEI0BLykU+zQza5CAKgW0lOy9oBSz3/DvYz4w=
|
github.com/ExpediaDotCom/haystack-client-go v0.0.0-20190315171017-e7edbdf53a61/go.mod h1:62qWSDaEI0BLykU+zQza5CAKgW0lOy9oBSz3/DvYz4w=
|
||||||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
||||||
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
||||||
|
github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
|
||||||
|
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||||
|
@ -184,6 +186,7 @@ github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki
|
||||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=
|
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=
|
||||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
|
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
|
||||||
github.com/ahmetb/gen-crd-api-reference-docs v0.3.0/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8=
|
github.com/ahmetb/gen-crd-api-reference-docs v0.3.0/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8=
|
||||||
|
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1 h1:bLzehmpyCwQiqCE1Qe9Ny6fbFqs7hPlmo9vKv2orUxs=
|
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1 h1:bLzehmpyCwQiqCE1Qe9Ny6fbFqs7hPlmo9vKv2orUxs=
|
||||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1/go.mod h1:kX6YddBkXqqywAe8c9LyvgTCyFuZCTMF4cRPQhc3Fy8=
|
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1/go.mod h1:kX6YddBkXqqywAe8c9LyvgTCyFuZCTMF4cRPQhc3Fy8=
|
||||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||||
|
@ -426,8 +429,6 @@ github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e h1:D+uTE
|
||||||
github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e/go.mod h1:s8kLgBQolDbsJOPVIGCEEv9zGAKUUf/685Gi0Qqg8z8=
|
github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e/go.mod h1:s8kLgBQolDbsJOPVIGCEEv9zGAKUUf/685Gi0Qqg8z8=
|
||||||
github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595 h1:aPspFRO6b94To3gl4yTDOEtpjFwXI7V2W+z0JcNljQ4=
|
github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595 h1:aPspFRO6b94To3gl4yTDOEtpjFwXI7V2W+z0JcNljQ4=
|
||||||
github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595/go.mod h1:+lHFbEasIiQVGzhVDVw/cn0ZaOzde2OwNncp1NhXV4c=
|
github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595/go.mod h1:+lHFbEasIiQVGzhVDVw/cn0ZaOzde2OwNncp1NhXV4c=
|
||||||
github.com/containous/multibuf v0.0.0-20220419123348-2d0b12e116c6 h1:KzERnBo5Jn4RRKjo8hdDPS4llWjHlJtM6kfm4mRkIew=
|
|
||||||
github.com/containous/multibuf v0.0.0-20220419123348-2d0b12e116c6/go.mod h1:zkWcASFUJEst6QwCrxLdkuw1gvaKqmflEipm+iecV5M=
|
|
||||||
github.com/containous/mux v0.0.0-20220113180107-8ffa4f6d063c h1:g6JvgTtfpS6AfhRjY87NZ0g39CrNDbdm8R+1CD85Cfo=
|
github.com/containous/mux v0.0.0-20220113180107-8ffa4f6d063c h1:g6JvgTtfpS6AfhRjY87NZ0g39CrNDbdm8R+1CD85Cfo=
|
||||||
github.com/containous/mux v0.0.0-20220113180107-8ffa4f6d063c/go.mod h1:z8WW7n06n8/1xF9Jl9WmuDeZuHAhfL+bwarNjsciwwg=
|
github.com/containous/mux v0.0.0-20220113180107-8ffa4f6d063c/go.mod h1:z8WW7n06n8/1xF9Jl9WmuDeZuHAhfL+bwarNjsciwwg=
|
||||||
github.com/coredns/coredns v1.1.2/go.mod h1:zASH/MVDgR6XZTbxvOnsZfffS+31vg6Ackf/wo1+AM0=
|
github.com/coredns/coredns v1.1.2/go.mod h1:zASH/MVDgR6XZTbxvOnsZfffS+31vg6Ackf/wo1+AM0=
|
||||||
|
@ -599,6 +600,7 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||||
|
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
|
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||||
|
@ -710,6 +712,7 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
@ -843,11 +846,12 @@ github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu
|
||||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
|
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
|
||||||
github.com/gravitational/trace v0.0.0-20190726142706-a535a178675f h1:68WxnfBzJRYktZ30fmIjGQ74RsXYLoeH2/NITPktTMY=
|
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf h1:C1GPyPJrOlJlIrcaBBiBpDsqZena2Ks8spa5xZqr1XQ=
|
||||||
github.com/gravitational/trace v0.0.0-20190726142706-a535a178675f/go.mod h1:RvdOUHE4SHqR3oXlFFKnGzms8a5dugHygGw1bqDstYI=
|
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf/go.mod h1:zXqxTI6jXDdKnlf8s+nT+3c8LrwUEy3yNpO4XJL90lA=
|
||||||
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
@ -1037,8 +1041,9 @@ github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVz
|
||||||
github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
|
github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
|
||||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
|
||||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
||||||
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
|
||||||
|
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA=
|
github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA=
|
||||||
github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f/go.mod h1:KDSfL7qe5ZfQqvlDMkVjCztbmcpp/c8M77vhQP8ZPvk=
|
github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f/go.mod h1:KDSfL7qe5ZfQqvlDMkVjCztbmcpp/c8M77vhQP8ZPvk=
|
||||||
|
@ -1059,6 +1064,7 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
|
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
|
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
|
||||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||||
|
@ -1133,6 +1139,8 @@ github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
|
||||||
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||||
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
||||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||||
|
github.com/mailgun/multibuf v0.1.2 h1:QE9kE27lK6LFZB4aYNVtUPlWVHVCT0zpgUr2uoq/+jk=
|
||||||
|
github.com/mailgun/multibuf v0.1.2/go.mod h1:E+sUhIy69qgT6EM57kCPdUTlHnjTuxQBO/yf6af9Hes=
|
||||||
github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 h1:Kg/NPZLLC3aAFr1YToMs98dbCdhootQ1hZIvZU28hAQ=
|
github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 h1:Kg/NPZLLC3aAFr1YToMs98dbCdhootQ1hZIvZU28hAQ=
|
||||||
github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51/go.mod h1:RYmqHbhWwIz3z9eVmQ2rx82rulEMG0t+Q1bzfc9DYN4=
|
github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51/go.mod h1:RYmqHbhWwIz3z9eVmQ2rx82rulEMG0t+Q1bzfc9DYN4=
|
||||||
github.com/mailgun/ttlmap v0.0.0-20170619185759-c1c17f74874f h1:ZZYhg16XocqSKPGNQAe0aeweNtFxuedbwwb4fSlg7h4=
|
github.com/mailgun/ttlmap v0.0.0-20170619185759-c1c17f74874f h1:ZZYhg16XocqSKPGNQAe0aeweNtFxuedbwwb4fSlg7h4=
|
||||||
|
@ -1627,8 +1635,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154 h1:XGopsea1Dw7ecQ8JscCNQXDGYAKDiWjDeXnpN/+BY9g=
|
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154 h1:XGopsea1Dw7ecQ8JscCNQXDGYAKDiWjDeXnpN/+BY9g=
|
||||||
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
|
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
|
||||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
|
@ -1657,8 +1666,8 @@ github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305 h1:y/1cL5AL2oRcfz
|
||||||
github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305/go.mod h1:gXOLibKqQTRAVuVZ9gX7G9Ykky8ll8yb4slxsEMoY0c=
|
github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305/go.mod h1:gXOLibKqQTRAVuVZ9gX7G9Ykky8ll8yb4slxsEMoY0c=
|
||||||
github.com/traefik/paerser v0.1.5 h1:crit7KzQ9PUWGCYu+H2acwyr7ZKb3RQDSn6iJCtxBhE=
|
github.com/traefik/paerser v0.1.5 h1:crit7KzQ9PUWGCYu+H2acwyr7ZKb3RQDSn6iJCtxBhE=
|
||||||
github.com/traefik/paerser v0.1.5/go.mod h1:Fuwl9DWJfGpZPPwZY6djYIF0vhvzhLmCizn6P66UeLY=
|
github.com/traefik/paerser v0.1.5/go.mod h1:Fuwl9DWJfGpZPPwZY6djYIF0vhvzhLmCizn6P66UeLY=
|
||||||
github.com/traefik/yaegi v0.11.3 h1:TuuIc0TC4oaWkVngjVAKkFd4fH35B0B95DmbS76uqs8=
|
github.com/traefik/yaegi v0.12.0 h1:1gSdARfQ5JB/yEvwEyy9e0AOyLuJrocGiDfkTftQpEo=
|
||||||
github.com/traefik/yaegi v0.11.3/go.mod h1:RuCwD8/wsX7b6KoQHOaIFUfuH3gQIK4KWnFFmJMw5VA=
|
github.com/traefik/yaegi v0.12.0/go.mod h1:RuCwD8/wsX7b6KoQHOaIFUfuH3gQIK4KWnFFmJMw5VA=
|
||||||
github.com/transip/gotransip/v6 v6.6.1 h1:nsCU1ErZS5G0FeOpgGXc4FsWvBff9GPswSMggsC4564=
|
github.com/transip/gotransip/v6 v6.6.1 h1:nsCU1ErZS5G0FeOpgGXc4FsWvBff9GPswSMggsC4564=
|
||||||
github.com/transip/gotransip/v6 v6.6.1/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g=
|
github.com/transip/gotransip/v6 v6.6.1/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g=
|
||||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8=
|
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8=
|
||||||
|
@ -1666,8 +1675,8 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri
|
||||||
github.com/uber-go/atomic v1.3.2 h1:Azu9lPBWRNKzYXSIwRfgRuDuS0YKsK4NFhiQv98gkxo=
|
github.com/uber-go/atomic v1.3.2 h1:Azu9lPBWRNKzYXSIwRfgRuDuS0YKsK4NFhiQv98gkxo=
|
||||||
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
||||||
github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||||
github.com/uber/jaeger-client-go v2.29.1+incompatible h1:R9ec3zO3sGpzs0abd43Y+fBZRJ9uiH6lXyR/+u6brW4=
|
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
|
||||||
github.com/uber/jaeger-client-go v2.29.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||||
github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=
|
github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=
|
||||||
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
|
@ -1703,10 +1712,10 @@ github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6Ac
|
||||||
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||||
github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
|
github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
|
||||||
github.com/vulcand/oxy v1.3.0 h1:358BVHmJNLjhOrhbjq2EVJX5NQ3HxrP0d5OyHLRliX0=
|
github.com/vulcand/oxy v1.4.1 h1:8FUsbr5xhSJqNlSrpUBcw93WuZIEI9JUyvThB9YqqF8=
|
||||||
github.com/vulcand/oxy v1.3.0/go.mod h1:hN/gw/jg+GH4A+bqvznsW26Izd4jNGV6h1z3s7drRzs=
|
github.com/vulcand/oxy v1.4.1/go.mod h1:Yq8OBb0XWU/7nPSglwUH5LS2Pcp4yvad8SVayobZbSo=
|
||||||
github.com/vulcand/predicate v1.1.0 h1:Gq/uWopa4rx/tnZu2opOSBqHK63Yqlou/SzrbwdJiNg=
|
github.com/vulcand/predicate v1.2.0 h1:uFsW1gcnnR7R+QTID+FVcs0sSYlIGntoGOTb3rQJt50=
|
||||||
github.com/vulcand/predicate v1.1.0/go.mod h1:mlccC5IRBoc2cIFmCB8ZM62I3VDb6p2GXESMHa3CnZg=
|
github.com/vulcand/predicate v1.2.0/go.mod h1:VipoNYXny6c8N381zGUWkjuuNHiRbeAZhE7Qm9c+2GA=
|
||||||
github.com/vultr/govultr/v2 v2.7.1 h1:uF9ERet++Gb+7Cqs3p1P6b6yebeaZqVd7t5P2uZCaJU=
|
github.com/vultr/govultr/v2 v2.7.1 h1:uF9ERet++Gb+7Cqs3p1P6b6yebeaZqVd7t5P2uZCaJU=
|
||||||
github.com/vultr/govultr/v2 v2.7.1/go.mod h1:BvOhVe6/ZpjwcoL6/unkdQshmbS9VGbowI4QT+3DGVU=
|
github.com/vultr/govultr/v2 v2.7.1/go.mod h1:BvOhVe6/ZpjwcoL6/unkdQshmbS9VGbowI4QT+3DGVU=
|
||||||
github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
|
github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
|
||||||
|
@ -1840,9 +1849,13 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
|
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
|
||||||
|
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||||
|
@ -1851,7 +1864,9 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
|
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
@ -1945,8 +1960,9 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
|
||||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
|
||||||
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
@ -2093,12 +2109,14 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 h1:8IVLkfbr2cLhv0a/vKq4UFUcJym8RmDoDboxCFWEjYE=
|
||||||
|
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
|
|
||||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -2107,8 +2125,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
@ -2121,12 +2140,14 @@ golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
@ -2198,6 +2219,11 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
|
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
|
||||||
|
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||||
|
gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM=
|
||||||
|
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||||
|
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||||
|
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
|
||||||
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
|
@ -2506,6 +2532,7 @@ launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80
|
||||||
mvdan.cc/xurls/v2 v2.1.0 h1:KaMb5GLhlcSX+e+qhbRJODnUUBvlw01jt4yrjFIHAuA=
|
mvdan.cc/xurls/v2 v2.1.0 h1:KaMb5GLhlcSX+e+qhbRJODnUUBvlw01jt4yrjFIHAuA=
|
||||||
mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E=
|
mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
|
||||||
|
|
|
@ -1072,7 +1072,7 @@ func (s *HTTPSSuite) TestEntryPointHttpsRedirectAndPathModification(c *check.C)
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
|
|
||||||
location := resp.Header.Get("Location")
|
location := resp.Header.Get("Location")
|
||||||
expected := fmt.Sprintf("https://%s:8443%s", host, test.path)
|
expected := "https://" + net.JoinHostPort(host, "8443") + test.path
|
||||||
|
|
||||||
c.Assert(location, checker.Equals, expected)
|
c.Assert(location, checker.Equals, expected)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
@ -38,7 +39,8 @@ func (s *TimeoutSuite) TestForwardingTimeouts(c *check.C) {
|
||||||
c.Assert(response.StatusCode, checker.Equals, http.StatusGatewayTimeout)
|
c.Assert(response.StatusCode, checker.Equals, http.StatusGatewayTimeout)
|
||||||
|
|
||||||
// Check that timeout service is available
|
// Check that timeout service is available
|
||||||
statusURL := fmt.Sprintf("http://%s:9000/statusTest?status=200", timeoutEndpointIP)
|
statusURL := fmt.Sprintf("http://%s/statusTest?status=200",
|
||||||
|
net.JoinHostPort(timeoutEndpointIP, "9000"))
|
||||||
c.Assert(try.GetRequest(statusURL, 60*time.Second, try.StatusCodeIs(http.StatusOK)), checker.IsNil)
|
c.Assert(try.GetRequest(statusURL, 60*time.Second, try.StatusCodeIs(http.StatusOK)), checker.IsNil)
|
||||||
|
|
||||||
// This simulates a ResponseHeaderTimeout.
|
// This simulates a ResponseHeaderTimeout.
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
"github.com/traefik/traefik/v2/pkg/version"
|
"github.com/traefik/traefik/v2/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// collectorURL URL where the stats are send.
|
// collectorURL URL where the stats are sent.
|
||||||
const collectorURL = "https://collect.traefik.io/9vxmmkcdmalbdi635d4jgc5p5rx0h7h8"
|
const collectorURL = "https://collect.traefik.io/9vxmmkcdmalbdi635d4jgc5p5rx0h7h8"
|
||||||
|
|
||||||
// Collected data.
|
// Collected data.
|
||||||
|
@ -30,16 +30,30 @@ type data struct {
|
||||||
|
|
||||||
// Collect anonymous data.
|
// Collect anonymous data.
|
||||||
func Collect(staticConfiguration *static.Configuration) error {
|
func Collect(staticConfiguration *static.Configuration) error {
|
||||||
anonConfig, err := redactor.Anonymize(staticConfiguration)
|
buf, err := createBody(staticConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resp, err := makeHTTPClient().Post(collectorURL, "application/json; charset=utf-8", buf)
|
||||||
|
if resp != nil {
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func createBody(staticConfiguration *static.Configuration) (*bytes.Buffer, error) {
|
||||||
|
anonConfig, err := redactor.Anonymize(staticConfiguration)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
log.WithoutContext().Infof("Anonymous stats sent to %s: %s", collectorURL, anonConfig)
|
log.WithoutContext().Infof("Anonymous stats sent to %s: %s", collectorURL, anonConfig)
|
||||||
|
|
||||||
hashConf, err := hashstructure.Hash(staticConfiguration, nil)
|
hashConf, err := hashstructure.Hash(staticConfiguration, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
data := &data{
|
data := &data{
|
||||||
|
@ -53,15 +67,10 @@ func Collect(staticConfiguration *static.Configuration) error {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
err = json.NewEncoder(buf).Encode(data)
|
err = json.NewEncoder(buf).Encode(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := makeHTTPClient().Post(collectorURL, "application/json; charset=utf-8", buf)
|
return buf, err
|
||||||
if resp != nil {
|
|
||||||
resp.Body.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHTTPClient() *http.Client {
|
func makeHTTPClient() *http.Client {
|
||||||
|
|
21
pkg/collector/collector_test.go
Normal file
21
pkg/collector/collector_test.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/traefik/traefik/v2/pkg/config/static"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_createBody(t *testing.T) {
|
||||||
|
var staticConfiguration static.Configuration
|
||||||
|
|
||||||
|
err := hydrate(&staticConfiguration)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
buffer, err := createBody(&staticConfiguration)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.NotEmpty(t, buffer)
|
||||||
|
}
|
166
pkg/collector/hydration_test.go
Normal file
166
pkg/collector/hydration_test.go
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/traefik/paerser/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
sliceItemNumber = 2
|
||||||
|
mapItemNumber = 2
|
||||||
|
defaultString = "foobar"
|
||||||
|
defaultNumber = 42
|
||||||
|
defaultBool = true
|
||||||
|
defaultMapKeyPrefix = "name"
|
||||||
|
)
|
||||||
|
|
||||||
|
func hydrate(element interface{}) error {
|
||||||
|
field := reflect.ValueOf(element)
|
||||||
|
return fill(field)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fill(field reflect.Value) error {
|
||||||
|
switch field.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
if err := setStruct(field); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case reflect.Ptr:
|
||||||
|
if err := setPointer(field); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
if err := setSlice(field); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case reflect.Map:
|
||||||
|
if err := setMap(field); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case reflect.Interface:
|
||||||
|
if err := fill(field.Elem()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
setTyped(field, defaultString)
|
||||||
|
case reflect.Int:
|
||||||
|
setTyped(field, defaultNumber)
|
||||||
|
case reflect.Int8:
|
||||||
|
setTyped(field, int8(defaultNumber))
|
||||||
|
case reflect.Int16:
|
||||||
|
setTyped(field, int16(defaultNumber))
|
||||||
|
case reflect.Int32:
|
||||||
|
setTyped(field, int32(defaultNumber))
|
||||||
|
case reflect.Int64:
|
||||||
|
switch field.Type() {
|
||||||
|
case reflect.TypeOf(types.Duration(time.Second)):
|
||||||
|
setTyped(field, int64(defaultNumber*int(time.Second)))
|
||||||
|
default:
|
||||||
|
setTyped(field, int64(defaultNumber))
|
||||||
|
}
|
||||||
|
case reflect.Uint:
|
||||||
|
setTyped(field, uint(defaultNumber))
|
||||||
|
case reflect.Uint8:
|
||||||
|
setTyped(field, uint8(defaultNumber))
|
||||||
|
case reflect.Uint16:
|
||||||
|
setTyped(field, uint16(defaultNumber))
|
||||||
|
case reflect.Uint32:
|
||||||
|
setTyped(field, uint32(defaultNumber))
|
||||||
|
case reflect.Uint64:
|
||||||
|
setTyped(field, uint64(defaultNumber))
|
||||||
|
case reflect.Bool:
|
||||||
|
setTyped(field, defaultBool)
|
||||||
|
case reflect.Float32:
|
||||||
|
setTyped(field, float32(defaultNumber))
|
||||||
|
case reflect.Float64:
|
||||||
|
setTyped(field, float64(defaultNumber))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTyped(field reflect.Value, i interface{}) {
|
||||||
|
baseValue := reflect.ValueOf(i)
|
||||||
|
if field.Kind().String() == field.Type().String() {
|
||||||
|
field.Set(baseValue)
|
||||||
|
} else {
|
||||||
|
field.Set(baseValue.Convert(field.Type()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setMap(field reflect.Value) error {
|
||||||
|
field.Set(reflect.MakeMap(field.Type()))
|
||||||
|
|
||||||
|
for i := 0; i < mapItemNumber; i++ {
|
||||||
|
baseKeyName := makeKeyName(field.Type().Elem())
|
||||||
|
key := reflect.ValueOf(fmt.Sprintf("%s%d", baseKeyName, i))
|
||||||
|
|
||||||
|
// generate value
|
||||||
|
ptrType := reflect.PtrTo(field.Type().Elem())
|
||||||
|
ptrValue := reflect.New(ptrType)
|
||||||
|
if err := fill(ptrValue); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value := ptrValue.Elem().Elem()
|
||||||
|
|
||||||
|
field.SetMapIndex(key, value)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeKeyName(typ reflect.Type) string {
|
||||||
|
switch typ.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
return typ.Elem().Name()
|
||||||
|
case reflect.String,
|
||||||
|
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||||
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||||
|
reflect.Bool, reflect.Float32, reflect.Float64:
|
||||||
|
return defaultMapKeyPrefix
|
||||||
|
default:
|
||||||
|
return typ.Name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setStruct(field reflect.Value) error {
|
||||||
|
for i := 0; i < field.NumField(); i++ {
|
||||||
|
fld := field.Field(i)
|
||||||
|
stFld := field.Type().Field(i)
|
||||||
|
|
||||||
|
if !stFld.IsExported() || fld.Kind() == reflect.Func {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := fill(fld); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setSlice(field reflect.Value) error {
|
||||||
|
field.Set(reflect.MakeSlice(field.Type(), sliceItemNumber, sliceItemNumber))
|
||||||
|
for j := 0; j < field.Len(); j++ {
|
||||||
|
if err := fill(field.Index(j)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPointer(field reflect.Value) error {
|
||||||
|
if field.IsNil() {
|
||||||
|
field.Set(reflect.New(field.Type().Elem()))
|
||||||
|
if err := fill(field.Elem()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := fill(field.Elem()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
53
pkg/config/static/hub.go
Normal file
53
pkg/config/static/hub.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package static
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/traefik/traefik/v2/pkg/log"
|
||||||
|
"github.com/traefik/traefik/v2/pkg/provider/hub"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Configuration) initHubProvider() error {
|
||||||
|
// Hub provider is an experimental feature. It requires the experimental flag to be enabled before continuing.
|
||||||
|
if c.Experimental == nil || !c.Experimental.Hub {
|
||||||
|
return errors.New("the experimental flag for Hub is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := c.EntryPoints[hub.TunnelEntrypoint]; !ok {
|
||||||
|
var ep EntryPoint
|
||||||
|
ep.SetDefaults()
|
||||||
|
ep.Address = ":9901"
|
||||||
|
c.EntryPoints[hub.TunnelEntrypoint] = &ep
|
||||||
|
log.WithoutContext().Infof("The entryPoint %q is created on port 9901 to allow exposition of services.", hub.TunnelEntrypoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Hub.TLS == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Hub.TLS.Insecure && (c.Hub.TLS.CA != "" || c.Hub.TLS.Cert != "" || c.Hub.TLS.Key != "") {
|
||||||
|
return errors.New("mTLS configuration for Hub and insecure TLS for Hub are mutually exclusive")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Hub.TLS.Insecure && (c.Hub.TLS.CA == "" || c.Hub.TLS.Cert == "" || c.Hub.TLS.Key == "") {
|
||||||
|
return errors.New("incomplete mTLS configuration for Hub")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Hub.TLS.Insecure {
|
||||||
|
log.WithoutContext().Warn("Hub is in `insecure` mode. Do not run in production with this setup.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := c.EntryPoints[hub.APIEntrypoint]; !ok {
|
||||||
|
var ep EntryPoint
|
||||||
|
ep.SetDefaults()
|
||||||
|
ep.Address = ":9900"
|
||||||
|
c.EntryPoints[hub.APIEntrypoint] = &ep
|
||||||
|
log.WithoutContext().Infof("The entryPoint %q is created on port 9900 to allow Traefik to communicate with the Hub Agent for Traefik.", hub.APIEntrypoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.EntryPoints[hub.APIEntrypoint].HTTP.TLS = &TLSConfig{
|
||||||
|
Options: "traefik-hub",
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package static
|
package static
|
||||||
|
|
||||||
// Pilot Configuration related to Traefik Pilot.
|
// Pilot Configuration related to Traefik Pilot.
|
||||||
// Deprecated.
|
|
||||||
type Pilot struct {
|
type Pilot struct {
|
||||||
Token string `description:"Traefik Pilot token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
|
Token string `description:"Traefik Pilot token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
|
||||||
Dashboard bool `description:"Enable Traefik Pilot in the dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty"`
|
Dashboard bool `description:"Enable Traefik Pilot in the dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty"`
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package static
|
package static
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
stdlog "log"
|
stdlog "log"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -78,7 +77,6 @@ type Configuration struct {
|
||||||
|
|
||||||
CertificatesResolvers map[string]CertificateResolver `description:"Certificates resolvers configuration." json:"certificatesResolvers,omitempty" toml:"certificatesResolvers,omitempty" yaml:"certificatesResolvers,omitempty" export:"true"`
|
CertificatesResolvers map[string]CertificateResolver `description:"Certificates resolvers configuration." json:"certificatesResolvers,omitempty" toml:"certificatesResolvers,omitempty" yaml:"certificatesResolvers,omitempty" export:"true"`
|
||||||
|
|
||||||
// Deprecated.
|
|
||||||
Pilot *Pilot `description:"Traefik Pilot configuration." json:"pilot,omitempty" toml:"pilot,omitempty" yaml:"pilot,omitempty" export:"true"`
|
Pilot *Pilot `description:"Traefik Pilot configuration." json:"pilot,omitempty" toml:"pilot,omitempty" yaml:"pilot,omitempty" export:"true"`
|
||||||
|
|
||||||
Hub *hub.Provider `description:"Traefik Hub configuration." json:"hub,omitempty" toml:"hub,omitempty" yaml:"hub,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
Hub *hub.Provider `description:"Traefik Hub configuration." json:"hub,omitempty" toml:"hub,omitempty" yaml:"hub,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||||
|
@ -201,7 +199,7 @@ type Providers struct {
|
||||||
// It also takes care of maintaining backwards compatibility.
|
// It also takes care of maintaining backwards compatibility.
|
||||||
func (c *Configuration) SetEffectiveConfiguration() {
|
func (c *Configuration) SetEffectiveConfiguration() {
|
||||||
// Creates the default entry point if needed
|
// Creates the default entry point if needed
|
||||||
if len(c.EntryPoints) == 0 || (c.Hub != nil && len(c.EntryPoints) == 1 && c.EntryPoints[c.Hub.EntryPoint] != nil) {
|
if !c.hasUserDefinedEntrypoint() {
|
||||||
ep := &EntryPoint{Address: ":80"}
|
ep := &EntryPoint{Address: ":80"}
|
||||||
ep.SetDefaults()
|
ep.SetDefaults()
|
||||||
// TODO: double check this tomorrow
|
// TODO: double check this tomorrow
|
||||||
|
@ -287,6 +285,21 @@ func (c *Configuration) SetEffectiveConfiguration() {
|
||||||
c.initACMEProvider()
|
c.initACMEProvider()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) hasUserDefinedEntrypoint() bool {
|
||||||
|
if len(c.EntryPoints) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch len(c.EntryPoints) {
|
||||||
|
case 1:
|
||||||
|
return c.EntryPoints[hub.TunnelEntrypoint] == nil
|
||||||
|
case 2:
|
||||||
|
return c.EntryPoints[hub.TunnelEntrypoint] == nil || c.EntryPoints[hub.APIEntrypoint] == nil
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Configuration) initACMEProvider() {
|
func (c *Configuration) initACMEProvider() {
|
||||||
for _, resolver := range c.CertificatesResolvers {
|
for _, resolver := range c.CertificatesResolvers {
|
||||||
if resolver.ACME != nil {
|
if resolver.ACME != nil {
|
||||||
|
@ -297,46 +310,6 @@ func (c *Configuration) initACMEProvider() {
|
||||||
legolog.Logger = stdlog.New(log.WithoutContext().WriterLevel(logrus.DebugLevel), "legolog: ", 0)
|
legolog.Logger = stdlog.New(log.WithoutContext().WriterLevel(logrus.DebugLevel), "legolog: ", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configuration) initHubProvider() error {
|
|
||||||
// Hub provider is an experimental feature. Require the experimental flag to be enabled before continuing.
|
|
||||||
if c.Experimental == nil || !c.Experimental.Hub {
|
|
||||||
return errors.New("experimental flag for Hub not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Hub.TLS == nil {
|
|
||||||
return errors.New("no TLS configuration defined for Hub")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Hub.TLS.Insecure && (c.Hub.TLS.CA != "" || c.Hub.TLS.Cert != "" || c.Hub.TLS.Key != "") {
|
|
||||||
return errors.New("mTLS configuration for Hub and insecure TLS for Hub are mutually exclusive")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.Hub.TLS.Insecure && (c.Hub.TLS.CA == "" || c.Hub.TLS.Cert == "" || c.Hub.TLS.Key == "") {
|
|
||||||
return errors.New("incomplete mTLS configuration for Hub")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Hub.TLS.Insecure {
|
|
||||||
log.WithoutContext().Warn("Hub is in `insecure` mode. Do not run in production with this setup.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates the internal Hub entry point if needed.
|
|
||||||
if c.Hub.EntryPoint == hub.DefaultEntryPointName {
|
|
||||||
if _, ok := c.EntryPoints[hub.DefaultEntryPointName]; !ok {
|
|
||||||
var ep EntryPoint
|
|
||||||
ep.SetDefaults()
|
|
||||||
ep.Address = ":9900"
|
|
||||||
c.EntryPoints[hub.DefaultEntryPointName] = &ep
|
|
||||||
log.WithoutContext().Infof("The entryPoint %q is created on port 9900 to allow Traefik to communicate with the Hub Agent for Traefik.", hub.DefaultEntryPointName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.EntryPoints[c.Hub.EntryPoint].HTTP.TLS = &TLSConfig{
|
|
||||||
Options: "traefik-hub",
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateConfiguration validate that configuration is coherent.
|
// ValidateConfiguration validate that configuration is coherent.
|
||||||
func (c *Configuration) ValidateConfiguration() error {
|
func (c *Configuration) ValidateConfiguration() error {
|
||||||
var acmeEmail string
|
var acmeEmail string
|
||||||
|
|
88
pkg/config/static/static_config_test.go
Normal file
88
pkg/config/static/static_config_test.go
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
package static
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/traefik/traefik/v2/pkg/provider/hub"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHasEntrypoint(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
entryPoints map[string]*EntryPoint
|
||||||
|
assert assert.BoolAssertionFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "no user defined entryPoints",
|
||||||
|
assert: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "user defined entryPoints",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
"foo": {},
|
||||||
|
},
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "user defined entryPoints + hub entryPoint (tunnel)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
"foo": {},
|
||||||
|
hub.TunnelEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "hub entryPoint (tunnel)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
hub.TunnelEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "user defined entryPoints + hub entryPoint (api)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
"foo": {},
|
||||||
|
hub.APIEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "hub entryPoint (api)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
hub.APIEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "user defined entryPoints + hub entryPoints (tunnel, api)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
"foo": {},
|
||||||
|
hub.TunnelEntrypoint: {},
|
||||||
|
hub.APIEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "hub entryPoints (tunnel, api)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
hub.TunnelEntrypoint: {},
|
||||||
|
hub.APIEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cfg := &Configuration{
|
||||||
|
EntryPoints: test.entryPoints,
|
||||||
|
}
|
||||||
|
|
||||||
|
test.assert(t, cfg.hasUserDefinedEntrypoint())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -95,32 +95,21 @@ func NewMuxer() (*Muxer, error) {
|
||||||
return &Muxer{parser: parser}, nil
|
return &Muxer{parser: parser}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match returns the handler of the first route matching the connection metadata.
|
// Match returns the handler of the first route matching the connection metadata,
|
||||||
func (m Muxer) Match(meta ConnData) tcp.Handler {
|
// and whether the match is exactly from the rule HostSNI(*).
|
||||||
|
func (m Muxer) Match(meta ConnData) (tcp.Handler, bool) {
|
||||||
for _, route := range m.routes {
|
for _, route := range m.routes {
|
||||||
if route.matchers.match(meta) {
|
if route.matchers.match(meta) {
|
||||||
return route.handler
|
return route.handler, route.catchAll
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRoute adds a new route, associated to the given handler, at the given
|
// AddRoute adds a new route, associated to the given handler, at the given
|
||||||
// priority, to the muxer.
|
// priority, to the muxer.
|
||||||
func (m *Muxer) AddRoute(rule string, priority int, handler tcp.Handler) error {
|
func (m *Muxer) AddRoute(rule string, priority int, handler tcp.Handler) error {
|
||||||
// Special case for when the catchAll fallback is present.
|
|
||||||
// When no user-defined priority is found, the lowest computable priority minus one is used,
|
|
||||||
// in order to make the fallback the last to be evaluated.
|
|
||||||
if priority == 0 && rule == "HostSNI(`*`)" {
|
|
||||||
priority = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default value, which means the user has not set it, so we'll compute it.
|
|
||||||
if priority == 0 {
|
|
||||||
priority = len(rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
parse, err := m.parser.Parse(rule)
|
parse, err := m.parser.Parse(rule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error while parsing rule %s: %w", rule, err)
|
return fmt.Errorf("error while parsing rule %s: %w", rule, err)
|
||||||
|
@ -131,16 +120,36 @@ func (m *Muxer) AddRoute(rule string, priority int, handler tcp.Handler) error {
|
||||||
return fmt.Errorf("error while parsing rule %s", rule)
|
return fmt.Errorf("error while parsing rule %s", rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ruleTree := buildTree()
|
||||||
|
|
||||||
var matchers matchersTree
|
var matchers matchersTree
|
||||||
err = addRule(&matchers, buildTree())
|
err = addRule(&matchers, ruleTree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var catchAll bool
|
||||||
|
if ruleTree.RuleLeft == nil && ruleTree.RuleRight == nil && len(ruleTree.Value) == 1 {
|
||||||
|
catchAll = ruleTree.Value[0] == "*" && strings.EqualFold(ruleTree.Matcher, "HostSNI")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for when the catchAll fallback is present.
|
||||||
|
// When no user-defined priority is found, the lowest computable priority minus one is used,
|
||||||
|
// in order to make the fallback the last to be evaluated.
|
||||||
|
if priority == 0 && catchAll {
|
||||||
|
priority = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default value, which means the user has not set it, so we'll compute it.
|
||||||
|
if priority == 0 {
|
||||||
|
priority = len(rule)
|
||||||
|
}
|
||||||
|
|
||||||
newRoute := &route{
|
newRoute := &route{
|
||||||
handler: handler,
|
handler: handler,
|
||||||
priority: priority,
|
|
||||||
matchers: matchers,
|
matchers: matchers,
|
||||||
|
catchAll: catchAll,
|
||||||
|
priority: priority,
|
||||||
}
|
}
|
||||||
m.routes = append(m.routes, newRoute)
|
m.routes = append(m.routes, newRoute)
|
||||||
|
|
||||||
|
@ -207,9 +216,10 @@ type route struct {
|
||||||
matchers matchersTree
|
matchers matchersTree
|
||||||
// handler responsible for handling the route.
|
// handler responsible for handling the route.
|
||||||
handler tcp.Handler
|
handler tcp.Handler
|
||||||
|
// catchAll indicates whether the route rule has exactly the catchAll value (HostSNI(`*`)).
|
||||||
// Used to disambiguate between two (or more) rules that would both match for a
|
catchAll bool
|
||||||
// given request.
|
// priority is used to disambiguate between two (or more) rules that would
|
||||||
|
// all match for a given request.
|
||||||
// Computed from the matching rule length, if not user-set.
|
// Computed from the matching rule length, if not user-set.
|
||||||
priority int
|
priority int
|
||||||
}
|
}
|
||||||
|
|
|
@ -474,7 +474,7 @@ func Test_addTCPRoute(t *testing.T) {
|
||||||
connData, err := NewConnData(test.serverName, conn)
|
connData, err := NewConnData(test.serverName, conn)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
matchingHandler := router.Match(connData)
|
matchingHandler, _ := router.Match(connData)
|
||||||
if test.matchErr {
|
if test.matchErr {
|
||||||
require.Nil(t, matchingHandler)
|
require.Nil(t, matchingHandler)
|
||||||
return
|
return
|
||||||
|
@ -568,6 +568,54 @@ func TestParseHostSNI(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_HostSNICatchAll(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
rule string
|
||||||
|
isCatchAll bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "HostSNI(`foobar`) is not catchAll",
|
||||||
|
rule: "HostSNI(`foobar`)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HostSNI(`*`) is catchAll",
|
||||||
|
rule: "HostSNI(`*`)",
|
||||||
|
isCatchAll: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HOSTSNI(`*`) is catchAll",
|
||||||
|
rule: "HOSTSNI(`*`)",
|
||||||
|
isCatchAll: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: `HostSNI("*") is catchAll`,
|
||||||
|
rule: `HostSNI("*")`,
|
||||||
|
isCatchAll: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
muxer, err := NewMuxer()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = muxer.AddRoute(test.rule, 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
handler, catchAll := muxer.Match(ConnData{
|
||||||
|
serverName: "foobar",
|
||||||
|
})
|
||||||
|
require.NotNil(t, handler)
|
||||||
|
assert.Equal(t, test.isCatchAll, catchAll)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_HostSNI(t *testing.T) {
|
func Test_HostSNI(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
@ -934,7 +982,7 @@ func Test_Priority(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := muxer.Match(ConnData{
|
handler, _ := muxer.Match(ConnData{
|
||||||
serverName: test.serverName,
|
serverName: test.serverName,
|
||||||
remoteIP: test.remoteIP,
|
remoteIP: test.remoteIP,
|
||||||
})
|
})
|
||||||
|
|
|
@ -538,7 +538,7 @@ func (p *Provider) addCertificateForDomain(domain types.Domain, certificate, key
|
||||||
// The second (RenewInterval) is the interval between renew attempts.
|
// The second (RenewInterval) is the interval between renew attempts.
|
||||||
func getCertificateRenewDurations(certificatesDuration int) (time.Duration, time.Duration) {
|
func getCertificateRenewDurations(certificatesDuration int) (time.Duration, time.Duration) {
|
||||||
switch {
|
switch {
|
||||||
case certificatesDuration >= 265*24: // >= 1 year
|
case certificatesDuration >= 365*24: // >= 1 year
|
||||||
return 4 * 30 * 24 * time.Hour, 7 * 24 * time.Hour // 4 month, 1 week
|
return 4 * 30 * 24 * time.Hour, 7 * 24 * time.Hour // 4 month, 1 week
|
||||||
case certificatesDuration >= 3*30*24: // >= 90 days
|
case certificatesDuration >= 3*30*24: // >= 90 days
|
||||||
return 30 * 24 * time.Hour, 24 * time.Hour // 30 days, 1 day
|
return 30 * 24 * time.Hour, 24 * time.Hour // 30 days, 1 day
|
||||||
|
|
|
@ -608,11 +608,17 @@ func Test_getCertificateRenewDurations(t *testing.T) {
|
||||||
expectRenewInterval: time.Minute,
|
expectRenewInterval: time.Minute,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "1 Year certificates: 2 months renew period, 1 week renew interval",
|
desc: "1 Year certificates: 4 months renew period, 1 week renew interval",
|
||||||
certificatesDurations: 24 * 365,
|
certificatesDurations: 24 * 365,
|
||||||
expectRenewPeriod: time.Hour * 24 * 30 * 4,
|
expectRenewPeriod: time.Hour * 24 * 30 * 4,
|
||||||
expectRenewInterval: time.Hour * 24 * 7,
|
expectRenewInterval: time.Hour * 24 * 7,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "265 Days certificates: 30 days renew period, 1 day renew interval",
|
||||||
|
certificatesDurations: 24 * 265,
|
||||||
|
expectRenewPeriod: time.Hour * 24 * 30,
|
||||||
|
expectRenewInterval: time.Hour * 24,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "90 Days certificates: 30 days renew period, 1 day renew interval",
|
desc: "90 Days certificates: 30 days renew period, 1 day renew interval",
|
||||||
certificatesDurations: 24 * 90,
|
certificatesDurations: 24 * 90,
|
||||||
|
|
|
@ -392,6 +392,13 @@ func (p *Provider) lookupEc2Instances(ctx context.Context, client *awsClient, cl
|
||||||
|
|
||||||
for _, container := range resp.ContainerInstances {
|
for _, container := range resp.ContainerInstances {
|
||||||
instanceIds[aws.StringValue(container.Ec2InstanceId)] = aws.StringValue(container.ContainerInstanceArn)
|
instanceIds[aws.StringValue(container.Ec2InstanceId)] = aws.StringValue(container.ContainerInstanceArn)
|
||||||
|
// Disallow Instance IDs of the form mi-*
|
||||||
|
// This prevents considering external instances in ECS Anywhere setups
|
||||||
|
// and getting InvalidInstanceID.Malformed error when calling the describe-instances endpoint.
|
||||||
|
if strings.HasPrefix(aws.StringValue(container.Ec2InstanceId), "mi-") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
instanceArns = append(instanceArns, container.Ec2InstanceId)
|
instanceArns = append(instanceArns, container.Ec2InstanceId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
@ -101,7 +102,7 @@ func (h *handler) handleDiscoverIP(rw http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) doDiscoveryReq(ctx context.Context, ip, port, nonce string) error {
|
func (h *handler) doDiscoveryReq(ctx context.Context, ip, port, nonce string) error {
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://%s:%s", ip, port), http.NoBody)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://%s", net.JoinHostPort(ip, port)), http.NoBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("creating request: %w", err)
|
return fmt.Errorf("creating request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,15 @@ import (
|
||||||
|
|
||||||
var _ provider.Provider = (*Provider)(nil)
|
var _ provider.Provider = (*Provider)(nil)
|
||||||
|
|
||||||
// DefaultEntryPointName is the name of the default internal entry point.
|
// Entrypoints created for Hub.
|
||||||
const DefaultEntryPointName = "traefik-hub"
|
const (
|
||||||
|
APIEntrypoint = "traefikhub-api"
|
||||||
|
TunnelEntrypoint = "traefikhub-tunl"
|
||||||
|
)
|
||||||
|
|
||||||
// Provider holds configurations of the provider.
|
// Provider holds configurations of the provider.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
EntryPoint string `description:"Entrypoint that exposes data for Traefik Hub. It should be a dedicated one, and not used by any router." json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty" export:"true"`
|
TLS *TLS `description:"TLS configuration for mTLS communication between Traefik and Hub Agent." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||||
TLS *TLS `description:"TLS configuration for mTLS communication between Traefik and Hub Agent." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
|
||||||
|
|
||||||
server *http.Server
|
server *http.Server
|
||||||
}
|
}
|
||||||
|
@ -36,11 +38,6 @@ type TLS struct {
|
||||||
Key ttls.FileOrContent `description:"The TLS key for Traefik Proxy as a TLS client." json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty" loggable:"false"`
|
Key ttls.FileOrContent `description:"The TLS key for Traefik Proxy as a TLS client." json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty" loggable:"false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaults sets the default values.
|
|
||||||
func (p *Provider) SetDefaults() {
|
|
||||||
p.EntryPoint = DefaultEntryPointName
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init the provider.
|
// Init the provider.
|
||||||
func (p *Provider) Init() error {
|
func (p *Provider) Init() error {
|
||||||
return nil
|
return nil
|
||||||
|
@ -48,10 +45,15 @@ func (p *Provider) Init() error {
|
||||||
|
|
||||||
// Provide allows the hub provider to provide configurations to traefik using the given configuration channel.
|
// Provide allows the hub provider to provide configurations to traefik using the given configuration channel.
|
||||||
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, _ *safe.Pool) error {
|
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, _ *safe.Pool) error {
|
||||||
|
if p.TLS == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("listener: %w", err)
|
return fmt.Errorf("listener: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
port := listener.Addr().(*net.TCPAddr).Port
|
port := listener.Addr().(*net.TCPAddr).Port
|
||||||
|
|
||||||
client, err := createAgentClient(p.TLS)
|
client, err := createAgentClient(p.TLS)
|
||||||
|
@ -59,7 +61,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, _ *safe.Poo
|
||||||
return fmt.Errorf("creating Hub Agent HTTP client: %w", err)
|
return fmt.Errorf("creating Hub Agent HTTP client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.server = &http.Server{Handler: newHandler(p.EntryPoint, port, configurationChan, p.TLS, client)}
|
p.server = &http.Server{Handler: newHandler(APIEntrypoint, port, configurationChan, p.TLS, client)}
|
||||||
|
|
||||||
// TODO: this is going to be leaky (because no context to make it terminate)
|
// TODO: this is going to be leaky (because no context to make it terminate)
|
||||||
// if/when Provide lifecycle differs with Traefik lifecycle.
|
// if/when Provide lifecycle differs with Traefik lifecycle.
|
||||||
|
@ -70,7 +72,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, _ *safe.Poo
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
exposeAPIAndMetrics(configurationChan, p.EntryPoint, port, p.TLS)
|
exposeAPIAndMetrics(configurationChan, APIEntrypoint, port, p.TLS)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -413,7 +413,7 @@ func getServicePort(svc *corev1.Service, port intstr.IntOrString) (*corev1.Servi
|
||||||
|
|
||||||
if hasValidPort {
|
if hasValidPort {
|
||||||
log.WithoutContext().
|
log.WithoutContext().
|
||||||
Warning("The port %d from IngressRoute doesn't match with ports defined in the ExternalName service %s/%s.", port, svc.Namespace, svc.Name)
|
Warnf("The port %s from IngressRoute doesn't match with ports defined in the ExternalName service %s/%s.", port, svc.Namespace, svc.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &corev1.ServicePort{Port: port.IntVal}, nil
|
return &corev1.ServicePort{Port: port.IntVal}, nil
|
||||||
|
|
|
@ -93,7 +93,7 @@ func (r *Router) ServeTCP(conn tcp.WriteCloser) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := r.muxerTCP.Match(connData)
|
handler, _ := r.muxerTCP.Match(connData)
|
||||||
// If there is a handler matching the connection metadata,
|
// If there is a handler matching the connection metadata,
|
||||||
// we let it handle the connection.
|
// we let it handle the connection.
|
||||||
if handler != nil {
|
if handler != nil {
|
||||||
|
@ -133,7 +133,7 @@ func (r *Router) ServeTCP(conn tcp.WriteCloser) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !tls {
|
if !tls {
|
||||||
handler := r.muxerTCP.Match(connData)
|
handler, _ := r.muxerTCP.Match(connData)
|
||||||
switch {
|
switch {
|
||||||
case handler != nil:
|
case handler != nil:
|
||||||
handler.ServeTCP(r.GetConn(conn, peeked))
|
handler.ServeTCP(r.GetConn(conn, peeked))
|
||||||
|
@ -145,20 +145,38 @@ func (r *Router) ServeTCP(conn tcp.WriteCloser) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := r.muxerTCPTLS.Match(connData)
|
// For real, the handler eventually used for HTTPS is (almost) always the same:
|
||||||
if handler != nil {
|
// it is the httpsForwarder that is used for all HTTPS connections that match
|
||||||
handler.ServeTCP(r.GetConn(conn, peeked))
|
// (which is also incidentally the same used in the last block below for 404s).
|
||||||
|
// The added value from doing Match is to find and use the specific TLS config
|
||||||
|
// (wrapped inside the returned handler) requested for the given HostSNI.
|
||||||
|
handlerHTTPS, catchAllHTTPS := r.muxerHTTPS.Match(connData)
|
||||||
|
if handlerHTTPS != nil && !catchAllHTTPS {
|
||||||
|
// In order not to depart from the behavior in 2.6, we only allow an HTTPS router
|
||||||
|
// to take precedence over a TCP-TLS router if it is _not_ an HostSNI(*) router (so
|
||||||
|
// basically any router that has a specific HostSNI based rule).
|
||||||
|
handlerHTTPS.ServeTCP(r.GetConn(conn, peeked))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// for real, the handler returned here is (almost) always the same:
|
// Contains also TCP TLS passthrough routes.
|
||||||
// it is the httpsForwarder that is used for all HTTPS connections that match
|
handlerTCPTLS, catchAllTCPTLS := r.muxerTCPTLS.Match(connData)
|
||||||
// (which is also incidentally the same used in the last block below for 404s).
|
if handlerTCPTLS != nil && !catchAllTCPTLS {
|
||||||
// The added value from doing Match, is to find and use the specific TLS config
|
handlerTCPTLS.ServeTCP(r.GetConn(conn, peeked))
|
||||||
// requested for the given HostSNI.
|
return
|
||||||
handler = r.muxerHTTPS.Match(connData)
|
}
|
||||||
if handler != nil {
|
|
||||||
handler.ServeTCP(r.GetConn(conn, peeked))
|
// Fallback on HTTPS catchAll.
|
||||||
|
// We end up here for e.g. an HTTPS router that only has a PathPrefix rule,
|
||||||
|
// which under the scenes is counted as an HostSNI(*) rule.
|
||||||
|
if handlerHTTPS != nil {
|
||||||
|
handlerHTTPS.ServeTCP(r.GetConn(conn, peeked))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback on TCP TLS catchAll.
|
||||||
|
if handlerTCPTLS != nil {
|
||||||
|
handlerTCPTLS.ServeTCP(r.GetConn(conn, peeked))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
919
pkg/server/router/tcp/router_test.go
Normal file
919
pkg/server/router/tcp/router_test.go
Normal file
|
@ -0,0 +1,919 @@
|
||||||
|
package tcp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||||
|
"github.com/traefik/traefik/v2/pkg/config/runtime"
|
||||||
|
tcpmiddleware "github.com/traefik/traefik/v2/pkg/server/middleware/tcp"
|
||||||
|
"github.com/traefik/traefik/v2/pkg/server/service/tcp"
|
||||||
|
tcp2 "github.com/traefik/traefik/v2/pkg/tcp"
|
||||||
|
traefiktls "github.com/traefik/traefik/v2/pkg/tls"
|
||||||
|
)
|
||||||
|
|
||||||
|
type applyRouter func(conf *runtime.Configuration)
|
||||||
|
|
||||||
|
type checkRouter func(addr string, timeout time.Duration) error
|
||||||
|
|
||||||
|
type httpForwarder struct {
|
||||||
|
net.Listener
|
||||||
|
connChan chan net.Conn
|
||||||
|
errChan chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
func newHTTPForwarder(ln net.Listener) *httpForwarder {
|
||||||
|
return &httpForwarder{
|
||||||
|
Listener: ln,
|
||||||
|
connChan: make(chan net.Conn),
|
||||||
|
errChan: make(chan error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the Listener.
|
||||||
|
func (h *httpForwarder) Close() error {
|
||||||
|
h.errChan <- http.ErrServerClosed
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServeTCP uses the connection to serve it later in "Accept".
|
||||||
|
func (h *httpForwarder) ServeTCP(conn tcp2.WriteCloser) {
|
||||||
|
h.connChan <- conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept retrieves a served connection in ServeTCP.
|
||||||
|
func (h *httpForwarder) Accept() (net.Conn, error) {
|
||||||
|
select {
|
||||||
|
case conn := <-h.connChan:
|
||||||
|
return conn, nil
|
||||||
|
case err := <-h.errChan:
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test_Routing aims to settle the behavior between routers of different types on the same TCP entryPoint.
|
||||||
|
// It has been introduced as a regression test following a fix on the v2.7 TCP Muxer.
|
||||||
|
//
|
||||||
|
// The routing precedence is roughly as follows:
|
||||||
|
// - TCP over HTTP
|
||||||
|
// - HTTPS over TCP-TLS
|
||||||
|
//
|
||||||
|
// Discrepancies for server sending first bytes support:
|
||||||
|
// - On v2.6, it is possible as long as you have one and only one TCP Non-TLS HostSNI(`*`) router (so called CatchAllNoTLS) defined.
|
||||||
|
// - On v2.7, it is possible as long as you have zero TLS/HTTPS router defined.
|
||||||
|
//
|
||||||
|
// Discrepancies in routing precedence between TCP and HTTP routers:
|
||||||
|
// - TCP HostSNI(`*`) and HTTP Host(`foobar`)
|
||||||
|
// - On v2.6 and v2.7, the TCP one takes precedence.
|
||||||
|
//
|
||||||
|
// - TCP ClientIP(`[::]`) and HTTP Host(`foobar`)
|
||||||
|
// - On v2.6, ClientIP matcher doesn't exist.
|
||||||
|
// - On v2.7, the TCP one takes precedence.
|
||||||
|
//
|
||||||
|
// Routing precedence between TCP-TLS and HTTPS routers (considering a request/connection with the servername "foobar"):
|
||||||
|
// - TCP-TLS HostSNI(`*`) and HTTPS Host(`foobar`)
|
||||||
|
// - On v2.6 and v2.7, the HTTPS one takes precedence.
|
||||||
|
//
|
||||||
|
// - TCP-TLS HostSNI(`foobar`) and HTTPS Host(`foobar`)
|
||||||
|
// - On v2.6 and v2.7, the HTTPS one takes precedence (overriding the TCP-TLS one in v2.6).
|
||||||
|
//
|
||||||
|
// - TCP-TLS HostSNI(`*`) and HTTPS PathPrefix(`/`)
|
||||||
|
// - On v2.6 and v2.7, the HTTPS one takes precedence (overriding the TCP-TLS one in v2.6).
|
||||||
|
//
|
||||||
|
// - TCP-TLS HostSNI(`foobar`) and HTTPS PathPrefix(`/`)
|
||||||
|
// - On v2.6 and v2.7, the TCP-TLS one takes precedence.
|
||||||
|
//
|
||||||
|
func Test_Routing(t *testing.T) {
|
||||||
|
// This listener simulates the backend service.
|
||||||
|
// It is capable of switching into server first communication mode,
|
||||||
|
// if the client takes to long to send the first bytes.
|
||||||
|
tcpBackendListener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
require.NoError(t, err)
|
||||||
|
// This allows the closing of the TCP backend listener to happen last.
|
||||||
|
t.Cleanup(func() {
|
||||||
|
tcpBackendListener.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
conn, err := tcpBackendListener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Temporary() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = conn.SetReadDeadline(time.Now().Add(200 * time.Millisecond))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, 100)
|
||||||
|
_, err = conn.Read(buf)
|
||||||
|
|
||||||
|
var opErr *net.OpError
|
||||||
|
if err == nil {
|
||||||
|
_, err = fmt.Fprint(conn, "TCP-CLIENT-FIRST")
|
||||||
|
require.NoError(t, err)
|
||||||
|
} else if errors.As(err, &opErr) && opErr.Timeout() {
|
||||||
|
_, err = fmt.Fprint(conn, "TCP-SERVER-FIRST")
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = conn.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Configuration defining the TCP backend service, used by TCP routers later.
|
||||||
|
conf := &runtime.Configuration{
|
||||||
|
TCPServices: map[string]*runtime.TCPServiceInfo{
|
||||||
|
"tcp": {
|
||||||
|
TCPService: &dynamic.TCPService{
|
||||||
|
LoadBalancer: &dynamic.TCPServersLoadBalancer{
|
||||||
|
Servers: []dynamic.TCPServer{
|
||||||
|
{
|
||||||
|
Address: tcpBackendListener.Addr().String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceManager := tcp.NewManager(conf)
|
||||||
|
|
||||||
|
// Creates the tlsManager and defines the TLS 1.0 and 1.2 TLSOptions.
|
||||||
|
tlsManager := traefiktls.NewManager()
|
||||||
|
tlsManager.UpdateConfigs(
|
||||||
|
context.Background(),
|
||||||
|
map[string]traefiktls.Store{},
|
||||||
|
map[string]traefiktls.Options{
|
||||||
|
"default": {
|
||||||
|
MaxVersion: "VersionTLS10",
|
||||||
|
},
|
||||||
|
"tls10": {
|
||||||
|
MaxVersion: "VersionTLS10",
|
||||||
|
},
|
||||||
|
"tls12": {
|
||||||
|
MinVersion: "VersionTLS12",
|
||||||
|
MaxVersion: "VersionTLS12",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]*traefiktls.CertAndStores{})
|
||||||
|
|
||||||
|
middlewaresBuilder := tcpmiddleware.NewBuilder(conf.TCPMiddlewares)
|
||||||
|
|
||||||
|
manager := NewManager(conf, serviceManager, middlewaresBuilder,
|
||||||
|
nil, nil, tlsManager)
|
||||||
|
|
||||||
|
type checkCase struct {
|
||||||
|
checkRouter
|
||||||
|
|
||||||
|
desc string
|
||||||
|
expectedError string
|
||||||
|
timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
routers []applyRouter
|
||||||
|
checks []checkCase
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "No routers",
|
||||||
|
routers: []applyRouter{},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP with client sending first bytes should fail",
|
||||||
|
checkRouter: checkTCPClientFirst,
|
||||||
|
expectedError: "i/o timeout",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP with server sending first bytes should fail",
|
||||||
|
checkRouter: checkTCPServerFirst,
|
||||||
|
expectedError: "i/o timeout",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTP request should be handled by HTTP service (404)",
|
||||||
|
checkRouter: checkHTTP,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.0 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS10,
|
||||||
|
expectedError: "i/o timeout",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.2 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS12,
|
||||||
|
// The HTTPS forwarder catches the connection with the TLS 1.0 config,
|
||||||
|
// because no matching routes are defined with the custom TLS Config.
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.0 request should be handled by HTTPS (HTTPS forwarder with tls 1.0 config) (404)",
|
||||||
|
checkRouter: checkHTTPSTLS10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.2 request should fail",
|
||||||
|
checkRouter: checkHTTPSTLS12,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Single TCP CatchAll router",
|
||||||
|
routers: []applyRouter{routerTCPCatchAll},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP with client sending first bytes should be handled by TCP service",
|
||||||
|
checkRouter: checkTCPClientFirst,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP with server sending first bytes should be handled by TCP service",
|
||||||
|
checkRouter: checkTCPServerFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Single HTTP router",
|
||||||
|
routers: []applyRouter{routerHTTP},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "HTTP request should be handled by HTTP service",
|
||||||
|
checkRouter: checkHTTP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Single TCP TLS router",
|
||||||
|
routers: []applyRouter{routerTCPTLS},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.0 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.2 connection should be handled by TCP service",
|
||||||
|
checkRouter: checkTCPTLS12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Single TCP TLS CatchAll router",
|
||||||
|
routers: []applyRouter{routerTCPTLSCatchAll},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.0 connection should be handled by TCP service",
|
||||||
|
checkRouter: checkTCPTLS10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.2 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS12,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Single HTTPS router",
|
||||||
|
routers: []applyRouter{routerHTTPS},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.0 request should fail",
|
||||||
|
checkRouter: checkHTTPSTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.2 request should be handled by HTTPS service",
|
||||||
|
checkRouter: checkHTTPSTLS12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Single HTTPS PathPrefix router",
|
||||||
|
routers: []applyRouter{routerHTTPSPathPrefix},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.0 request should be handled by HTTPS service",
|
||||||
|
checkRouter: checkHTTPSTLS10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.2 request should fail",
|
||||||
|
checkRouter: checkHTTPSTLS12,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP CatchAll router && HTTP router",
|
||||||
|
routers: []applyRouter{routerTCPCatchAll, routerHTTP},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP client sending first bytes should be handled by TCP service",
|
||||||
|
checkRouter: checkTCPClientFirst,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP server sending first bytes should be handled by TCP service",
|
||||||
|
checkRouter: checkTCPServerFirst,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTP request should fail, because handled by TCP service",
|
||||||
|
checkRouter: checkHTTP,
|
||||||
|
expectedError: "malformed HTTP response",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS CatchAll router && HTTP router",
|
||||||
|
routers: []applyRouter{routerTCPTLS, routerHTTP},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.0 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.2 connection should be handled by TCP service",
|
||||||
|
checkRouter: checkTCPTLS12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTP request should be handled by HTTP service",
|
||||||
|
checkRouter: checkHTTP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP CatchAll router && HTTPS router",
|
||||||
|
routers: []applyRouter{routerTCPCatchAll, routerHTTPS},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP client sending first bytes should be handled by TCP service",
|
||||||
|
checkRouter: checkTCPClientFirst,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP server sending first bytes should timeout on clientHello",
|
||||||
|
checkRouter: checkTCPServerFirst,
|
||||||
|
expectedError: "i/o timeout",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTP request should fail, because handled by TCP service",
|
||||||
|
checkRouter: checkHTTP,
|
||||||
|
expectedError: "malformed HTTP response",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.0 request should be handled by HTTPS service",
|
||||||
|
checkRouter: checkHTTPSTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.2 request should be handled by HTTPS service",
|
||||||
|
checkRouter: checkHTTPSTLS12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// We show that a not CatchAll HTTPS router takes priority over a TCP-TLS router.
|
||||||
|
desc: "TCP TLS router && HTTPS router",
|
||||||
|
routers: []applyRouter{routerTCPTLS, routerHTTPS},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.0 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.2 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS12,
|
||||||
|
// The connection is handled by the HTTPS router,
|
||||||
|
// which has the correct TLS config,
|
||||||
|
// but the HTTP server is detecting a malformed request which ends with a timeout.
|
||||||
|
expectedError: "i/o timeout",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.0 request should fail",
|
||||||
|
checkRouter: checkHTTPSTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.2 request should be handled by HTTPS service",
|
||||||
|
checkRouter: checkHTTPSTLS12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// We show that a not CatchAll HTTPS router takes priority over a CatchAll TCP-TLS router.
|
||||||
|
desc: "TCP TLS CatchAll router && HTTPS router",
|
||||||
|
routers: []applyRouter{routerTCPCatchAll, routerHTTPS},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.0 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.2 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS12,
|
||||||
|
// The connection is handled by the HTTPS router,
|
||||||
|
// which has the correct TLS config,
|
||||||
|
// but the HTTP server is detecting a malformed request which ends with a timeout.
|
||||||
|
expectedError: "i/o timeout",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.0 request should fail",
|
||||||
|
checkRouter: checkHTTPSTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.2 request should be handled by HTTPS service",
|
||||||
|
checkRouter: checkHTTPSTLS12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// We show that TCP-TLS router (not CatchAll) takes priority over non-Host rule HTTPS router (CatchAll).
|
||||||
|
desc: "TCP TLS router && HTTPS Path prefix router",
|
||||||
|
routers: []applyRouter{routerTCPTLS, routerHTTPSPathPrefix},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.0 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.2 connection should be handled by TCP service",
|
||||||
|
checkRouter: checkTCPTLS12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.0 request should fail",
|
||||||
|
checkRouter: checkHTTPSTLS10,
|
||||||
|
expectedError: "malformed HTTP response",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.2 should fail",
|
||||||
|
checkRouter: checkHTTPSTLS12,
|
||||||
|
expectedError: "malformed HTTP response",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS router && TCP TLS CatchAll router",
|
||||||
|
routers: []applyRouter{routerTCPTLS, routerTCPTLSCatchAll},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.0 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.2 connection should be handled by TCP service",
|
||||||
|
checkRouter: checkTCPTLS12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "All routers, all checks",
|
||||||
|
routers: []applyRouter{routerTCPCatchAll, routerHTTP, routerHTTPS, routerTCPTLS, routerTCPTLSCatchAll},
|
||||||
|
checks: []checkCase{
|
||||||
|
{
|
||||||
|
desc: "TCP client sending first bytes should be handled by TCP service",
|
||||||
|
checkRouter: checkTCPClientFirst,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP server sending first bytes should timeout on clientHello",
|
||||||
|
checkRouter: checkTCPServerFirst,
|
||||||
|
expectedError: "i/o timeout",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTP request should fail, because handled by TCP service",
|
||||||
|
checkRouter: checkHTTP,
|
||||||
|
expectedError: "malformed HTTP response",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.0 request should fail",
|
||||||
|
checkRouter: checkHTTPSTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTPS TLS 1.2 request should be handled by HTTPS service",
|
||||||
|
checkRouter: checkHTTPSTLS12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.0 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS10,
|
||||||
|
expectedError: "wrong TLS version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TCP TLS 1.2 connection should fail",
|
||||||
|
checkRouter: checkTCPTLS12,
|
||||||
|
// The connection is handled by the HTTPS router,
|
||||||
|
// witch have the correct TLS config,
|
||||||
|
// but the HTTP server is detecting a malformed request which ends with a timeout.
|
||||||
|
expectedError: "i/o timeout",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
dynConf := &runtime.Configuration{
|
||||||
|
Routers: map[string]*runtime.RouterInfo{},
|
||||||
|
TCPRouters: map[string]*runtime.TCPRouterInfo{},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, router := range test.routers {
|
||||||
|
router(dynConf)
|
||||||
|
}
|
||||||
|
|
||||||
|
router, err := manager.buildEntryPointHandler(context.Background(), dynConf.TCPRouters, dynConf.Routers, nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
epListener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// serverHTTP handler returns only the "HTTP" value as body for further checks.
|
||||||
|
serverHTTP := &http.Server{
|
||||||
|
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, err = fmt.Fprint(w, "HTTP")
|
||||||
|
require.NoError(t, err)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
stoppedHTTP := make(chan struct{})
|
||||||
|
forwarder := newHTTPForwarder(epListener)
|
||||||
|
go func() {
|
||||||
|
defer close(stoppedHTTP)
|
||||||
|
_ = serverHTTP.Serve(forwarder)
|
||||||
|
}()
|
||||||
|
|
||||||
|
router.SetHTTPForwarder(forwarder)
|
||||||
|
|
||||||
|
// serverHTTPS handler returns only the "HTTPS" value as body for further checks.
|
||||||
|
serverHTTPS := &http.Server{
|
||||||
|
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, err = fmt.Fprint(w, "HTTPS")
|
||||||
|
require.NoError(t, err)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
stoppedHTTPS := make(chan struct{})
|
||||||
|
httpsForwarder := newHTTPForwarder(epListener)
|
||||||
|
go func() {
|
||||||
|
defer close(stoppedHTTPS)
|
||||||
|
_ = serverHTTPS.Serve(httpsForwarder)
|
||||||
|
}()
|
||||||
|
|
||||||
|
router.SetHTTPSForwarder(httpsForwarder)
|
||||||
|
|
||||||
|
stoppedTCP := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer close(stoppedTCP)
|
||||||
|
for {
|
||||||
|
conn, err := epListener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tcpConn, ok := conn.(*net.TCPConn)
|
||||||
|
if !ok {
|
||||||
|
t.Error("not a write closer")
|
||||||
|
}
|
||||||
|
|
||||||
|
router.ServeTCP(tcpConn)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, check := range test.checks {
|
||||||
|
timeout := 2 * time.Second
|
||||||
|
if check.timeout > 0 {
|
||||||
|
timeout = check.timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
err := check.checkRouter(epListener.Addr().String(), timeout)
|
||||||
|
|
||||||
|
if check.expectedError != "" {
|
||||||
|
require.NotNil(t, err, check.desc)
|
||||||
|
assert.Contains(t, err.Error(), check.expectedError, check.desc)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Nil(t, err, check.desc)
|
||||||
|
}
|
||||||
|
|
||||||
|
epListener.Close()
|
||||||
|
|
||||||
|
<-stoppedTCP
|
||||||
|
|
||||||
|
serverHTTP.Close()
|
||||||
|
serverHTTPS.Close()
|
||||||
|
|
||||||
|
<-stoppedHTTP
|
||||||
|
<-stoppedHTTPS
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// routerTCPCatchAll configures a TCP CatchAll No TLS - HostSNI(`*`) router.
|
||||||
|
func routerTCPCatchAll(conf *runtime.Configuration) {
|
||||||
|
conf.TCPRouters["tcp-catchall"] = &runtime.TCPRouterInfo{
|
||||||
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "tcp",
|
||||||
|
Rule: "HostSNI(`*`)",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// routerHTTP configures an HTTP - Host(`foo.bar`) router.
|
||||||
|
func routerHTTP(conf *runtime.Configuration) {
|
||||||
|
conf.Routers["http"] = &runtime.RouterInfo{
|
||||||
|
Router: &dynamic.Router{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "http",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// routerTCPTLSCatchAll a TCP TLS CatchAll - HostSNI(`*`) router with TLS 1.0 config.
|
||||||
|
func routerTCPTLSCatchAll(conf *runtime.Configuration) {
|
||||||
|
conf.TCPRouters["tcp-tls-catchall"] = &runtime.TCPRouterInfo{
|
||||||
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "tcp",
|
||||||
|
Rule: "HostSNI(`*`)",
|
||||||
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
|
Options: "tls10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// routerTCPTLS configures a TCP TLS - HostSNI(`foo.bar`) router with TLS 1.2 config.
|
||||||
|
func routerTCPTLS(conf *runtime.Configuration) {
|
||||||
|
conf.TCPRouters["tcp-tls"] = &runtime.TCPRouterInfo{
|
||||||
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "tcp",
|
||||||
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
|
Options: "tls12",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// routerHTTPSPathPrefix configures an HTTPS - PathPrefix(`/`) router with TLS 1.0 config.
|
||||||
|
func routerHTTPSPathPrefix(conf *runtime.Configuration) {
|
||||||
|
conf.Routers["https"] = &runtime.RouterInfo{
|
||||||
|
Router: &dynamic.Router{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "http",
|
||||||
|
Rule: "PathPrefix(`/`)",
|
||||||
|
TLS: &dynamic.RouterTLSConfig{
|
||||||
|
Options: "tls10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// routerHTTPS configures an HTTPS - Host(`foo.bar`) router with TLS 1.2 config.
|
||||||
|
func routerHTTPS(conf *runtime.Configuration) {
|
||||||
|
conf.Routers["https-custom-tls"] = &runtime.RouterInfo{
|
||||||
|
Router: &dynamic.Router{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "http",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
TLS: &dynamic.RouterTLSConfig{
|
||||||
|
Options: "tls12",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkTCPClientFirst simulates a TCP client sending first bytes first.
|
||||||
|
// It returns an error if it doesn't receive the expected response.
|
||||||
|
func checkTCPClientFirst(addr string, timeout time.Duration) (err error) {
|
||||||
|
conn, err := net.Dial("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
closeErr := conn.Close()
|
||||||
|
if closeErr != nil && err == nil {
|
||||||
|
err = closeErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
fmt.Fprint(conn, "HELLO")
|
||||||
|
|
||||||
|
err = conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_, err = io.Copy(&buf, conn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(buf.String(), "TCP-CLIENT-FIRST") {
|
||||||
|
return fmt.Errorf("unexpected response: %s", buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkTCPServerFirst simulates a TCP client waiting for the server first bytes.
|
||||||
|
// It returns an error if it doesn't receive the expected response.
|
||||||
|
func checkTCPServerFirst(addr string, timeout time.Duration) (err error) {
|
||||||
|
conn, err := net.Dial("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
closeErr := conn.Close()
|
||||||
|
if closeErr != nil && err == nil {
|
||||||
|
err = closeErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_, err = io.Copy(&buf, conn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(buf.String(), "TCP-SERVER-FIRST") {
|
||||||
|
return fmt.Errorf("unexpected response: %s", buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkHTTP simulates an HTTP client.
|
||||||
|
// It returns an error if it doesn't receive the expected response.
|
||||||
|
func checkHTTP(addr string, timeout time.Duration) error {
|
||||||
|
httpClient := &http.Client{Timeout: timeout}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "http://"+addr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("Host", "foo.bar")
|
||||||
|
|
||||||
|
resp, err := httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(body), "HTTP") {
|
||||||
|
return fmt.Errorf("unexpected response: %s", string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkTCPTLS simulates a TCP client connection.
|
||||||
|
// It returns an error if it doesn't receive the expected response.
|
||||||
|
func checkTCPTLS(addr string, timeout time.Duration, tlsVersion uint16) (err error) {
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
ServerName: "foo.bar",
|
||||||
|
MinVersion: tls.VersionTLS10,
|
||||||
|
MaxVersion: tls.VersionTLS12,
|
||||||
|
}
|
||||||
|
conn, err := tls.Dial("tcp", addr, tlsConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
closeErr := conn.Close()
|
||||||
|
if closeErr != nil && err == nil {
|
||||||
|
err = closeErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if conn.ConnectionState().Version != tlsVersion {
|
||||||
|
return fmt.Errorf("wrong TLS version. wanted %X, got %X", tlsVersion, conn.ConnectionState().Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(conn, "HELLO")
|
||||||
|
|
||||||
|
err = conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_, err = io.Copy(&buf, conn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(buf.String(), "TCP-CLIENT-FIRST") {
|
||||||
|
return fmt.Errorf("unexpected response: %s", buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkTCPTLS10 simulates a TCP client connection with TLS 1.0.
|
||||||
|
// It returns an error if it doesn't receive the expected response.
|
||||||
|
func checkTCPTLS10(addr string, timeout time.Duration) error {
|
||||||
|
return checkTCPTLS(addr, timeout, tls.VersionTLS10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkTCPTLS12 simulates a TCP client connection with TLS 1.2.
|
||||||
|
// It returns an error if it doesn't receive the expected response.
|
||||||
|
func checkTCPTLS12(addr string, timeout time.Duration) error {
|
||||||
|
return checkTCPTLS(addr, timeout, tls.VersionTLS12)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkHTTPS makes an HTTPS request and checks the given TLS.
|
||||||
|
// It returns an error if it doesn't receive the expected response.
|
||||||
|
func checkHTTPS(addr string, timeout time.Duration, tlsVersion uint16) error {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "https://"+addr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("Host", "foo.bar")
|
||||||
|
|
||||||
|
httpClient := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
ServerName: "foo.bar",
|
||||||
|
MinVersion: tls.VersionTLS10,
|
||||||
|
MaxVersion: tls.VersionTLS12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Timeout: timeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.TLS.Version != tlsVersion {
|
||||||
|
return fmt.Errorf("wrong TLS version. wanted %X, got %X", tlsVersion, resp.TLS.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(body), "HTTPS") {
|
||||||
|
return fmt.Errorf("unexpected response: %s", string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkHTTPSTLS10 makes an HTTP request with TLS version 1.0.
|
||||||
|
// It returns an error if it doesn't receive the expected response.
|
||||||
|
func checkHTTPSTLS10(addr string, timeout time.Duration) error {
|
||||||
|
return checkHTTPS(addr, timeout, tls.VersionTLS10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkHTTPSTLS12 makes an HTTP request with TLS version 1.2.
|
||||||
|
// It returns an error if it doesn't receive the expected response.
|
||||||
|
func checkHTTPSTLS12(addr string, timeout time.Duration) error {
|
||||||
|
return checkHTTPS(addr, timeout, tls.VersionTLS12)
|
||||||
|
}
|
|
@ -14,33 +14,31 @@ import (
|
||||||
// Proxy forwards a TCP request to a TCP service.
|
// Proxy forwards a TCP request to a TCP service.
|
||||||
type Proxy struct {
|
type Proxy struct {
|
||||||
address string
|
address string
|
||||||
target *net.TCPAddr
|
tcpAddr *net.TCPAddr
|
||||||
terminationDelay time.Duration
|
terminationDelay time.Duration
|
||||||
proxyProtocol *dynamic.ProxyProtocol
|
proxyProtocol *dynamic.ProxyProtocol
|
||||||
refreshTarget bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProxy creates a new Proxy.
|
// NewProxy creates a new Proxy.
|
||||||
func NewProxy(address string, terminationDelay time.Duration, proxyProtocol *dynamic.ProxyProtocol) (*Proxy, error) {
|
func NewProxy(address string, terminationDelay time.Duration, proxyProtocol *dynamic.ProxyProtocol) (*Proxy, error) {
|
||||||
tcpAddr, err := net.ResolveTCPAddr("tcp", address)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if proxyProtocol != nil && (proxyProtocol.Version < 1 || proxyProtocol.Version > 2) {
|
if proxyProtocol != nil && (proxyProtocol.Version < 1 || proxyProtocol.Version > 2) {
|
||||||
return nil, fmt.Errorf("unknown proxyProtocol version: %d", proxyProtocol.Version)
|
return nil, fmt.Errorf("unknown proxyProtocol version: %d", proxyProtocol.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable the refresh of the target only if the address in not an IP
|
// Creates the tcpAddr only for IP based addresses,
|
||||||
refreshTarget := false
|
// because there is no need to resolve the name on every new connection,
|
||||||
if host, _, err := net.SplitHostPort(address); err == nil && net.ParseIP(host) == nil {
|
// and building it should happen once.
|
||||||
refreshTarget = true
|
var tcpAddr *net.TCPAddr
|
||||||
|
if host, _, err := net.SplitHostPort(address); err == nil && net.ParseIP(host) != nil {
|
||||||
|
tcpAddr, err = net.ResolveTCPAddr("tcp", address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Proxy{
|
return &Proxy{
|
||||||
address: address,
|
address: address,
|
||||||
target: tcpAddr,
|
tcpAddr: tcpAddr,
|
||||||
refreshTarget: refreshTarget,
|
|
||||||
terminationDelay: terminationDelay,
|
terminationDelay: terminationDelay,
|
||||||
proxyProtocol: proxyProtocol,
|
proxyProtocol: proxyProtocol,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -83,10 +81,14 @@ func (p *Proxy) ServeTCP(conn WriteCloser) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Proxy) dialBackend() (*net.TCPConn, error) {
|
func (p Proxy) dialBackend() (*net.TCPConn, error) {
|
||||||
if !p.refreshTarget {
|
// Dial using directly the TCPAddr for IP based addresses.
|
||||||
return net.DialTCP("tcp", nil, p.target)
|
if p.tcpAddr != nil {
|
||||||
|
return net.DialTCP("tcp", nil, p.tcpAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.WithoutContext().Debugf("Dial with lookup to address %s", p.address)
|
||||||
|
|
||||||
|
// Dial with DNS lookup for host based addresses.
|
||||||
conn, err := net.Dial("tcp", p.address)
|
conn, err := net.Dial("tcp", p.address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -176,16 +176,20 @@ func TestLookupAddress(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
address string
|
address string
|
||||||
expectRefresh bool
|
expectAddr assert.ComparisonAssertionFunc
|
||||||
|
expectRefresh assert.ValueAssertionFunc
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "IP doesn't need refresh",
|
desc: "IP doesn't need refresh",
|
||||||
address: "8.8.4.4:53",
|
address: "8.8.4.4:53",
|
||||||
|
expectAddr: assert.Equal,
|
||||||
|
expectRefresh: assert.NotNil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Hostname needs refresh",
|
desc: "Hostname needs refresh",
|
||||||
address: "dns.google:53",
|
address: "dns.google:53",
|
||||||
expectRefresh: true,
|
expectAddr: assert.NotEqual,
|
||||||
|
expectRefresh: assert.Nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,16 +201,12 @@ func TestLookupAddress(t *testing.T) {
|
||||||
proxy, err := NewProxy(test.address, 10*time.Millisecond, nil)
|
proxy, err := NewProxy(test.address, 10*time.Millisecond, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.NotNil(t, proxy.target)
|
test.expectRefresh(t, proxy.tcpAddr)
|
||||||
|
|
||||||
conn, err := proxy.dialBackend()
|
conn, err := proxy.dialBackend()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if test.expectRefresh {
|
test.expectAddr(t, test.address, conn.RemoteAddr().String())
|
||||||
assert.NotEqual(t, test.address, conn.RemoteAddr().String())
|
|
||||||
} else {
|
|
||||||
assert.Equal(t, test.address, conn.RemoteAddr().String())
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,6 +171,13 @@ func (m *Manager) Get(storeName, configName string) (*tls.Config, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if store == nil {
|
||||||
|
log.WithoutContext().Errorf("TLS: No certificate store found with this name: %q, closing connection", storeName)
|
||||||
|
|
||||||
|
// Same comment as above, as in the isACMETLS case.
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
log.WithoutContext().Debugf("Serving default certificate for request: %q", domainToCheck)
|
log.WithoutContext().Debugf("Serving default certificate for request: %q", domainToCheck)
|
||||||
return store.DefaultCertificate, nil
|
return store.DefaultCertificate, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,6 +171,36 @@ func TestManager_Get(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestManager_Get_GetCertificate(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
expectedGetConfigErr require.ErrorAssertionFunc
|
||||||
|
expectedCertificate assert.ValueAssertionFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Get a default certificate from non-existing store",
|
||||||
|
expectedGetConfigErr: require.Error,
|
||||||
|
expectedCertificate: assert.Nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsManager := NewManager()
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
config, err := tlsManager.Get("default", "foo")
|
||||||
|
test.expectedGetConfigErr(t, err)
|
||||||
|
|
||||||
|
certificate, err := config.GetCertificate(&tls.ClientHelloInfo{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
test.expectedCertificate(t, certificate)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestClientAuth(t *testing.T) {
|
func TestClientAuth(t *testing.T) {
|
||||||
tlsConfigs := map[string]Options{
|
tlsConfigs := map[string]Options{
|
||||||
"eca": {
|
"eca": {
|
||||||
|
|
|
@ -4,11 +4,11 @@ RepositoryName = "traefik"
|
||||||
OutputType = "file"
|
OutputType = "file"
|
||||||
FileName = "traefik_changelog.md"
|
FileName = "traefik_changelog.md"
|
||||||
|
|
||||||
# example new bugfix v2.6.3
|
# example new bugfix v2.6.7
|
||||||
CurrentRef = "v2.6"
|
CurrentRef = "v2.6"
|
||||||
PreviousRef = "v2.6.2"
|
PreviousRef = "v2.6.6"
|
||||||
BaseBranch = "v2.6"
|
BaseBranch = "v2.6"
|
||||||
FutureCurrentRefName = "v2.6.3"
|
FutureCurrentRefName = "v2.6.7"
|
||||||
|
|
||||||
ThresholdPreviousRef = 10
|
ThresholdPreviousRef = 10
|
||||||
ThresholdCurrentRef = 10
|
ThresholdCurrentRef = 10
|
||||||
|
|
|
@ -4,11 +4,11 @@ RepositoryName = "traefik"
|
||||||
OutputType = "file"
|
OutputType = "file"
|
||||||
FileName = "traefik_changelog.md"
|
FileName = "traefik_changelog.md"
|
||||||
|
|
||||||
# example final release of v2.6.0
|
# example final release of v2.7.0
|
||||||
CurrentRef = "v2.6"
|
CurrentRef = "v2.7"
|
||||||
PreviousRef = "v2.6.0-rc1"
|
PreviousRef = "v2.7.0-rc1"
|
||||||
BaseBranch = "v2.6"
|
BaseBranch = "v2.7"
|
||||||
FutureCurrentRefName = "v2.6.0"
|
FutureCurrentRefName = "v2.7.0"
|
||||||
|
|
||||||
ThresholdPreviousRef = 10
|
ThresholdPreviousRef = 10
|
||||||
ThresholdCurrentRef = 10
|
ThresholdCurrentRef = 10
|
||||||
|
|
|
@ -4,11 +4,11 @@ RepositoryName = "traefik"
|
||||||
OutputType = "file"
|
OutputType = "file"
|
||||||
FileName = "traefik_changelog.md"
|
FileName = "traefik_changelog.md"
|
||||||
|
|
||||||
# example final release of v2.6.0
|
# example final release of v2.7.0
|
||||||
CurrentRef = "v2.6.0-rc1"
|
CurrentRef = "v2.7.0-rc1"
|
||||||
PreviousRef = "v2.5.0-rc1"
|
PreviousRef = "v2.6.0-rc1"
|
||||||
BaseBranch = "master"
|
BaseBranch = "master"
|
||||||
FutureCurrentRefName = "v2.6.0-rc1"
|
FutureCurrentRefName = "v2.7.0-rc1"
|
||||||
|
|
||||||
ThresholdPreviousRef = 10
|
ThresholdPreviousRef = 10
|
||||||
ThresholdCurrentRef = 10
|
ThresholdCurrentRef = 10
|
||||||
|
|
|
@ -2,6 +2,8 @@ FROM node:14.16
|
||||||
# Current Active LTS release according to (https://nodejs.org/en/about/releases/)
|
# Current Active LTS release according to (https://nodejs.org/en/about/releases/)
|
||||||
|
|
||||||
ENV WEBUI_DIR /src/webui
|
ENV WEBUI_DIR /src/webui
|
||||||
|
ARG ARG_PLATFORM_URL=https://pilot.traefik.io
|
||||||
|
ENV PLATFORM_URL=${ARG_PLATFORM_URL}
|
||||||
RUN mkdir -p $WEBUI_DIR
|
RUN mkdir -p $WEBUI_DIR
|
||||||
|
|
||||||
COPY package.json $WEBUI_DIR/
|
COPY package.json $WEBUI_DIR/
|
||||||
|
|
|
@ -5,7 +5,7 @@ const folder = process.argv[2]
|
||||||
async function execute () {
|
async function execute () {
|
||||||
try {
|
try {
|
||||||
await fs.emptyDir('./static')
|
await fs.emptyDir('./static')
|
||||||
await fs.outputFile('./static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md', 'For more information show `webui/readme.md`')
|
await fs.outputFile('./static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md', 'For more information see `webui/readme.md`')
|
||||||
console.log('Deleted static folder contents!')
|
console.log('Deleted static folder contents!')
|
||||||
await fs.copy(`./dist/${folder}`, './static', { overwrite: true })
|
await fs.copy(`./dist/${folder}`, './static', { overwrite: true })
|
||||||
console.log('Installed new files in static folder!')
|
console.log('Installed new files in static folder!')
|
||||||
|
|
|
@ -118,11 +118,13 @@ module.exports = function (ctx) {
|
||||||
env: process.env.APP_ENV === 'development'
|
env: process.env.APP_ENV === 'development'
|
||||||
? { // staging:
|
? { // staging:
|
||||||
APP_ENV: JSON.stringify(process.env.APP_ENV),
|
APP_ENV: JSON.stringify(process.env.APP_ENV),
|
||||||
APP_API: JSON.stringify(process.env.APP_API || '/api')
|
APP_API: JSON.stringify(process.env.APP_API || '/api'),
|
||||||
|
PLATFORM_URL: JSON.stringify(process.env.PLATFORM_URL || 'https://pilot.traefik.io')
|
||||||
}
|
}
|
||||||
: { // production:
|
: { // production:
|
||||||
APP_ENV: JSON.stringify(process.env.APP_ENV),
|
APP_ENV: JSON.stringify(process.env.APP_ENV),
|
||||||
APP_API: JSON.stringify(process.env.APP_API || '/api')
|
APP_API: JSON.stringify(process.env.APP_API || '/api'),
|
||||||
|
PLATFORM_URL: JSON.stringify(process.env.PLATFORM_URL || 'https://pilot.traefik.io')
|
||||||
},
|
},
|
||||||
uglifyOptions: {
|
uglifyOptions: {
|
||||||
compress: {
|
compress: {
|
||||||
|
|
|
@ -1,17 +1,26 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="q-app">
|
<div id="q-app">
|
||||||
<router-view />
|
<router-view />
|
||||||
|
<platform-panel
|
||||||
|
v-if="pilotEnabled" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { APP } from './_helpers/APP'
|
import { APP } from './_helpers/APP'
|
||||||
|
import PlatformPanel from './components/platform/PlatformPanel'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
|
components: {
|
||||||
|
PlatformPanel
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters('core', { coreVersion: 'version' })
|
...mapGetters('core', { coreVersion: 'version' }),
|
||||||
|
pilotEnabled () {
|
||||||
|
return this.coreVersion.pilotEnabled
|
||||||
|
}
|
||||||
},
|
},
|
||||||
beforeCreate () {
|
beforeCreate () {
|
||||||
// Set vue instance
|
// Set vue instance
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
const APP = {
|
const APP = {
|
||||||
config: {
|
config: {
|
||||||
env: process.env.APP_ENV,
|
env: process.env.APP_ENV,
|
||||||
apiUrl: process.env.APP_API
|
apiUrl: process.env.APP_API,
|
||||||
|
platformUrl: process.env.PLATFORM_URL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
</q-tabs>
|
</q-tabs>
|
||||||
<div class="right-menu">
|
<div class="right-menu">
|
||||||
<q-tabs>
|
<q-tabs>
|
||||||
<q-btn type="a" href="https://hub.traefik.io/" target="_blank" flat no-caps label="Go to Hub Dashboard →" class="btn-menu btn-hub" />
|
|
||||||
<q-btn @click="$q.dark.toggle()" stretch flat no-caps icon="invert_colors" :label="`${$q.dark.isActive ? 'Light' : 'Dark'} theme`" class="btn-menu" />
|
<q-btn @click="$q.dark.toggle()" stretch flat no-caps icon="invert_colors" :label="`${$q.dark.isActive ? 'Light' : 'Dark'} theme`" class="btn-menu" />
|
||||||
<q-btn stretch flat icon="eva-question-mark-circle-outline">
|
<q-btn stretch flat icon="eva-question-mark-circle-outline">
|
||||||
<q-menu anchor="bottom left" auto-close>
|
<q-menu anchor="bottom left" auto-close>
|
||||||
|
@ -29,6 +28,8 @@
|
||||||
</q-menu>
|
</q-menu>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</q-tabs>
|
</q-tabs>
|
||||||
|
<platform-auth-state
|
||||||
|
v-if="pilotEnabled" />
|
||||||
</div>
|
</div>
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,10 +45,12 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import config from '../../../package'
|
import config from '../../../package'
|
||||||
|
import PlatformAuthState from '../platform/PlatformAuthState'
|
||||||
import { mapActions, mapGetters } from 'vuex'
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'NavBar',
|
name: 'NavBar',
|
||||||
|
components: { PlatformAuthState },
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters('core', { coreVersion: 'version' }),
|
...mapGetters('core', { coreVersion: 'version' }),
|
||||||
version () {
|
version () {
|
||||||
|
@ -56,6 +59,9 @@ export default {
|
||||||
? this.coreVersion.Version
|
? this.coreVersion.Version
|
||||||
: this.coreVersion.Version.substring(0, 7)
|
: this.coreVersion.Version.substring(0, 7)
|
||||||
},
|
},
|
||||||
|
pilotEnabled () {
|
||||||
|
return this.coreVersion.pilotEnabled
|
||||||
|
},
|
||||||
parsedVersion () {
|
parsedVersion () {
|
||||||
if (!this.version) {
|
if (!this.version) {
|
||||||
return 'master'
|
return 'master'
|
||||||
|
@ -138,11 +144,6 @@ export default {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-hub {
|
|
||||||
color: #0e204c;
|
|
||||||
background: #deea48;
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-item {
|
.q-item {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
82
webui/src/components/platform/PlatformAuthState.vue
Normal file
82
webui/src/components/platform/PlatformAuthState.vue
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<template>
|
||||||
|
<div class="iframe-wrapper" v-if="isOnline">
|
||||||
|
<iframe
|
||||||
|
id="platform-auth-state"
|
||||||
|
:src="iFrameUrl"
|
||||||
|
v-if="renderIrame"
|
||||||
|
v-resize="resizeOpts"
|
||||||
|
height="64px"
|
||||||
|
frameBorder="0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
|
import qs from 'query-string'
|
||||||
|
import '../../_directives/resize'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'PlatformPanel',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
renderIrame: true,
|
||||||
|
resizeOpts: {
|
||||||
|
log: false,
|
||||||
|
onMessage: ({ iframe, message }) => {
|
||||||
|
if (typeof message === 'string') {
|
||||||
|
// 1st condition for backward compatibility
|
||||||
|
if (message === 'open:profile') {
|
||||||
|
this.openPlatform('/')
|
||||||
|
} else if (message.includes('open:')) {
|
||||||
|
this.openPlatform(message.split('open:')[1])
|
||||||
|
} else if (message === 'logout') {
|
||||||
|
this.closePlatform()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.getInstanceInfos()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters('platform', { isPlatformOpen: 'isOpen', platformPath: 'path' }),
|
||||||
|
...mapGetters('core', { instanceInfos: 'version' }),
|
||||||
|
isOnline () {
|
||||||
|
return window.navigator.onLine
|
||||||
|
},
|
||||||
|
iFrameUrl () {
|
||||||
|
const instanceInfos = JSON.stringify(this.instanceInfos)
|
||||||
|
const authRedirectUrl = `${window.location.href.split('?')[0]}?platform=${this.platformPath}`
|
||||||
|
|
||||||
|
return qs.stringifyUrl({ url: `${this.platformUrl}/partials/auth-state`, query: { authRedirectUrl, instanceInfos } })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions('platform', { openPlatform: 'open' }, { closePlatform: 'close' }),
|
||||||
|
...mapActions('core', { getInstanceInfos: 'getVersion' })
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
isPlatformOpen (isOpen, wasOpen) {
|
||||||
|
if (!isOpen && wasOpen) {
|
||||||
|
this.renderIrame = false
|
||||||
|
this.$nextTick().then(() => {
|
||||||
|
this.renderIrame = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../css/sass/variables";
|
||||||
|
|
||||||
|
#platform-auth-state {
|
||||||
|
width: 1px;
|
||||||
|
min-width: 296px;
|
||||||
|
}
|
||||||
|
</style>
|
112
webui/src/components/platform/PlatformPanel.vue
Normal file
112
webui/src/components/platform/PlatformPanel.vue
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
<template>
|
||||||
|
<side-panel
|
||||||
|
:isOpen="isPlatformOpen"
|
||||||
|
@onClose="closePlatform()"
|
||||||
|
v-if="isOnline"
|
||||||
|
>
|
||||||
|
<div class="iframe-wrapper">
|
||||||
|
<iframe
|
||||||
|
id="platform-iframe"
|
||||||
|
:src="iFrameUrl"
|
||||||
|
v-resize="resizeOpts"
|
||||||
|
style="position: relative; height: 100%; width: 100%;"
|
||||||
|
frameBorder="0"
|
||||||
|
scrolling="yes"
|
||||||
|
@load="onIFrameLoad"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</side-panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
|
import qs from 'query-string'
|
||||||
|
import SidePanel from '../_commons/SidePanel'
|
||||||
|
import Helps from '../../_helpers/Helps'
|
||||||
|
import '../../_directives/resize'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'PlatformPanel',
|
||||||
|
components: {
|
||||||
|
SidePanel
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
resizeOpts: {
|
||||||
|
log: false,
|
||||||
|
resize: false,
|
||||||
|
scrolling: true,
|
||||||
|
onMessage: ({ iframe, message }) => {
|
||||||
|
if (typeof message === 'string') {
|
||||||
|
// 1st condition for backward compatibility
|
||||||
|
if (message === 'open:profile') {
|
||||||
|
this.openPlatform('/')
|
||||||
|
} else if (message.includes('open:')) {
|
||||||
|
this.openPlatform(message.split('open:')[1])
|
||||||
|
} else if (message === 'logout') {
|
||||||
|
this.closePlatform()
|
||||||
|
}
|
||||||
|
} else if (message.type) {
|
||||||
|
switch (message.type) {
|
||||||
|
case 'copy-to-clipboard':
|
||||||
|
navigator.clipboard.writeText(message.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if (message.isAuthenticated) {
|
||||||
|
this.isAuthenticated = message.isAuthenticated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.getInstanceInfos()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters('platform', { isPlatformOpen: 'isOpen', platformPath: 'path' }),
|
||||||
|
...mapGetters('core', { instanceInfos: 'version' }),
|
||||||
|
iFrameUrl () {
|
||||||
|
const instanceInfos = JSON.stringify(this.instanceInfos)
|
||||||
|
const authRedirectUrl = `${window.location.href.split('?')[0]}?platform=${this.platformPath}`
|
||||||
|
|
||||||
|
return qs.stringifyUrl({ url: `${this.platformUrl}${this.platformPath}`, query: { authRedirectUrl, instanceInfos } })
|
||||||
|
},
|
||||||
|
isOnline () {
|
||||||
|
return window.navigator.onLine
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions('platform', { openPlatform: 'open', closePlatform: 'close' }),
|
||||||
|
...mapActions('core', { getInstanceInfos: 'getVersion' })
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route (to, from) {
|
||||||
|
const wasOpen = from.query && from.query.platform
|
||||||
|
const isOpen = to.query && to.query.platform
|
||||||
|
|
||||||
|
if (!wasOpen && isOpen) {
|
||||||
|
this.openPlatform(to.query.platform)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isPlatformOpen (newValue, oldValue) {
|
||||||
|
if (newValue !== oldValue) {
|
||||||
|
document.querySelector('body').style.overflow = newValue ? 'hidden' : 'visible'
|
||||||
|
|
||||||
|
this.$router.push({
|
||||||
|
path: this.$route.path,
|
||||||
|
query: Helps.removeEmptyObjects({
|
||||||
|
...this.$route.query,
|
||||||
|
platform: this.platformPath ? this.platformPath : undefined
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.iframe-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1 +1 @@
|
||||||
For more information show `webui/readme.md`
|
For more information see `webui/readme.md`
|
Loading…
Reference in a new issue