Compare commits
30 commits
fa154de4a2
...
ca45770bbd
Author | SHA1 | Date | |
---|---|---|---|
ca45770bbd | |||
|
3174c69c66 | ||
|
f4f3dbe1f5 | ||
|
aece9a1051 | ||
|
190b9b1afa | ||
|
9befe0dd51 | ||
|
683e2ee5c6 | ||
|
21da705ec9 | ||
|
a3ac456199 | ||
|
9843757834 | ||
|
f9831f5b1b | ||
|
177c4b0ed1 | ||
|
bab48bed22 | ||
|
6cb2ff2af9 | ||
|
5e0855ecc7 | ||
|
f57cee578f | ||
|
8da38ec0a5 | ||
|
a6d462f6e8 | ||
d69e3d80af | |||
|
0eeb85d01d | ||
|
64ff214ff8 | ||
|
111f3716fa | ||
|
4e0a05406b | ||
|
39b0aa6650 | ||
|
319517adef | ||
|
7a315bb043 | ||
|
34d2a816c2 | ||
|
81ce45271d | ||
|
3a461d2f23 | ||
|
e78374aa29 |
124 changed files with 7629 additions and 1302 deletions
|
@ -1,5 +1,5 @@
|
||||||
dist/
|
dist/
|
||||||
!dist/traefik
|
!dist/**/traefik
|
||||||
site/
|
site/
|
||||||
vendor/
|
vendor/
|
||||||
.idea/
|
.idea/
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -19,3 +19,4 @@ plugins-storage/
|
||||||
plugins-local/
|
plugins-local/
|
||||||
traefik_changelog.md
|
traefik_changelog.md
|
||||||
integration/tailscale.secret
|
integration/tailscale.secret
|
||||||
|
integration/conformance-reports/
|
||||||
|
|
|
@ -280,3 +280,9 @@ issues:
|
||||||
text: 'unusedwrite: unused write to field'
|
text: 'unusedwrite: unused write to field'
|
||||||
linters:
|
linters:
|
||||||
- govet
|
- govet
|
||||||
|
- path: pkg/cli/deprecation.go
|
||||||
|
linters:
|
||||||
|
- goconst
|
||||||
|
- path: pkg/cli/loader_file.go
|
||||||
|
linters:
|
||||||
|
- goconst
|
||||||
|
|
13
Dockerfile
13
Dockerfile
|
@ -1,6 +1,13 @@
|
||||||
FROM scratch
|
# syntax=docker/dockerfile:1.2
|
||||||
COPY script/ca-certificates.crt /etc/ssl/certs/
|
FROM alpine:3.19
|
||||||
COPY dist/traefik /
|
|
||||||
|
RUN apk --no-cache --no-progress add ca-certificates tzdata \
|
||||||
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
COPY ./dist/$TARGETPLATFORM/traefik /
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
VOLUME ["/tmp"]
|
VOLUME ["/tmp"]
|
||||||
|
|
||||||
ENTRYPOINT ["/traefik"]
|
ENTRYPOINT ["/traefik"]
|
||||||
|
|
149
Makefile
149
Makefile
|
@ -7,8 +7,22 @@ VERSION := $(if $(VERSION),$(VERSION),$(VERSION_GIT))
|
||||||
|
|
||||||
GIT_BRANCH := $(subst heads/,,$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null))
|
GIT_BRANCH := $(subst heads/,,$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null))
|
||||||
|
|
||||||
|
REPONAME := $(shell echo $(REPO) | tr '[:upper:]' '[:lower:]')
|
||||||
|
BIN_NAME := traefik
|
||||||
|
CODENAME := cheddar
|
||||||
|
|
||||||
|
DATE := $(shell date -u '+%Y-%m-%d_%I:%M:%S%p')
|
||||||
|
|
||||||
|
# Default build target
|
||||||
|
GOOS := $(shell go env GOOS)
|
||||||
|
GOARCH := $(shell go env GOARCH)
|
||||||
|
|
||||||
|
LINT_EXECUTABLES = misspell shellcheck
|
||||||
|
|
||||||
|
DOCKER_BUILD_PLATFORMS ?= linux/amd64,linux/arm64
|
||||||
|
|
||||||
.PHONY: default
|
.PHONY: default
|
||||||
default: binary
|
default: generate binary
|
||||||
|
|
||||||
## Create the "dist" directory
|
## Create the "dist" directory
|
||||||
dist:
|
dist:
|
||||||
|
@ -35,43 +49,68 @@ webui/static/index.html:
|
||||||
.PHONY: generate-webui
|
.PHONY: generate-webui
|
||||||
generate-webui: webui/static/index.html
|
generate-webui: webui/static/index.html
|
||||||
|
|
||||||
|
## Generate code
|
||||||
|
.PHONY: generate
|
||||||
|
generate:
|
||||||
|
go generate
|
||||||
|
|
||||||
## Build the binary
|
## Build the binary
|
||||||
.PHONY: binary
|
.PHONY: binary
|
||||||
binary: generate-webui
|
binary: generate-webui dist
|
||||||
./script/make.sh generate binary
|
@echo SHA: $(VERSION) $(CODENAME) $(DATE)
|
||||||
|
CGO_ENABLED=0 GOGC=off GOOS=${GOOS} GOARCH=${GOARCH} go build ${FLAGS[*]} -ldflags "-s -w \
|
||||||
|
-X github.com/traefik/traefik/v3/pkg/version.Version=$(VERSION) \
|
||||||
|
-X github.com/traefik/traefik/v3/pkg/version.Codename=$(CODENAME) \
|
||||||
|
-X github.com/traefik/traefik/v3/pkg/version.BuildDate=$(DATE)" \
|
||||||
|
-installsuffix nocgo -o "./dist/${GOOS}/${GOARCH}/$(BIN_NAME)" ./cmd/traefik
|
||||||
|
|
||||||
## Build the linux binary locally
|
binary-linux-arm64: export GOOS := linux
|
||||||
.PHONY: binary-debug
|
binary-linux-arm64: export GOARCH := arm64
|
||||||
binary-debug: generate-webui
|
binary-linux-arm64:
|
||||||
GOOS=linux ./script/make.sh binary
|
@$(MAKE) binary
|
||||||
|
|
||||||
|
binary-linux-amd64: export GOOS := linux
|
||||||
|
binary-linux-amd64: export GOARCH := amd64
|
||||||
|
binary-linux-amd64:
|
||||||
|
@$(MAKE) binary
|
||||||
|
|
||||||
|
binary-windows-amd64: export GOOS := windows
|
||||||
|
binary-windows-amd64: export GOARCH := amd64
|
||||||
|
binary-windows-amd64: export BIN_NAME := traefik.exe
|
||||||
|
binary-windows-amd64:
|
||||||
|
@$(MAKE) binary
|
||||||
|
|
||||||
## Build the binary for the standard platforms (linux, darwin, windows)
|
## Build the binary for the standard platforms (linux, darwin, windows)
|
||||||
.PHONY: crossbinary-default
|
.PHONY: crossbinary-default
|
||||||
crossbinary-default: generate-webui
|
crossbinary-default: generate generate-webui
|
||||||
./script/make.sh generate crossbinary-default
|
$(CURDIR)/script/crossbinary-default.sh
|
||||||
|
|
||||||
## Build the binary for the standard platforms (linux, darwin, windows) in parallel
|
|
||||||
.PHONY: crossbinary-default-parallel
|
|
||||||
crossbinary-default-parallel:
|
|
||||||
$(MAKE) generate-webui
|
|
||||||
$(MAKE) crossbinary-default
|
|
||||||
|
|
||||||
## Run the unit and integration tests
|
## Run the unit and integration tests
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test:
|
test: test-unit test-integration
|
||||||
./script/make.sh generate test-unit binary test-integration
|
|
||||||
|
|
||||||
## Run the unit tests
|
## Run the unit tests
|
||||||
.PHONY: test-unit
|
.PHONY: test-unit
|
||||||
test-unit:
|
test-unit:
|
||||||
./script/make.sh generate test-unit
|
GOOS=$(GOOS) GOARCH=$(GOARCH) go test -cover "-coverprofile=cover.out" -v $(TESTFLAGS) ./pkg/... ./cmd/...
|
||||||
|
|
||||||
## Run the integration tests
|
## Run the integration tests
|
||||||
.PHONY: test-integration
|
.PHONY: test-integration
|
||||||
test-integration:
|
test-integration: binary
|
||||||
./script/make.sh generate binary test-integration
|
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -test.timeout=20m -failfast -v $(TESTFLAGS)
|
||||||
|
|
||||||
## Pull all images for integration tests
|
## Run the conformance tests
|
||||||
|
.PHONY: test-gateway-api-conformance
|
||||||
|
test-gateway-api-conformance: binary
|
||||||
|
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -v -test.run K8sConformanceSuite -k8sConformance=true $(TESTFLAGS)
|
||||||
|
|
||||||
|
## TODO: Need to be fixed to work in all situations.
|
||||||
|
## Run the conformance tests
|
||||||
|
.PHONY: test-gateway-api-conformance-ci
|
||||||
|
test-gateway-api-conformance-ci:
|
||||||
|
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -v -test.run K8sConformanceSuite -k8sConformance=true $(TESTFLAGS)
|
||||||
|
|
||||||
|
## Pull all Docker images to avoid timeout during integration tests
|
||||||
.PHONY: pull-images
|
.PHONY: pull-images
|
||||||
pull-images:
|
pull-images:
|
||||||
grep --no-filename -E '^\s+image:' ./integration/resources/compose/*.yml \
|
grep --no-filename -E '^\s+image:' ./integration/resources/compose/*.yml \
|
||||||
|
@ -80,38 +119,47 @@ pull-images:
|
||||||
| uniq \
|
| uniq \
|
||||||
| xargs -P 6 -n 1 docker pull
|
| xargs -P 6 -n 1 docker pull
|
||||||
|
|
||||||
EXECUTABLES = misspell shellcheck
|
## Lint run golangci-lint
|
||||||
|
.PHONY: lint
|
||||||
|
lint:
|
||||||
|
golangci-lint run
|
||||||
|
|
||||||
## Validate code and docs
|
## Validate code and docs
|
||||||
.PHONY: validate-files
|
.PHONY: validate-files
|
||||||
validate-files:
|
validate-files: lint
|
||||||
$(foreach exec,$(EXECUTABLES),\
|
$(foreach exec,$(LINT_EXECUTABLES),\
|
||||||
$(if $(shell which $(exec)),,$(error "No $(exec) in PATH")))
|
$(if $(shell which $(exec)),,$(error "No $(exec) in PATH")))
|
||||||
./script/make.sh generate validate-lint validate-misspell
|
$(CURDIR)/script/validate-misspell.sh
|
||||||
bash $(CURDIR)/script/validate-shell-script.sh
|
$(CURDIR)/script/validate-shell-script.sh
|
||||||
|
|
||||||
## Validate code, docs, and vendor
|
## Validate code, docs, and vendor
|
||||||
.PHONY: validate
|
.PHONY: validate
|
||||||
validate:
|
validate: lint
|
||||||
$(foreach exec,$(EXECUTABLES),\
|
$(foreach exec,$(EXECUTABLES),\
|
||||||
$(if $(shell which $(exec)),,$(error "No $(exec) in PATH")))
|
$(if $(shell which $(exec)),,$(error "No $(exec) in PATH")))
|
||||||
./script/make.sh generate validate-lint validate-misspell validate-vendor
|
$(CURDIR)/script/validate-vendor.sh
|
||||||
bash $(CURDIR)/script/validate-shell-script.sh
|
$(CURDIR)/script/validate-misspell.sh
|
||||||
|
$(CURDIR)/script/validate-shell-script.sh
|
||||||
|
|
||||||
|
# Target for building images for multiple architectures.
|
||||||
|
.PHONY: multi-arch-image-%
|
||||||
|
multi-arch-image-%: binary-linux-amd64 binary-linux-arm64
|
||||||
|
docker buildx build $(DOCKER_BUILDX_ARGS) -t traefik/traefik:$* --platform=$(DOCKER_BUILD_PLATFORMS) -f Dockerfile .
|
||||||
|
|
||||||
|
|
||||||
## Clean up static directory and build a Docker Traefik image
|
## Clean up static directory and build a Docker Traefik image
|
||||||
.PHONY: build-image
|
.PHONY: build-image
|
||||||
build-image: clean-webui binary
|
build-image: export DOCKER_BUILDX_ARGS := --load
|
||||||
docker build -t $(TRAEFIK_IMAGE) .
|
build-image: export DOCKER_BUILD_PLATFORMS := linux/$(GOARCH)
|
||||||
|
build-image: clean-webui
|
||||||
|
@$(MAKE) multi-arch-image-latest
|
||||||
|
|
||||||
## Build a Docker Traefik image without re-building the webui
|
## Build a Docker Traefik image without re-building the webui when it's already built
|
||||||
.PHONY: build-image-dirty
|
.PHONY: build-image-dirty
|
||||||
build-image-dirty: binary
|
build-image-dirty: export DOCKER_BUILDX_ARGS := --load
|
||||||
docker build -t $(TRAEFIK_IMAGE) .
|
build-image-dirty: export DOCKER_BUILD_PLATFORMS := linux/$(GOARCH)
|
||||||
|
build-image-dirty:
|
||||||
## Locally build traefik for linux, then shove it an alpine image, with basic tools.
|
@$(MAKE) multi-arch-image-latest
|
||||||
.PHONY: build-image-debug
|
|
||||||
build-image-debug: binary-debug
|
|
||||||
docker build -t $(TRAEFIK_IMAGE) -f debug.Dockerfile .
|
|
||||||
|
|
||||||
## Build documentation site
|
## Build documentation site
|
||||||
.PHONY: docs
|
.PHONY: docs
|
||||||
|
@ -141,30 +189,9 @@ generate-genconf:
|
||||||
## Create packages for the release
|
## Create packages for the release
|
||||||
.PHONY: release-packages
|
.PHONY: release-packages
|
||||||
release-packages: generate-webui
|
release-packages: generate-webui
|
||||||
rm -rf dist
|
$(CURDIR)/script/release-packages.sh
|
||||||
@- $(foreach os, linux darwin windows freebsd openbsd, \
|
|
||||||
goreleaser release --skip-publish -p 2 --timeout="90m" --config $(shell go run ./internal/release $(os)); \
|
|
||||||
go clean -cache; \
|
|
||||||
)
|
|
||||||
|
|
||||||
cat dist/**/*_checksums.txt >> dist/traefik_${VERSION}_checksums.txt
|
|
||||||
rm dist/**/*_checksums.txt
|
|
||||||
tar cfz dist/traefik-${VERSION}.src.tar.gz \
|
|
||||||
--exclude-vcs \
|
|
||||||
--exclude .idea \
|
|
||||||
--exclude .travis \
|
|
||||||
--exclude .semaphoreci \
|
|
||||||
--exclude .github \
|
|
||||||
--exclude dist .
|
|
||||||
chown -R $(shell id -u):$(shell id -g) dist/
|
|
||||||
|
|
||||||
## Format the Code
|
## Format the Code
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
fmt:
|
fmt:
|
||||||
gofmt -s -l -w $(SRCS)
|
gofmt -s -l -w $(SRCS)
|
||||||
|
|
||||||
.PHONY: run-dev
|
|
||||||
run-dev:
|
|
||||||
go generate
|
|
||||||
GO111MODULE=on go build ./cmd/traefik
|
|
||||||
./traefik
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
FROM golang:1.21-alpine
|
|
||||||
|
|
||||||
RUN apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar ca-certificates tzdata \
|
|
||||||
&& update-ca-certificates \
|
|
||||||
&& rm -rf /var/cache/apk/*
|
|
||||||
|
|
||||||
# Which docker version to test on
|
|
||||||
ARG DOCKER_VERSION=18.09.7
|
|
||||||
|
|
||||||
# Download docker
|
|
||||||
RUN mkdir -p /usr/local/bin \
|
|
||||||
&& curl -fL https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz \
|
|
||||||
| tar -xzC /usr/local/bin --transform 's#^.+/##x'
|
|
||||||
|
|
||||||
# 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.55.2
|
|
||||||
|
|
||||||
# Download misspell binary to bin folder in $GOPATH
|
|
||||||
RUN curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.4.0
|
|
||||||
|
|
||||||
# Download goreleaser binary to bin folder in $GOPATH
|
|
||||||
RUN curl -sfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | sh
|
|
||||||
|
|
||||||
WORKDIR /go/src/github.com/traefik/traefik
|
|
||||||
|
|
||||||
# Because of CVE-2022-24765 (https://github.blog/2022-04-12-git-security-vulnerability-announced/),
|
|
||||||
# we configure git to allow the Traefik codebase path on the Host for docker in docker usages.
|
|
||||||
ARG HOST_PWD=""
|
|
||||||
|
|
||||||
RUN git config --global --add safe.directory "${HOST_PWD}"
|
|
||||||
|
|
||||||
# Download go modules
|
|
||||||
COPY go.mod .
|
|
||||||
COPY go.sum .
|
|
||||||
RUN GO111MODULE=on GOPROXY=https://proxy.golang.org go mod download
|
|
||||||
|
|
||||||
COPY . /go/src/github.com/traefik/traefik
|
|
|
@ -53,7 +53,7 @@ func main() {
|
||||||
// traefik config inits
|
// traefik config inits
|
||||||
tConfig := cmd.NewTraefikConfiguration()
|
tConfig := cmd.NewTraefikConfiguration()
|
||||||
|
|
||||||
loaders := []cli.ResourceLoader{&tcli.FileLoader{}, &tcli.FlagLoader{}, &tcli.EnvLoader{}}
|
loaders := []cli.ResourceLoader{&tcli.DeprecationLoader{}, &tcli.FileLoader{}, &tcli.FlagLoader{}, &tcli.EnvLoader{}}
|
||||||
|
|
||||||
cmdTraefik := &cli.Command{
|
cmdTraefik := &cli.Command{
|
||||||
Name: "traefik",
|
Name: "traefik",
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
FROM alpine:3.14
|
|
||||||
# Feel free to add below any helpful dependency for debugging.
|
|
||||||
# iproute2 is for ss.
|
|
||||||
RUN apk --no-cache --no-progress add bash curl ca-certificates tzdata lsof iproute2 \
|
|
||||||
&& update-ca-certificates \
|
|
||||||
&& rm -rf /var/cache/apk/*
|
|
||||||
COPY dist/traefik /
|
|
||||||
EXPOSE 80
|
|
||||||
VOLUME ["/tmp"]
|
|
||||||
ENTRYPOINT ["/traefik"]
|
|
|
@ -58,10 +58,12 @@ Once you've set up your go environment and cloned the source repository, you can
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ make binary
|
$ make binary
|
||||||
./script/make.sh generate binary
|
SHA: 8fddfe118288bb5280eb5e77fa952f52def360b4 cheddar 2024-01-11_03:14:57PM
|
||||||
---> Making bundle: generate (in .)
|
CGO_ENABLED=0 GOGC=off GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w \
|
||||||
|
-X github.com/traefik/traefik/v2/pkg/version.Version=8fddfe118288bb5280eb5e77fa952f52def360b4 \
|
||||||
---> Making bundle: binary (in .)
|
-X github.com/traefik/traefik/v2/pkg/version.Codename=cheddar \
|
||||||
|
-X github.com/traefik/traefik/v2/pkg/version.BuildDate=2024-01-11_03:14:57PM" \
|
||||||
|
-installsuffix nocgo -o "./dist/darwin/arm64/traefik" ./cmd/traefik
|
||||||
|
|
||||||
$ ls dist/
|
$ ls dist/
|
||||||
traefik*
|
traefik*
|
||||||
|
@ -77,10 +79,7 @@ Run all tests (unit and integration) using the `test` target.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ make test-unit
|
$ make test-unit
|
||||||
./script/make.sh generate test-unit
|
GOOS=darwin GOARCH=arm64 go test -cover "-coverprofile=cover.out" -v ./pkg/... ./cmd/...
|
||||||
---> Making bundle: generate (in .)
|
|
||||||
|
|
||||||
---> Making bundle: test-unit (in .)
|
|
||||||
+ go test -cover -coverprofile=cover.out .
|
+ go test -cover -coverprofile=cover.out .
|
||||||
ok github.com/traefik/traefik 0.005s coverage: 4.1% of statements
|
ok github.com/traefik/traefik 0.005s coverage: 4.1% of statements
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ The main features include dynamic configuration, automatic service discovery, an
|
||||||
|
|
||||||
## Edge Router
|
## Edge Router
|
||||||
|
|
||||||
Traefik is an *Edge Router*, it means that it's the door to your platform, and that it intercepts and routes every incoming request:
|
Traefik is an *Edge Router*; this means that it's the door to your platform, and that it intercepts and routes every incoming request:
|
||||||
it knows all the logic and every [rule](../routing/routers/index.md#rule "Link to docs about routing rules") that determine which services handle which requests (based on the *path*, the *host*, *headers*, etc.).
|
it knows all the logic and every [rule](../routing/routers/index.md#rule "Link to docs about routing rules") that determine which services handle which requests (based on the *path*, the *host*, *headers*, etc.).
|
||||||
|
|
||||||
![The Door to Your Infrastructure](../assets/img/traefik-concepts-1.png "Picture explaining the infrastructure")
|
![The Door to Your Infrastructure](../assets/img/traefik-concepts-1.png "Picture explaining the infrastructure")
|
||||||
|
@ -38,7 +38,7 @@ Deploying your services, you attach information that tells Traefik the character
|
||||||
|
|
||||||
![Decentralized Configuration](../assets/img/traefik-concepts-2.png "Picture about Decentralized Configuration")
|
![Decentralized Configuration](../assets/img/traefik-concepts-2.png "Picture about Decentralized Configuration")
|
||||||
|
|
||||||
It means that when a service is deployed, Traefik detects it immediately and updates the routing rules in real time.
|
This means that when a service is deployed, Traefik detects it immediately and updates the routing rules in real time.
|
||||||
Similarly, when a service is removed from the infrastructure, the corresponding route is deleted accordingly.
|
Similarly, when a service is removed from the infrastructure, the corresponding route is deleted accordingly.
|
||||||
|
|
||||||
You no longer need to create and synchronize configuration files cluttered with IP addresses or other rules.
|
You no longer need to create and synchronize configuration files cluttered with IP addresses or other rules.
|
||||||
|
|
|
@ -19,7 +19,7 @@ version: '3'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
reverse-proxy:
|
reverse-proxy:
|
||||||
# The official v2 Traefik docker image
|
# The official v3 Traefik docker image
|
||||||
image: traefik:v3.0
|
image: traefik:v3.0
|
||||||
# Enables the web UI and tells Traefik to listen to docker
|
# Enables the web UI and tells Traefik to listen to docker
|
||||||
command: --api.insecure=true --providers.docker
|
command: --api.insecure=true --providers.docker
|
||||||
|
|
|
@ -55,10 +55,10 @@ http:
|
||||||
Responses are compressed when the following criteria are all met:
|
Responses are compressed when the following criteria are all met:
|
||||||
|
|
||||||
* The `Accept-Encoding` request header contains `gzip`, `*`, and/or `br` with or without [quality values](https://developer.mozilla.org/en-US/docs/Glossary/Quality_values).
|
* The `Accept-Encoding` request header contains `gzip`, `*`, and/or `br` with or without [quality values](https://developer.mozilla.org/en-US/docs/Glossary/Quality_values).
|
||||||
If the `Accept-Encoding` request header is absent, it is meant as br compression is requested.
|
If the `Accept-Encoding` request header is absent, the response won't be encoded.
|
||||||
If it is present, but its value is the empty string, then compression is disabled.
|
If it is present, but its value is the empty string, then compression is disabled.
|
||||||
* The response is not already compressed, i.e. the `Content-Encoding` response header is not already set.
|
* The response is not already compressed, i.e. the `Content-Encoding` response header is not already set.
|
||||||
* The response`Content-Type` header is not one among the [excludedContentTypes options](#excludedcontenttypes).
|
* The response`Content-Type` header is not one among the [excludedContentTypes options](#excludedcontenttypes), or is one among the [includedContentTypes options](#includedcontenttypes).
|
||||||
* The response body is larger than the [configured minimum amount of bytes](#minresponsebodybytes) (default is `1024`).
|
* The response body is larger than the [configured minimum amount of bytes](#minresponsebodybytes) (default is `1024`).
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
@ -73,6 +73,10 @@ The responses with content types defined in `excludedContentTypes` are not compr
|
||||||
|
|
||||||
Content types are compared in a case-insensitive, whitespace-ignored manner.
|
Content types are compared in a case-insensitive, whitespace-ignored manner.
|
||||||
|
|
||||||
|
!!! info
|
||||||
|
|
||||||
|
The `excludedContentTypes` and `includedContentTypes` options are mutually exclusive.
|
||||||
|
|
||||||
!!! info "In the case of gzip"
|
!!! info "In the case of gzip"
|
||||||
|
|
||||||
If the `Content-Type` header is not defined, or empty, the compress middleware will automatically [detect](https://mimesniff.spec.whatwg.org/) a content type.
|
If the `Content-Type` header is not defined, or empty, the compress middleware will automatically [detect](https://mimesniff.spec.whatwg.org/) a content type.
|
||||||
|
@ -117,6 +121,59 @@ http:
|
||||||
excludedContentTypes = ["text/event-stream"]
|
excludedContentTypes = ["text/event-stream"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `includedContentTypes`
|
||||||
|
|
||||||
|
_Optional, Default=""_
|
||||||
|
|
||||||
|
`includedContentTypes` specifies a list of content types to compare the `Content-Type` header of the responses before compressing.
|
||||||
|
|
||||||
|
The responses with content types defined in `includedContentTypes` are compressed.
|
||||||
|
|
||||||
|
Content types are compared in a case-insensitive, whitespace-ignored manner.
|
||||||
|
|
||||||
|
!!! info
|
||||||
|
|
||||||
|
The `excludedContentTypes` and `includedContentTypes` options are mutually exclusive.
|
||||||
|
|
||||||
|
```yaml tab="Docker & Swarm"
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.test-compress.compress.includedcontenttypes=application/json,text/html,text/plain"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes"
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: test-compress
|
||||||
|
spec:
|
||||||
|
compress:
|
||||||
|
includedContentTypes:
|
||||||
|
- application/json
|
||||||
|
- text/html
|
||||||
|
- text/plain
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Consul Catalog"
|
||||||
|
- "traefik.http.middlewares.test-compress.compress.includedcontenttypes=application/json,text/html,text/plain"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
http:
|
||||||
|
middlewares:
|
||||||
|
test-compress:
|
||||||
|
compress:
|
||||||
|
includedContentTypes:
|
||||||
|
- application/json
|
||||||
|
- text/html
|
||||||
|
- text/plain
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[http.middlewares]
|
||||||
|
[http.middlewares.test-compress.compress]
|
||||||
|
includedContentTypes = ["application/json","text/html","text/plain"]
|
||||||
|
```
|
||||||
|
|
||||||
### `minResponseBodyBytes`
|
### `minResponseBodyBytes`
|
||||||
|
|
||||||
_Optional, Default=1024_
|
_Optional, Default=1024_
|
||||||
|
|
|
@ -285,6 +285,55 @@ http:
|
||||||
authRequestHeaders = "Accept,X-CustomHeader"
|
authRequestHeaders = "Accept,X-CustomHeader"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `addAuthCookiesToResponse`
|
||||||
|
|
||||||
|
The `addAuthCookiesToResponse` option is the list of cookies to copy from the authentication server to the response,
|
||||||
|
replacing any existing conflicting cookie from the forwarded response.
|
||||||
|
|
||||||
|
!!! info
|
||||||
|
|
||||||
|
Please note that all backend cookies matching the configured list will not be added to the response.
|
||||||
|
|
||||||
|
```yaml tab="Docker"
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.test-auth.forwardauth.addAuthCookiesToResponse=Session-Cookie,State-Cookie"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes"
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: test-auth
|
||||||
|
spec:
|
||||||
|
forwardAuth:
|
||||||
|
address: https://example.com/auth
|
||||||
|
addAuthCookiesToResponse:
|
||||||
|
- Session-Cookie
|
||||||
|
- State-Cookie
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Consul Catalog"
|
||||||
|
- "traefik.http.middlewares.test-auth.forwardauth.addAuthCookiesToResponse=Session-Cookie,State-Cookie"
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[http.middlewares]
|
||||||
|
[http.middlewares.test-auth.forwardAuth]
|
||||||
|
address = "https://example.com/auth"
|
||||||
|
addAuthCookiesToResponse = ["Session-Cookie", "State-Cookie"]
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
http:
|
||||||
|
middlewares:
|
||||||
|
test-auth:
|
||||||
|
forwardAuth:
|
||||||
|
address: "https://example.com/auth"
|
||||||
|
addAuthCookiesToResponse:
|
||||||
|
- "Session-Cookie"
|
||||||
|
- "State-Cookie"
|
||||||
|
```
|
||||||
|
|
||||||
### `tls`
|
### `tls`
|
||||||
|
|
||||||
_Optional_
|
_Optional_
|
||||||
|
|
|
@ -19,6 +19,8 @@ and how it now looks like in v3.
|
||||||
|
|
||||||
### Docker & Docker Swarm
|
### Docker & Docker Swarm
|
||||||
|
|
||||||
|
#### SwarmMode
|
||||||
|
|
||||||
In v3, the provider Docker has been split into 2 providers:
|
In v3, the provider Docker has been split into 2 providers:
|
||||||
|
|
||||||
- Docker provider (without Swarm support)
|
- Docker provider (without Swarm support)
|
||||||
|
@ -43,7 +45,7 @@ In v3, the provider Docker has been split into 2 providers:
|
||||||
|
|
||||||
This configuration is now unsupported and would prevent Traefik to start.
|
This configuration is now unsupported and would prevent Traefik to start.
|
||||||
|
|
||||||
#### Remediation
|
##### Remediation
|
||||||
|
|
||||||
In v3, the `swarmMode` should not be used with the Docker provider, and, to use Swarm, the Swarm provider should be used instead.
|
In v3, the `swarmMode` should not be used with the Docker provider, and, to use Swarm, the Swarm provider should be used instead.
|
||||||
|
|
||||||
|
@ -64,7 +66,35 @@ In v3, the `swarmMode` should not be used with the Docker provider, and, to use
|
||||||
--providers.swarm.endpoint=tcp://127.0.0.1:2377
|
--providers.swarm.endpoint=tcp://127.0.0.1:2377
|
||||||
```
|
```
|
||||||
|
|
||||||
### HTTP3 Experimental Configuration
|
#### TLS.CAOptional
|
||||||
|
|
||||||
|
Docker provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType).
|
||||||
|
|
||||||
|
??? example "An example usage of the TLS.CAOptional option"
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
providers:
|
||||||
|
docker:
|
||||||
|
tls:
|
||||||
|
caOptional: true
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[providers.docker.tls]
|
||||||
|
caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
--providers.docker.tls.caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Remediation
|
||||||
|
|
||||||
|
The `tls.caOptional` option should be removed from the Docker provider static configuration.
|
||||||
|
|
||||||
|
### Experimental Configuration
|
||||||
|
|
||||||
|
#### HTTP3
|
||||||
|
|
||||||
In v3, HTTP/3 is no longer an experimental feature.
|
In v3, HTTP/3 is no longer an experimental feature.
|
||||||
It can be enabled on entry points without the associated `experimental.http3` option, which is now removed.
|
It can be enabled on entry points without the associated `experimental.http3` option, which is now removed.
|
||||||
|
@ -86,12 +116,14 @@ It is now unsupported and would prevent Traefik to start.
|
||||||
--experimental.http3=true
|
--experimental.http3=true
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Remediation
|
##### Remediation
|
||||||
|
|
||||||
The `http3` option should be removed from the static configuration experimental section.
|
The `http3` option should be removed from the static configuration experimental section.
|
||||||
|
|
||||||
### Consul provider
|
### Consul provider
|
||||||
|
|
||||||
|
#### namespace
|
||||||
|
|
||||||
The Consul provider `namespace` option was deprecated in v2 and is now removed in v3.
|
The Consul provider `namespace` option was deprecated in v2 and is now removed in v3.
|
||||||
It is now unsupported and would prevent Traefik to start.
|
It is now unsupported and would prevent Traefik to start.
|
||||||
|
|
||||||
|
@ -111,7 +143,7 @@ It is now unsupported and would prevent Traefik to start.
|
||||||
--consul.namespace=foobar
|
--consul.namespace=foobar
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Remediation
|
##### Remediation
|
||||||
|
|
||||||
In v3, the `namespaces` option should be used instead of the `namespace` option.
|
In v3, the `namespaces` option should be used instead of the `namespace` option.
|
||||||
|
|
||||||
|
@ -132,8 +164,36 @@ In v3, the `namespaces` option should be used instead of the `namespace` option.
|
||||||
--consul.namespaces=foobar
|
--consul.namespaces=foobar
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### TLS.CAOptional
|
||||||
|
|
||||||
|
Consul provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType).
|
||||||
|
|
||||||
|
??? example "An example usage of the TLS.CAOptional option"
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
providers:
|
||||||
|
consul:
|
||||||
|
tls:
|
||||||
|
caOptional: true
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[providers.consul.tls]
|
||||||
|
caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
--providers.consul.tls.caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Remediation
|
||||||
|
|
||||||
|
The `tls.caOptional` option should be removed from the Consul provider static configuration.
|
||||||
|
|
||||||
### ConsulCatalog provider
|
### ConsulCatalog provider
|
||||||
|
|
||||||
|
#### namespace
|
||||||
|
|
||||||
The ConsulCatalog provider `namespace` option was deprecated in v2 and is now removed in v3.
|
The ConsulCatalog provider `namespace` option was deprecated in v2 and is now removed in v3.
|
||||||
It is now unsupported and would prevent Traefik to start.
|
It is now unsupported and would prevent Traefik to start.
|
||||||
|
|
||||||
|
@ -153,7 +213,7 @@ It is now unsupported and would prevent Traefik to start.
|
||||||
--consulCatalog.namespace=foobar
|
--consulCatalog.namespace=foobar
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Remediation
|
##### Remediation
|
||||||
|
|
||||||
In v3, the `namespaces` option should be used instead of the `namespace` option.
|
In v3, the `namespaces` option should be used instead of the `namespace` option.
|
||||||
|
|
||||||
|
@ -174,8 +234,37 @@ In v3, the `namespaces` option should be used instead of the `namespace` option.
|
||||||
--consulCatalog.namespaces=foobar
|
--consulCatalog.namespaces=foobar
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Endpoint.TLS.CAOptional
|
||||||
|
|
||||||
|
ConsulCatalog provider `endpoint.tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType).
|
||||||
|
|
||||||
|
??? example "An example usage of the Endpoint.TLS.CAOptional option"
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
providers:
|
||||||
|
consulCatalog:
|
||||||
|
endpoint:
|
||||||
|
tls:
|
||||||
|
caOptional: true
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[providers.consulCatalog.endpoint.tls]
|
||||||
|
caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
--providers.consulCatalog.endpoint.tls.caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Remediation
|
||||||
|
|
||||||
|
The `endpoint.tls.caOptional` option should be removed from the ConsulCatalog provider static configuration.
|
||||||
|
|
||||||
### Nomad provider
|
### Nomad provider
|
||||||
|
|
||||||
|
#### namespace
|
||||||
|
|
||||||
The Nomad provider `namespace` option was deprecated in v2 and is now removed in v3.
|
The Nomad provider `namespace` option was deprecated in v2 and is now removed in v3.
|
||||||
It is now unsupported and would prevent Traefik to start.
|
It is now unsupported and would prevent Traefik to start.
|
||||||
|
|
||||||
|
@ -195,7 +284,7 @@ It is now unsupported and would prevent Traefik to start.
|
||||||
--nomad.namespace=foobar
|
--nomad.namespace=foobar
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Remediation
|
##### Remediation
|
||||||
|
|
||||||
In v3, the `namespaces` option should be used instead of the `namespace` option.
|
In v3, the `namespaces` option should be used instead of the `namespace` option.
|
||||||
|
|
||||||
|
@ -216,6 +305,33 @@ In v3, the `namespaces` option should be used instead of the `namespace` option.
|
||||||
--nomad.namespaces=foobar
|
--nomad.namespaces=foobar
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Endpoint.TLS.CAOptional
|
||||||
|
|
||||||
|
Nomad provider `endpoint.tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType).
|
||||||
|
|
||||||
|
??? example "An example usage of the Endpoint.TLS.CAOptional option"
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
providers:
|
||||||
|
nomad:
|
||||||
|
endpoint:
|
||||||
|
tls:
|
||||||
|
caOptional: true
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[providers.nomad.endpoint.tls]
|
||||||
|
caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
--providers.nomad.endpoint.tls.caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Remediation
|
||||||
|
|
||||||
|
The `endpoint.tls.caOptional` option should be removed from the Nomad provider static configuration.
|
||||||
|
|
||||||
### Rancher v1 Provider
|
### Rancher v1 Provider
|
||||||
|
|
||||||
In v3, the Rancher v1 provider has been removed because Rancher v1 is [no longer actively maintaned](https://rancher.com/docs/os/v1.x/en/support/),
|
In v3, the Rancher v1 provider has been removed because Rancher v1 is [no longer actively maintaned](https://rancher.com/docs/os/v1.x/en/support/),
|
||||||
|
@ -271,6 +387,90 @@ This configuration is now unsupported and would prevent Traefik to start.
|
||||||
|
|
||||||
All Marathon provider related configuration should be removed from the static configuration.
|
All Marathon provider related configuration should be removed from the static configuration.
|
||||||
|
|
||||||
|
### HTTP Provider
|
||||||
|
|
||||||
|
#### TLS.CAOptional
|
||||||
|
|
||||||
|
HTTP provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType).
|
||||||
|
|
||||||
|
??? example "An example usage of the TLS.CAOptional option"
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
providers:
|
||||||
|
http:
|
||||||
|
tls:
|
||||||
|
caOptional: true
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[providers.http.tls]
|
||||||
|
caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
--providers.http.tls.caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Remediation
|
||||||
|
|
||||||
|
The `tls.caOptional` option should be removed from the HTTP provider static configuration.
|
||||||
|
|
||||||
|
### ETCD Provider
|
||||||
|
|
||||||
|
#### TLS.CAOptional
|
||||||
|
|
||||||
|
ETCD provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType).
|
||||||
|
|
||||||
|
??? example "An example usage of the TLS.CAOptional option"
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
providers:
|
||||||
|
etcd:
|
||||||
|
tls:
|
||||||
|
caOptional: true
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[providers.etcd.tls]
|
||||||
|
caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
--providers.etcd.tls.caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Remediation
|
||||||
|
|
||||||
|
The `tls.caOptional` option should be removed from the ETCD provider static configuration.
|
||||||
|
|
||||||
|
### Redis Provider
|
||||||
|
|
||||||
|
#### TLS.CAOptional
|
||||||
|
|
||||||
|
Redis provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType).
|
||||||
|
|
||||||
|
??? example "An example usage of the TLS.CAOptional option"
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
providers:
|
||||||
|
redis:
|
||||||
|
tls:
|
||||||
|
caOptional: true
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[providers.redis.tls]
|
||||||
|
caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
--providers.redis.tls.caOptional=true
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Remediation
|
||||||
|
|
||||||
|
The `tls.caOptional` option should be removed from the Redis provider static configuration.
|
||||||
|
|
||||||
### InfluxDB v1
|
### InfluxDB v1
|
||||||
|
|
||||||
InfluxDB v1.x maintenance [ended in 2021](https://www.influxdata.com/blog/influxdb-oss-and-enterprise-roadmap-update-from-influxdays-emea/).
|
InfluxDB v1.x maintenance [ended in 2021](https://www.influxdata.com/blog/influxdb-oss-and-enterprise-roadmap-update-from-influxdays-emea/).
|
||||||
|
@ -326,21 +526,16 @@ All Pilot related configuration should be removed from the static configuration.
|
||||||
|
|
||||||
## Dynamic configuration
|
## Dynamic configuration
|
||||||
|
|
||||||
### IPWhiteList
|
### Router Rule Matchers
|
||||||
|
|
||||||
In v3, we renamed the `IPWhiteList` middleware to `IPAllowList` without changing anything to the configuration.
|
In v3, a new rule matchers syntax has been introduced for HTTP and TCP routers.
|
||||||
|
The default rule matchers syntax is now the v3 one, but for backward compatibility this can be configured.
|
||||||
|
The v2 rule matchers syntax is deprecated and its support will be removed in the next major version.
|
||||||
|
For this reason, we encourage migrating to the new syntax.
|
||||||
|
|
||||||
### Deprecated Options Removal
|
#### New V3 Syntax Notable Changes
|
||||||
|
|
||||||
- The `tracing.datadog.globaltag` option has been removed.
|
The `Headers` and `HeadersRegexp` matchers have been renamed to `Header` and `HeaderRegexp` respectively.
|
||||||
- The `tls.caOptional` option has been removed from the ForwardAuth middleware, as well as from the HTTP, Consul, Etcd, Redis, ZooKeeper, Consul Catalog, and Docker providers.
|
|
||||||
- `sslRedirect`, `sslTemporaryRedirect`, `sslHost`, `sslForceHost` and `featurePolicy` options of the Headers middleware have been removed.
|
|
||||||
- The `forceSlash` option of the StripPrefix middleware has been removed.
|
|
||||||
- The `preferServerCipherSuites` option has been removed.
|
|
||||||
|
|
||||||
### Matchers
|
|
||||||
|
|
||||||
In v3, the `Headers` and `HeadersRegexp` matchers have been renamed to `Header` and `HeaderRegexp` respectively.
|
|
||||||
|
|
||||||
`PathPrefix` no longer uses regular expressions to match path prefixes.
|
`PathPrefix` no longer uses regular expressions to match path prefixes.
|
||||||
|
|
||||||
|
@ -355,6 +550,87 @@ and should be explicitly combined using logical operators to mimic previous beha
|
||||||
|
|
||||||
`HostHeader` has been removed, use `Host` instead.
|
`HostHeader` has been removed, use `Host` instead.
|
||||||
|
|
||||||
|
#### Remediation
|
||||||
|
|
||||||
|
##### Configure the Default Syntax In Static Configuration
|
||||||
|
|
||||||
|
The default rule matchers syntax is the expected syntax for any router that is not self opt-out from this default value.
|
||||||
|
It can be configured in the static configuration.
|
||||||
|
|
||||||
|
??? example "An example configuration for the default rule matchers syntax"
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
# static configuration
|
||||||
|
core:
|
||||||
|
defaultRuleSyntax: v2
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
# static configuration
|
||||||
|
[core]
|
||||||
|
defaultRuleSyntax="v2"
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
# static configuration
|
||||||
|
--core.defaultRuleSyntax=v2
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Configure the Syntax Per Router
|
||||||
|
|
||||||
|
The rule syntax can also be configured on a per-router basis.
|
||||||
|
This allows to have heterogeneous router configurations and ease migration.
|
||||||
|
|
||||||
|
??? example "An example router with syntax configuration"
|
||||||
|
|
||||||
|
```yaml tab="Docker & Swarm"
|
||||||
|
labels:
|
||||||
|
- "traefik.http.routers.test.ruleSyntax=v2"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes"
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
routes:
|
||||||
|
- match: PathPrefix(`/foo`, `/bar`)
|
||||||
|
syntax: v2
|
||||||
|
kind: Rule
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Consul Catalog"
|
||||||
|
- "traefik.http.routers.test.ruleSyntax=v2"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
http:
|
||||||
|
routers:
|
||||||
|
test:
|
||||||
|
ruleSyntax: v2
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.test]
|
||||||
|
ruleSyntax = "v2"
|
||||||
|
```
|
||||||
|
|
||||||
|
### IPWhiteList
|
||||||
|
|
||||||
|
In v3, we renamed the `IPWhiteList` middleware to `IPAllowList` without changing anything to the configuration.
|
||||||
|
|
||||||
|
### Deprecated Options Removal
|
||||||
|
|
||||||
|
- The `tracing.datadog.globaltag` option has been removed.
|
||||||
|
- The `tls.caOptional` option has been removed from the ForwardAuth middleware, as well as from the HTTP, Consul, Etcd, Redis, ZooKeeper, Consul Catalog, and Docker providers.
|
||||||
|
- `sslRedirect`, `sslTemporaryRedirect`, `sslHost`, `sslForceHost` and `featurePolicy` options of the Headers middleware have been removed.
|
||||||
|
- The `forceSlash` option of the StripPrefix middleware has been removed.
|
||||||
|
- The `preferServerCipherSuites` option has been removed.
|
||||||
|
|
||||||
### TCP LoadBalancer `terminationDelay` option
|
### TCP LoadBalancer `terminationDelay` option
|
||||||
|
|
||||||
The TCP LoadBalancer `terminationDelay` option has been removed.
|
The TCP LoadBalancer `terminationDelay` option has been removed.
|
||||||
|
@ -415,3 +691,5 @@ Here are two possible transition strategies:
|
||||||
For legacy stacks that cannot immediately upgrade to the latest vendor agents supporting OTLP ingestion,
|
For legacy stacks that cannot immediately upgrade to the latest vendor agents supporting OTLP ingestion,
|
||||||
using OpenTelemetry (OTel) collectors with appropriate exporters configuration is a viable solution.
|
using OpenTelemetry (OTel) collectors with appropriate exporters configuration is a viable solution.
|
||||||
This allows continued compatibility with the existing infrastructure.
|
This allows continued compatibility with the existing infrastructure.
|
||||||
|
|
||||||
|
Please check the [OpenTelemetry Tracing provider documention](../observability/tracing/opentelemetry.md) for more information.
|
||||||
|
|
|
@ -1,128 +1,138 @@
|
||||||
- "traefik.http.middlewares.middleware00.addprefix.prefix=foobar"
|
## CODE GENERATED AUTOMATICALLY
|
||||||
- "traefik.http.middlewares.middleware01.basicauth.headerfield=foobar"
|
## THIS FILE MUST NOT BE EDITED BY HAND
|
||||||
- "traefik.http.middlewares.middleware01.basicauth.realm=foobar"
|
- "traefik.http.middlewares.middleware01.addprefix.prefix=foobar"
|
||||||
- "traefik.http.middlewares.middleware01.basicauth.removeheader=true"
|
- "traefik.http.middlewares.middleware02.basicauth.headerfield=foobar"
|
||||||
- "traefik.http.middlewares.middleware01.basicauth.users=foobar, foobar"
|
- "traefik.http.middlewares.middleware02.basicauth.realm=foobar"
|
||||||
- "traefik.http.middlewares.middleware01.basicauth.usersfile=foobar"
|
- "traefik.http.middlewares.middleware02.basicauth.removeheader=true"
|
||||||
- "traefik.http.middlewares.middleware02.buffering.maxrequestbodybytes=42"
|
- "traefik.http.middlewares.middleware02.basicauth.users=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware02.buffering.maxresponsebodybytes=42"
|
- "traefik.http.middlewares.middleware02.basicauth.usersfile=foobar"
|
||||||
- "traefik.http.middlewares.middleware02.buffering.memrequestbodybytes=42"
|
- "traefik.http.middlewares.middleware03.buffering.maxrequestbodybytes=42"
|
||||||
- "traefik.http.middlewares.middleware02.buffering.memresponsebodybytes=42"
|
- "traefik.http.middlewares.middleware03.buffering.maxresponsebodybytes=42"
|
||||||
- "traefik.http.middlewares.middleware02.buffering.retryexpression=foobar"
|
- "traefik.http.middlewares.middleware03.buffering.memrequestbodybytes=42"
|
||||||
- "traefik.http.middlewares.middleware03.chain.middlewares=foobar, foobar"
|
- "traefik.http.middlewares.middleware03.buffering.memresponsebodybytes=42"
|
||||||
- "traefik.http.middlewares.middleware04.circuitbreaker.expression=foobar"
|
- "traefik.http.middlewares.middleware03.buffering.retryexpression=foobar"
|
||||||
- "traefik.http.middlewares.middleware04.circuitbreaker.checkperiod=42s"
|
- "traefik.http.middlewares.middleware04.chain.middlewares=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware04.circuitbreaker.fallbackduration=42s"
|
- "traefik.http.middlewares.middleware05.circuitbreaker.checkperiod=42s"
|
||||||
- "traefik.http.middlewares.middleware04.circuitbreaker.recoveryduration=42s"
|
- "traefik.http.middlewares.middleware05.circuitbreaker.expression=foobar"
|
||||||
- "traefik.http.middlewares.middleware05.compress=true"
|
- "traefik.http.middlewares.middleware05.circuitbreaker.fallbackduration=42s"
|
||||||
- "traefik.http.middlewares.middleware05.compress.excludedcontenttypes=foobar, foobar"
|
- "traefik.http.middlewares.middleware05.circuitbreaker.recoveryduration=42s"
|
||||||
- "traefik.http.middlewares.middleware05.compress.minresponsebodybytes=42"
|
- "traefik.http.middlewares.middleware06.compress=true"
|
||||||
- "traefik.http.middlewares.middleware06.contenttype=true"
|
- "traefik.http.middlewares.middleware06.compress.excludedcontenttypes=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware07.digestauth.headerfield=foobar"
|
- "traefik.http.middlewares.middleware06.compress.includedcontenttypes=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware07.digestauth.realm=foobar"
|
- "traefik.http.middlewares.middleware06.compress.minresponsebodybytes=42"
|
||||||
- "traefik.http.middlewares.middleware07.digestauth.removeheader=true"
|
- "traefik.http.middlewares.middleware07.contenttype=true"
|
||||||
- "traefik.http.middlewares.middleware07.digestauth.users=foobar, foobar"
|
- "traefik.http.middlewares.middleware08.digestauth.headerfield=foobar"
|
||||||
- "traefik.http.middlewares.middleware07.digestauth.usersfile=foobar"
|
- "traefik.http.middlewares.middleware08.digestauth.realm=foobar"
|
||||||
- "traefik.http.middlewares.middleware08.errors.query=foobar"
|
- "traefik.http.middlewares.middleware08.digestauth.removeheader=true"
|
||||||
- "traefik.http.middlewares.middleware08.errors.service=foobar"
|
- "traefik.http.middlewares.middleware08.digestauth.users=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware08.errors.status=foobar, foobar"
|
- "traefik.http.middlewares.middleware08.digestauth.usersfile=foobar"
|
||||||
- "traefik.http.middlewares.middleware09.forwardauth.address=foobar"
|
- "traefik.http.middlewares.middleware09.errors.query=foobar"
|
||||||
- "traefik.http.middlewares.middleware09.forwardauth.authresponseheaders=foobar, foobar"
|
- "traefik.http.middlewares.middleware09.errors.service=foobar"
|
||||||
- "traefik.http.middlewares.middleware09.forwardauth.authresponseheadersregex=foobar"
|
- "traefik.http.middlewares.middleware09.errors.status=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware09.forwardauth.authrequestheaders=foobar, foobar"
|
- "traefik.http.middlewares.middleware10.forwardauth.addauthcookiestoresponse=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware09.forwardauth.tls.ca=foobar"
|
- "traefik.http.middlewares.middleware10.forwardauth.address=foobar"
|
||||||
- "traefik.http.middlewares.middleware09.forwardauth.tls.cert=foobar"
|
- "traefik.http.middlewares.middleware10.forwardauth.authrequestheaders=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware09.forwardauth.tls.insecureskipverify=true"
|
- "traefik.http.middlewares.middleware10.forwardauth.authresponseheaders=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware09.forwardauth.tls.key=foobar"
|
- "traefik.http.middlewares.middleware10.forwardauth.authresponseheadersregex=foobar"
|
||||||
- "traefik.http.middlewares.middleware09.forwardauth.trustforwardheader=true"
|
- "traefik.http.middlewares.middleware10.forwardauth.tls.ca=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.accesscontrolallowcredentials=true"
|
- "traefik.http.middlewares.middleware10.forwardauth.tls.cert=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.accesscontrolallowheaders=foobar, foobar"
|
- "traefik.http.middlewares.middleware10.forwardauth.tls.insecureskipverify=true"
|
||||||
- "traefik.http.middlewares.middleware10.headers.accesscontrolallowmethods=foobar, foobar"
|
- "traefik.http.middlewares.middleware10.forwardauth.tls.key=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.accesscontrolalloworiginlist=foobar, foobar"
|
- "traefik.http.middlewares.middleware10.forwardauth.trustforwardheader=true"
|
||||||
- "traefik.http.middlewares.middleware10.headers.accesscontrolalloworiginlistregex=foobar, foobar"
|
- "traefik.http.middlewares.middleware11.grpcweb.alloworigins=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.accesscontrolexposeheaders=foobar, foobar"
|
- "traefik.http.middlewares.middleware12.headers.accesscontrolallowcredentials=true"
|
||||||
- "traefik.http.middlewares.middleware10.headers.accesscontrolmaxage=42"
|
- "traefik.http.middlewares.middleware12.headers.accesscontrolallowheaders=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.addvaryheader=true"
|
- "traefik.http.middlewares.middleware12.headers.accesscontrolallowmethods=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.allowedhosts=foobar, foobar"
|
- "traefik.http.middlewares.middleware12.headers.accesscontrolalloworiginlist=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.browserxssfilter=true"
|
- "traefik.http.middlewares.middleware12.headers.accesscontrolalloworiginlistregex=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.contentsecuritypolicy=foobar"
|
- "traefik.http.middlewares.middleware12.headers.accesscontrolexposeheaders=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.contenttypenosniff=true"
|
- "traefik.http.middlewares.middleware12.headers.accesscontrolmaxage=42"
|
||||||
- "traefik.http.middlewares.middleware10.headers.custombrowserxssvalue=foobar"
|
- "traefik.http.middlewares.middleware12.headers.addvaryheader=true"
|
||||||
- "traefik.http.middlewares.middleware10.headers.customframeoptionsvalue=foobar"
|
- "traefik.http.middlewares.middleware12.headers.allowedhosts=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.customrequestheaders.name0=foobar"
|
- "traefik.http.middlewares.middleware12.headers.browserxssfilter=true"
|
||||||
- "traefik.http.middlewares.middleware10.headers.customrequestheaders.name1=foobar"
|
- "traefik.http.middlewares.middleware12.headers.contentsecuritypolicy=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.customresponseheaders.name0=foobar"
|
- "traefik.http.middlewares.middleware12.headers.contenttypenosniff=true"
|
||||||
- "traefik.http.middlewares.middleware10.headers.customresponseheaders.name1=foobar"
|
- "traefik.http.middlewares.middleware12.headers.custombrowserxssvalue=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.forcestsheader=true"
|
- "traefik.http.middlewares.middleware12.headers.customframeoptionsvalue=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.framedeny=true"
|
- "traefik.http.middlewares.middleware12.headers.customrequestheaders.name0=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.hostsproxyheaders=foobar, foobar"
|
- "traefik.http.middlewares.middleware12.headers.customrequestheaders.name1=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.isdevelopment=true"
|
- "traefik.http.middlewares.middleware12.headers.customresponseheaders.name0=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.permissionspolicy=foobar"
|
- "traefik.http.middlewares.middleware12.headers.customresponseheaders.name1=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.publickey=foobar"
|
- "traefik.http.middlewares.middleware12.headers.forcestsheader=true"
|
||||||
- "traefik.http.middlewares.middleware10.headers.referrerpolicy=foobar"
|
- "traefik.http.middlewares.middleware12.headers.framedeny=true"
|
||||||
- "traefik.http.middlewares.middleware10.headers.sslproxyheaders.name0=foobar"
|
- "traefik.http.middlewares.middleware12.headers.hostsproxyheaders=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.sslproxyheaders.name1=foobar"
|
- "traefik.http.middlewares.middleware12.headers.isdevelopment=true"
|
||||||
- "traefik.http.middlewares.middleware10.headers.stsincludesubdomains=true"
|
- "traefik.http.middlewares.middleware12.headers.permissionspolicy=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.stspreload=true"
|
- "traefik.http.middlewares.middleware12.headers.publickey=foobar"
|
||||||
- "traefik.http.middlewares.middleware10.headers.stsseconds=42"
|
- "traefik.http.middlewares.middleware12.headers.referrerpolicy=foobar"
|
||||||
- "traefik.http.middlewares.middleware11.ipwhitelist.ipstrategy.depth=42"
|
- "traefik.http.middlewares.middleware12.headers.sslproxyheaders.name0=foobar"
|
||||||
- "traefik.http.middlewares.middleware11.ipwhitelist.ipstrategy.excludedips=foobar, foobar"
|
- "traefik.http.middlewares.middleware12.headers.sslproxyheaders.name1=foobar"
|
||||||
- "traefik.http.middlewares.middleware12.ipwhitelist.sourcerange=foobar, foobar"
|
- "traefik.http.middlewares.middleware12.headers.stsincludesubdomains=true"
|
||||||
- "traefik.http.middlewares.middleware12.ipallowlist.ipstrategy.depth=42"
|
- "traefik.http.middlewares.middleware12.headers.stspreload=true"
|
||||||
- "traefik.http.middlewares.middleware12.ipallowlist.ipstrategy.excludedips=foobar, foobar"
|
- "traefik.http.middlewares.middleware12.headers.stsseconds=42"
|
||||||
- "traefik.http.middlewares.middleware12.ipallowlist.sourcerange=foobar, foobar"
|
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy=true"
|
||||||
- "traefik.http.middlewares.middleware12.ipallowlist.rejectstatuscode=404"
|
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy.depth=42"
|
||||||
- "traefik.http.middlewares.middleware13.inflightreq.amount=42"
|
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy.excludedips=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.ipstrategy.depth=42"
|
- "traefik.http.middlewares.middleware13.ipallowlist.rejectstatuscode=42"
|
||||||
- "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
|
- "traefik.http.middlewares.middleware13.ipallowlist.sourcerange=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.requestheadername=foobar"
|
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy=true"
|
||||||
- "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.requesthost=true"
|
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy.depth=42"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.commonname=true"
|
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy.excludedips=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.country=true"
|
- "traefik.http.middlewares.middleware14.ipwhitelist.sourcerange=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.domaincomponent=true"
|
- "traefik.http.middlewares.middleware15.inflightreq.amount=42"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.locality=true"
|
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.ipstrategy.depth=42"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.organization=true"
|
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.province=true"
|
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.requestheadername=foobar"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.serialnumber=true"
|
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.requesthost=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.notafter=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.commonname=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.notbefore=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.country=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.sans=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.domaincomponent=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.serialnumber=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.locality=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.commonname=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.organization=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.country=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.province=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.domaincomponent=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.serialnumber=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.locality=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.notafter=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.organization=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.notbefore=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.organizationalunit=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.sans=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.province=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.serialnumber=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.serialnumber=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.commonname=true"
|
||||||
- "traefik.http.middlewares.middleware14.passtlsclientcert.pem=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.country=true"
|
||||||
- "traefik.http.middlewares.middleware15.plugin.foobar.foo=bar"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.domaincomponent=true"
|
||||||
- "traefik.http.middlewares.middleware16.ratelimit.average=42"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.locality=true"
|
||||||
- "traefik.http.middlewares.middleware16.ratelimit.burst=42"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.organization=true"
|
||||||
- "traefik.http.middlewares.middleware16.ratelimit.period=42"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.organizationalunit=true"
|
||||||
- "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.ipstrategy.depth=42"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.province=true"
|
||||||
- "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.serialnumber=true"
|
||||||
- "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.requestheadername=foobar"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.pem=true"
|
||||||
- "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.requesthost=true"
|
- "traefik.http.middlewares.middleware17.plugin.pluginconf0.name0=foobar"
|
||||||
- "traefik.http.middlewares.middleware17.redirectregex.permanent=true"
|
- "traefik.http.middlewares.middleware17.plugin.pluginconf0.name1=foobar"
|
||||||
- "traefik.http.middlewares.middleware17.redirectregex.regex=foobar"
|
- "traefik.http.middlewares.middleware17.plugin.pluginconf1.name0=foobar"
|
||||||
- "traefik.http.middlewares.middleware17.redirectregex.replacement=foobar"
|
- "traefik.http.middlewares.middleware17.plugin.pluginconf1.name1=foobar"
|
||||||
- "traefik.http.middlewares.middleware18.redirectscheme.permanent=true"
|
- "traefik.http.middlewares.middleware18.ratelimit.average=42"
|
||||||
- "traefik.http.middlewares.middleware18.redirectscheme.port=foobar"
|
- "traefik.http.middlewares.middleware18.ratelimit.burst=42"
|
||||||
- "traefik.http.middlewares.middleware18.redirectscheme.scheme=foobar"
|
- "traefik.http.middlewares.middleware18.ratelimit.period=42s"
|
||||||
- "traefik.http.middlewares.middleware19.replacepath.path=foobar"
|
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.ipstrategy.depth=42"
|
||||||
- "traefik.http.middlewares.middleware20.replacepathregex.regex=foobar"
|
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware20.replacepathregex.replacement=foobar"
|
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.requestheadername=foobar"
|
||||||
- "traefik.http.middlewares.middleware21.retry.attempts=42"
|
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.requesthost=true"
|
||||||
- "traefik.http.middlewares.middleware21.retry.initialinterval=42"
|
- "traefik.http.middlewares.middleware19.redirectregex.permanent=true"
|
||||||
- "traefik.http.middlewares.middleware22.stripprefix.prefixes=foobar, foobar"
|
- "traefik.http.middlewares.middleware19.redirectregex.regex=foobar"
|
||||||
- "traefik.http.middlewares.middleware23.stripprefixregex.regex=foobar, foobar"
|
- "traefik.http.middlewares.middleware19.redirectregex.replacement=foobar"
|
||||||
- "traefik.http.middlewares.middleware24.grpcweb.alloworigins=foobar, foobar"
|
- "traefik.http.middlewares.middleware20.redirectscheme.permanent=true"
|
||||||
|
- "traefik.http.middlewares.middleware20.redirectscheme.port=foobar"
|
||||||
|
- "traefik.http.middlewares.middleware20.redirectscheme.scheme=foobar"
|
||||||
|
- "traefik.http.middlewares.middleware21.replacepath.path=foobar"
|
||||||
|
- "traefik.http.middlewares.middleware22.replacepathregex.regex=foobar"
|
||||||
|
- "traefik.http.middlewares.middleware22.replacepathregex.replacement=foobar"
|
||||||
|
- "traefik.http.middlewares.middleware23.retry.attempts=42"
|
||||||
|
- "traefik.http.middlewares.middleware23.retry.initialinterval=42s"
|
||||||
|
- "traefik.http.middlewares.middleware24.stripprefix.prefixes=foobar, foobar"
|
||||||
|
- "traefik.http.middlewares.middleware25.stripprefixregex.regex=foobar, foobar"
|
||||||
- "traefik.http.routers.router0.entrypoints=foobar, foobar"
|
- "traefik.http.routers.router0.entrypoints=foobar, foobar"
|
||||||
- "traefik.http.routers.router0.middlewares=foobar, foobar"
|
- "traefik.http.routers.router0.middlewares=foobar, foobar"
|
||||||
- "traefik.http.routers.router0.priority=42"
|
- "traefik.http.routers.router0.priority=42"
|
||||||
- "traefik.http.routers.router0.rule=foobar"
|
- "traefik.http.routers.router0.rule=foobar"
|
||||||
|
- "traefik.http.routers.router0.rulesyntax=foobar"
|
||||||
- "traefik.http.routers.router0.service=foobar"
|
- "traefik.http.routers.router0.service=foobar"
|
||||||
- "traefik.http.routers.router0.tls=true"
|
- "traefik.http.routers.router0.tls=true"
|
||||||
- "traefik.http.routers.router0.tls.certresolver=foobar"
|
- "traefik.http.routers.router0.tls.certresolver=foobar"
|
||||||
|
@ -135,6 +145,7 @@
|
||||||
- "traefik.http.routers.router1.middlewares=foobar, foobar"
|
- "traefik.http.routers.router1.middlewares=foobar, foobar"
|
||||||
- "traefik.http.routers.router1.priority=42"
|
- "traefik.http.routers.router1.priority=42"
|
||||||
- "traefik.http.routers.router1.rule=foobar"
|
- "traefik.http.routers.router1.rule=foobar"
|
||||||
|
- "traefik.http.routers.router1.rulesyntax=foobar"
|
||||||
- "traefik.http.routers.router1.service=foobar"
|
- "traefik.http.routers.router1.service=foobar"
|
||||||
- "traefik.http.routers.router1.tls=true"
|
- "traefik.http.routers.router1.tls=true"
|
||||||
- "traefik.http.routers.router1.tls.certresolver=foobar"
|
- "traefik.http.routers.router1.tls.certresolver=foobar"
|
||||||
|
@ -143,35 +154,39 @@
|
||||||
- "traefik.http.routers.router1.tls.domains[1].main=foobar"
|
- "traefik.http.routers.router1.tls.domains[1].main=foobar"
|
||||||
- "traefik.http.routers.router1.tls.domains[1].sans=foobar, foobar"
|
- "traefik.http.routers.router1.tls.domains[1].sans=foobar, foobar"
|
||||||
- "traefik.http.routers.router1.tls.options=foobar"
|
- "traefik.http.routers.router1.tls.options=foobar"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.followredirects=true"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.followredirects=true"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.headers.name0=foobar"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.headers.name0=foobar"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.headers.name1=foobar"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.headers.name1=foobar"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.hostname=foobar"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.hostname=foobar"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.interval=foobar"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.interval=42s"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.path=foobar"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.method=foobar"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.method=foobar"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.mode=foobar"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.status=42"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.path=foobar"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.port=42"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.port=42"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.scheme=foobar"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.scheme=foobar"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.mode=foobar"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.status=42"
|
||||||
- "traefik.http.services.service01.loadbalancer.healthcheck.timeout=foobar"
|
- "traefik.http.services.service02.loadbalancer.healthcheck.timeout=42s"
|
||||||
- "traefik.http.services.service01.loadbalancer.passhostheader=true"
|
- "traefik.http.services.service02.loadbalancer.passhostheader=true"
|
||||||
- "traefik.http.services.service01.loadbalancer.responseforwarding.flushinterval=foobar"
|
- "traefik.http.services.service02.loadbalancer.responseforwarding.flushinterval=42s"
|
||||||
- "traefik.http.services.service01.loadbalancer.serverstransport=foobar"
|
- "traefik.http.services.service02.loadbalancer.serverstransport=foobar"
|
||||||
- "traefik.http.services.service01.loadbalancer.sticky.cookie=true"
|
- "traefik.http.services.service02.loadbalancer.sticky=true"
|
||||||
- "traefik.http.services.service01.loadbalancer.sticky.cookie.httponly=true"
|
- "traefik.http.services.service02.loadbalancer.sticky.cookie=true"
|
||||||
- "traefik.http.services.service01.loadbalancer.sticky.cookie.name=foobar"
|
- "traefik.http.services.service02.loadbalancer.sticky.cookie.httponly=true"
|
||||||
- "traefik.http.services.service01.loadbalancer.sticky.cookie.samesite=foobar"
|
- "traefik.http.services.service02.loadbalancer.sticky.cookie.maxage=42"
|
||||||
- "traefik.http.services.service01.loadbalancer.sticky.cookie.secure=true"
|
- "traefik.http.services.service02.loadbalancer.sticky.cookie.name=foobar"
|
||||||
- "traefik.http.services.service01.loadbalancer.server.port=foobar"
|
- "traefik.http.services.service02.loadbalancer.sticky.cookie.samesite=foobar"
|
||||||
- "traefik.http.services.service01.loadbalancer.server.scheme=foobar"
|
- "traefik.http.services.service02.loadbalancer.sticky.cookie.secure=true"
|
||||||
- "traefik.tcp.middlewares.tcpmiddleware00.inflightconn.amount=42"
|
- "traefik.http.services.service02.loadbalancer.server.port=foobar"
|
||||||
- "traefik.tcp.middlewares.tcpmiddleware01.ipwhitelist.sourcerange=foobar, foobar"
|
- "traefik.http.services.service02.loadbalancer.server.scheme=foobar"
|
||||||
- "traefik.tcp.middlewares.tcpmiddleware02.ipallowlist.sourcerange=foobar, foobar"
|
- "traefik.http.services.service02.loadbalancer.server.weight=42"
|
||||||
|
- "traefik.tcp.middlewares.tcpmiddleware01.ipallowlist.sourcerange=foobar, foobar"
|
||||||
|
- "traefik.tcp.middlewares.tcpmiddleware02.ipwhitelist.sourcerange=foobar, foobar"
|
||||||
|
- "traefik.tcp.middlewares.tcpmiddleware03.inflightconn.amount=42"
|
||||||
- "traefik.tcp.routers.tcprouter0.entrypoints=foobar, foobar"
|
- "traefik.tcp.routers.tcprouter0.entrypoints=foobar, foobar"
|
||||||
- "traefik.tcp.routers.tcprouter0.middlewares=foobar, foobar"
|
- "traefik.tcp.routers.tcprouter0.middlewares=foobar, foobar"
|
||||||
- "traefik.tcp.routers.tcprouter0.rule=foobar"
|
|
||||||
- "traefik.tcp.routers.tcprouter0.priority=42"
|
- "traefik.tcp.routers.tcprouter0.priority=42"
|
||||||
|
- "traefik.tcp.routers.tcprouter0.rule=foobar"
|
||||||
|
- "traefik.tcp.routers.tcprouter0.rulesyntax=foobar"
|
||||||
- "traefik.tcp.routers.tcprouter0.service=foobar"
|
- "traefik.tcp.routers.tcprouter0.service=foobar"
|
||||||
- "traefik.tcp.routers.tcprouter0.tls=true"
|
- "traefik.tcp.routers.tcprouter0.tls=true"
|
||||||
- "traefik.tcp.routers.tcprouter0.tls.certresolver=foobar"
|
- "traefik.tcp.routers.tcprouter0.tls.certresolver=foobar"
|
||||||
|
@ -183,8 +198,9 @@
|
||||||
- "traefik.tcp.routers.tcprouter0.tls.passthrough=true"
|
- "traefik.tcp.routers.tcprouter0.tls.passthrough=true"
|
||||||
- "traefik.tcp.routers.tcprouter1.entrypoints=foobar, foobar"
|
- "traefik.tcp.routers.tcprouter1.entrypoints=foobar, foobar"
|
||||||
- "traefik.tcp.routers.tcprouter1.middlewares=foobar, foobar"
|
- "traefik.tcp.routers.tcprouter1.middlewares=foobar, foobar"
|
||||||
- "traefik.tcp.routers.tcprouter1.rule=foobar"
|
|
||||||
- "traefik.tcp.routers.tcprouter1.priority=42"
|
- "traefik.tcp.routers.tcprouter1.priority=42"
|
||||||
|
- "traefik.tcp.routers.tcprouter1.rule=foobar"
|
||||||
|
- "traefik.tcp.routers.tcprouter1.rulesyntax=foobar"
|
||||||
- "traefik.tcp.routers.tcprouter1.service=foobar"
|
- "traefik.tcp.routers.tcprouter1.service=foobar"
|
||||||
- "traefik.tcp.routers.tcprouter1.tls=true"
|
- "traefik.tcp.routers.tcprouter1.tls=true"
|
||||||
- "traefik.tcp.routers.tcprouter1.tls.certresolver=foobar"
|
- "traefik.tcp.routers.tcprouter1.tls.certresolver=foobar"
|
||||||
|
@ -194,22 +210,13 @@
|
||||||
- "traefik.tcp.routers.tcprouter1.tls.domains[1].sans=foobar, foobar"
|
- "traefik.tcp.routers.tcprouter1.tls.domains[1].sans=foobar, foobar"
|
||||||
- "traefik.tcp.routers.tcprouter1.tls.options=foobar"
|
- "traefik.tcp.routers.tcprouter1.tls.options=foobar"
|
||||||
- "traefik.tcp.routers.tcprouter1.tls.passthrough=true"
|
- "traefik.tcp.routers.tcprouter1.tls.passthrough=true"
|
||||||
|
- "traefik.tcp.services.tcpservice01.loadbalancer.proxyprotocol=true"
|
||||||
- "traefik.tcp.services.tcpservice01.loadbalancer.proxyprotocol.version=42"
|
- "traefik.tcp.services.tcpservice01.loadbalancer.proxyprotocol.version=42"
|
||||||
|
- "traefik.tcp.services.tcpservice01.loadbalancer.serverstransport=foobar"
|
||||||
- "traefik.tcp.services.tcpservice01.loadbalancer.server.port=foobar"
|
- "traefik.tcp.services.tcpservice01.loadbalancer.server.port=foobar"
|
||||||
- "traefik.tcp.services.tcpservice01.loadbalancer.server.tls=true"
|
- "traefik.tcp.services.tcpservice01.loadbalancer.server.tls=true"
|
||||||
- "traefik.tcp.services.tcpservice01.loadbalancer.serverstransport=foobar"
|
|
||||||
- "traefik.udp.routers.udprouter0.entrypoints=foobar, foobar"
|
- "traefik.udp.routers.udprouter0.entrypoints=foobar, foobar"
|
||||||
- "traefik.udp.routers.udprouter0.service=foobar"
|
- "traefik.udp.routers.udprouter0.service=foobar"
|
||||||
- "traefik.udp.routers.udprouter1.entrypoints=foobar, foobar"
|
- "traefik.udp.routers.udprouter1.entrypoints=foobar, foobar"
|
||||||
- "traefik.udp.routers.udprouter1.service=foobar"
|
- "traefik.udp.routers.udprouter1.service=foobar"
|
||||||
- "traefik.udp.services.udpservice01.loadbalancer.server.port=foobar"
|
- "traefik.udp.services.udpservice01.loadbalancer.server.port=foobar"
|
||||||
- "traefik.tls.stores.Store0.defaultcertificate.certfile=foobar"
|
|
||||||
- "traefik.tls.stores.Store0.defaultcertificate.keyfile=foobar"
|
|
||||||
- "traefik.tls.stores.Store0.defaultgeneratedcert.domain.main=foobar"
|
|
||||||
- "traefik.tls.stores.Store0.defaultgeneratedcert.domain.sans=foobar, foobar"
|
|
||||||
- "traefik.tls.stores.Store0.defaultgeneratedcert.resolver=foobar"
|
|
||||||
- "traefik.tls.stores.Store1.defaultcertificate.certfile=foobar"
|
|
||||||
- "traefik.tls.stores.Store1.defaultcertificate.keyfile=foobar"
|
|
||||||
- "traefik.tls.stores.Store1.defaultgeneratedcert.domain.main=foobar"
|
|
||||||
- "traefik.tls.stores.Store1.defaultgeneratedcert.domain.sans=foobar, foobar"
|
|
||||||
- "traefik.tls.stores.Store1.defaultgeneratedcert.resolver=foobar"
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
## CODE GENERATED AUTOMATICALLY
|
||||||
|
## THIS FILE MUST NOT BE EDITED BY HAND
|
||||||
[http]
|
[http]
|
||||||
[http.routers]
|
[http.routers]
|
||||||
[http.routers.Router0]
|
[http.routers.Router0]
|
||||||
|
@ -5,6 +7,7 @@
|
||||||
middlewares = ["foobar", "foobar"]
|
middlewares = ["foobar", "foobar"]
|
||||||
service = "foobar"
|
service = "foobar"
|
||||||
rule = "foobar"
|
rule = "foobar"
|
||||||
|
ruleSyntax = "foobar"
|
||||||
priority = 42
|
priority = 42
|
||||||
[http.routers.Router0.tls]
|
[http.routers.Router0.tls]
|
||||||
options = "foobar"
|
options = "foobar"
|
||||||
|
@ -22,6 +25,7 @@
|
||||||
middlewares = ["foobar", "foobar"]
|
middlewares = ["foobar", "foobar"]
|
||||||
service = "foobar"
|
service = "foobar"
|
||||||
rule = "foobar"
|
rule = "foobar"
|
||||||
|
ruleSyntax = "foobar"
|
||||||
priority = 42
|
priority = 42
|
||||||
[http.routers.Router1.tls]
|
[http.routers.Router1.tls]
|
||||||
options = "foobar"
|
options = "foobar"
|
||||||
|
@ -36,22 +40,30 @@
|
||||||
sans = ["foobar", "foobar"]
|
sans = ["foobar", "foobar"]
|
||||||
[http.services]
|
[http.services]
|
||||||
[http.services.Service01]
|
[http.services.Service01]
|
||||||
[http.services.Service01.loadBalancer]
|
[http.services.Service01.failover]
|
||||||
|
service = "foobar"
|
||||||
|
fallback = "foobar"
|
||||||
|
[http.services.Service01.failover.healthCheck]
|
||||||
|
[http.services.Service02]
|
||||||
|
[http.services.Service02.loadBalancer]
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
serversTransport = "foobar"
|
serversTransport = "foobar"
|
||||||
[http.services.Service01.loadBalancer.sticky]
|
[http.services.Service02.loadBalancer.sticky]
|
||||||
[http.services.Service01.loadBalancer.sticky.cookie]
|
[http.services.Service02.loadBalancer.sticky.cookie]
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
secure = true
|
secure = true
|
||||||
httpOnly = true
|
httpOnly = true
|
||||||
sameSite = "foobar"
|
sameSite = "foobar"
|
||||||
|
maxAge = 42
|
||||||
|
|
||||||
[[http.services.Service01.loadBalancer.servers]]
|
[[http.services.Service02.loadBalancer.servers]]
|
||||||
url = "foobar"
|
url = "foobar"
|
||||||
|
weight = 42
|
||||||
|
|
||||||
[[http.services.Service01.loadBalancer.servers]]
|
[[http.services.Service02.loadBalancer.servers]]
|
||||||
url = "foobar"
|
url = "foobar"
|
||||||
[http.services.Service01.loadBalancer.healthCheck]
|
weight = 42
|
||||||
|
[http.services.Service02.loadBalancer.healthCheck]
|
||||||
scheme = "foobar"
|
scheme = "foobar"
|
||||||
mode = "foobar"
|
mode = "foobar"
|
||||||
path = "foobar"
|
path = "foobar"
|
||||||
|
@ -62,107 +74,106 @@
|
||||||
timeout = "42s"
|
timeout = "42s"
|
||||||
hostname = "foobar"
|
hostname = "foobar"
|
||||||
followRedirects = true
|
followRedirects = true
|
||||||
[http.services.Service01.loadBalancer.healthCheck.headers]
|
[http.services.Service02.loadBalancer.healthCheck.headers]
|
||||||
name0 = "foobar"
|
name0 = "foobar"
|
||||||
name1 = "foobar"
|
name1 = "foobar"
|
||||||
[http.services.Service01.loadBalancer.responseForwarding]
|
[http.services.Service02.loadBalancer.responseForwarding]
|
||||||
flushInterval = "42s"
|
flushInterval = "42s"
|
||||||
[http.services.Service02]
|
[http.services.Service03]
|
||||||
[http.services.Service02.mirroring]
|
[http.services.Service03.mirroring]
|
||||||
service = "foobar"
|
service = "foobar"
|
||||||
maxBodySize = 42
|
maxBodySize = 42
|
||||||
|
|
||||||
[http.services.Service02.mirroring.healthCheck]
|
[[http.services.Service03.mirroring.mirrors]]
|
||||||
|
|
||||||
[[http.services.Service02.mirroring.mirrors]]
|
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
percent = 42
|
percent = 42
|
||||||
|
|
||||||
[[http.services.Service02.mirroring.mirrors]]
|
[[http.services.Service03.mirroring.mirrors]]
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
percent = 42
|
percent = 42
|
||||||
[http.services.Service03]
|
[http.services.Service03.mirroring.healthCheck]
|
||||||
[http.services.Service03.weighted]
|
[http.services.Service04]
|
||||||
[http.services.Service03.weighted.healthCheck]
|
[http.services.Service04.weighted]
|
||||||
|
|
||||||
[[http.services.Service03.weighted.services]]
|
[[http.services.Service04.weighted.services]]
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
weight = 42
|
weight = 42
|
||||||
|
|
||||||
[[http.services.Service03.weighted.services]]
|
[[http.services.Service04.weighted.services]]
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
weight = 42
|
weight = 42
|
||||||
[http.services.Service03.weighted.sticky]
|
[http.services.Service04.weighted.sticky]
|
||||||
[http.services.Service03.weighted.sticky.cookie]
|
[http.services.Service04.weighted.sticky.cookie]
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
secure = true
|
secure = true
|
||||||
httpOnly = true
|
httpOnly = true
|
||||||
sameSite = "foobar"
|
sameSite = "foobar"
|
||||||
[http.services.Service04]
|
maxAge = 42
|
||||||
[http.services.Service04.failover]
|
[http.services.Service04.weighted.healthCheck]
|
||||||
service = "foobar"
|
|
||||||
fallback = "foobar"
|
|
||||||
|
|
||||||
[http.services.Service04.failover.healthCheck]
|
|
||||||
[http.middlewares]
|
[http.middlewares]
|
||||||
[http.middlewares.Middleware00]
|
|
||||||
[http.middlewares.Middleware00.addPrefix]
|
|
||||||
prefix = "foobar"
|
|
||||||
[http.middlewares.Middleware01]
|
[http.middlewares.Middleware01]
|
||||||
[http.middlewares.Middleware01.basicAuth]
|
[http.middlewares.Middleware01.addPrefix]
|
||||||
|
prefix = "foobar"
|
||||||
|
[http.middlewares.Middleware02]
|
||||||
|
[http.middlewares.Middleware02.basicAuth]
|
||||||
users = ["foobar", "foobar"]
|
users = ["foobar", "foobar"]
|
||||||
usersFile = "foobar"
|
usersFile = "foobar"
|
||||||
realm = "foobar"
|
realm = "foobar"
|
||||||
removeHeader = true
|
removeHeader = true
|
||||||
headerField = "foobar"
|
headerField = "foobar"
|
||||||
[http.middlewares.Middleware02]
|
[http.middlewares.Middleware03]
|
||||||
[http.middlewares.Middleware02.buffering]
|
[http.middlewares.Middleware03.buffering]
|
||||||
maxRequestBodyBytes = 42
|
maxRequestBodyBytes = 42
|
||||||
memRequestBodyBytes = 42
|
memRequestBodyBytes = 42
|
||||||
maxResponseBodyBytes = 42
|
maxResponseBodyBytes = 42
|
||||||
memResponseBodyBytes = 42
|
memResponseBodyBytes = 42
|
||||||
retryExpression = "foobar"
|
retryExpression = "foobar"
|
||||||
[http.middlewares.Middleware03]
|
|
||||||
[http.middlewares.Middleware03.chain]
|
|
||||||
middlewares = ["foobar", "foobar"]
|
|
||||||
[http.middlewares.Middleware04]
|
[http.middlewares.Middleware04]
|
||||||
[http.middlewares.Middleware04.circuitBreaker]
|
[http.middlewares.Middleware04.chain]
|
||||||
|
middlewares = ["foobar", "foobar"]
|
||||||
|
[http.middlewares.Middleware05]
|
||||||
|
[http.middlewares.Middleware05.circuitBreaker]
|
||||||
expression = "foobar"
|
expression = "foobar"
|
||||||
checkPeriod = "42s"
|
checkPeriod = "42s"
|
||||||
fallbackDuration = "42s"
|
fallbackDuration = "42s"
|
||||||
recoveryDuration = "42s"
|
recoveryDuration = "42s"
|
||||||
[http.middlewares.Middleware05]
|
|
||||||
[http.middlewares.Middleware05.compress]
|
|
||||||
excludedContentTypes = ["foobar", "foobar"]
|
|
||||||
minResponseBodyBytes = 42
|
|
||||||
[http.middlewares.Middleware06]
|
[http.middlewares.Middleware06]
|
||||||
[http.middlewares.Middleware06.contentType]
|
[http.middlewares.Middleware06.compress]
|
||||||
|
excludedContentTypes = ["foobar", "foobar"]
|
||||||
|
includedContentTypes = ["foobar", "foobar"]
|
||||||
|
minResponseBodyBytes = 42
|
||||||
[http.middlewares.Middleware07]
|
[http.middlewares.Middleware07]
|
||||||
[http.middlewares.Middleware07.digestAuth]
|
[http.middlewares.Middleware07.contentType]
|
||||||
|
[http.middlewares.Middleware08]
|
||||||
|
[http.middlewares.Middleware08.digestAuth]
|
||||||
users = ["foobar", "foobar"]
|
users = ["foobar", "foobar"]
|
||||||
usersFile = "foobar"
|
usersFile = "foobar"
|
||||||
removeHeader = true
|
removeHeader = true
|
||||||
realm = "foobar"
|
realm = "foobar"
|
||||||
headerField = "foobar"
|
headerField = "foobar"
|
||||||
[http.middlewares.Middleware08]
|
[http.middlewares.Middleware09]
|
||||||
[http.middlewares.Middleware08.errors]
|
[http.middlewares.Middleware09.errors]
|
||||||
status = ["foobar", "foobar"]
|
status = ["foobar", "foobar"]
|
||||||
service = "foobar"
|
service = "foobar"
|
||||||
query = "foobar"
|
query = "foobar"
|
||||||
[http.middlewares.Middleware09]
|
[http.middlewares.Middleware10]
|
||||||
[http.middlewares.Middleware09.forwardAuth]
|
[http.middlewares.Middleware10.forwardAuth]
|
||||||
address = "foobar"
|
address = "foobar"
|
||||||
trustForwardHeader = true
|
trustForwardHeader = true
|
||||||
authResponseHeaders = ["foobar", "foobar"]
|
authResponseHeaders = ["foobar", "foobar"]
|
||||||
authResponseHeadersRegex = "foobar"
|
authResponseHeadersRegex = "foobar"
|
||||||
authRequestHeaders = ["foobar", "foobar"]
|
authRequestHeaders = ["foobar", "foobar"]
|
||||||
[http.middlewares.Middleware09.forwardAuth.tls]
|
addAuthCookiesToResponse = ["foobar", "foobar"]
|
||||||
|
[http.middlewares.Middleware10.forwardAuth.tls]
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
cert = "foobar"
|
cert = "foobar"
|
||||||
key = "foobar"
|
key = "foobar"
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
[http.middlewares.Middleware10]
|
[http.middlewares.Middleware11]
|
||||||
[http.middlewares.Middleware10.headers]
|
[http.middlewares.Middleware11.grpcWeb]
|
||||||
|
allowOrigins = ["foobar", "foobar"]
|
||||||
|
[http.middlewares.Middleware12]
|
||||||
|
[http.middlewares.Middleware12.headers]
|
||||||
accessControlAllowCredentials = true
|
accessControlAllowCredentials = true
|
||||||
accessControlAllowHeaders = ["foobar", "foobar"]
|
accessControlAllowHeaders = ["foobar", "foobar"]
|
||||||
accessControlAllowMethods = ["foobar", "foobar"]
|
accessControlAllowMethods = ["foobar", "foobar"]
|
||||||
|
@ -187,46 +198,46 @@
|
||||||
referrerPolicy = "foobar"
|
referrerPolicy = "foobar"
|
||||||
permissionsPolicy = "foobar"
|
permissionsPolicy = "foobar"
|
||||||
isDevelopment = true
|
isDevelopment = true
|
||||||
[http.middlewares.Middleware10.headers.customRequestHeaders]
|
[http.middlewares.Middleware12.headers.customRequestHeaders]
|
||||||
name0 = "foobar"
|
name0 = "foobar"
|
||||||
name1 = "foobar"
|
name1 = "foobar"
|
||||||
[http.middlewares.Middleware10.headers.customResponseHeaders]
|
[http.middlewares.Middleware12.headers.customResponseHeaders]
|
||||||
name0 = "foobar"
|
name0 = "foobar"
|
||||||
name1 = "foobar"
|
name1 = "foobar"
|
||||||
[http.middlewares.Middleware10.headers.sslProxyHeaders]
|
[http.middlewares.Middleware12.headers.sslProxyHeaders]
|
||||||
name0 = "foobar"
|
name0 = "foobar"
|
||||||
name1 = "foobar"
|
name1 = "foobar"
|
||||||
[http.middlewares.Middleware11]
|
|
||||||
[http.middlewares.Middleware11.ipWhiteList]
|
|
||||||
sourceRange = ["foobar", "foobar"]
|
|
||||||
[http.middlewares.Middleware11.ipWhiteList.ipStrategy]
|
|
||||||
depth = 42
|
|
||||||
excludedIPs = ["foobar", "foobar"]
|
|
||||||
[http.middlewares.Middleware12]
|
|
||||||
[http.middlewares.Middleware12.ipAllowList]
|
|
||||||
sourceRange = ["foobar", "foobar"]
|
|
||||||
rejectStatusCode = 404
|
|
||||||
[http.middlewares.Middleware12.ipAllowList.ipStrategy]
|
|
||||||
depth = 42
|
|
||||||
excludedIPs = ["foobar", "foobar"]
|
|
||||||
[http.middlewares.Middleware13]
|
[http.middlewares.Middleware13]
|
||||||
[http.middlewares.Middleware13.inFlightReq]
|
[http.middlewares.Middleware13.ipAllowList]
|
||||||
|
sourceRange = ["foobar", "foobar"]
|
||||||
|
rejectStatusCode = 42
|
||||||
|
[http.middlewares.Middleware13.ipAllowList.ipStrategy]
|
||||||
|
depth = 42
|
||||||
|
excludedIPs = ["foobar", "foobar"]
|
||||||
|
[http.middlewares.Middleware14]
|
||||||
|
[http.middlewares.Middleware14.ipWhiteList]
|
||||||
|
sourceRange = ["foobar", "foobar"]
|
||||||
|
[http.middlewares.Middleware14.ipWhiteList.ipStrategy]
|
||||||
|
depth = 42
|
||||||
|
excludedIPs = ["foobar", "foobar"]
|
||||||
|
[http.middlewares.Middleware15]
|
||||||
|
[http.middlewares.Middleware15.inFlightReq]
|
||||||
amount = 42
|
amount = 42
|
||||||
[http.middlewares.Middleware13.inFlightReq.sourceCriterion]
|
[http.middlewares.Middleware15.inFlightReq.sourceCriterion]
|
||||||
requestHeaderName = "foobar"
|
requestHeaderName = "foobar"
|
||||||
requestHost = true
|
requestHost = true
|
||||||
[http.middlewares.Middleware13.inFlightReq.sourceCriterion.ipStrategy]
|
[http.middlewares.Middleware15.inFlightReq.sourceCriterion.ipStrategy]
|
||||||
depth = 42
|
depth = 42
|
||||||
excludedIPs = ["foobar", "foobar"]
|
excludedIPs = ["foobar", "foobar"]
|
||||||
[http.middlewares.Middleware14]
|
[http.middlewares.Middleware16]
|
||||||
[http.middlewares.Middleware14.passTLSClientCert]
|
[http.middlewares.Middleware16.passTLSClientCert]
|
||||||
pem = true
|
pem = true
|
||||||
[http.middlewares.Middleware14.passTLSClientCert.info]
|
[http.middlewares.Middleware16.passTLSClientCert.info]
|
||||||
notAfter = true
|
notAfter = true
|
||||||
notBefore = true
|
notBefore = true
|
||||||
sans = true
|
sans = true
|
||||||
serialNumber = true
|
serialNumber = true
|
||||||
[http.middlewares.Middleware14.passTLSClientCert.info.subject]
|
[http.middlewares.Middleware16.passTLSClientCert.info.subject]
|
||||||
country = true
|
country = true
|
||||||
province = true
|
province = true
|
||||||
locality = true
|
locality = true
|
||||||
|
@ -235,7 +246,7 @@
|
||||||
commonName = true
|
commonName = true
|
||||||
serialNumber = true
|
serialNumber = true
|
||||||
domainComponent = true
|
domainComponent = true
|
||||||
[http.middlewares.Middleware14.passTLSClientCert.info.issuer]
|
[http.middlewares.Middleware16.passTLSClientCert.info.issuer]
|
||||||
country = true
|
country = true
|
||||||
province = true
|
province = true
|
||||||
locality = true
|
locality = true
|
||||||
|
@ -243,51 +254,52 @@
|
||||||
commonName = true
|
commonName = true
|
||||||
serialNumber = true
|
serialNumber = true
|
||||||
domainComponent = true
|
domainComponent = true
|
||||||
[http.middlewares.Middleware15]
|
[http.middlewares.Middleware17]
|
||||||
[http.middlewares.Middleware15.plugin]
|
[http.middlewares.Middleware17.plugin]
|
||||||
[http.middlewares.Middleware15.plugin.PluginConf]
|
[http.middlewares.Middleware17.plugin.PluginConf0]
|
||||||
foo = "bar"
|
name0 = "foobar"
|
||||||
[http.middlewares.Middleware16]
|
name1 = "foobar"
|
||||||
[http.middlewares.Middleware16.rateLimit]
|
[http.middlewares.Middleware17.plugin.PluginConf1]
|
||||||
|
name0 = "foobar"
|
||||||
|
name1 = "foobar"
|
||||||
|
[http.middlewares.Middleware18]
|
||||||
|
[http.middlewares.Middleware18.rateLimit]
|
||||||
average = 42
|
average = 42
|
||||||
period = "42s"
|
period = "42s"
|
||||||
burst = 42
|
burst = 42
|
||||||
[http.middlewares.Middleware16.rateLimit.sourceCriterion]
|
[http.middlewares.Middleware18.rateLimit.sourceCriterion]
|
||||||
requestHeaderName = "foobar"
|
requestHeaderName = "foobar"
|
||||||
requestHost = true
|
requestHost = true
|
||||||
[http.middlewares.Middleware16.rateLimit.sourceCriterion.ipStrategy]
|
[http.middlewares.Middleware18.rateLimit.sourceCriterion.ipStrategy]
|
||||||
depth = 42
|
depth = 42
|
||||||
excludedIPs = ["foobar", "foobar"]
|
excludedIPs = ["foobar", "foobar"]
|
||||||
[http.middlewares.Middleware17]
|
[http.middlewares.Middleware19]
|
||||||
[http.middlewares.Middleware17.redirectRegex]
|
[http.middlewares.Middleware19.redirectRegex]
|
||||||
regex = "foobar"
|
regex = "foobar"
|
||||||
replacement = "foobar"
|
replacement = "foobar"
|
||||||
permanent = true
|
permanent = true
|
||||||
[http.middlewares.Middleware18]
|
[http.middlewares.Middleware20]
|
||||||
[http.middlewares.Middleware18.redirectScheme]
|
[http.middlewares.Middleware20.redirectScheme]
|
||||||
scheme = "foobar"
|
scheme = "foobar"
|
||||||
port = "foobar"
|
port = "foobar"
|
||||||
permanent = true
|
permanent = true
|
||||||
[http.middlewares.Middleware19]
|
[http.middlewares.Middleware21]
|
||||||
[http.middlewares.Middleware19.replacePath]
|
[http.middlewares.Middleware21.replacePath]
|
||||||
path = "foobar"
|
path = "foobar"
|
||||||
[http.middlewares.Middleware20]
|
[http.middlewares.Middleware22]
|
||||||
[http.middlewares.Middleware20.replacePathRegex]
|
[http.middlewares.Middleware22.replacePathRegex]
|
||||||
regex = "foobar"
|
regex = "foobar"
|
||||||
replacement = "foobar"
|
replacement = "foobar"
|
||||||
[http.middlewares.Middleware21]
|
[http.middlewares.Middleware23]
|
||||||
[http.middlewares.Middleware21.retry]
|
[http.middlewares.Middleware23.retry]
|
||||||
attempts = 42
|
attempts = 42
|
||||||
initialInterval = "42s"
|
initialInterval = "42s"
|
||||||
[http.middlewares.Middleware22]
|
|
||||||
[http.middlewares.Middleware22.stripPrefix]
|
|
||||||
prefixes = ["foobar", "foobar"]
|
|
||||||
[http.middlewares.Middleware23]
|
|
||||||
[http.middlewares.Middleware23.stripPrefixRegex]
|
|
||||||
regex = ["foobar", "foobar"]
|
|
||||||
[http.middlewares.Middleware24]
|
[http.middlewares.Middleware24]
|
||||||
[http.middlewares.Middleware24.grpcWeb]
|
[http.middlewares.Middleware24.stripPrefix]
|
||||||
allowOrigins = ["foobar", "foobar"]
|
prefixes = ["foobar", "foobar"]
|
||||||
|
[http.middlewares.Middleware25]
|
||||||
|
[http.middlewares.Middleware25.stripPrefixRegex]
|
||||||
|
regex = ["foobar", "foobar"]
|
||||||
[http.serversTransports]
|
[http.serversTransports]
|
||||||
[http.serversTransports.ServersTransport0]
|
[http.serversTransports.ServersTransport0]
|
||||||
serverName = "foobar"
|
serverName = "foobar"
|
||||||
|
@ -304,18 +316,15 @@
|
||||||
[[http.serversTransports.ServersTransport0.certificates]]
|
[[http.serversTransports.ServersTransport0.certificates]]
|
||||||
certFile = "foobar"
|
certFile = "foobar"
|
||||||
keyFile = "foobar"
|
keyFile = "foobar"
|
||||||
|
|
||||||
[http.serversTransports.ServersTransport0.forwardingTimeouts]
|
[http.serversTransports.ServersTransport0.forwardingTimeouts]
|
||||||
dialTimeout = "42s"
|
dialTimeout = "42s"
|
||||||
responseHeaderTimeout = "42s"
|
responseHeaderTimeout = "42s"
|
||||||
idleConnTimeout = "42s"
|
idleConnTimeout = "42s"
|
||||||
readIdleTimeout = "42s"
|
readIdleTimeout = "42s"
|
||||||
pingTimeout = "42s"
|
pingTimeout = "42s"
|
||||||
|
|
||||||
[http.serversTransports.ServersTransport0.spiffe]
|
[http.serversTransports.ServersTransport0.spiffe]
|
||||||
ids = ["foobar", "foobar"]
|
ids = ["foobar", "foobar"]
|
||||||
trustDomain = "foobar"
|
trustDomain = "foobar"
|
||||||
|
|
||||||
[http.serversTransports.ServersTransport1]
|
[http.serversTransports.ServersTransport1]
|
||||||
serverName = "foobar"
|
serverName = "foobar"
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
|
@ -331,14 +340,12 @@
|
||||||
[[http.serversTransports.ServersTransport1.certificates]]
|
[[http.serversTransports.ServersTransport1.certificates]]
|
||||||
certFile = "foobar"
|
certFile = "foobar"
|
||||||
keyFile = "foobar"
|
keyFile = "foobar"
|
||||||
|
|
||||||
[http.serversTransports.ServersTransport1.forwardingTimeouts]
|
[http.serversTransports.ServersTransport1.forwardingTimeouts]
|
||||||
dialTimeout = "42s"
|
dialTimeout = "42s"
|
||||||
responseHeaderTimeout = "42s"
|
responseHeaderTimeout = "42s"
|
||||||
idleConnTimeout = "42s"
|
idleConnTimeout = "42s"
|
||||||
readIdleTimeout = "42s"
|
readIdleTimeout = "42s"
|
||||||
pingTimeout = "42s"
|
pingTimeout = "42s"
|
||||||
|
|
||||||
[http.serversTransports.ServersTransport1.spiffe]
|
[http.serversTransports.ServersTransport1.spiffe]
|
||||||
ids = ["foobar", "foobar"]
|
ids = ["foobar", "foobar"]
|
||||||
trustDomain = "foobar"
|
trustDomain = "foobar"
|
||||||
|
@ -350,6 +357,7 @@
|
||||||
middlewares = ["foobar", "foobar"]
|
middlewares = ["foobar", "foobar"]
|
||||||
service = "foobar"
|
service = "foobar"
|
||||||
rule = "foobar"
|
rule = "foobar"
|
||||||
|
ruleSyntax = "foobar"
|
||||||
priority = 42
|
priority = 42
|
||||||
[tcp.routers.TCPRouter0.tls]
|
[tcp.routers.TCPRouter0.tls]
|
||||||
passthrough = true
|
passthrough = true
|
||||||
|
@ -368,6 +376,7 @@
|
||||||
middlewares = ["foobar", "foobar"]
|
middlewares = ["foobar", "foobar"]
|
||||||
service = "foobar"
|
service = "foobar"
|
||||||
rule = "foobar"
|
rule = "foobar"
|
||||||
|
ruleSyntax = "foobar"
|
||||||
priority = 42
|
priority = 42
|
||||||
[tcp.routers.TCPRouter1.tls]
|
[tcp.routers.TCPRouter1.tls]
|
||||||
passthrough = true
|
passthrough = true
|
||||||
|
@ -405,21 +414,21 @@
|
||||||
[[tcp.services.TCPService02.weighted.services]]
|
[[tcp.services.TCPService02.weighted.services]]
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
weight = 42
|
weight = 42
|
||||||
|
|
||||||
[tcp.middlewares]
|
[tcp.middlewares]
|
||||||
[tcp.middlewares.TCPMiddleware00]
|
|
||||||
[tcp.middlewares.TCPMiddleware00.ipAllowList]
|
|
||||||
sourceRange = ["foobar", "foobar"]
|
|
||||||
[tcp.middlewares.TCPMiddleware01]
|
[tcp.middlewares.TCPMiddleware01]
|
||||||
[tcp.middlewares.TCPMiddleware01.inFlightConn]
|
[tcp.middlewares.TCPMiddleware01.ipAllowList]
|
||||||
|
sourceRange = ["foobar", "foobar"]
|
||||||
|
[tcp.middlewares.TCPMiddleware02]
|
||||||
|
[tcp.middlewares.TCPMiddleware02.ipWhiteList]
|
||||||
|
sourceRange = ["foobar", "foobar"]
|
||||||
|
[tcp.middlewares.TCPMiddleware03]
|
||||||
|
[tcp.middlewares.TCPMiddleware03.inFlightConn]
|
||||||
amount = 42
|
amount = 42
|
||||||
|
|
||||||
[tcp.serversTransports]
|
[tcp.serversTransports]
|
||||||
[tcp.serversTransports.TCPServersTransport0]
|
[tcp.serversTransports.TCPServersTransport0]
|
||||||
dialTimeout = "42s"
|
|
||||||
dialKeepAlive = "42s"
|
dialKeepAlive = "42s"
|
||||||
|
dialTimeout = "42s"
|
||||||
terminationDelay = "42s"
|
terminationDelay = "42s"
|
||||||
|
|
||||||
[tcp.serversTransports.TCPServersTransport0.tls]
|
[tcp.serversTransports.TCPServersTransport0.tls]
|
||||||
serverName = "foobar"
|
serverName = "foobar"
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
|
@ -433,16 +442,13 @@
|
||||||
[[tcp.serversTransports.TCPServersTransport0.tls.certificates]]
|
[[tcp.serversTransports.TCPServersTransport0.tls.certificates]]
|
||||||
certFile = "foobar"
|
certFile = "foobar"
|
||||||
keyFile = "foobar"
|
keyFile = "foobar"
|
||||||
|
[tcp.serversTransports.TCPServersTransport0.tls.spiffe]
|
||||||
[tcp.serversTransports.TCPServersTransport0.spiffe]
|
ids = ["foobar", "foobar"]
|
||||||
ids = ["foobar", "foobar"]
|
trustDomain = "foobar"
|
||||||
trustDomain = "foobar"
|
|
||||||
|
|
||||||
[tcp.serversTransports.TCPServersTransport1]
|
[tcp.serversTransports.TCPServersTransport1]
|
||||||
dialTimeout = "42s"
|
|
||||||
dialKeepAlive = "42s"
|
dialKeepAlive = "42s"
|
||||||
|
dialTimeout = "42s"
|
||||||
terminationDelay = "42s"
|
terminationDelay = "42s"
|
||||||
|
|
||||||
[tcp.serversTransports.TCPServersTransport1.tls]
|
[tcp.serversTransports.TCPServersTransport1.tls]
|
||||||
serverName = "foobar"
|
serverName = "foobar"
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
|
@ -456,10 +462,9 @@
|
||||||
[[tcp.serversTransports.TCPServersTransport1.tls.certificates]]
|
[[tcp.serversTransports.TCPServersTransport1.tls.certificates]]
|
||||||
certFile = "foobar"
|
certFile = "foobar"
|
||||||
keyFile = "foobar"
|
keyFile = "foobar"
|
||||||
|
[tcp.serversTransports.TCPServersTransport1.tls.spiffe]
|
||||||
[tcp.serversTransports.TCPServersTransport1.spiffe]
|
ids = ["foobar", "foobar"]
|
||||||
ids = ["foobar", "foobar"]
|
trustDomain = "foobar"
|
||||||
trustDomain = "foobar"
|
|
||||||
|
|
||||||
[udp]
|
[udp]
|
||||||
[udp.routers]
|
[udp.routers]
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
## CODE GENERATED AUTOMATICALLY
|
||||||
|
## THIS FILE MUST NOT BE EDITED BY HAND
|
||||||
http:
|
http:
|
||||||
routers:
|
routers:
|
||||||
Router0:
|
Router0:
|
||||||
|
@ -9,6 +11,7 @@ http:
|
||||||
- foobar
|
- foobar
|
||||||
service: foobar
|
service: foobar
|
||||||
rule: foobar
|
rule: foobar
|
||||||
|
ruleSyntax: foobar
|
||||||
priority: 42
|
priority: 42
|
||||||
tls:
|
tls:
|
||||||
options: foobar
|
options: foobar
|
||||||
|
@ -31,6 +34,7 @@ http:
|
||||||
- foobar
|
- foobar
|
||||||
service: foobar
|
service: foobar
|
||||||
rule: foobar
|
rule: foobar
|
||||||
|
ruleSyntax: foobar
|
||||||
priority: 42
|
priority: 42
|
||||||
tls:
|
tls:
|
||||||
options: foobar
|
options: foobar
|
||||||
|
@ -46,6 +50,11 @@ http:
|
||||||
- foobar
|
- foobar
|
||||||
services:
|
services:
|
||||||
Service01:
|
Service01:
|
||||||
|
failover:
|
||||||
|
service: foobar
|
||||||
|
fallback: foobar
|
||||||
|
healthCheck: {}
|
||||||
|
Service02:
|
||||||
loadBalancer:
|
loadBalancer:
|
||||||
sticky:
|
sticky:
|
||||||
cookie:
|
cookie:
|
||||||
|
@ -53,9 +62,12 @@ http:
|
||||||
secure: true
|
secure: true
|
||||||
httpOnly: true
|
httpOnly: true
|
||||||
sameSite: foobar
|
sameSite: foobar
|
||||||
|
maxAge: 42
|
||||||
servers:
|
servers:
|
||||||
- url: foobar
|
- url: foobar
|
||||||
|
weight: 42
|
||||||
- url: foobar
|
- url: foobar
|
||||||
|
weight: 42
|
||||||
healthCheck:
|
healthCheck:
|
||||||
scheme: foobar
|
scheme: foobar
|
||||||
mode: foobar
|
mode: foobar
|
||||||
|
@ -74,19 +86,18 @@ http:
|
||||||
responseForwarding:
|
responseForwarding:
|
||||||
flushInterval: 42s
|
flushInterval: 42s
|
||||||
serversTransport: foobar
|
serversTransport: foobar
|
||||||
Service02:
|
Service03:
|
||||||
mirroring:
|
mirroring:
|
||||||
service: foobar
|
service: foobar
|
||||||
maxBodySize: 42
|
maxBodySize: 42
|
||||||
healthCheck: {}
|
|
||||||
mirrors:
|
mirrors:
|
||||||
- name: foobar
|
- name: foobar
|
||||||
percent: 42
|
percent: 42
|
||||||
- name: foobar
|
- name: foobar
|
||||||
percent: 42
|
percent: 42
|
||||||
Service03:
|
|
||||||
weighted:
|
|
||||||
healthCheck: {}
|
healthCheck: {}
|
||||||
|
Service04:
|
||||||
|
weighted:
|
||||||
services:
|
services:
|
||||||
- name: foobar
|
- name: foobar
|
||||||
weight: 42
|
weight: 42
|
||||||
|
@ -98,16 +109,13 @@ http:
|
||||||
secure: true
|
secure: true
|
||||||
httpOnly: true
|
httpOnly: true
|
||||||
sameSite: foobar
|
sameSite: foobar
|
||||||
Service04:
|
maxAge: 42
|
||||||
failover:
|
|
||||||
service: foobar
|
|
||||||
fallback: foobar
|
|
||||||
healthCheck: {}
|
healthCheck: {}
|
||||||
middlewares:
|
middlewares:
|
||||||
Middleware00:
|
Middleware01:
|
||||||
addPrefix:
|
addPrefix:
|
||||||
prefix: foobar
|
prefix: foobar
|
||||||
Middleware01:
|
Middleware02:
|
||||||
basicAuth:
|
basicAuth:
|
||||||
users:
|
users:
|
||||||
- foobar
|
- foobar
|
||||||
|
@ -116,33 +124,36 @@ http:
|
||||||
realm: foobar
|
realm: foobar
|
||||||
removeHeader: true
|
removeHeader: true
|
||||||
headerField: foobar
|
headerField: foobar
|
||||||
Middleware02:
|
Middleware03:
|
||||||
buffering:
|
buffering:
|
||||||
maxRequestBodyBytes: 42
|
maxRequestBodyBytes: 42
|
||||||
memRequestBodyBytes: 42
|
memRequestBodyBytes: 42
|
||||||
maxResponseBodyBytes: 42
|
maxResponseBodyBytes: 42
|
||||||
memResponseBodyBytes: 42
|
memResponseBodyBytes: 42
|
||||||
retryExpression: foobar
|
retryExpression: foobar
|
||||||
Middleware03:
|
Middleware04:
|
||||||
chain:
|
chain:
|
||||||
middlewares:
|
middlewares:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
Middleware04:
|
Middleware05:
|
||||||
circuitBreaker:
|
circuitBreaker:
|
||||||
expression: foobar
|
expression: foobar
|
||||||
checkPeriod: 42s
|
checkPeriod: 42s
|
||||||
fallbackDuration: 42s
|
fallbackDuration: 42s
|
||||||
recoveryDuration: 42s
|
recoveryDuration: 42s
|
||||||
Middleware05:
|
Middleware06:
|
||||||
compress:
|
compress:
|
||||||
excludedContentTypes:
|
excludedContentTypes:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
|
includedContentTypes:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
minResponseBodyBytes: 42
|
minResponseBodyBytes: 42
|
||||||
Middleware06:
|
|
||||||
contentType: {}
|
|
||||||
Middleware07:
|
Middleware07:
|
||||||
|
contentType: {}
|
||||||
|
Middleware08:
|
||||||
digestAuth:
|
digestAuth:
|
||||||
users:
|
users:
|
||||||
- foobar
|
- foobar
|
||||||
|
@ -151,14 +162,14 @@ http:
|
||||||
removeHeader: true
|
removeHeader: true
|
||||||
realm: foobar
|
realm: foobar
|
||||||
headerField: foobar
|
headerField: foobar
|
||||||
Middleware08:
|
Middleware09:
|
||||||
errors:
|
errors:
|
||||||
status:
|
status:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
service: foobar
|
service: foobar
|
||||||
query: foobar
|
query: foobar
|
||||||
Middleware09:
|
Middleware10:
|
||||||
forwardAuth:
|
forwardAuth:
|
||||||
address: foobar
|
address: foobar
|
||||||
tls:
|
tls:
|
||||||
|
@ -174,7 +185,15 @@ http:
|
||||||
authRequestHeaders:
|
authRequestHeaders:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
Middleware10:
|
addAuthCookiesToResponse:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
Middleware11:
|
||||||
|
grpcWeb:
|
||||||
|
allowOrigins:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
Middleware12:
|
||||||
headers:
|
headers:
|
||||||
customRequestHeaders:
|
customRequestHeaders:
|
||||||
name0: foobar
|
name0: foobar
|
||||||
|
@ -223,7 +242,18 @@ http:
|
||||||
referrerPolicy: foobar
|
referrerPolicy: foobar
|
||||||
permissionsPolicy: foobar
|
permissionsPolicy: foobar
|
||||||
isDevelopment: true
|
isDevelopment: true
|
||||||
Middleware11:
|
Middleware13:
|
||||||
|
ipAllowList:
|
||||||
|
sourceRange:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
ipStrategy:
|
||||||
|
depth: 42
|
||||||
|
excludedIPs:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
rejectStatusCode: 42
|
||||||
|
Middleware14:
|
||||||
ipWhiteList:
|
ipWhiteList:
|
||||||
sourceRange:
|
sourceRange:
|
||||||
- foobar
|
- foobar
|
||||||
|
@ -233,18 +263,7 @@ http:
|
||||||
excludedIPs:
|
excludedIPs:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
Middleware12:
|
Middleware15:
|
||||||
ipAllowList:
|
|
||||||
rejectStatusCode: 404
|
|
||||||
sourceRange:
|
|
||||||
- foobar
|
|
||||||
- foobar
|
|
||||||
ipStrategy:
|
|
||||||
depth: 42
|
|
||||||
excludedIPs:
|
|
||||||
- foobar
|
|
||||||
- foobar
|
|
||||||
Middleware13:
|
|
||||||
inFlightReq:
|
inFlightReq:
|
||||||
amount: 42
|
amount: 42
|
||||||
sourceCriterion:
|
sourceCriterion:
|
||||||
|
@ -255,13 +274,14 @@ http:
|
||||||
- foobar
|
- foobar
|
||||||
requestHeaderName: foobar
|
requestHeaderName: foobar
|
||||||
requestHost: true
|
requestHost: true
|
||||||
Middleware14:
|
Middleware16:
|
||||||
passTLSClientCert:
|
passTLSClientCert:
|
||||||
pem: true
|
pem: true
|
||||||
info:
|
info:
|
||||||
notAfter: true
|
notAfter: true
|
||||||
notBefore: true
|
notBefore: true
|
||||||
sans: true
|
sans: true
|
||||||
|
serialNumber: true
|
||||||
subject:
|
subject:
|
||||||
country: true
|
country: true
|
||||||
province: true
|
province: true
|
||||||
|
@ -279,12 +299,15 @@ http:
|
||||||
commonName: true
|
commonName: true
|
||||||
serialNumber: true
|
serialNumber: true
|
||||||
domainComponent: true
|
domainComponent: true
|
||||||
serialNumber: true
|
Middleware17:
|
||||||
Middleware15:
|
|
||||||
plugin:
|
plugin:
|
||||||
PluginConf:
|
PluginConf0:
|
||||||
foo: bar
|
name0: foobar
|
||||||
Middleware16:
|
name1: foobar
|
||||||
|
PluginConf1:
|
||||||
|
name0: foobar
|
||||||
|
name1: foobar
|
||||||
|
Middleware18:
|
||||||
rateLimit:
|
rateLimit:
|
||||||
average: 42
|
average: 42
|
||||||
period: 42s
|
period: 42s
|
||||||
|
@ -297,42 +320,37 @@ http:
|
||||||
- foobar
|
- foobar
|
||||||
requestHeaderName: foobar
|
requestHeaderName: foobar
|
||||||
requestHost: true
|
requestHost: true
|
||||||
Middleware17:
|
Middleware19:
|
||||||
redirectRegex:
|
redirectRegex:
|
||||||
regex: foobar
|
regex: foobar
|
||||||
replacement: foobar
|
replacement: foobar
|
||||||
permanent: true
|
permanent: true
|
||||||
Middleware18:
|
Middleware20:
|
||||||
redirectScheme:
|
redirectScheme:
|
||||||
scheme: foobar
|
scheme: foobar
|
||||||
port: foobar
|
port: foobar
|
||||||
permanent: true
|
permanent: true
|
||||||
Middleware19:
|
Middleware21:
|
||||||
replacePath:
|
replacePath:
|
||||||
path: foobar
|
path: foobar
|
||||||
Middleware20:
|
Middleware22:
|
||||||
replacePathRegex:
|
replacePathRegex:
|
||||||
regex: foobar
|
regex: foobar
|
||||||
replacement: foobar
|
replacement: foobar
|
||||||
Middleware21:
|
Middleware23:
|
||||||
retry:
|
retry:
|
||||||
attempts: 42
|
attempts: 42
|
||||||
initialInterval: 42s
|
initialInterval: 42s
|
||||||
Middleware22:
|
Middleware24:
|
||||||
stripPrefix:
|
stripPrefix:
|
||||||
prefixes:
|
prefixes:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
Middleware23:
|
Middleware25:
|
||||||
stripPrefixRegex:
|
stripPrefixRegex:
|
||||||
regex:
|
regex:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
Middleware24:
|
|
||||||
grpcWeb:
|
|
||||||
allowOrigins:
|
|
||||||
- foobar
|
|
||||||
- foobar
|
|
||||||
serversTransports:
|
serversTransports:
|
||||||
ServersTransport0:
|
ServersTransport0:
|
||||||
serverName: foobar
|
serverName: foobar
|
||||||
|
@ -359,7 +377,6 @@ http:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
trustDomain: foobar
|
trustDomain: foobar
|
||||||
|
|
||||||
ServersTransport1:
|
ServersTransport1:
|
||||||
serverName: foobar
|
serverName: foobar
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
|
@ -385,7 +402,6 @@ http:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
trustDomain: foobar
|
trustDomain: foobar
|
||||||
|
|
||||||
tcp:
|
tcp:
|
||||||
routers:
|
routers:
|
||||||
TCPRouter0:
|
TCPRouter0:
|
||||||
|
@ -397,6 +413,7 @@ tcp:
|
||||||
- foobar
|
- foobar
|
||||||
service: foobar
|
service: foobar
|
||||||
rule: foobar
|
rule: foobar
|
||||||
|
ruleSyntax: foobar
|
||||||
priority: 42
|
priority: 42
|
||||||
tls:
|
tls:
|
||||||
passthrough: true
|
passthrough: true
|
||||||
|
@ -420,6 +437,7 @@ tcp:
|
||||||
- foobar
|
- foobar
|
||||||
service: foobar
|
service: foobar
|
||||||
rule: foobar
|
rule: foobar
|
||||||
|
ruleSyntax: foobar
|
||||||
priority: 42
|
priority: 42
|
||||||
tls:
|
tls:
|
||||||
passthrough: true
|
passthrough: true
|
||||||
|
@ -437,7 +455,6 @@ tcp:
|
||||||
services:
|
services:
|
||||||
TCPService01:
|
TCPService01:
|
||||||
loadBalancer:
|
loadBalancer:
|
||||||
serversTransport: foobar
|
|
||||||
proxyProtocol:
|
proxyProtocol:
|
||||||
version: 42
|
version: 42
|
||||||
servers:
|
servers:
|
||||||
|
@ -445,6 +462,7 @@ tcp:
|
||||||
tls: true
|
tls: true
|
||||||
- address: foobar
|
- address: foobar
|
||||||
tls: true
|
tls: true
|
||||||
|
serversTransport: foobar
|
||||||
TCPService02:
|
TCPService02:
|
||||||
weighted:
|
weighted:
|
||||||
services:
|
services:
|
||||||
|
@ -453,23 +471,23 @@ tcp:
|
||||||
- name: foobar
|
- name: foobar
|
||||||
weight: 42
|
weight: 42
|
||||||
middlewares:
|
middlewares:
|
||||||
TCPMiddleware00:
|
TCPMiddleware01:
|
||||||
ipAllowList:
|
ipAllowList:
|
||||||
sourceRange:
|
sourceRange:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
TCPMiddleware01:
|
TCPMiddleware02:
|
||||||
|
ipWhiteList:
|
||||||
|
sourceRange:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
TCPMiddleware03:
|
||||||
inFlightConn:
|
inFlightConn:
|
||||||
amount: 42
|
amount: 42
|
||||||
TCPMiddleware02:
|
|
||||||
ipAllowList:
|
|
||||||
sourceRange:
|
|
||||||
- foobar
|
|
||||||
- foobar
|
|
||||||
serversTransports:
|
serversTransports:
|
||||||
TCPServersTransport0:
|
TCPServersTransport0:
|
||||||
dialTimeout: 42s
|
|
||||||
dialKeepAlive: 42s
|
dialKeepAlive: 42s
|
||||||
|
dialTimeout: 42s
|
||||||
terminationDelay: 42s
|
terminationDelay: 42s
|
||||||
tls:
|
tls:
|
||||||
serverName: foobar
|
serverName: foobar
|
||||||
|
@ -483,14 +501,14 @@ tcp:
|
||||||
- certFile: foobar
|
- certFile: foobar
|
||||||
keyFile: foobar
|
keyFile: foobar
|
||||||
peerCertURI: foobar
|
peerCertURI: foobar
|
||||||
spiffe:
|
spiffe:
|
||||||
ids:
|
ids:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
trustDomain: foobar
|
trustDomain: foobar
|
||||||
TCPServersTransport1:
|
TCPServersTransport1:
|
||||||
dialTimeout: 42s
|
|
||||||
dialKeepAlive: 42s
|
dialKeepAlive: 42s
|
||||||
|
dialTimeout: 42s
|
||||||
terminationDelay: 42s
|
terminationDelay: 42s
|
||||||
tls:
|
tls:
|
||||||
serverName: foobar
|
serverName: foobar
|
||||||
|
@ -504,11 +522,11 @@ tcp:
|
||||||
- certFile: foobar
|
- certFile: foobar
|
||||||
keyFile: foobar
|
keyFile: foobar
|
||||||
peerCertURI: foobar
|
peerCertURI: foobar
|
||||||
spiffe:
|
spiffe:
|
||||||
ids:
|
ids:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
trustDomain: foobar
|
trustDomain: foobar
|
||||||
udp:
|
udp:
|
||||||
routers:
|
routers:
|
||||||
UDPRouter0:
|
UDPRouter0:
|
||||||
|
|
|
@ -160,6 +160,12 @@ spec:
|
||||||
can be accessed by client-side APIs, such as
|
can be accessed by client-side APIs, such as
|
||||||
JavaScript.
|
JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When
|
||||||
|
set to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -189,6 +195,10 @@ spec:
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
syntax:
|
||||||
|
description: 'Syntax defines the router''s rule syntax. More
|
||||||
|
info: https://doc.traefik.io/traefik/v3.0/routing/routers/#rulesyntax'
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- kind
|
- kind
|
||||||
- match
|
- match
|
||||||
|
@ -396,6 +406,10 @@ spec:
|
||||||
- port
|
- port
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
syntax:
|
||||||
|
description: 'Syntax defines the router''s rule syntax. More
|
||||||
|
info: https://doc.traefik.io/traefik/v3.0/routing/routers/#rulesyntax_1'
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- match
|
- match
|
||||||
type: object
|
type: object
|
||||||
|
@ -750,6 +764,13 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
includedContentTypes:
|
||||||
|
description: IncludedContentTypes defines the list of content
|
||||||
|
types to compare the Content-Type header of the responses before
|
||||||
|
compressing.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
minResponseBodyBytes:
|
minResponseBodyBytes:
|
||||||
description: 'MinResponseBodyBytes defines the minimum amount
|
description: 'MinResponseBodyBytes defines the minimum amount
|
||||||
of bytes a response body must have to be compressed. Default:
|
of bytes a response body must have to be compressed. Default:
|
||||||
|
@ -870,6 +891,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie can
|
description: HTTPOnly defines whether the cookie can
|
||||||
be accessed by client-side APIs, such as JavaScript.
|
be accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When set
|
||||||
|
to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -912,6 +939,12 @@ spec:
|
||||||
This middleware delegates the request authentication to a Service.
|
This middleware delegates the request authentication to a Service.
|
||||||
More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/forwardauth/'
|
More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/forwardauth/'
|
||||||
properties:
|
properties:
|
||||||
|
addAuthCookiesToResponse:
|
||||||
|
description: AddAuthCookiesToResponse defines the list of cookies
|
||||||
|
to copy from the authentication server response to the response.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
address:
|
address:
|
||||||
description: Address defines the authentication server address.
|
description: Address defines the authentication server address.
|
||||||
type: string
|
type: string
|
||||||
|
@ -2145,6 +2178,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie
|
description: HTTPOnly defines whether the cookie
|
||||||
can be accessed by client-side APIs, such as JavaScript.
|
can be accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When set
|
||||||
|
to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -2236,6 +2275,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie can be
|
description: HTTPOnly defines whether the cookie can be
|
||||||
accessed by client-side APIs, such as JavaScript.
|
accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds until
|
||||||
|
the cookie expires. When set to a negative number, the
|
||||||
|
cookie expires immediately. When set to zero, the cookie
|
||||||
|
never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -2343,6 +2388,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie
|
description: HTTPOnly defines whether the cookie
|
||||||
can be accessed by client-side APIs, such as JavaScript.
|
can be accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When set
|
||||||
|
to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -2382,6 +2433,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie can be
|
description: HTTPOnly defines whether the cookie can be
|
||||||
accessed by client-side APIs, such as JavaScript.
|
accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds until
|
||||||
|
the cookie expires. When set to a negative number, the
|
||||||
|
cookie expires immediately. When set to zero, the cookie
|
||||||
|
never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -1,152 +1,164 @@
|
||||||
| `traefik/http/middlewares/Middleware00/addPrefix/prefix` | `foobar` |
|
<!--
|
||||||
| `traefik/http/middlewares/Middleware01/basicAuth/headerField` | `foobar` |
|
CODE GENERATED AUTOMATICALLY
|
||||||
| `traefik/http/middlewares/Middleware01/basicAuth/realm` | `foobar` |
|
THIS FILE MUST NOT BE EDITED BY HAND
|
||||||
| `traefik/http/middlewares/Middleware01/basicAuth/removeHeader` | `true` |
|
-->
|
||||||
| `traefik/http/middlewares/Middleware01/basicAuth/users/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware01/addPrefix/prefix` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware01/basicAuth/users/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware02/basicAuth/headerField` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware01/basicAuth/usersFile` | `foobar` |
|
| `traefik/http/middlewares/Middleware02/basicAuth/realm` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware02/buffering/maxRequestBodyBytes` | `42` |
|
| `traefik/http/middlewares/Middleware02/basicAuth/removeHeader` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware02/buffering/maxResponseBodyBytes` | `42` |
|
| `traefik/http/middlewares/Middleware02/basicAuth/users/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware02/buffering/memRequestBodyBytes` | `42` |
|
| `traefik/http/middlewares/Middleware02/basicAuth/users/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware02/buffering/memResponseBodyBytes` | `42` |
|
| `traefik/http/middlewares/Middleware02/basicAuth/usersFile` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware02/buffering/retryExpression` | `foobar` |
|
| `traefik/http/middlewares/Middleware03/buffering/maxRequestBodyBytes` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware03/chain/middlewares/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware03/buffering/maxResponseBodyBytes` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware03/chain/middlewares/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware03/buffering/memRequestBodyBytes` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware04/circuitBreaker/checkPeriod` | `42s` |
|
| `traefik/http/middlewares/Middleware03/buffering/memResponseBodyBytes` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware04/circuitBreaker/expression` | `foobar` |
|
| `traefik/http/middlewares/Middleware03/buffering/retryExpression` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware04/circuitBreaker/fallbackDuration` | `42s` |
|
| `traefik/http/middlewares/Middleware04/chain/middlewares/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware04/circuitBreaker/recoveryDuration` | `42s` |
|
| `traefik/http/middlewares/Middleware04/chain/middlewares/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware05/compress/excludedContentTypes/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware05/circuitBreaker/checkPeriod` | `42s` |
|
||||||
| `traefik/http/middlewares/Middleware05/compress/excludedContentTypes/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware05/circuitBreaker/expression` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware05/compress/minResponseBodyBytes` | `42` |
|
| `traefik/http/middlewares/Middleware05/circuitBreaker/fallbackDuration` | `42s` |
|
||||||
| `traefik/http/middlewares/Middleware06/contentType` | `` |
|
| `traefik/http/middlewares/Middleware05/circuitBreaker/recoveryDuration` | `42s` |
|
||||||
| `traefik/http/middlewares/Middleware07/digestAuth/headerField` | `foobar` |
|
| `traefik/http/middlewares/Middleware06/compress/excludedContentTypes/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware07/digestAuth/realm` | `foobar` |
|
| `traefik/http/middlewares/Middleware06/compress/excludedContentTypes/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware07/digestAuth/removeHeader` | `true` |
|
| `traefik/http/middlewares/Middleware06/compress/includedContentTypes/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware07/digestAuth/users/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware06/compress/includedContentTypes/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware07/digestAuth/users/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware06/compress/minResponseBodyBytes` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware07/digestAuth/usersFile` | `foobar` |
|
| `traefik/http/middlewares/Middleware07/contentType` | `` |
|
||||||
| `traefik/http/middlewares/Middleware08/errors/query` | `foobar` |
|
| `traefik/http/middlewares/Middleware08/digestAuth/headerField` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware08/errors/service` | `foobar` |
|
| `traefik/http/middlewares/Middleware08/digestAuth/realm` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware08/errors/status/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware08/digestAuth/removeHeader` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware08/errors/status/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware08/digestAuth/users/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware09/forwardAuth/address` | `foobar` |
|
| `traefik/http/middlewares/Middleware08/digestAuth/users/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware09/forwardAuth/authRequestHeaders/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware08/digestAuth/usersFile` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware09/forwardAuth/authRequestHeaders/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware09/errors/query` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware09/forwardAuth/authResponseHeaders/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware09/errors/service` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware09/forwardAuth/authResponseHeaders/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware09/errors/status/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware09/forwardAuth/authResponseHeadersRegex` | `foobar` |
|
| `traefik/http/middlewares/Middleware09/errors/status/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware09/forwardAuth/tls/ca` | `foobar` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/addAuthCookiesToResponse/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware09/forwardAuth/tls/cert` | `foobar` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/addAuthCookiesToResponse/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware09/forwardAuth/tls/insecureSkipVerify` | `true` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/address` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware09/forwardAuth/tls/key` | `foobar` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/authRequestHeaders/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware09/forwardAuth/trustForwardHeader` | `true` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/authRequestHeaders/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlAllowCredentials` | `true` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/authResponseHeaders/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlAllowHeaders/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/authResponseHeaders/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlAllowHeaders/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/authResponseHeadersRegex` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlAllowMethods/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/tls/ca` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlAllowMethods/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/tls/cert` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlAllowOriginList/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/tls/insecureSkipVerify` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlAllowOriginList/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/tls/key` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlAllowOriginListRegex/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware10/forwardAuth/trustForwardHeader` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlAllowOriginListRegex/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware11/grpcWeb/allowOrigins/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlExposeHeaders/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware11/grpcWeb/allowOrigins/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlExposeHeaders/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowCredentials` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/accessControlMaxAge` | `42` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowHeaders/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/addVaryHeader` | `true` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowHeaders/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/allowedHosts/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowMethods/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/allowedHosts/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowMethods/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/browserXssFilter` | `true` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowOriginList/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/contentSecurityPolicy` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowOriginList/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/contentTypeNosniff` | `true` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowOriginListRegex/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/customBrowserXSSValue` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowOriginListRegex/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/customFrameOptionsValue` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlExposeHeaders/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/customRequestHeaders/name0` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlExposeHeaders/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/customRequestHeaders/name1` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/accessControlMaxAge` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/customResponseHeaders/name0` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/addVaryHeader` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/customResponseHeaders/name1` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/allowedHosts/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/forceSTSHeader` | `true` |
|
| `traefik/http/middlewares/Middleware12/headers/allowedHosts/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/frameDeny` | `true` |
|
| `traefik/http/middlewares/Middleware12/headers/browserXssFilter` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/hostsProxyHeaders/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/contentSecurityPolicy` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/hostsProxyHeaders/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/contentTypeNosniff` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/isDevelopment` | `true` |
|
| `traefik/http/middlewares/Middleware12/headers/customBrowserXSSValue` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/permissionsPolicy` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/customFrameOptionsValue` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/publicKey` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/customRequestHeaders/name0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/referrerPolicy` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/customRequestHeaders/name1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/sslProxyHeaders/name0` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/customResponseHeaders/name0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/sslProxyHeaders/name1` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/customResponseHeaders/name1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/stsIncludeSubdomains` | `true` |
|
| `traefik/http/middlewares/Middleware12/headers/forceSTSHeader` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/stsPreload` | `true` |
|
| `traefik/http/middlewares/Middleware12/headers/frameDeny` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware10/headers/stsSeconds` | `42` |
|
| `traefik/http/middlewares/Middleware12/headers/hostsProxyHeaders/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware11/ipWhiteList/ipStrategy/depth` | `42` |
|
| `traefik/http/middlewares/Middleware12/headers/hostsProxyHeaders/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware11/ipWhiteList/ipStrategy/excludedIPs/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/isDevelopment` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware11/ipWhiteList/ipStrategy/excludedIPs/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/permissionsPolicy` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware11/ipWhiteList/sourceRange/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/publicKey` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware11/ipWhiteList/sourceRange/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/referrerPolicy` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware12/ipAllowList/ipStrategy/depth` | `42` |
|
| `traefik/http/middlewares/Middleware12/headers/sslProxyHeaders/name0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware12/ipAllowList/ipStrategy/excludedIPs/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/sslProxyHeaders/name1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware12/ipAllowList/ipStrategy/excludedIPs/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/stsIncludeSubdomains` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware12/ipAllowList/rejectStatusCode` | `404` |
|
| `traefik/http/middlewares/Middleware12/headers/stsPreload` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware12/ipAllowList/sourceRange/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware12/headers/stsSeconds` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware12/ipAllowList/sourceRange/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/depth` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware13/inFlightReq/amount` | `42` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/excludedIPs/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/ipStrategy/depth` | `42` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/excludedIPs/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/rejectStatusCode` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/sourceRange/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/requestHeaderName` | `foobar` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/sourceRange/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/requestHost` | `true` |
|
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/depth` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/commonName` | `true` |
|
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/excludedIPs/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/country` | `true` |
|
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/excludedIPs/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/domainComponent` | `true` |
|
| `traefik/http/middlewares/Middleware14/ipWhiteList/sourceRange/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/locality` | `true` |
|
| `traefik/http/middlewares/Middleware14/ipWhiteList/sourceRange/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/organization` | `true` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/amount` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/province` | `true` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/depth` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/serialNumber` | `true` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/notAfter` | `true` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/notBefore` | `true` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/requestHeaderName` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/sans` | `true` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/requestHost` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/serialNumber` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/commonName` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/commonName` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/country` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/country` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/domainComponent` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/domainComponent` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/locality` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/locality` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/organization` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/organization` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/province` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/organizationalUnit` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/serialNumber` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/province` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/notAfter` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/serialNumber` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/notBefore` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware14/passTLSClientCert/pem` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/sans` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware15/plugin/PluginConf/foo` | `bar` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/serialNumber` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware16/rateLimit/average` | `42` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/commonName` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware16/rateLimit/burst` | `42` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/country` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware16/rateLimit/period` | `42s` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/domainComponent` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/ipStrategy/depth` | `42` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/locality` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/organization` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/organizationalUnit` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/requestHeaderName` | `foobar` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/province` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/requestHost` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/serialNumber` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware17/redirectRegex/permanent` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/pem` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware17/redirectRegex/regex` | `foobar` |
|
| `traefik/http/middlewares/Middleware17/plugin/PluginConf0/name0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware17/redirectRegex/replacement` | `foobar` |
|
| `traefik/http/middlewares/Middleware17/plugin/PluginConf0/name1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware18/redirectScheme/permanent` | `true` |
|
| `traefik/http/middlewares/Middleware17/plugin/PluginConf1/name0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware18/redirectScheme/port` | `foobar` |
|
| `traefik/http/middlewares/Middleware17/plugin/PluginConf1/name1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware18/redirectScheme/scheme` | `foobar` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/average` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware19/replacePath/path` | `foobar` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/burst` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware20/replacePathRegex/regex` | `foobar` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/period` | `42s` |
|
||||||
| `traefik/http/middlewares/Middleware20/replacePathRegex/replacement` | `foobar` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/depth` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware21/retry/attempts` | `42` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware21/retry/initialInterval` | `42s` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware22/stripPrefix/prefixes/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/requestHeaderName` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware22/stripPrefix/prefixes/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/requestHost` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware23/stripPrefixRegex/regex/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware19/redirectRegex/permanent` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware23/stripPrefixRegex/regex/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware19/redirectRegex/regex` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware24/grpcWeb/allowOrigins/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware19/redirectRegex/replacement` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware24/grpcWeb/allowOrigins/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware20/redirectScheme/permanent` | `true` |
|
||||||
|
| `traefik/http/middlewares/Middleware20/redirectScheme/port` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware20/redirectScheme/scheme` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware21/replacePath/path` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware22/replacePathRegex/regex` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware22/replacePathRegex/replacement` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware23/retry/attempts` | `42` |
|
||||||
|
| `traefik/http/middlewares/Middleware23/retry/initialInterval` | `42s` |
|
||||||
|
| `traefik/http/middlewares/Middleware24/stripPrefix/prefixes/0` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware24/stripPrefix/prefixes/1` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware25/stripPrefixRegex/regex/0` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware25/stripPrefixRegex/regex/1` | `foobar` |
|
||||||
| `traefik/http/routers/Router0/entryPoints/0` | `foobar` |
|
| `traefik/http/routers/Router0/entryPoints/0` | `foobar` |
|
||||||
| `traefik/http/routers/Router0/entryPoints/1` | `foobar` |
|
| `traefik/http/routers/Router0/entryPoints/1` | `foobar` |
|
||||||
| `traefik/http/routers/Router0/middlewares/0` | `foobar` |
|
| `traefik/http/routers/Router0/middlewares/0` | `foobar` |
|
||||||
| `traefik/http/routers/Router0/middlewares/1` | `foobar` |
|
| `traefik/http/routers/Router0/middlewares/1` | `foobar` |
|
||||||
| `traefik/http/routers/Router0/priority` | `42` |
|
| `traefik/http/routers/Router0/priority` | `42` |
|
||||||
| `traefik/http/routers/Router0/rule` | `foobar` |
|
| `traefik/http/routers/Router0/rule` | `foobar` |
|
||||||
|
| `traefik/http/routers/Router0/ruleSyntax` | `foobar` |
|
||||||
| `traefik/http/routers/Router0/service` | `foobar` |
|
| `traefik/http/routers/Router0/service` | `foobar` |
|
||||||
| `traefik/http/routers/Router0/tls/certResolver` | `foobar` |
|
| `traefik/http/routers/Router0/tls/certResolver` | `foobar` |
|
||||||
| `traefik/http/routers/Router0/tls/domains/0/main` | `foobar` |
|
| `traefik/http/routers/Router0/tls/domains/0/main` | `foobar` |
|
||||||
|
@ -162,6 +174,7 @@
|
||||||
| `traefik/http/routers/Router1/middlewares/1` | `foobar` |
|
| `traefik/http/routers/Router1/middlewares/1` | `foobar` |
|
||||||
| `traefik/http/routers/Router1/priority` | `42` |
|
| `traefik/http/routers/Router1/priority` | `42` |
|
||||||
| `traefik/http/routers/Router1/rule` | `foobar` |
|
| `traefik/http/routers/Router1/rule` | `foobar` |
|
||||||
|
| `traefik/http/routers/Router1/ruleSyntax` | `foobar` |
|
||||||
| `traefik/http/routers/Router1/service` | `foobar` |
|
| `traefik/http/routers/Router1/service` | `foobar` |
|
||||||
| `traefik/http/routers/Router1/tls/certResolver` | `foobar` |
|
| `traefik/http/routers/Router1/tls/certResolver` | `foobar` |
|
||||||
| `traefik/http/routers/Router1/tls/domains/0/main` | `foobar` |
|
| `traefik/http/routers/Router1/tls/domains/0/main` | `foobar` |
|
||||||
|
@ -209,55 +222,62 @@
|
||||||
| `traefik/http/serversTransports/ServersTransport1/spiffe/ids/0` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport1/spiffe/ids/0` | `foobar` |
|
||||||
| `traefik/http/serversTransports/ServersTransport1/spiffe/ids/1` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport1/spiffe/ids/1` | `foobar` |
|
||||||
| `traefik/http/serversTransports/ServersTransport1/spiffe/trustDomain` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport1/spiffe/trustDomain` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/followRedirects` | `true` |
|
| `traefik/http/services/Service01/failover/fallback` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/headers/name0` | `foobar` |
|
| `traefik/http/services/Service01/failover/healthCheck` | `` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/headers/name1` | `foobar` |
|
| `traefik/http/services/Service01/failover/service` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/hostname` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/followRedirects` | `true` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/interval` | `42s` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/headers/name0` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/method` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/headers/name1` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/mode` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/hostname` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/path` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/interval` | `42s` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/port` | `42` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/method` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/scheme` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/mode` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/status` | `42` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/path` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/timeout` | `42s` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/port` | `42` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/passHostHeader` | `true` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/scheme` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/responseForwarding/flushInterval` | `42s` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/status` | `42` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/servers/0/url` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/healthCheck/timeout` | `42s` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/servers/1/url` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/passHostHeader` | `true` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/serversTransport` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/responseForwarding/flushInterval` | `42s` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/sticky/cookie/httpOnly` | `true` |
|
| `traefik/http/services/Service02/loadBalancer/servers/0/url` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/sticky/cookie/name` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/servers/0/weight` | `42` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/sticky/cookie/sameSite` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/servers/1/url` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/sticky/cookie/secure` | `true` |
|
| `traefik/http/services/Service02/loadBalancer/servers/1/weight` | `42` |
|
||||||
| `traefik/http/services/Service02/mirroring/healthCheck` | `` |
|
| `traefik/http/services/Service02/loadBalancer/serversTransport` | `foobar` |
|
||||||
| `traefik/http/services/Service02/mirroring/maxBodySize` | `42` |
|
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/httpOnly` | `true` |
|
||||||
| `traefik/http/services/Service02/mirroring/mirrors/0/name` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/maxAge` | `42` |
|
||||||
| `traefik/http/services/Service02/mirroring/mirrors/0/percent` | `42` |
|
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/name` | `foobar` |
|
||||||
| `traefik/http/services/Service02/mirroring/mirrors/1/name` | `foobar` |
|
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/sameSite` | `foobar` |
|
||||||
| `traefik/http/services/Service02/mirroring/mirrors/1/percent` | `42` |
|
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/secure` | `true` |
|
||||||
| `traefik/http/services/Service02/mirroring/service` | `foobar` |
|
| `traefik/http/services/Service03/mirroring/healthCheck` | `` |
|
||||||
| `traefik/http/services/Service03/weighted/healthCheck` | `` |
|
| `traefik/http/services/Service03/mirroring/maxBodySize` | `42` |
|
||||||
| `traefik/http/services/Service03/weighted/services/0/name` | `foobar` |
|
| `traefik/http/services/Service03/mirroring/mirrors/0/name` | `foobar` |
|
||||||
| `traefik/http/services/Service03/weighted/services/0/weight` | `42` |
|
| `traefik/http/services/Service03/mirroring/mirrors/0/percent` | `42` |
|
||||||
| `traefik/http/services/Service03/weighted/services/1/name` | `foobar` |
|
| `traefik/http/services/Service03/mirroring/mirrors/1/name` | `foobar` |
|
||||||
| `traefik/http/services/Service03/weighted/services/1/weight` | `42` |
|
| `traefik/http/services/Service03/mirroring/mirrors/1/percent` | `42` |
|
||||||
| `traefik/http/services/Service03/weighted/sticky/cookie/httpOnly` | `true` |
|
| `traefik/http/services/Service03/mirroring/service` | `foobar` |
|
||||||
| `traefik/http/services/Service03/weighted/sticky/cookie/name` | `foobar` |
|
| `traefik/http/services/Service04/weighted/healthCheck` | `` |
|
||||||
| `traefik/http/services/Service03/weighted/sticky/cookie/sameSite` | `foobar` |
|
| `traefik/http/services/Service04/weighted/services/0/name` | `foobar` |
|
||||||
| `traefik/http/services/Service03/weighted/sticky/cookie/secure` | `true` |
|
| `traefik/http/services/Service04/weighted/services/0/weight` | `42` |
|
||||||
| `traefik/http/services/Service04/failover/fallback` | `foobar` |
|
| `traefik/http/services/Service04/weighted/services/1/name` | `foobar` |
|
||||||
| `traefik/http/services/Service04/failover/healthCheck` | `` |
|
| `traefik/http/services/Service04/weighted/services/1/weight` | `42` |
|
||||||
| `traefik/http/services/Service04/failover/service` | `foobar` |
|
| `traefik/http/services/Service04/weighted/sticky/cookie/httpOnly` | `true` |
|
||||||
| `traefik/tcp/middlewares/TCPMiddleware00/ipAllowList/sourceRange/0` | `foobar` |
|
| `traefik/http/services/Service04/weighted/sticky/cookie/maxAge` | `42` |
|
||||||
| `traefik/tcp/middlewares/TCPMiddleware00/ipAllowList/sourceRange/1` | `foobar` |
|
| `traefik/http/services/Service04/weighted/sticky/cookie/name` | `foobar` |
|
||||||
| `traefik/tcp/middlewares/TCPMiddleware01/inFlightConn/amount` | `42` |
|
| `traefik/http/services/Service04/weighted/sticky/cookie/sameSite` | `foobar` |
|
||||||
|
| `traefik/http/services/Service04/weighted/sticky/cookie/secure` | `true` |
|
||||||
|
| `traefik/tcp/middlewares/TCPMiddleware01/ipAllowList/sourceRange/0` | `foobar` |
|
||||||
|
| `traefik/tcp/middlewares/TCPMiddleware01/ipAllowList/sourceRange/1` | `foobar` |
|
||||||
|
| `traefik/tcp/middlewares/TCPMiddleware02/ipWhiteList/sourceRange/0` | `foobar` |
|
||||||
|
| `traefik/tcp/middlewares/TCPMiddleware02/ipWhiteList/sourceRange/1` | `foobar` |
|
||||||
|
| `traefik/tcp/middlewares/TCPMiddleware03/inFlightConn/amount` | `42` |
|
||||||
| `traefik/tcp/routers/TCPRouter0/entryPoints/0` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter0/entryPoints/0` | `foobar` |
|
||||||
| `traefik/tcp/routers/TCPRouter0/entryPoints/1` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter0/entryPoints/1` | `foobar` |
|
||||||
| `traefik/tcp/routers/TCPRouter0/middlewares/0` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter0/middlewares/0` | `foobar` |
|
||||||
| `traefik/tcp/routers/TCPRouter0/middlewares/1` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter0/middlewares/1` | `foobar` |
|
||||||
| `traefik/tcp/routers/TCPRouter0/priority` | `42` |
|
| `traefik/tcp/routers/TCPRouter0/priority` | `42` |
|
||||||
| `traefik/tcp/routers/TCPRouter0/rule` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter0/rule` | `foobar` |
|
||||||
|
| `traefik/tcp/routers/TCPRouter0/ruleSyntax` | `foobar` |
|
||||||
| `traefik/tcp/routers/TCPRouter0/service` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter0/service` | `foobar` |
|
||||||
| `traefik/tcp/routers/TCPRouter0/tls/certResolver` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter0/tls/certResolver` | `foobar` |
|
||||||
| `traefik/tcp/routers/TCPRouter0/tls/domains/0/main` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter0/tls/domains/0/main` | `foobar` |
|
||||||
|
@ -274,6 +294,7 @@
|
||||||
| `traefik/tcp/routers/TCPRouter1/middlewares/1` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter1/middlewares/1` | `foobar` |
|
||||||
| `traefik/tcp/routers/TCPRouter1/priority` | `42` |
|
| `traefik/tcp/routers/TCPRouter1/priority` | `42` |
|
||||||
| `traefik/tcp/routers/TCPRouter1/rule` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter1/rule` | `foobar` |
|
||||||
|
| `traefik/tcp/routers/TCPRouter1/ruleSyntax` | `foobar` |
|
||||||
| `traefik/tcp/routers/TCPRouter1/service` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter1/service` | `foobar` |
|
||||||
| `traefik/tcp/routers/TCPRouter1/tls/certResolver` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter1/tls/certResolver` | `foobar` |
|
||||||
| `traefik/tcp/routers/TCPRouter1/tls/domains/0/main` | `foobar` |
|
| `traefik/tcp/routers/TCPRouter1/tls/domains/0/main` | `foobar` |
|
||||||
|
@ -286,9 +307,6 @@
|
||||||
| `traefik/tcp/routers/TCPRouter1/tls/passthrough` | `true` |
|
| `traefik/tcp/routers/TCPRouter1/tls/passthrough` | `true` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport0/dialKeepAlive` | `42s` |
|
| `traefik/tcp/serversTransports/TCPServersTransport0/dialKeepAlive` | `42s` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport0/dialTimeout` | `42s` |
|
| `traefik/tcp/serversTransports/TCPServersTransport0/dialTimeout` | `42s` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport0/spiffe/ids/0` | `foobar` |
|
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport0/spiffe/ids/1` | `foobar` |
|
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport0/spiffe/trustDomain` | `foobar` |
|
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport0/terminationDelay` | `42s` |
|
| `traefik/tcp/serversTransports/TCPServersTransport0/terminationDelay` | `42s` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/certificates/0/certFile` | `foobar` |
|
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/certificates/0/certFile` | `foobar` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/certificates/0/keyFile` | `foobar` |
|
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/certificates/0/keyFile` | `foobar` |
|
||||||
|
@ -299,11 +317,11 @@
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/rootCAs/0` | `foobar` |
|
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/rootCAs/0` | `foobar` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/rootCAs/1` | `foobar` |
|
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/rootCAs/1` | `foobar` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/serverName` | `foobar` |
|
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/serverName` | `foobar` |
|
||||||
|
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/spiffe/ids/0` | `foobar` |
|
||||||
|
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/spiffe/ids/1` | `foobar` |
|
||||||
|
| `traefik/tcp/serversTransports/TCPServersTransport0/tls/spiffe/trustDomain` | `foobar` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport1/dialKeepAlive` | `42s` |
|
| `traefik/tcp/serversTransports/TCPServersTransport1/dialKeepAlive` | `42s` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport1/dialTimeout` | `42s` |
|
| `traefik/tcp/serversTransports/TCPServersTransport1/dialTimeout` | `42s` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport1/spiffe/ids/0` | `foobar` |
|
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport1/spiffe/ids/1` | `foobar` |
|
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport1/spiffe/trustDomain` | `foobar` |
|
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport1/terminationDelay` | `42s` |
|
| `traefik/tcp/serversTransports/TCPServersTransport1/terminationDelay` | `42s` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/certificates/0/certFile` | `foobar` |
|
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/certificates/0/certFile` | `foobar` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/certificates/0/keyFile` | `foobar` |
|
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/certificates/0/keyFile` | `foobar` |
|
||||||
|
@ -314,6 +332,9 @@
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/rootCAs/0` | `foobar` |
|
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/rootCAs/0` | `foobar` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/rootCAs/1` | `foobar` |
|
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/rootCAs/1` | `foobar` |
|
||||||
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/serverName` | `foobar` |
|
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/serverName` | `foobar` |
|
||||||
|
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/spiffe/ids/0` | `foobar` |
|
||||||
|
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/spiffe/ids/1` | `foobar` |
|
||||||
|
| `traefik/tcp/serversTransports/TCPServersTransport1/tls/spiffe/trustDomain` | `foobar` |
|
||||||
| `traefik/tcp/services/TCPService01/loadBalancer/proxyProtocol/version` | `42` |
|
| `traefik/tcp/services/TCPService01/loadBalancer/proxyProtocol/version` | `42` |
|
||||||
| `traefik/tcp/services/TCPService01/loadBalancer/servers/0/address` | `foobar` |
|
| `traefik/tcp/services/TCPService01/loadBalancer/servers/0/address` | `foobar` |
|
||||||
| `traefik/tcp/services/TCPService01/loadBalancer/servers/0/tls` | `true` |
|
| `traefik/tcp/services/TCPService01/loadBalancer/servers/0/tls` | `true` |
|
||||||
|
|
|
@ -160,6 +160,12 @@ spec:
|
||||||
can be accessed by client-side APIs, such as
|
can be accessed by client-side APIs, such as
|
||||||
JavaScript.
|
JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When
|
||||||
|
set to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -189,6 +195,10 @@ spec:
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
syntax:
|
||||||
|
description: 'Syntax defines the router''s rule syntax. More
|
||||||
|
info: https://doc.traefik.io/traefik/v3.0/routing/routers/#rulesyntax'
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- kind
|
- kind
|
||||||
- match
|
- match
|
||||||
|
|
|
@ -129,6 +129,10 @@ spec:
|
||||||
- port
|
- port
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
syntax:
|
||||||
|
description: 'Syntax defines the router''s rule syntax. More
|
||||||
|
info: https://doc.traefik.io/traefik/v3.0/routing/routers/#rulesyntax_1'
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- match
|
- match
|
||||||
type: object
|
type: object
|
||||||
|
|
|
@ -175,6 +175,13 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
includedContentTypes:
|
||||||
|
description: IncludedContentTypes defines the list of content
|
||||||
|
types to compare the Content-Type header of the responses before
|
||||||
|
compressing.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
minResponseBodyBytes:
|
minResponseBodyBytes:
|
||||||
description: 'MinResponseBodyBytes defines the minimum amount
|
description: 'MinResponseBodyBytes defines the minimum amount
|
||||||
of bytes a response body must have to be compressed. Default:
|
of bytes a response body must have to be compressed. Default:
|
||||||
|
@ -295,6 +302,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie can
|
description: HTTPOnly defines whether the cookie can
|
||||||
be accessed by client-side APIs, such as JavaScript.
|
be accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When set
|
||||||
|
to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -337,6 +350,12 @@ spec:
|
||||||
This middleware delegates the request authentication to a Service.
|
This middleware delegates the request authentication to a Service.
|
||||||
More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/forwardauth/'
|
More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/forwardauth/'
|
||||||
properties:
|
properties:
|
||||||
|
addAuthCookiesToResponse:
|
||||||
|
description: AddAuthCookiesToResponse defines the list of cookies
|
||||||
|
to copy from the authentication server response to the response.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
address:
|
address:
|
||||||
description: Address defines the authentication server address.
|
description: Address defines the authentication server address.
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -134,6 +134,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie
|
description: HTTPOnly defines whether the cookie
|
||||||
can be accessed by client-side APIs, such as JavaScript.
|
can be accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When set
|
||||||
|
to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -225,6 +231,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie can be
|
description: HTTPOnly defines whether the cookie can be
|
||||||
accessed by client-side APIs, such as JavaScript.
|
accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds until
|
||||||
|
the cookie expires. When set to a negative number, the
|
||||||
|
cookie expires immediately. When set to zero, the cookie
|
||||||
|
never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -332,6 +344,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie
|
description: HTTPOnly defines whether the cookie
|
||||||
can be accessed by client-side APIs, such as JavaScript.
|
can be accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When set
|
||||||
|
to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -371,6 +389,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie can be
|
description: HTTPOnly defines whether the cookie can be
|
||||||
accessed by client-side APIs, such as JavaScript.
|
accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds until
|
||||||
|
the cookie expires. When set to a negative number, the
|
||||||
|
cookie expires immediately. When set to zero, the cookie
|
||||||
|
never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -105,6 +105,9 @@ Activate TLS-ALPN-01 Challenge. (Default: ```true```)
|
||||||
`--certificatesresolvers.<name>.tailscale`:
|
`--certificatesresolvers.<name>.tailscale`:
|
||||||
Enables Tailscale certificate resolution. (Default: ```true```)
|
Enables Tailscale certificate resolution. (Default: ```true```)
|
||||||
|
|
||||||
|
`--core.defaultrulesyntax`:
|
||||||
|
Defines the rule parser default syntax (v2 or v3) (Default: ```v3```)
|
||||||
|
|
||||||
`--entrypoints.<name>`:
|
`--entrypoints.<name>`:
|
||||||
Entry points definition. (Default: ```false```)
|
Entry points definition. (Default: ```false```)
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,9 @@ Activate TLS-ALPN-01 Challenge. (Default: ```true```)
|
||||||
`TRAEFIK_CERTIFICATESRESOLVERS_<NAME>_TAILSCALE`:
|
`TRAEFIK_CERTIFICATESRESOLVERS_<NAME>_TAILSCALE`:
|
||||||
Enables Tailscale certificate resolution. (Default: ```true```)
|
Enables Tailscale certificate resolution. (Default: ```true```)
|
||||||
|
|
||||||
|
`TRAEFIK_CORE_DEFAULTRULESYNTAX`:
|
||||||
|
Defines the rule parser default syntax (v2 or v3) (Default: ```v3```)
|
||||||
|
|
||||||
`TRAEFIK_ENTRYPOINTS_<NAME>`:
|
`TRAEFIK_ENTRYPOINTS_<NAME>`:
|
||||||
Entry points definition. (Default: ```false```)
|
Entry points definition. (Default: ```false```)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
## CODE GENERATED AUTOMATICALLY
|
||||||
|
## THIS FILE MUST NOT BE EDITED BY HAND
|
||||||
[global]
|
[global]
|
||||||
checkNewVersion = true
|
checkNewVersion = true
|
||||||
sendAnonymousUsage = true
|
sendAnonymousUsage = true
|
||||||
|
@ -6,26 +8,21 @@
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
rootCAs = ["foobar", "foobar"]
|
rootCAs = ["foobar", "foobar"]
|
||||||
maxIdleConnsPerHost = 42
|
maxIdleConnsPerHost = 42
|
||||||
|
|
||||||
[serversTransport.forwardingTimeouts]
|
[serversTransport.forwardingTimeouts]
|
||||||
dialTimeout = "42s"
|
dialTimeout = "42s"
|
||||||
responseHeaderTimeout = "42s"
|
responseHeaderTimeout = "42s"
|
||||||
idleConnTimeout = "42s"
|
idleConnTimeout = "42s"
|
||||||
readIdleTimeout = "42s"
|
|
||||||
pingTimeout = "42s"
|
|
||||||
|
|
||||||
[serversTransport.spiffe]
|
[serversTransport.spiffe]
|
||||||
ids = ["foobar", "foobar"]
|
ids = ["foobar", "foobar"]
|
||||||
trustDomain = "foobar"
|
trustDomain = "foobar"
|
||||||
|
|
||||||
[tcpServersTransport]
|
[tcpServersTransport]
|
||||||
dialTimeout = "42s"
|
|
||||||
dialKeepAlive = "42s"
|
dialKeepAlive = "42s"
|
||||||
|
dialTimeout = "42s"
|
||||||
|
terminationDelay = "42s"
|
||||||
[tcpServersTransport.tls]
|
[tcpServersTransport.tls]
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
rootCAs = ["foobar", "foobar"]
|
rootCAs = ["foobar", "foobar"]
|
||||||
|
|
||||||
[tcpServersTransport.tls.spiffe]
|
[tcpServersTransport.tls.spiffe]
|
||||||
ids = ["foobar", "foobar"]
|
ids = ["foobar", "foobar"]
|
||||||
trustDomain = "foobar"
|
trustDomain = "foobar"
|
||||||
|
@ -35,8 +32,8 @@
|
||||||
address = "foobar"
|
address = "foobar"
|
||||||
asDefault = true
|
asDefault = true
|
||||||
[entryPoints.EntryPoint0.transport]
|
[entryPoints.EntryPoint0.transport]
|
||||||
keepAliveMaxRequests = 42
|
|
||||||
keepAliveMaxTime = "42s"
|
keepAliveMaxTime = "42s"
|
||||||
|
keepAliveMaxRequests = 42
|
||||||
[entryPoints.EntryPoint0.transport.lifeCycle]
|
[entryPoints.EntryPoint0.transport.lifeCycle]
|
||||||
requestAcceptGraceTimeout = "42s"
|
requestAcceptGraceTimeout = "42s"
|
||||||
graceTimeOut = "42s"
|
graceTimeOut = "42s"
|
||||||
|
@ -80,31 +77,31 @@
|
||||||
[providers]
|
[providers]
|
||||||
providersThrottleDuration = "42s"
|
providersThrottleDuration = "42s"
|
||||||
[providers.docker]
|
[providers.docker]
|
||||||
constraints = "foobar"
|
|
||||||
watch = true
|
|
||||||
endpoint = "foobar"
|
|
||||||
defaultRule = "foobar"
|
|
||||||
exposedByDefault = true
|
exposedByDefault = true
|
||||||
useBindPortIP = true
|
constraints = "foobar"
|
||||||
network = "foobar"
|
|
||||||
httpClientTimeout = "42s"
|
|
||||||
allowEmptyServices = true
|
allowEmptyServices = true
|
||||||
|
network = "foobar"
|
||||||
|
useBindPortIP = true
|
||||||
|
watch = true
|
||||||
|
defaultRule = "foobar"
|
||||||
|
endpoint = "foobar"
|
||||||
|
httpClientTimeout = "42s"
|
||||||
[providers.docker.tls]
|
[providers.docker.tls]
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
cert = "foobar"
|
cert = "foobar"
|
||||||
key = "foobar"
|
key = "foobar"
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
[providers.swarm]
|
[providers.swarm]
|
||||||
constraints = "foobar"
|
|
||||||
watch = true
|
|
||||||
endpoint = "foobar"
|
|
||||||
defaultRule = "foobar"
|
|
||||||
exposedByDefault = true
|
exposedByDefault = true
|
||||||
useBindPortIP = true
|
constraints = "foobar"
|
||||||
network = "foobar"
|
|
||||||
refreshSeconds = "42s"
|
|
||||||
httpClientTimeout = "42s"
|
|
||||||
allowEmptyServices = true
|
allowEmptyServices = true
|
||||||
|
network = "foobar"
|
||||||
|
useBindPortIP = true
|
||||||
|
watch = true
|
||||||
|
defaultRule = "foobar"
|
||||||
|
endpoint = "foobar"
|
||||||
|
httpClientTimeout = "42s"
|
||||||
|
refreshSeconds = "42s"
|
||||||
[providers.swarm.tls]
|
[providers.swarm.tls]
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
cert = "foobar"
|
cert = "foobar"
|
||||||
|
@ -183,9 +180,9 @@
|
||||||
constraints = "foobar"
|
constraints = "foobar"
|
||||||
prefix = "foobar"
|
prefix = "foobar"
|
||||||
stale = true
|
stale = true
|
||||||
namespaces = ["foobar", "foobar"]
|
|
||||||
exposedByDefault = true
|
exposedByDefault = true
|
||||||
refreshInterval = "42s"
|
refreshInterval = "42s"
|
||||||
|
namespaces = ["foobar", "foobar"]
|
||||||
[providers.nomad.endpoint]
|
[providers.nomad.endpoint]
|
||||||
address = "foobar"
|
address = "foobar"
|
||||||
region = "foobar"
|
region = "foobar"
|
||||||
|
@ -203,11 +200,11 @@
|
||||||
defaultRule = "foobar"
|
defaultRule = "foobar"
|
||||||
clusters = ["foobar", "foobar"]
|
clusters = ["foobar", "foobar"]
|
||||||
autoDiscoverClusters = true
|
autoDiscoverClusters = true
|
||||||
|
healthyTasksOnly = true
|
||||||
|
ecsAnywhere = true
|
||||||
region = "foobar"
|
region = "foobar"
|
||||||
accessKeyID = "foobar"
|
accessKeyID = "foobar"
|
||||||
secretAccessKey = "foobar"
|
secretAccessKey = "foobar"
|
||||||
ecsAnywhere = true
|
|
||||||
healthyTasksOnly = true
|
|
||||||
[providers.consul]
|
[providers.consul]
|
||||||
rootKey = "foobar"
|
rootKey = "foobar"
|
||||||
endpoints = ["foobar", "foobar"]
|
endpoints = ["foobar", "foobar"]
|
||||||
|
@ -265,14 +262,18 @@
|
||||||
key = "foobar"
|
key = "foobar"
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
[providers.plugin]
|
[providers.plugin]
|
||||||
[providers.plugin.Descriptor0]
|
[providers.plugin.PluginConf0]
|
||||||
[providers.plugin.Descriptor1]
|
name0 = "foobar"
|
||||||
|
name1 = "foobar"
|
||||||
|
[providers.plugin.PluginConf1]
|
||||||
|
name0 = "foobar"
|
||||||
|
name1 = "foobar"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
insecure = true
|
insecure = true
|
||||||
dashboard = true
|
dashboard = true
|
||||||
debug = true
|
debug = true
|
||||||
disabledashboardad = false
|
disableDashboardAd = true
|
||||||
|
|
||||||
[metrics]
|
[metrics]
|
||||||
[metrics.prometheus]
|
[metrics.prometheus]
|
||||||
|
@ -283,8 +284,8 @@
|
||||||
entryPoint = "foobar"
|
entryPoint = "foobar"
|
||||||
manualRouting = true
|
manualRouting = true
|
||||||
[metrics.prometheus.headerLabels]
|
[metrics.prometheus.headerLabels]
|
||||||
label1 = "foobar"
|
name0 = "foobar"
|
||||||
label2 = "foobar"
|
name1 = "foobar"
|
||||||
[metrics.datadog]
|
[metrics.datadog]
|
||||||
address = "foobar"
|
address = "foobar"
|
||||||
pushInterval = "42s"
|
pushInterval = "42s"
|
||||||
|
@ -316,20 +317,19 @@
|
||||||
addEntryPointsLabels = true
|
addEntryPointsLabels = true
|
||||||
addRoutersLabels = true
|
addRoutersLabels = true
|
||||||
addServicesLabels = true
|
addServicesLabels = true
|
||||||
pushInterval = "42s"
|
explicitBoundaries = [42.0, 42.0]
|
||||||
path = "foobar"
|
|
||||||
explicitBoundaries = [42.0, 42.0]
|
|
||||||
insecure = true
|
insecure = true
|
||||||
|
path = "foobar"
|
||||||
|
pushInterval = "42s"
|
||||||
|
[metrics.openTelemetry.grpc]
|
||||||
[metrics.openTelemetry.headers]
|
[metrics.openTelemetry.headers]
|
||||||
name0 = "foobar"
|
name0 = "foobar"
|
||||||
name1 = "foobar"
|
name1 = "foobar"
|
||||||
[metrics.openTelemetry.tls]
|
[metrics.openTelemetry.tls]
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
caOptional = true
|
|
||||||
cert = "foobar"
|
cert = "foobar"
|
||||||
insecureSkipVerify = true
|
|
||||||
key = "foobar"
|
key = "foobar"
|
||||||
[metrics.openTelemetry.grpc]
|
insecureSkipVerify = true
|
||||||
|
|
||||||
[ping]
|
[ping]
|
||||||
entryPoint = "foobar"
|
entryPoint = "foobar"
|
||||||
|
@ -342,8 +342,8 @@
|
||||||
noColor = true
|
noColor = true
|
||||||
filePath = "foobar"
|
filePath = "foobar"
|
||||||
maxSize = 42
|
maxSize = 42
|
||||||
maxBackups = 42
|
|
||||||
maxAge = 42
|
maxAge = 42
|
||||||
|
maxBackups = 42
|
||||||
compress = true
|
compress = true
|
||||||
|
|
||||||
[accessLog]
|
[accessLog]
|
||||||
|
@ -367,28 +367,29 @@
|
||||||
|
|
||||||
[tracing]
|
[tracing]
|
||||||
serviceName = "foobar"
|
serviceName = "foobar"
|
||||||
sampleRate = 42
|
sampleRate = 42.0
|
||||||
[tracing.headers]
|
[tracing.headers]
|
||||||
header1 = "foobar"
|
name0 = "foobar"
|
||||||
header2 = "foobar"
|
name1 = "foobar"
|
||||||
[tracing.globalAttributes]
|
[tracing.globalAttributes]
|
||||||
attr1 = "foobar"
|
name0 = "foobar"
|
||||||
attr2 = "foobar"
|
name1 = "foobar"
|
||||||
[tracing.otlp.grpc]
|
[tracing.otlp]
|
||||||
endpoint = "foobar"
|
[tracing.otlp.grpc]
|
||||||
insecure = true
|
endpoint = "foobar"
|
||||||
[tracing.otlp.grpc.tls]
|
insecure = true
|
||||||
ca = "foobar"
|
[tracing.otlp.grpc.tls]
|
||||||
cert = "foobar"
|
ca = "foobar"
|
||||||
key = "foobar"
|
cert = "foobar"
|
||||||
insecureSkipVerify = true
|
key = "foobar"
|
||||||
[tracing.otlp.http]
|
insecureSkipVerify = true
|
||||||
endpoint = "foobar"
|
[tracing.otlp.http]
|
||||||
[tracing.otlp.http.tls]
|
endpoint = "foobar"
|
||||||
ca = "foobar"
|
[tracing.otlp.http.tls]
|
||||||
cert = "foobar"
|
ca = "foobar"
|
||||||
key = "foobar"
|
cert = "foobar"
|
||||||
insecureSkipVerify = true
|
key = "foobar"
|
||||||
|
insecureSkipVerify = true
|
||||||
|
|
||||||
[hostResolver]
|
[hostResolver]
|
||||||
cnameFlattening = true
|
cnameFlattening = true
|
||||||
|
@ -415,7 +416,27 @@
|
||||||
[certificatesResolvers.CertificateResolver0.acme.httpChallenge]
|
[certificatesResolvers.CertificateResolver0.acme.httpChallenge]
|
||||||
entryPoint = "foobar"
|
entryPoint = "foobar"
|
||||||
[certificatesResolvers.CertificateResolver0.acme.tlsChallenge]
|
[certificatesResolvers.CertificateResolver0.acme.tlsChallenge]
|
||||||
[certificatesResolvers.CertificateResolver1.tailscale]
|
[certificatesResolvers.CertificateResolver0.tailscale]
|
||||||
|
[certificatesResolvers.CertificateResolver1]
|
||||||
|
[certificatesResolvers.CertificateResolver1.acme]
|
||||||
|
email = "foobar"
|
||||||
|
caServer = "foobar"
|
||||||
|
preferredChain = "foobar"
|
||||||
|
storage = "foobar"
|
||||||
|
keyType = "foobar"
|
||||||
|
certificatesDuration = 42
|
||||||
|
[certificatesResolvers.CertificateResolver1.acme.eab]
|
||||||
|
kid = "foobar"
|
||||||
|
hmacEncoded = "foobar"
|
||||||
|
[certificatesResolvers.CertificateResolver1.acme.dnsChallenge]
|
||||||
|
provider = "foobar"
|
||||||
|
delayBeforeCheck = "42s"
|
||||||
|
resolvers = ["foobar", "foobar"]
|
||||||
|
disablePropagationCheck = true
|
||||||
|
[certificatesResolvers.CertificateResolver1.acme.httpChallenge]
|
||||||
|
entryPoint = "foobar"
|
||||||
|
[certificatesResolvers.CertificateResolver1.acme.tlsChallenge]
|
||||||
|
[certificatesResolvers.CertificateResolver1.tailscale]
|
||||||
|
|
||||||
[experimental]
|
[experimental]
|
||||||
kubernetesGateway = true
|
kubernetesGateway = true
|
||||||
|
@ -427,7 +448,13 @@
|
||||||
moduleName = "foobar"
|
moduleName = "foobar"
|
||||||
version = "foobar"
|
version = "foobar"
|
||||||
[experimental.localPlugins]
|
[experimental.localPlugins]
|
||||||
[experimental.localPlugins.Descriptor0]
|
[experimental.localPlugins.LocalDescriptor0]
|
||||||
moduleName = "foobar"
|
moduleName = "foobar"
|
||||||
[experimental.localPlugins.Descriptor1]
|
[experimental.localPlugins.LocalDescriptor1]
|
||||||
moduleName = "foobar"
|
moduleName = "foobar"
|
||||||
|
|
||||||
|
[core]
|
||||||
|
defaultRuleSyntax = "foobar"
|
||||||
|
|
||||||
|
[spiffe]
|
||||||
|
workloadAPIAddr = "foobar"
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
## CODE GENERATED AUTOMATICALLY
|
||||||
|
## THIS FILE MUST NOT BE EDITED BY HAND
|
||||||
global:
|
global:
|
||||||
checkNewVersion: true
|
checkNewVersion: true
|
||||||
sendAnonymousUsage: true
|
sendAnonymousUsage: true
|
||||||
serversTransports:
|
serversTransport:
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
rootCAs:
|
rootCAs:
|
||||||
- foobar
|
- foobar
|
||||||
|
@ -11,16 +13,15 @@ serversTransports:
|
||||||
dialTimeout: 42s
|
dialTimeout: 42s
|
||||||
responseHeaderTimeout: 42s
|
responseHeaderTimeout: 42s
|
||||||
idleConnTimeout: 42s
|
idleConnTimeout: 42s
|
||||||
readIdleTimeout: 42s
|
|
||||||
pingTimeout: 42s
|
|
||||||
spiffe:
|
spiffe:
|
||||||
ids:
|
ids:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
trustDomain: foobar
|
trustDomain: foobar
|
||||||
tcpServersTransport:
|
tcpServersTransport:
|
||||||
dialTimeout: 42s
|
|
||||||
dialKeepAlive: 42s
|
dialKeepAlive: 42s
|
||||||
|
dialTimeout: 42s
|
||||||
|
terminationDelay: 42s
|
||||||
tls:
|
tls:
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
rootCAs:
|
rootCAs:
|
||||||
|
@ -36,8 +37,6 @@ entryPoints:
|
||||||
address: foobar
|
address: foobar
|
||||||
asDefault: true
|
asDefault: true
|
||||||
transport:
|
transport:
|
||||||
keepAliveMaxRequests: 42
|
|
||||||
keepAliveMaxTime: 42s
|
|
||||||
lifeCycle:
|
lifeCycle:
|
||||||
requestAcceptGraceTimeout: 42s
|
requestAcceptGraceTimeout: 42s
|
||||||
graceTimeOut: 42s
|
graceTimeOut: 42s
|
||||||
|
@ -45,6 +44,8 @@ entryPoints:
|
||||||
readTimeout: 42s
|
readTimeout: 42s
|
||||||
writeTimeout: 42s
|
writeTimeout: 42s
|
||||||
idleTimeout: 42s
|
idleTimeout: 42s
|
||||||
|
keepAliveMaxTime: 42s
|
||||||
|
keepAliveMaxRequests: 42
|
||||||
proxyProtocol:
|
proxyProtocol:
|
||||||
insecure: true
|
insecure: true
|
||||||
trustedIPs:
|
trustedIPs:
|
||||||
|
@ -56,7 +57,6 @@ entryPoints:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
http:
|
http:
|
||||||
encodeQuerySemicolons: true
|
|
||||||
redirections:
|
redirections:
|
||||||
entryPoint:
|
entryPoint:
|
||||||
to: foobar
|
to: foobar
|
||||||
|
@ -78,6 +78,7 @@ entryPoints:
|
||||||
sans:
|
sans:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
|
encodeQuerySemicolons: true
|
||||||
http2:
|
http2:
|
||||||
maxConcurrentStreams: 42
|
maxConcurrentStreams: 42
|
||||||
http3:
|
http3:
|
||||||
|
@ -87,36 +88,36 @@ entryPoints:
|
||||||
providers:
|
providers:
|
||||||
providersThrottleDuration: 42s
|
providersThrottleDuration: 42s
|
||||||
docker:
|
docker:
|
||||||
|
exposedByDefault: true
|
||||||
constraints: foobar
|
constraints: foobar
|
||||||
|
allowEmptyServices: true
|
||||||
|
network: foobar
|
||||||
|
useBindPortIP: true
|
||||||
watch: true
|
watch: true
|
||||||
endpoint: foobar
|
|
||||||
defaultRule: foobar
|
defaultRule: foobar
|
||||||
|
endpoint: foobar
|
||||||
tls:
|
tls:
|
||||||
ca: foobar
|
ca: foobar
|
||||||
cert: foobar
|
cert: foobar
|
||||||
key: foobar
|
key: foobar
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
exposedByDefault: true
|
|
||||||
useBindPortIP: true
|
|
||||||
network: foobar
|
|
||||||
httpClientTimeout: 42s
|
httpClientTimeout: 42s
|
||||||
allowEmptyServices: true
|
|
||||||
swarm:
|
swarm:
|
||||||
|
exposedByDefault: true
|
||||||
constraints: foobar
|
constraints: foobar
|
||||||
|
allowEmptyServices: true
|
||||||
|
network: foobar
|
||||||
|
useBindPortIP: true
|
||||||
watch: true
|
watch: true
|
||||||
endpoint: foobar
|
|
||||||
defaultRule: foobar
|
defaultRule: foobar
|
||||||
|
endpoint: foobar
|
||||||
tls:
|
tls:
|
||||||
ca: foobar
|
ca: foobar
|
||||||
cert: foobar
|
cert: foobar
|
||||||
key: foobar
|
key: foobar
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
exposedByDefault: true
|
|
||||||
useBindPortIP: true
|
|
||||||
network: foobar
|
|
||||||
refreshSeconds: 42s
|
|
||||||
httpClientTimeout: 42s
|
httpClientTimeout: 42s
|
||||||
allowEmptyServices: true
|
refreshSeconds: 42s
|
||||||
file:
|
file:
|
||||||
directory: foobar
|
directory: foobar
|
||||||
watch: true
|
watch: true
|
||||||
|
@ -131,14 +132,14 @@ providers:
|
||||||
- foobar
|
- foobar
|
||||||
labelSelector: foobar
|
labelSelector: foobar
|
||||||
ingressClass: foobar
|
ingressClass: foobar
|
||||||
throttleDuration: 42s
|
|
||||||
allowEmptyServices: true
|
|
||||||
allowExternalNameServices: true
|
|
||||||
disableIngressClassLookup: true
|
|
||||||
ingressEndpoint:
|
ingressEndpoint:
|
||||||
ip: foobar
|
ip: foobar
|
||||||
hostname: foobar
|
hostname: foobar
|
||||||
publishedService: foobar
|
publishedService: foobar
|
||||||
|
throttleDuration: 42s
|
||||||
|
allowEmptyServices: true
|
||||||
|
allowExternalNameServices: true
|
||||||
|
disableIngressClassLookup: true
|
||||||
kubernetesCRD:
|
kubernetesCRD:
|
||||||
endpoint: foobar
|
endpoint: foobar
|
||||||
token: foobar
|
token: foobar
|
||||||
|
@ -165,6 +166,20 @@ providers:
|
||||||
insecure: true
|
insecure: true
|
||||||
consulCatalog:
|
consulCatalog:
|
||||||
constraints: foobar
|
constraints: foobar
|
||||||
|
endpoint:
|
||||||
|
address: foobar
|
||||||
|
scheme: foobar
|
||||||
|
datacenter: foobar
|
||||||
|
token: foobar
|
||||||
|
tls:
|
||||||
|
ca: foobar
|
||||||
|
cert: foobar
|
||||||
|
key: foobar
|
||||||
|
insecureSkipVerify: true
|
||||||
|
httpAuth:
|
||||||
|
username: foobar
|
||||||
|
password: foobar
|
||||||
|
endpointWaitTime: 42s
|
||||||
prefix: foobar
|
prefix: foobar
|
||||||
refreshInterval: 42s
|
refreshInterval: 42s
|
||||||
requireConsistent: true
|
requireConsistent: true
|
||||||
|
@ -179,40 +194,26 @@ providers:
|
||||||
namespaces:
|
namespaces:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
endpoint:
|
|
||||||
address: foobar
|
|
||||||
scheme: foobar
|
|
||||||
datacenter: foobar
|
|
||||||
token: foobar
|
|
||||||
endpointWaitTime: 42s
|
|
||||||
tls:
|
|
||||||
ca: foobar
|
|
||||||
cert: foobar
|
|
||||||
key: foobar
|
|
||||||
insecureSkipVerify: true
|
|
||||||
httpAuth:
|
|
||||||
username: foobar
|
|
||||||
password: foobar
|
|
||||||
nomad:
|
nomad:
|
||||||
defaultRule: foobar
|
defaultRule: foobar
|
||||||
constraints: foobar
|
constraints: foobar
|
||||||
prefix: foobar
|
|
||||||
stale: true
|
|
||||||
namespaces:
|
|
||||||
- foobar
|
|
||||||
- foobar
|
|
||||||
exposedByDefault: true
|
|
||||||
refreshInterval: 42s
|
|
||||||
endpoint:
|
endpoint:
|
||||||
address: foobar
|
address: foobar
|
||||||
region: foobar
|
region: foobar
|
||||||
token: foobar
|
token: foobar
|
||||||
endpointWaitTime: 42s
|
|
||||||
tls:
|
tls:
|
||||||
ca: foobar
|
ca: foobar
|
||||||
cert: foobar
|
cert: foobar
|
||||||
key: foobar
|
key: foobar
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
|
endpointWaitTime: 42s
|
||||||
|
prefix: foobar
|
||||||
|
stale: true
|
||||||
|
exposedByDefault: true
|
||||||
|
refreshInterval: 42s
|
||||||
|
namespaces:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
ecs:
|
ecs:
|
||||||
constraints: foobar
|
constraints: foobar
|
||||||
exposedByDefault: true
|
exposedByDefault: true
|
||||||
|
@ -222,37 +223,37 @@ providers:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
autoDiscoverClusters: true
|
autoDiscoverClusters: true
|
||||||
|
healthyTasksOnly: true
|
||||||
|
ecsAnywhere: true
|
||||||
region: foobar
|
region: foobar
|
||||||
accessKeyID: foobar
|
accessKeyID: foobar
|
||||||
secretAccessKey: foobar
|
secretAccessKey: foobar
|
||||||
ecsAnywhere: true
|
|
||||||
healthyTasksOnly: true
|
|
||||||
consul:
|
consul:
|
||||||
rootKey: foobar
|
rootKey: foobar
|
||||||
endpoints:
|
endpoints:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
token: foobar
|
token: foobar
|
||||||
namespaces:
|
|
||||||
- foobar
|
|
||||||
- foobar
|
|
||||||
tls:
|
tls:
|
||||||
ca: foobar
|
ca: foobar
|
||||||
cert: foobar
|
cert: foobar
|
||||||
key: foobar
|
key: foobar
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
|
namespaces:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
etcd:
|
etcd:
|
||||||
rootKey: foobar
|
rootKey: foobar
|
||||||
endpoints:
|
endpoints:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
username: foobar
|
|
||||||
password: foobar
|
|
||||||
tls:
|
tls:
|
||||||
ca: foobar
|
ca: foobar
|
||||||
cert: foobar
|
cert: foobar
|
||||||
key: foobar
|
key: foobar
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
|
username: foobar
|
||||||
|
password: foobar
|
||||||
zooKeeper:
|
zooKeeper:
|
||||||
rootKey: foobar
|
rootKey: foobar
|
||||||
endpoints:
|
endpoints:
|
||||||
|
@ -265,14 +266,14 @@ providers:
|
||||||
endpoints:
|
endpoints:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
username: foobar
|
|
||||||
password: foobar
|
|
||||||
db: 42
|
|
||||||
tls:
|
tls:
|
||||||
ca: foobar
|
ca: foobar
|
||||||
cert: foobar
|
cert: foobar
|
||||||
key: foobar
|
key: foobar
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
|
username: foobar
|
||||||
|
password: foobar
|
||||||
|
db: 42
|
||||||
sentinel:
|
sentinel:
|
||||||
masterName: foobar
|
masterName: foobar
|
||||||
username: foobar
|
username: foobar
|
||||||
|
@ -294,13 +295,17 @@ providers:
|
||||||
key: foobar
|
key: foobar
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
plugin:
|
plugin:
|
||||||
Descriptor0: {}
|
PluginConf0:
|
||||||
Descriptor1: {}
|
name0: foobar
|
||||||
|
name1: foobar
|
||||||
|
PluginConf1:
|
||||||
|
name0: foobar
|
||||||
|
name1: foobar
|
||||||
api:
|
api:
|
||||||
insecure: true
|
insecure: true
|
||||||
dashboard: true
|
dashboard: true
|
||||||
debug: true
|
debug: true
|
||||||
disabledashboardad: false
|
disableDashboardAd: true
|
||||||
metrics:
|
metrics:
|
||||||
prometheus:
|
prometheus:
|
||||||
buckets:
|
buckets:
|
||||||
|
@ -312,8 +317,8 @@ metrics:
|
||||||
entryPoint: foobar
|
entryPoint: foobar
|
||||||
manualRouting: true
|
manualRouting: true
|
||||||
headerLabels:
|
headerLabels:
|
||||||
label1: foobar
|
name0: foobar
|
||||||
label2: foobar
|
name1: foobar
|
||||||
datadog:
|
datadog:
|
||||||
address: foobar
|
address: foobar
|
||||||
pushInterval: 42s
|
pushInterval: 42s
|
||||||
|
@ -341,6 +346,7 @@ metrics:
|
||||||
name0: foobar
|
name0: foobar
|
||||||
name1: foobar
|
name1: foobar
|
||||||
openTelemetry:
|
openTelemetry:
|
||||||
|
grpc: {}
|
||||||
address: foobar
|
address: foobar
|
||||||
addEntryPointsLabels: true
|
addEntryPointsLabels: true
|
||||||
addRoutersLabels: true
|
addRoutersLabels: true
|
||||||
|
@ -356,12 +362,9 @@ metrics:
|
||||||
pushInterval: 42s
|
pushInterval: 42s
|
||||||
tls:
|
tls:
|
||||||
ca: foobar
|
ca: foobar
|
||||||
caOptional: true
|
|
||||||
cert: foobar
|
cert: foobar
|
||||||
insecureSkipVerify: true
|
|
||||||
key: foobar
|
key: foobar
|
||||||
grpc: {}
|
insecureSkipVerify: true
|
||||||
|
|
||||||
ping:
|
ping:
|
||||||
entryPoint: foobar
|
entryPoint: foobar
|
||||||
manualRouting: true
|
manualRouting: true
|
||||||
|
@ -372,8 +375,8 @@ log:
|
||||||
noColor: true
|
noColor: true
|
||||||
filePath: foobar
|
filePath: foobar
|
||||||
maxSize: 42
|
maxSize: 42
|
||||||
maxBackups: 42
|
|
||||||
maxAge: 42
|
maxAge: 42
|
||||||
|
maxBackups: 42
|
||||||
compress: true
|
compress: true
|
||||||
accessLog:
|
accessLog:
|
||||||
filePath: foobar
|
filePath: foobar
|
||||||
|
@ -397,13 +400,13 @@ accessLog:
|
||||||
bufferingSize: 42
|
bufferingSize: 42
|
||||||
tracing:
|
tracing:
|
||||||
serviceName: foobar
|
serviceName: foobar
|
||||||
sampleRate: 42
|
|
||||||
headers:
|
headers:
|
||||||
header1: foobar
|
name0: foobar
|
||||||
header2: foobar
|
name1: foobar
|
||||||
globalAttributes:
|
globalAttributes:
|
||||||
attr1: foobar
|
name0: foobar
|
||||||
attr2: foobar
|
name1: foobar
|
||||||
|
sampleRate: 42
|
||||||
otlp:
|
otlp:
|
||||||
grpc:
|
grpc:
|
||||||
endpoint: foobar
|
endpoint: foobar
|
||||||
|
@ -429,13 +432,13 @@ certificatesResolvers:
|
||||||
acme:
|
acme:
|
||||||
email: foobar
|
email: foobar
|
||||||
caServer: foobar
|
caServer: foobar
|
||||||
certificatesDuration: 42
|
|
||||||
preferredChain: foobar
|
preferredChain: foobar
|
||||||
storage: foobar
|
storage: foobar
|
||||||
keyType: foobar
|
keyType: foobar
|
||||||
eab:
|
eab:
|
||||||
kid: foobar
|
kid: foobar
|
||||||
hmacEncoded: foobar
|
hmacEncoded: foobar
|
||||||
|
certificatesDuration: 42
|
||||||
dnsChallenge:
|
dnsChallenge:
|
||||||
provider: foobar
|
provider: foobar
|
||||||
delayBeforeCheck: 42s
|
delayBeforeCheck: 42s
|
||||||
|
@ -446,10 +449,30 @@ certificatesResolvers:
|
||||||
httpChallenge:
|
httpChallenge:
|
||||||
entryPoint: foobar
|
entryPoint: foobar
|
||||||
tlsChallenge: {}
|
tlsChallenge: {}
|
||||||
|
tailscale: {}
|
||||||
CertificateResolver1:
|
CertificateResolver1:
|
||||||
|
acme:
|
||||||
|
email: foobar
|
||||||
|
caServer: foobar
|
||||||
|
preferredChain: foobar
|
||||||
|
storage: foobar
|
||||||
|
keyType: foobar
|
||||||
|
eab:
|
||||||
|
kid: foobar
|
||||||
|
hmacEncoded: foobar
|
||||||
|
certificatesDuration: 42
|
||||||
|
dnsChallenge:
|
||||||
|
provider: foobar
|
||||||
|
delayBeforeCheck: 42s
|
||||||
|
resolvers:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
disablePropagationCheck: true
|
||||||
|
httpChallenge:
|
||||||
|
entryPoint: foobar
|
||||||
|
tlsChallenge: {}
|
||||||
tailscale: {}
|
tailscale: {}
|
||||||
experimental:
|
experimental:
|
||||||
kubernetesGateway: true
|
|
||||||
plugins:
|
plugins:
|
||||||
Descriptor0:
|
Descriptor0:
|
||||||
moduleName: foobar
|
moduleName: foobar
|
||||||
|
@ -458,7 +481,12 @@ experimental:
|
||||||
moduleName: foobar
|
moduleName: foobar
|
||||||
version: foobar
|
version: foobar
|
||||||
localPlugins:
|
localPlugins:
|
||||||
Descriptor0:
|
LocalDescriptor0:
|
||||||
moduleName: foobar
|
moduleName: foobar
|
||||||
Descriptor1:
|
LocalDescriptor1:
|
||||||
moduleName: foobar
|
moduleName: foobar
|
||||||
|
kubernetesGateway: true
|
||||||
|
core:
|
||||||
|
defaultRuleSyntax: foobar
|
||||||
|
spiffe:
|
||||||
|
workloadAPIAddr: foobar
|
||||||
|
|
|
@ -273,6 +273,14 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
|
||||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none
|
traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.maxage`"
|
||||||
|
|
||||||
|
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
traefik.http.services.myservice.loadbalancer.sticky.cookie.maxage=42
|
||||||
|
```
|
||||||
|
|
||||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||||
|
|
||||||
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
||||||
|
|
|
@ -376,6 +376,14 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
|
||||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none"
|
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.maxage`"
|
||||||
|
|
||||||
|
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.maxage=42"
|
||||||
|
```
|
||||||
|
|
||||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||||
|
|
||||||
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
||||||
|
|
|
@ -275,6 +275,14 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
|
||||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none
|
traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.maxage`"
|
||||||
|
|
||||||
|
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
traefik.http.services.myservice.loadbalancer.sticky.cookie.maxage=42
|
||||||
|
```
|
||||||
|
|
||||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||||
|
|
||||||
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
||||||
|
|
|
@ -348,6 +348,7 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
|
||||||
name: cookie
|
name: cookie
|
||||||
secure: true
|
secure: true
|
||||||
sameSite: none
|
sameSite: none
|
||||||
|
maxAge: 42
|
||||||
strategy: RoundRobin
|
strategy: RoundRobin
|
||||||
weight: 10
|
weight: 10
|
||||||
nativeLB: true # [11]
|
nativeLB: true # [11]
|
||||||
|
|
|
@ -351,6 +351,14 @@ which in turn will create the resulting routers, services, handlers, etc.
|
||||||
traefik.ingress.kubernetes.io/service.sticky.cookie.httponly: "true"
|
traefik.ingress.kubernetes.io/service.sticky.cookie.httponly: "true"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? info "`traefik.ingress.kubernetes.io/service.sticky.cookie.maxage`"
|
||||||
|
|
||||||
|
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
traefik.ingress.kubernetes.io/service.sticky.cookie.maxage: 42
|
||||||
|
```
|
||||||
|
|
||||||
## Path Types on Kubernetes 1.18+
|
## Path Types on Kubernetes 1.18+
|
||||||
|
|
||||||
If the Kubernetes cluster version is 1.18+,
|
If the Kubernetes cluster version is 1.18+,
|
||||||
|
|
|
@ -244,6 +244,14 @@ A Story of key & values
|
||||||
|-----------------------------------------------------------------------|--------|
|
|-----------------------------------------------------------------------|--------|
|
||||||
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/samesite` | `none` |
|
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/samesite` | `none` |
|
||||||
|
|
||||||
|
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/maxage`"
|
||||||
|
|
||||||
|
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||||
|
|
||||||
|
| Key (Path) | Value |
|
||||||
|
|---------------------------------------------------------------------|-------|
|
||||||
|
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/maxage` | `42` |
|
||||||
|
|
||||||
??? info "`traefik/http/services/<service_name>/loadbalancer/responseforwarding/flushinterval`"
|
??? info "`traefik/http/services/<service_name>/loadbalancer/responseforwarding/flushinterval`"
|
||||||
|
|
||||||
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
||||||
|
@ -306,6 +314,12 @@ A Story of key & values
|
||||||
|------------------------------------------------------------------------|--------|
|
|------------------------------------------------------------------------|--------|
|
||||||
| `traefik/http/services/<service_name>/weighted/sticky/cookie/httpOnly` | `true` |
|
| `traefik/http/services/<service_name>/weighted/sticky/cookie/httpOnly` | `true` |
|
||||||
|
|
||||||
|
??? info "`traefik/http/services/<service_name>/weighted/sticky/cookie/maxage`"
|
||||||
|
|
||||||
|
| Key (Path) | Value |
|
||||||
|
|----------------------------------------------------------------------|-------|
|
||||||
|
| `traefik/http/services/<service_name>/weighted/sticky/cookie/maxage` | `42` |
|
||||||
|
|
||||||
### Middleware
|
### Middleware
|
||||||
|
|
||||||
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
|
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
|
||||||
|
|
|
@ -265,6 +265,14 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
|
||||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none
|
traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.maxage`"
|
||||||
|
|
||||||
|
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
traefik.http.services.myservice.loadbalancer.sticky.cookie.maxage=42
|
||||||
|
```
|
||||||
|
|
||||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||||
|
|
||||||
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
See [response forwarding](../services/index.md#response-forwarding) for more information.
|
||||||
|
|
|
@ -515,6 +515,60 @@ A value of `0` for the priority is ignored: `priority = 0` means that the defaul
|
||||||
|
|
||||||
In this configuration, the priority is configured to allow `Router-2` to handle requests with the `foobar.traefik.com` host.
|
In this configuration, the priority is configured to allow `Router-2` to handle requests with the `foobar.traefik.com` host.
|
||||||
|
|
||||||
|
### RuleSyntax
|
||||||
|
|
||||||
|
In Traefik v3 a new rule syntax has been introduced ([migration guide](../../migration/v2-to-v3.md#router-rule-matchers)).
|
||||||
|
`ruleSyntax` option allows to configure the rule syntax to be used for parsing the rule on a per-router basis.
|
||||||
|
This allows to have heterogeneous router configurations and ease migration.
|
||||||
|
|
||||||
|
??? example "Set rule syntax -- using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
## Dynamic configuration
|
||||||
|
http:
|
||||||
|
routers:
|
||||||
|
Router-v3:
|
||||||
|
rule: HostRegexp(`[a-z]+\\.traefik\\.com`)
|
||||||
|
ruleSyntax: v3
|
||||||
|
Router-v2:
|
||||||
|
rule: HostRegexp(`{subdomain:[a-z]+}.traefik.com`)
|
||||||
|
ruleSyntax: v2
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
## Dynamic configuration
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.Router-v3]
|
||||||
|
rule = "HostRegexp(`[a-z]+\\.traefik\\.com`)"
|
||||||
|
ruleSyntax = v3
|
||||||
|
[http.routers.Router-v2]
|
||||||
|
rule = "HostRegexp(`{subdomain:[a-z]+}.traefik.com`)"
|
||||||
|
ruleSyntax = v2
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes traefik.io/v1alpha1"
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
routes:
|
||||||
|
# route v3
|
||||||
|
- match: HostRegexp(`[a-z]+\\.traefik\\.com`)
|
||||||
|
syntax: v3
|
||||||
|
kind: Rule
|
||||||
|
|
||||||
|
# route v2
|
||||||
|
- match: HostRegexp(`{subdomain:[a-z]+}.traefik.com`)
|
||||||
|
syntax: v2
|
||||||
|
kind: Rule
|
||||||
|
```
|
||||||
|
|
||||||
|
In this configuration, the ruleSyntax is configured to allow `Router-v2` to use v2 syntax,
|
||||||
|
while for `Router-v3` it is configured to use v3 syntax.
|
||||||
|
|
||||||
### Middlewares
|
### Middlewares
|
||||||
|
|
||||||
You can attach a list of [middlewares](../../middlewares/overview.md) to each HTTP router.
|
You can attach a list of [middlewares](../../middlewares/overview.md) to each HTTP router.
|
||||||
|
@ -1161,6 +1215,60 @@ A value of `0` for the priority is ignored: `priority = 0` means that the defaul
|
||||||
|
|
||||||
In this configuration, the priority is configured so that `Router-1` will handle requests from `192.168.0.12`.
|
In this configuration, the priority is configured so that `Router-1` will handle requests from `192.168.0.12`.
|
||||||
|
|
||||||
|
### RuleSyntax
|
||||||
|
|
||||||
|
In Traefik v3 a new rule syntax has been introduced ([migration guide](../../migration/v2-to-v3.md#router-rule-matchers)).
|
||||||
|
`ruleSyntax` option allows to configure the rule syntax to be used for parsing the rule on a per-router basis.
|
||||||
|
This allows to have heterogeneous router configurations and ease migration.
|
||||||
|
|
||||||
|
??? example "Set rule syntax -- using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
## Dynamic configuration
|
||||||
|
tcp:
|
||||||
|
routers:
|
||||||
|
Router-v3:
|
||||||
|
rule: ClientIP(`192.168.0.11`) || ClientIP(`192.168.0.12`)
|
||||||
|
ruleSyntax: v3
|
||||||
|
Router-v2:
|
||||||
|
rule: ClientIP(`192.168.0.11`, `192.168.0.12`)
|
||||||
|
ruleSyntax: v2
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
## Dynamic configuration
|
||||||
|
[tcp.routers]
|
||||||
|
[tcp.routers.Router-v3]
|
||||||
|
rule = "ClientIP(`192.168.0.11`) || ClientIP(`192.168.0.12`)"
|
||||||
|
ruleSyntax = v3
|
||||||
|
[tcp.routers.Router-v2]
|
||||||
|
rule = "ClientIP(`192.168.0.11`, `192.168.0.12`)"
|
||||||
|
ruleSyntax = v2
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes traefik.io/v1alpha1"
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRouteTCP
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
routes:
|
||||||
|
# route v3
|
||||||
|
- match: ClientIP(`192.168.0.11`) || ClientIP(`192.168.0.12`)
|
||||||
|
syntax: v3
|
||||||
|
kind: Rule
|
||||||
|
|
||||||
|
# route v2
|
||||||
|
- match: ClientIP(`192.168.0.11`, `192.168.0.12`)
|
||||||
|
syntax: v2
|
||||||
|
kind: Rule
|
||||||
|
```
|
||||||
|
|
||||||
|
In this configuration, the ruleSyntax is configured to allow `Router-v2` to use v2 syntax,
|
||||||
|
while for `Router-v3` it is configured to use v3 syntax.
|
||||||
|
|
||||||
### Middlewares
|
### Middlewares
|
||||||
|
|
||||||
You can attach a list of [middlewares](../../middlewares/overview.md) to each TCP router.
|
You can attach a list of [middlewares](../../middlewares/overview.md) to each TCP router.
|
||||||
|
|
|
@ -143,6 +143,36 @@ The `url` option point to a specific instance.
|
||||||
url = "http://private-ip-server-1/"
|
url = "http://private-ip-server-1/"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The `weight` option allows for weighted load balancing on the servers.
|
||||||
|
|
||||||
|
??? example "A Service with Two Servers with Weight -- Using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
|
```yaml tab="YAML"
|
||||||
|
## Dynamic configuration
|
||||||
|
http:
|
||||||
|
services:
|
||||||
|
my-service:
|
||||||
|
loadBalancer:
|
||||||
|
servers:
|
||||||
|
- url: "http://private-ip-server-1/"
|
||||||
|
weight: 2
|
||||||
|
- url: "http://private-ip-server-2/"
|
||||||
|
weight: 1
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="TOML"
|
||||||
|
## Dynamic configuration
|
||||||
|
[http.services]
|
||||||
|
[http.services.my-service.loadBalancer]
|
||||||
|
[[http.services.my-service.loadBalancer.servers]]
|
||||||
|
url = "http://private-ip-server-1/"
|
||||||
|
weight = 2
|
||||||
|
[[http.services.my-service.loadBalancer.servers]]
|
||||||
|
url = "http://private-ip-server-2/"
|
||||||
|
weight = 1
|
||||||
|
```
|
||||||
|
|
||||||
#### Load-balancing
|
#### Load-balancing
|
||||||
|
|
||||||
For now, only round robin load balancing is supported:
|
For now, only round robin load balancing is supported:
|
||||||
|
@ -187,6 +217,13 @@ On subsequent requests, to keep the session alive with the same server, the clie
|
||||||
|
|
||||||
The default cookie name is an abbreviation of a sha1 (ex: `_1d52e`).
|
The default cookie name is an abbreviation of a sha1 (ex: `_1d52e`).
|
||||||
|
|
||||||
|
!!! info "MaxAge"
|
||||||
|
|
||||||
|
By default, the affinity cookie will never expire as the `MaxAge` option is set to zero.
|
||||||
|
|
||||||
|
This option indicates the number of seconds until the cookie expires.
|
||||||
|
When set to a negative number, the cookie expires immediately.
|
||||||
|
|
||||||
!!! info "Secure & HTTPOnly & SameSite flags"
|
!!! info "Secure & HTTPOnly & SameSite flags"
|
||||||
|
|
||||||
By default, the affinity cookie is created without those flags.
|
By default, the affinity cookie is created without those flags.
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
# WEBUI
|
|
||||||
FROM node:12.11 as webui
|
|
||||||
|
|
||||||
ENV WEBUI_DIR /src/webui
|
|
||||||
RUN mkdir -p $WEBUI_DIR
|
|
||||||
|
|
||||||
COPY ./webui/ $WEBUI_DIR/
|
|
||||||
|
|
||||||
WORKDIR $WEBUI_DIR
|
|
||||||
|
|
||||||
RUN yarn install
|
|
||||||
RUN yarn build
|
|
||||||
|
|
||||||
# BUILD
|
|
||||||
FROM golang:1.21-alpine as gobuild
|
|
||||||
|
|
||||||
RUN apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar ca-certificates tzdata \
|
|
||||||
&& update-ca-certificates \
|
|
||||||
&& rm -rf /var/cache/apk/*
|
|
||||||
|
|
||||||
WORKDIR /go/src/github.com/traefik/traefik
|
|
||||||
|
|
||||||
# Download go modules
|
|
||||||
COPY go.mod .
|
|
||||||
COPY go.sum .
|
|
||||||
RUN GO111MODULE=on GOPROXY=https://proxy.golang.org go mod download
|
|
||||||
|
|
||||||
COPY . /go/src/github.com/traefik/traefik
|
|
||||||
|
|
||||||
RUN rm -rf /go/src/github.com/traefik/traefik/webui/static/
|
|
||||||
COPY --from=webui /src/webui/static/ /go/src/github.com/traefik/traefik/webui/static/
|
|
||||||
|
|
||||||
RUN ./script/make.sh generate binary
|
|
||||||
|
|
||||||
## IMAGE
|
|
||||||
FROM alpine:3.14
|
|
||||||
|
|
||||||
RUN apk --no-cache --no-progress add bash curl ca-certificates tzdata \
|
|
||||||
&& update-ca-certificates \
|
|
||||||
&& rm -rf /var/cache/apk/*
|
|
||||||
|
|
||||||
COPY --from=gobuild /go/src/github.com/traefik/traefik/dist/traefik /
|
|
||||||
|
|
||||||
EXPOSE 80
|
|
||||||
VOLUME ["/tmp"]
|
|
||||||
|
|
||||||
ENTRYPOINT ["/traefik"]
|
|
14
go.mod
14
go.mod
|
@ -28,7 +28,7 @@ require (
|
||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.4
|
github.com/hashicorp/go-retryablehttp v0.7.4
|
||||||
github.com/hashicorp/go-version v1.6.0
|
github.com/hashicorp/go-version v1.6.0
|
||||||
github.com/hashicorp/nomad/api v0.0.0-20220506174431-b5665129cd1f
|
github.com/hashicorp/nomad/api v0.0.0-20240122103822-8a4bd61caf74
|
||||||
github.com/http-wasm/http-wasm-host-go v0.5.2
|
github.com/http-wasm/http-wasm-host-go v0.5.2
|
||||||
github.com/influxdata/influxdb-client-go/v2 v2.7.0
|
github.com/influxdata/influxdb-client-go/v2 v2.7.0
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d
|
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d
|
||||||
|
@ -85,12 +85,13 @@ require (
|
||||||
golang.org/x/tools v0.14.0
|
golang.org/x/tools v0.14.0
|
||||||
google.golang.org/grpc v1.59.0
|
google.golang.org/grpc v1.59.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
k8s.io/api v0.28.3
|
k8s.io/api v0.28.4
|
||||||
k8s.io/apiextensions-apiserver v0.28.3
|
k8s.io/apiextensions-apiserver v0.28.3
|
||||||
k8s.io/apimachinery v0.28.3
|
k8s.io/apimachinery v0.28.4
|
||||||
k8s.io/client-go v0.28.3
|
k8s.io/client-go v0.28.4
|
||||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
|
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
|
||||||
mvdan.cc/xurls/v2 v2.5.0
|
mvdan.cc/xurls/v2 v2.5.0
|
||||||
|
sigs.k8s.io/controller-runtime v0.16.3
|
||||||
sigs.k8s.io/gateway-api v1.0.0
|
sigs.k8s.io/gateway-api v1.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -162,6 +163,7 @@ require (
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||||
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
|
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
|
||||||
|
github.com/evanphx/json-patch/v5 v5.7.0 // indirect
|
||||||
github.com/exoscale/egoscale v0.100.1 // indirect
|
github.com/exoscale/egoscale v0.100.1 // indirect
|
||||||
github.com/fatih/color v1.15.0 // indirect
|
github.com/fatih/color v1.15.0 // indirect
|
||||||
github.com/ghodss/yaml v1.0.0 // indirect
|
github.com/ghodss/yaml v1.0.0 // indirect
|
||||||
|
@ -196,7 +198,7 @@ require (
|
||||||
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae // indirect
|
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae // indirect
|
||||||
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf // indirect
|
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
|
||||||
github.com/hashicorp/cronexpr v1.1.1 // indirect
|
github.com/hashicorp/cronexpr v1.1.2 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||||
|
@ -236,6 +238,7 @@ require (
|
||||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||||
|
github.com/moby/spdystream v0.2.0 // indirect
|
||||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||||
github.com/moby/term v0.5.0 // indirect
|
github.com/moby/term v0.5.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
@ -254,7 +257,6 @@ require (
|
||||||
github.com/nzdjb/go-metaname v1.0.0 // indirect
|
github.com/nzdjb/go-metaname v1.0.0 // indirect
|
||||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
|
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
|
||||||
github.com/onsi/gomega v1.27.10 // indirect
|
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
|
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
|
||||||
github.com/opencontainers/runc v1.1.5 // indirect
|
github.com/opencontainers/runc v1.1.5 // indirect
|
||||||
|
|
37
go.sum
37
go.sum
|
@ -114,6 +114,8 @@ github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJ
|
||||||
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
|
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
|
@ -302,6 +304,8 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI=
|
github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI=
|
||||||
github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
|
github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc=
|
||||||
|
github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
||||||
github.com/exoscale/egoscale v0.100.1 h1:iXsV1Ei7daqe/6FYSCSDyrFs1iUG1l1X9qNh2uMw6z0=
|
github.com/exoscale/egoscale v0.100.1 h1:iXsV1Ei7daqe/6FYSCSDyrFs1iUG1l1X9qNh2uMw6z0=
|
||||||
github.com/exoscale/egoscale v0.100.1/go.mod h1:BAb9p4rmyU+Wl400CJZO5270H2sXtdsZjLcm5xMKkz4=
|
github.com/exoscale/egoscale v0.100.1/go.mod h1:BAb9p4rmyU+Wl400CJZO5270H2sXtdsZjLcm5xMKkz4=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
@ -311,6 +315,8 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
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.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||||
|
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||||
|
@ -356,6 +362,8 @@ github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
|
||||||
|
github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
|
@ -538,8 +546,8 @@ github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyN
|
||||||
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU=
|
github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU=
|
||||||
github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo=
|
github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo=
|
||||||
github.com/hashicorp/cronexpr v1.1.1 h1:NJZDd87hGXjoZBdvyCF9mX4DCq5Wy7+A/w+A7q0wn6c=
|
github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A=
|
||||||
github.com/hashicorp/cronexpr v1.1.1/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
|
github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
@ -590,8 +598,8 @@ github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/
|
||||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||||
github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
|
github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
|
||||||
github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
|
github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
|
||||||
github.com/hashicorp/nomad/api v0.0.0-20220506174431-b5665129cd1f h1:jSBbBJcPca465gK6XfwdXRQnFCd63e0oJmqllZTsawI=
|
github.com/hashicorp/nomad/api v0.0.0-20240122103822-8a4bd61caf74 h1:Q+WuGTnZkL2cJ7yNsg4Go4GNnRkcahGLiQP/WD41TTA=
|
||||||
github.com/hashicorp/nomad/api v0.0.0-20220506174431-b5665129cd1f/go.mod h1:b/AoT79m3PEpb6tKCFKva/M+q1rKJNUk5mdu1S8DymM=
|
github.com/hashicorp/nomad/api v0.0.0-20240122103822-8a4bd61caf74/go.mod h1:ijDwa6o1uG1jFSq6kERiX2PamKGpZzTmo0XOFNeFZgw=
|
||||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||||
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
|
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
|
||||||
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
|
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
|
||||||
|
@ -794,6 +802,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
|
||||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||||
|
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||||
|
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||||
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
|
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
|
||||||
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
||||||
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
||||||
|
@ -1004,8 +1014,9 @@ github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9
|
||||||
github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
|
github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
|
||||||
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||||
|
github.com/shoenig/test v1.7.0 h1:eWcHtTXa6QLnBvm0jgEabMRN/uJ4DMV3M8xUGgRkZmk=
|
||||||
|
github.com/shoenig/test v1.7.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
|
||||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
@ -1482,6 +1493,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
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.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
||||||
|
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
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 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM=
|
||||||
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||||
|
@ -1616,14 +1629,14 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM=
|
k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY=
|
||||||
k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc=
|
k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0=
|
||||||
k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08=
|
k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08=
|
||||||
k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc=
|
k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc=
|
||||||
k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A=
|
k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8=
|
||||||
k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8=
|
k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg=
|
||||||
k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4=
|
k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY=
|
||||||
k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo=
|
k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4=
|
||||||
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
|
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
|
||||||
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
|
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
|
||||||
|
@ -1637,6 +1650,8 @@ nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0
|
||||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
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/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4=
|
||||||
|
sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0=
|
||||||
sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs=
|
sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs=
|
||||||
sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c=
|
sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -55,6 +56,56 @@ func (s *DockerSuite) TestSimpleConfiguration() {
|
||||||
require.NoError(s.T(), err)
|
require.NoError(s.T(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestWRRServer() {
|
||||||
|
tempObjects := struct {
|
||||||
|
DockerHost string
|
||||||
|
DefaultRule string
|
||||||
|
}{
|
||||||
|
DockerHost: s.getDockerHost(),
|
||||||
|
DefaultRule: "Host(`{{ normalize .Name }}.docker.localhost`)",
|
||||||
|
}
|
||||||
|
|
||||||
|
file := s.adaptFile("fixtures/docker/simple.toml", tempObjects)
|
||||||
|
|
||||||
|
s.composeUp()
|
||||||
|
|
||||||
|
s.traefikCmd(withConfigFile(file))
|
||||||
|
|
||||||
|
whoami1IP := s.getComposeServiceIP("wrr-server")
|
||||||
|
whoami2IP := s.getComposeServiceIP("wrr-server2")
|
||||||
|
|
||||||
|
// Expected a 404 as we did not configure anything
|
||||||
|
err := try.GetRequest("http://127.0.0.1:8000/", 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/services", 1000*time.Millisecond, try.BodyContains("wrr-server"))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
repartition := map[string]int{}
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/whoami", nil)
|
||||||
|
req.Host = "my.wrr.host"
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
response, err := http.DefaultClient.Do(req)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
|
||||||
|
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
if strings.Contains(string(body), whoami1IP) {
|
||||||
|
repartition[whoami1IP]++
|
||||||
|
}
|
||||||
|
if strings.Contains(string(body), whoami2IP) {
|
||||||
|
repartition[whoami2IP]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(s.T(), 3, repartition[whoami1IP])
|
||||||
|
assert.Equal(s.T(), 1, repartition[whoami2IP])
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DockerSuite) TestDefaultDockerContainers() {
|
func (s *DockerSuite) TestDefaultDockerContainers() {
|
||||||
tempObjects := struct {
|
tempObjects := struct {
|
||||||
DockerHost string
|
DockerHost string
|
||||||
|
|
|
@ -160,6 +160,12 @@ spec:
|
||||||
can be accessed by client-side APIs, such as
|
can be accessed by client-side APIs, such as
|
||||||
JavaScript.
|
JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When
|
||||||
|
set to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -189,6 +195,10 @@ spec:
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
syntax:
|
||||||
|
description: 'Syntax defines the router''s rule syntax. More
|
||||||
|
info: https://doc.traefik.io/traefik/v3.0/routing/routers/#rulesyntax'
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- kind
|
- kind
|
||||||
- match
|
- match
|
||||||
|
@ -396,6 +406,10 @@ spec:
|
||||||
- port
|
- port
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
syntax:
|
||||||
|
description: 'Syntax defines the router''s rule syntax. More
|
||||||
|
info: https://doc.traefik.io/traefik/v3.0/routing/routers/#rulesyntax_1'
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- match
|
- match
|
||||||
type: object
|
type: object
|
||||||
|
@ -750,6 +764,13 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
includedContentTypes:
|
||||||
|
description: IncludedContentTypes defines the list of content
|
||||||
|
types to compare the Content-Type header of the responses before
|
||||||
|
compressing.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
minResponseBodyBytes:
|
minResponseBodyBytes:
|
||||||
description: 'MinResponseBodyBytes defines the minimum amount
|
description: 'MinResponseBodyBytes defines the minimum amount
|
||||||
of bytes a response body must have to be compressed. Default:
|
of bytes a response body must have to be compressed. Default:
|
||||||
|
@ -870,6 +891,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie can
|
description: HTTPOnly defines whether the cookie can
|
||||||
be accessed by client-side APIs, such as JavaScript.
|
be accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When set
|
||||||
|
to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -912,6 +939,12 @@ spec:
|
||||||
This middleware delegates the request authentication to a Service.
|
This middleware delegates the request authentication to a Service.
|
||||||
More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/forwardauth/'
|
More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/forwardauth/'
|
||||||
properties:
|
properties:
|
||||||
|
addAuthCookiesToResponse:
|
||||||
|
description: AddAuthCookiesToResponse defines the list of cookies
|
||||||
|
to copy from the authentication server response to the response.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
address:
|
address:
|
||||||
description: Address defines the authentication server address.
|
description: Address defines the authentication server address.
|
||||||
type: string
|
type: string
|
||||||
|
@ -2145,6 +2178,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie
|
description: HTTPOnly defines whether the cookie
|
||||||
can be accessed by client-side APIs, such as JavaScript.
|
can be accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When set
|
||||||
|
to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -2236,6 +2275,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie can be
|
description: HTTPOnly defines whether the cookie can be
|
||||||
accessed by client-side APIs, such as JavaScript.
|
accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds until
|
||||||
|
the cookie expires. When set to a negative number, the
|
||||||
|
cookie expires immediately. When set to zero, the cookie
|
||||||
|
never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -2343,6 +2388,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie
|
description: HTTPOnly defines whether the cookie
|
||||||
can be accessed by client-side APIs, such as JavaScript.
|
can be accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds
|
||||||
|
until the cookie expires. When set to a negative
|
||||||
|
number, the cookie expires immediately. When set
|
||||||
|
to zero, the cookie never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
@ -2382,6 +2433,12 @@ spec:
|
||||||
description: HTTPOnly defines whether the cookie can be
|
description: HTTPOnly defines whether the cookie can be
|
||||||
accessed by client-side APIs, such as JavaScript.
|
accessed by client-side APIs, such as JavaScript.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
maxAge:
|
||||||
|
description: MaxAge indicates the number of seconds until
|
||||||
|
the cookie expires. When set to a negative number, the
|
||||||
|
cookie expires immediately. When set to zero, the cookie
|
||||||
|
never expires.
|
||||||
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Name defines the Cookie name.
|
description: Name defines the Cookie name.
|
||||||
type: string
|
type: string
|
||||||
|
|
21
integration/fixtures/k8s_gateway_conformance.toml
Normal file
21
integration/fixtures/k8s_gateway_conformance.toml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
[global]
|
||||||
|
checkNewVersion = false
|
||||||
|
sendAnonymousUsage = false
|
||||||
|
|
||||||
|
[log]
|
||||||
|
level = "DEBUG"
|
||||||
|
noColor = true
|
||||||
|
|
||||||
|
[api]
|
||||||
|
insecure = true
|
||||||
|
|
||||||
|
[experimental]
|
||||||
|
kubernetesGateway = true
|
||||||
|
|
||||||
|
[entryPoints]
|
||||||
|
[entryPoints.web]
|
||||||
|
address = ":80"
|
||||||
|
[entryPoints.websecure]
|
||||||
|
address = ":443"
|
||||||
|
|
||||||
|
[providers.kubernetesGateway]
|
41
integration/fixtures/with_default_rule_syntax.toml
Normal file
41
integration/fixtures/with_default_rule_syntax.toml
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
[global]
|
||||||
|
checkNewVersion = false
|
||||||
|
sendAnonymousUsage = false
|
||||||
|
|
||||||
|
[core]
|
||||||
|
defaultRuleSyntax = "v2"
|
||||||
|
|
||||||
|
[log]
|
||||||
|
level = "DEBUG"
|
||||||
|
noColor = true
|
||||||
|
|
||||||
|
[entryPoints]
|
||||||
|
[entryPoints.web]
|
||||||
|
address = ":8000"
|
||||||
|
|
||||||
|
[api]
|
||||||
|
insecure = true
|
||||||
|
|
||||||
|
[providers.file]
|
||||||
|
filename = "{{ .SelfFilename }}"
|
||||||
|
|
||||||
|
## dynamic configuration ##
|
||||||
|
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.router1]
|
||||||
|
service = "service1"
|
||||||
|
rule = "PathPrefix(`/foo`, `/bar`)"
|
||||||
|
|
||||||
|
[http.routers.router2]
|
||||||
|
service = "service1"
|
||||||
|
rule = "QueryRegexp(`foo`, `bar`)"
|
||||||
|
|
||||||
|
[http.routers.router3]
|
||||||
|
service = "service1"
|
||||||
|
rule = "PathPrefix(`/foo`, `/bar`)"
|
||||||
|
ruleSyntax = "v3"
|
||||||
|
|
||||||
|
[http.services]
|
||||||
|
[http.services.service1]
|
||||||
|
[http.services.service1.loadBalancer]
|
||||||
|
[http.services.service1.loadBalancer.servers]
|
38
integration/fixtures/without_default_rule_syntax.toml
Normal file
38
integration/fixtures/without_default_rule_syntax.toml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
[global]
|
||||||
|
checkNewVersion = false
|
||||||
|
sendAnonymousUsage = false
|
||||||
|
|
||||||
|
[log]
|
||||||
|
level = "DEBUG"
|
||||||
|
noColor = true
|
||||||
|
|
||||||
|
[entryPoints]
|
||||||
|
[entryPoints.web]
|
||||||
|
address = ":8000"
|
||||||
|
|
||||||
|
[api]
|
||||||
|
insecure = true
|
||||||
|
|
||||||
|
[providers.file]
|
||||||
|
filename = "{{ .SelfFilename }}"
|
||||||
|
|
||||||
|
## dynamic configuration ##
|
||||||
|
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.router1]
|
||||||
|
service = "service1"
|
||||||
|
rule = "PathPrefix(`/foo`) || PathPrefix(`/bar`)"
|
||||||
|
|
||||||
|
[http.routers.router2]
|
||||||
|
service = "service1"
|
||||||
|
rule = "PathPrefix(`/foo`, `/bar`)"
|
||||||
|
|
||||||
|
[http.routers.router3]
|
||||||
|
service = "service1"
|
||||||
|
rule = "QueryRegexp(`foo`, `bar`)"
|
||||||
|
ruleSyntax = "v2"
|
||||||
|
|
||||||
|
[http.services]
|
||||||
|
[http.services.service1]
|
||||||
|
[http.services.service1.loadBalancer]
|
||||||
|
[http.services.service1.loadBalancer.servers]
|
35
integration/fixtures/wrr_server.toml
Normal file
35
integration/fixtures/wrr_server.toml
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
[global]
|
||||||
|
checkNewVersion = false
|
||||||
|
sendAnonymousUsage = false
|
||||||
|
|
||||||
|
[api]
|
||||||
|
insecure = true
|
||||||
|
|
||||||
|
[log]
|
||||||
|
level = "DEBUG"
|
||||||
|
noColor = true
|
||||||
|
|
||||||
|
[entryPoints]
|
||||||
|
|
||||||
|
[entryPoints.web]
|
||||||
|
address = ":8000"
|
||||||
|
|
||||||
|
[providers.file]
|
||||||
|
filename = "{{ .SelfFilename }}"
|
||||||
|
|
||||||
|
## dynamic configuration ##
|
||||||
|
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.router]
|
||||||
|
service = "service1"
|
||||||
|
rule = "Path(`/whoami`)"
|
||||||
|
|
||||||
|
[http.services]
|
||||||
|
|
||||||
|
[http.services.service1.loadBalancer]
|
||||||
|
[[http.services.service1.loadBalancer.servers]]
|
||||||
|
url = "{{ .Server1 }}"
|
||||||
|
weight = 3
|
||||||
|
[[http.services.service1.loadBalancer.servers]]
|
||||||
|
url = "{{ .Server2 }}"
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"runtime"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -34,7 +35,13 @@ import (
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var showLog = flag.Bool("tlog", false, "always show Traefik logs")
|
var (
|
||||||
|
showLog = flag.Bool("tlog", false, "always show Traefik logs")
|
||||||
|
k8sConformance = flag.Bool("k8sConformance", false, "run K8s Gateway API conformance test")
|
||||||
|
k8sConformanceRunTest = flag.String("k8sConformanceRunTest", "", "run a specific K8s Gateway API conformance test")
|
||||||
|
)
|
||||||
|
|
||||||
|
const tailscaleSecretFilePath = "tailscale.secret"
|
||||||
|
|
||||||
type composeConfig struct {
|
type composeConfig struct {
|
||||||
Services map[string]composeService `yaml:"services"`
|
Services map[string]composeService `yaml:"services"`
|
||||||
|
@ -56,8 +63,6 @@ type composeDeploy struct {
|
||||||
Replicas int `yaml:"replicas"`
|
Replicas int `yaml:"replicas"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var traefikBinary = "../dist/traefik"
|
|
||||||
|
|
||||||
type BaseSuite struct {
|
type BaseSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
containers map[string]testcontainers.Container
|
containers map[string]testcontainers.Container
|
||||||
|
@ -100,6 +105,11 @@ func (s *BaseSuite) displayTraefikLogFile(path string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BaseSuite) SetupSuite() {
|
func (s *BaseSuite) SetupSuite() {
|
||||||
|
if isDockerDesktop(context.Background(), s.T()) {
|
||||||
|
_, err := os.Stat(tailscaleSecretFilePath)
|
||||||
|
require.NoError(s.T(), err, "Tailscale need to be configured when running integration tests with Docker Desktop: (https://doc.traefik.io/traefik/v2.11/contributing/building-testing/#testing)")
|
||||||
|
}
|
||||||
|
|
||||||
// configure default standard log.
|
// configure default standard log.
|
||||||
stdlog.SetFlags(stdlog.Lshortfile | stdlog.LstdFlags)
|
stdlog.SetFlags(stdlog.Lshortfile | stdlog.LstdFlags)
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -125,7 +135,7 @@ func (s *BaseSuite) SetupSuite() {
|
||||||
s.hostIP = "172.31.42.1"
|
s.hostIP = "172.31.42.1"
|
||||||
if isDockerDesktop(ctx, s.T()) {
|
if isDockerDesktop(ctx, s.T()) {
|
||||||
s.hostIP = getDockerDesktopHostIP(ctx, s.T())
|
s.hostIP = getDockerDesktopHostIP(ctx, s.T())
|
||||||
s.setupVPN("tailscale.secret")
|
s.setupVPN(tailscaleSecretFilePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +318,13 @@ func (s *BaseSuite) composeDown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BaseSuite) cmdTraefik(args ...string) (*exec.Cmd, *bytes.Buffer) {
|
func (s *BaseSuite) cmdTraefik(args ...string) (*exec.Cmd, *bytes.Buffer) {
|
||||||
cmd := exec.Command(traefikBinary, args...)
|
binName := "traefik"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
binName += ".exe"
|
||||||
|
}
|
||||||
|
|
||||||
|
traefikBinPath := filepath.Join("..", "dist", runtime.GOOS, runtime.GOARCH, binName)
|
||||||
|
cmd := exec.Command(traefikBinPath, args...)
|
||||||
|
|
||||||
s.T().Cleanup(func() {
|
s.T().Cleanup(func() {
|
||||||
s.killCmd(cmd)
|
s.killCmd(cmd)
|
||||||
|
|
229
integration/k8s_conformance_test.go
Normal file
229
integration/k8s_conformance_test.go
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
"github.com/traefik/traefik/v3/integration/try"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/version"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
ktypes "k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
kclientset "k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
gatev1 "sigs.k8s.io/gateway-api/apis/v1"
|
||||||
|
gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
|
||||||
|
gatev1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
|
||||||
|
conformanceV1alpha1 "sigs.k8s.io/gateway-api/conformance/apis/v1alpha1"
|
||||||
|
"sigs.k8s.io/gateway-api/conformance/tests"
|
||||||
|
"sigs.k8s.io/gateway-api/conformance/utils/config"
|
||||||
|
ksuite "sigs.k8s.io/gateway-api/conformance/utils/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
// K8sConformanceSuite tests suite.
|
||||||
|
type K8sConformanceSuite struct{ BaseSuite }
|
||||||
|
|
||||||
|
func TestK8sConformanceSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(K8sConformanceSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *K8sConformanceSuite) SetupSuite() {
|
||||||
|
s.BaseSuite.SetupSuite()
|
||||||
|
|
||||||
|
s.createComposeProject("k8s")
|
||||||
|
s.composeUp()
|
||||||
|
|
||||||
|
abs, err := filepath.Abs("./fixtures/k8s/config.skip/kubeconfig.yaml")
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = try.Do(60*time.Second, func() error {
|
||||||
|
_, err := os.Stat(abs)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
data, err := os.ReadFile(abs)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
content := strings.ReplaceAll(string(data), "https://server:6443", fmt.Sprintf("https://%s", net.JoinHostPort(s.getComposeServiceIP("server"), "6443")))
|
||||||
|
|
||||||
|
err = os.WriteFile(abs, []byte(content), 0o644)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = os.Setenv("KUBECONFIG", abs)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *K8sConformanceSuite) TearDownSuite() {
|
||||||
|
s.BaseSuite.TearDownSuite()
|
||||||
|
|
||||||
|
generatedFiles := []string{
|
||||||
|
"./fixtures/k8s/config.skip/kubeconfig.yaml",
|
||||||
|
"./fixtures/k8s/config.skip/k3s.log",
|
||||||
|
"./fixtures/k8s/rolebindings.yaml",
|
||||||
|
"./fixtures/k8s/ccm.yaml",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, filename := range generatedFiles {
|
||||||
|
if err := os.Remove(filename); err != nil {
|
||||||
|
log.Warn().Err(err).Send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *K8sConformanceSuite) TestK8sGatewayAPIConformance() {
|
||||||
|
if !*k8sConformance {
|
||||||
|
s.T().Skip("Skip because it can take a long time to execute. To enable pass the `k8sConformance` flag.")
|
||||||
|
}
|
||||||
|
|
||||||
|
configFromFlags, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
|
||||||
|
if err != nil {
|
||||||
|
s.T().Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
kClient, err := client.New(configFromFlags, client.Options{})
|
||||||
|
if err != nil {
|
||||||
|
s.T().Fatalf("Error initializing Kubernetes client: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
kClientSet, err := kclientset.NewForConfig(configFromFlags)
|
||||||
|
if err != nil {
|
||||||
|
s.T().Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gatev1alpha2.AddToScheme(kClient.Scheme())
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
err = gatev1beta1.AddToScheme(kClient.Scheme())
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
err = gatev1.AddToScheme(kClient.Scheme())
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
s.traefikCmd(withConfigFile("fixtures/k8s_gateway_conformance.toml"))
|
||||||
|
|
||||||
|
// Wait for traefik to start
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/entrypoints", 10*time.Second, try.BodyContains(`"name":"web"`))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = try.Do(10*time.Second, func() error {
|
||||||
|
gwc := &gatev1.GatewayClass{}
|
||||||
|
err := kClient.Get(context.Background(), ktypes.NamespacedName{Name: "my-gateway-class"}, gwc)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error fetching GatewayClass: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
opts := ksuite.Options{
|
||||||
|
Client: kClient,
|
||||||
|
RestConfig: configFromFlags,
|
||||||
|
Clientset: kClientSet,
|
||||||
|
GatewayClassName: "my-gateway-class",
|
||||||
|
Debug: true,
|
||||||
|
CleanupBaseResources: true,
|
||||||
|
TimeoutConfig: config.TimeoutConfig{
|
||||||
|
CreateTimeout: 5 * time.Second,
|
||||||
|
DeleteTimeout: 5 * time.Second,
|
||||||
|
GetTimeout: 5 * time.Second,
|
||||||
|
GatewayMustHaveAddress: 5 * time.Second,
|
||||||
|
GatewayMustHaveCondition: 5 * time.Second,
|
||||||
|
GatewayStatusMustHaveListeners: 10 * time.Second,
|
||||||
|
GatewayListenersMustHaveCondition: 5 * time.Second,
|
||||||
|
GWCMustBeAccepted: 60 * time.Second, // Pod creation in k3s cluster can be long.
|
||||||
|
HTTPRouteMustNotHaveParents: 5 * time.Second,
|
||||||
|
HTTPRouteMustHaveCondition: 5 * time.Second,
|
||||||
|
TLSRouteMustHaveCondition: 5 * time.Second,
|
||||||
|
RouteMustHaveParents: 5 * time.Second,
|
||||||
|
ManifestFetchTimeout: 5 * time.Second,
|
||||||
|
MaxTimeToConsistency: 5 * time.Second,
|
||||||
|
NamespacesMustBeReady: 60 * time.Second, // Pod creation in k3s cluster can be long.
|
||||||
|
RequestTimeout: 5 * time.Second,
|
||||||
|
LatestObservedGenerationSet: 5 * time.Second,
|
||||||
|
RequiredConsecutiveSuccesses: 0,
|
||||||
|
},
|
||||||
|
SupportedFeatures: sets.New[ksuite.SupportedFeature]().
|
||||||
|
Insert(ksuite.GatewayCoreFeatures.UnsortedList()...),
|
||||||
|
EnableAllSupportedFeatures: false,
|
||||||
|
RunTest: *k8sConformanceRunTest,
|
||||||
|
// Until the feature are all supported, following tests are skipped.
|
||||||
|
SkipTests: []string{
|
||||||
|
"HTTPExactPathMatching",
|
||||||
|
"HTTPRouteHostnameIntersection",
|
||||||
|
"GatewaySecretReferenceGrantAllInNamespace",
|
||||||
|
"HTTPRouteListenerHostnameMatching",
|
||||||
|
"HTTPRouteRequestHeaderModifier",
|
||||||
|
"GatewaySecretInvalidReferenceGrant",
|
||||||
|
"GatewayClassObservedGenerationBump",
|
||||||
|
"HTTPRouteInvalidNonExistentBackendRef",
|
||||||
|
"GatewayWithAttachedRoutes",
|
||||||
|
"HTTPRouteCrossNamespace",
|
||||||
|
"HTTPRouteDisallowedKind",
|
||||||
|
"HTTPRouteInvalidReferenceGrant",
|
||||||
|
"HTTPRouteObservedGenerationBump",
|
||||||
|
"GatewayInvalidRouteKind",
|
||||||
|
"TLSRouteSimpleSameNamespace",
|
||||||
|
"TLSRouteInvalidReferenceGrant",
|
||||||
|
"HTTPRouteInvalidCrossNamespaceParentRef",
|
||||||
|
"HTTPRouteInvalidParentRefNotMatchingSectionName",
|
||||||
|
"GatewaySecretReferenceGrantSpecific",
|
||||||
|
"GatewayModifyListeners",
|
||||||
|
"GatewaySecretMissingReferenceGrant",
|
||||||
|
"GatewayInvalidTLSConfiguration",
|
||||||
|
"HTTPRouteInvalidCrossNamespaceBackendRef",
|
||||||
|
"HTTPRouteMatchingAcrossRoutes",
|
||||||
|
"HTTPRoutePartiallyInvalidViaInvalidReferenceGrant",
|
||||||
|
"HTTPRouteRedirectHostAndStatus",
|
||||||
|
"HTTPRouteInvalidBackendRefUnknownKind",
|
||||||
|
"HTTPRoutePathMatchOrder",
|
||||||
|
"HTTPRouteSimpleSameNamespace",
|
||||||
|
"HTTPRouteMatching",
|
||||||
|
"HTTPRouteHeaderMatching",
|
||||||
|
"HTTPRouteReferenceGrant",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cSuite, err := ksuite.NewExperimentalConformanceTestSuite(ksuite.ExperimentalConformanceOptions{
|
||||||
|
Options: opts,
|
||||||
|
Implementation: conformanceV1alpha1.Implementation{
|
||||||
|
Organization: "traefik",
|
||||||
|
Project: "traefik",
|
||||||
|
URL: "https://traefik.io/",
|
||||||
|
Version: version.Version,
|
||||||
|
Contact: []string{"@traefik/maintainers"},
|
||||||
|
},
|
||||||
|
ConformanceProfiles: sets.New[ksuite.ConformanceProfileName](
|
||||||
|
ksuite.HTTPConformanceProfileName,
|
||||||
|
ksuite.TLSConformanceProfileName,
|
||||||
|
),
|
||||||
|
})
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
cSuite.Setup(s.T())
|
||||||
|
err = cSuite.Run(s.T(), tests.ConformanceTests)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
report, err := cSuite.Report()
|
||||||
|
require.NoError(s.T(), err, "failed generating conformance report")
|
||||||
|
|
||||||
|
report.GatewayAPIVersion = "1.0.0"
|
||||||
|
|
||||||
|
rawReport, err := yaml.Marshal(report)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
s.T().Logf("Conformance report:\n%s", string(rawReport))
|
||||||
|
|
||||||
|
require.NoError(s.T(), os.MkdirAll("./conformance-reports", 0o755))
|
||||||
|
outFile := filepath.Join("conformance-reports", fmt.Sprintf("traefik-traefik-%d.yaml", time.Now().UnixNano()))
|
||||||
|
require.NoError(s.T(), os.WriteFile(outFile, rawReport, 0o600))
|
||||||
|
s.T().Logf("Report written to: %s", outFile)
|
||||||
|
}
|
|
@ -36,3 +36,14 @@ services:
|
||||||
labels:
|
labels:
|
||||||
traefik.http.Routers.Super.Rule: Host(`my.super.host`)
|
traefik.http.Routers.Super.Rule: Host(`my.super.host`)
|
||||||
traefik.http.Services.powpow.LoadBalancer.server.Port: 2375
|
traefik.http.Services.powpow.LoadBalancer.server.Port: 2375
|
||||||
|
|
||||||
|
wrr-server:
|
||||||
|
image: traefik/whoami
|
||||||
|
labels:
|
||||||
|
traefik.http.Routers.wrr-server.Rule: Host(`my.wrr.host`)
|
||||||
|
traefik.http.Services.wrr-server.LoadBalancer.server.Weight: 4
|
||||||
|
wrr-server2:
|
||||||
|
image: traefik/whoami
|
||||||
|
labels:
|
||||||
|
traefik.http.Routers.wrr-server.Rule: Host(`my.wrr.host`)
|
||||||
|
traefik.http.Services.wrr-server.LoadBalancer.server.Weight: 1
|
||||||
|
|
|
@ -659,6 +659,66 @@ func (s *SimpleSuite) TestSimpleConfigurationHostRequestTrailingPeriod() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSuite) TestWithDefaultRuleSyntax() {
|
||||||
|
file := s.adaptFile("fixtures/with_default_rule_syntax.toml", struct{}{})
|
||||||
|
|
||||||
|
s.traefikCmd(withConfigFile(file))
|
||||||
|
|
||||||
|
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("PathPrefix"))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
// router1 has no error
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router1@file", 1*time.Second, try.BodyContains(`"status":"enabled"`))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8000/notfound", 1*time.Second, try.StatusCodeIs(http.StatusNotFound))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8000/foo", 1*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8000/bar", 1*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
// router2 has an error because it uses the wrong rule syntax (v3 instead of v2)
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router2@file", 1*time.Second, try.BodyContains("error while parsing rule QueryRegexp(`foo`, `bar`): unsupported function: QueryRegexp"))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
// router3 has an error because it uses the wrong rule syntax (v2 instead of v3)
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router3@file", 1*time.Second, try.BodyContains("error while adding rule PathPrefix: unexpected number of parameters; got 2, expected one of [1]"))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSuite) TestWithoutDefaultRuleSyntax() {
|
||||||
|
file := s.adaptFile("fixtures/without_default_rule_syntax.toml", struct{}{})
|
||||||
|
|
||||||
|
s.traefikCmd(withConfigFile(file))
|
||||||
|
|
||||||
|
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("PathPrefix"))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
// router1 has no error
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router1@file", 1*time.Second, try.BodyContains(`"status":"enabled"`))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8000/notfound", 1*time.Second, try.StatusCodeIs(http.StatusNotFound))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8000/foo", 1*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8000/bar", 1*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
// router2 has an error because it uses the wrong rule syntax (v3 instead of v2)
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router2@file", 1*time.Second, try.BodyContains("error while adding rule PathPrefix: unexpected number of parameters; got 2, expected one of [1]"))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
// router2 has an error because it uses the wrong rule syntax (v2 instead of v3)
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router3@file", 1*time.Second, try.BodyContains("error while parsing rule QueryRegexp(`foo`, `bar`): unsupported function: QueryRegexp"))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SimpleSuite) TestRouterConfigErrors() {
|
func (s *SimpleSuite) TestRouterConfigErrors() {
|
||||||
file := s.adaptFile("fixtures/router_errors.toml", struct{}{})
|
file := s.adaptFile("fixtures/router_errors.toml", struct{}{})
|
||||||
|
|
||||||
|
@ -749,6 +809,49 @@ func (s *SimpleSuite) TestUDPServiceConfigErrors() {
|
||||||
require.NoError(s.T(), err)
|
require.NoError(s.T(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSuite) TestWRRServer() {
|
||||||
|
s.createComposeProject("base")
|
||||||
|
|
||||||
|
s.composeUp()
|
||||||
|
defer s.composeDown()
|
||||||
|
|
||||||
|
whoami1IP := s.getComposeServiceIP("whoami1")
|
||||||
|
whoami2IP := s.getComposeServiceIP("whoami2")
|
||||||
|
|
||||||
|
file := s.adaptFile("fixtures/wrr_server.toml", struct {
|
||||||
|
Server1 string
|
||||||
|
Server2 string
|
||||||
|
}{Server1: "http://" + whoami1IP, Server2: "http://" + whoami2IP})
|
||||||
|
|
||||||
|
s.traefikCmd(withConfigFile(file))
|
||||||
|
|
||||||
|
err := try.GetRequest("http://127.0.0.1:8080/api/http/services", 1000*time.Millisecond, try.BodyContains("service1"))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
repartition := map[string]int{}
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/whoami", nil)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
response, err := http.DefaultClient.Do(req)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
|
||||||
|
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
if strings.Contains(string(body), whoami1IP) {
|
||||||
|
repartition[whoami1IP]++
|
||||||
|
}
|
||||||
|
if strings.Contains(string(body), whoami2IP) {
|
||||||
|
repartition[whoami2IP]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(s.T(), 3, repartition[whoami1IP])
|
||||||
|
assert.Equal(s.T(), 1, repartition[whoami2IP])
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SimpleSuite) TestWRR() {
|
func (s *SimpleSuite) TestWRR() {
|
||||||
s.createComposeProject("base")
|
s.createComposeProject("base")
|
||||||
|
|
||||||
|
|
5
integration/testdata/rawdata-gateway.json
vendored
5
integration/testdata/rawdata-gateway.json
vendored
|
@ -34,6 +34,7 @@
|
||||||
],
|
],
|
||||||
"service": "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
"service": "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
||||||
"rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)",
|
"rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)",
|
||||||
|
"ruleSyntax": "v3",
|
||||||
"priority": 31,
|
"priority": 31,
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
|
@ -46,6 +47,7 @@
|
||||||
],
|
],
|
||||||
"service": "default-http-app-1-my-https-gateway-websecure-1c0cf64bde37d9d0df06-wrr",
|
"service": "default-http-app-1-my-https-gateway-websecure-1c0cf64bde37d9d0df06-wrr",
|
||||||
"rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)",
|
"rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)",
|
||||||
|
"ruleSyntax": "v3",
|
||||||
"priority": 31,
|
"priority": 31,
|
||||||
"tls": {},
|
"tls": {},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
@ -152,6 +154,7 @@
|
||||||
],
|
],
|
||||||
"service": "default-tcp-app-1-my-tcp-gateway-footcp-e3b0c44298fc1c149afb-wrr-0",
|
"service": "default-tcp-app-1-my-tcp-gateway-footcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
"rule": "HostSNI(`*`)",
|
"rule": "HostSNI(`*`)",
|
||||||
|
"ruleSyntax": "v3",
|
||||||
"priority": -1,
|
"priority": -1,
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
|
@ -164,6 +167,7 @@
|
||||||
],
|
],
|
||||||
"service": "default-tcp-app-1-my-tls-gateway-footlsterminate-e3b0c44298fc1c149afb-wrr-0",
|
"service": "default-tcp-app-1-my-tls-gateway-footlsterminate-e3b0c44298fc1c149afb-wrr-0",
|
||||||
"rule": "HostSNI(`*`)",
|
"rule": "HostSNI(`*`)",
|
||||||
|
"ruleSyntax": "v3",
|
||||||
"priority": -1,
|
"priority": -1,
|
||||||
"tls": {
|
"tls": {
|
||||||
"passthrough": false
|
"passthrough": false
|
||||||
|
@ -179,6 +183,7 @@
|
||||||
],
|
],
|
||||||
"service": "default-tls-app-1-my-tls-gateway-footlspassthrough-2279fe75c5156dc5eb26-wrr-0",
|
"service": "default-tls-app-1-my-tls-gateway-footlspassthrough-2279fe75c5156dc5eb26-wrr-0",
|
||||||
"rule": "HostSNI(`foo.bar`)",
|
"rule": "HostSNI(`foo.bar`)",
|
||||||
|
"ruleSyntax": "v3",
|
||||||
"priority": 18,
|
"priority": 18,
|
||||||
"tls": {
|
"tls": {
|
||||||
"passthrough": true
|
"passthrough": true
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -16,9 +19,65 @@ import (
|
||||||
"github.com/traefik/paerser/generator"
|
"github.com/traefik/paerser/generator"
|
||||||
"github.com/traefik/paerser/parser"
|
"github.com/traefik/paerser/parser"
|
||||||
"github.com/traefik/traefik/v3/cmd"
|
"github.com/traefik/traefik/v3/cmd"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/collector/hydratation"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var commentGenerated = `## CODE GENERATED AUTOMATICALLY
|
||||||
|
## THIS FILE MUST NOT BE EDITED BY HAND
|
||||||
|
`
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
logger := log.With().Logger()
|
||||||
|
|
||||||
|
dynConf := &dynamic.Configuration{}
|
||||||
|
|
||||||
|
err := hydratation.Hydrate(dynConf)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal().Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
dynConf.HTTP.Models = map[string]*dynamic.Model{}
|
||||||
|
clean(dynConf.HTTP.Middlewares)
|
||||||
|
clean(dynConf.TCP.Middlewares)
|
||||||
|
clean(dynConf.HTTP.Services)
|
||||||
|
clean(dynConf.TCP.Services)
|
||||||
|
clean(dynConf.UDP.Services)
|
||||||
|
|
||||||
|
err = tomlWrite("./docs/content/reference/dynamic-configuration/file.toml", dynConf)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal().Err(err).Send()
|
||||||
|
}
|
||||||
|
err = yamlWrite("./docs/content/reference/dynamic-configuration/file.yaml", dynConf)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal().Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = labelsWrite("./docs/content/reference/dynamic-configuration", dynConf)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal().Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
staticConf := &static.Configuration{}
|
||||||
|
|
||||||
|
err = hydratation.Hydrate(staticConf)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal().Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(staticConf.EntryPoints, "EntryPoint1")
|
||||||
|
|
||||||
|
err = tomlWrite("./docs/content/reference/static-configuration/file.toml", staticConf)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal().Err(err).Send()
|
||||||
|
}
|
||||||
|
err = yamlWrite("./docs/content/reference/static-configuration/file.yaml", staticConf)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal().Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
genStaticConfDoc("./docs/content/reference/static-configuration/env-ref.md", "", func(i interface{}) ([]parser.Flat, error) {
|
genStaticConfDoc("./docs/content/reference/static-configuration/env-ref.md", "", func(i interface{}) ([]parser.Flat, error) {
|
||||||
return env.Encode(env.DefaultNamePrefix, i)
|
return env.Encode(env.DefaultNamePrefix, i)
|
||||||
})
|
})
|
||||||
|
@ -26,6 +85,144 @@ func main() {
|
||||||
genKVDynConfDoc("./docs/content/reference/dynamic-configuration/kv-ref.md")
|
genKVDynConfDoc("./docs/content/reference/dynamic-configuration/kv-ref.md")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func labelsWrite(outputDir string, element *dynamic.Configuration) error {
|
||||||
|
cleanServers(element)
|
||||||
|
|
||||||
|
etnOpts := parser.EncoderToNodeOpts{OmitEmpty: true, TagName: parser.TagLabel, AllowSliceAsStruct: true}
|
||||||
|
node, err := parser.EncodeToNode(element, parser.DefaultRootName, etnOpts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
metaOpts := parser.MetadataOpts{TagName: parser.TagLabel, AllowSliceAsStruct: true}
|
||||||
|
err = parser.AddMetadata(element, node, metaOpts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
labels := make(map[string]string)
|
||||||
|
encodeNode(labels, node.Name, node)
|
||||||
|
|
||||||
|
var keys []string
|
||||||
|
for k := range labels {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
dockerLabels, err := os.Create(filepath.Join(outputDir, "docker-labels.yml"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer dockerLabels.Close()
|
||||||
|
|
||||||
|
// Write the comment at the beginning of the file
|
||||||
|
if _, err := dockerLabels.WriteString(commentGenerated); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
v := labels[k]
|
||||||
|
if v != "" {
|
||||||
|
if v == "42000000000" {
|
||||||
|
v = "42s"
|
||||||
|
}
|
||||||
|
fmt.Fprintln(dockerLabels, `- "`+strings.ToLower(k)+`=`+v+`"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanServers(element *dynamic.Configuration) {
|
||||||
|
for _, svc := range element.HTTP.Services {
|
||||||
|
if svc.LoadBalancer != nil {
|
||||||
|
server := svc.LoadBalancer.Servers[0]
|
||||||
|
svc.LoadBalancer.Servers = nil
|
||||||
|
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, svc := range element.TCP.Services {
|
||||||
|
if svc.LoadBalancer != nil {
|
||||||
|
server := svc.LoadBalancer.Servers[0]
|
||||||
|
svc.LoadBalancer.Servers = nil
|
||||||
|
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, svc := range element.UDP.Services {
|
||||||
|
if svc.LoadBalancer != nil {
|
||||||
|
server := svc.LoadBalancer.Servers[0]
|
||||||
|
svc.LoadBalancer.Servers = nil
|
||||||
|
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func yamlWrite(outputFile string, element any) error {
|
||||||
|
file, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// Write the comment at the beginning of the file
|
||||||
|
if _, err := file.WriteString(commentGenerated); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
encoder := yaml.NewEncoder(buf)
|
||||||
|
encoder.SetIndent(2)
|
||||||
|
err = encoder.Encode(element)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = file.Write(buf.Bytes())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func tomlWrite(outputFile string, element any) error {
|
||||||
|
file, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// Write the comment at the beginning of the file
|
||||||
|
if _, err := file.WriteString(commentGenerated); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return toml.NewEncoder(file).Encode(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
func clean(element any) {
|
||||||
|
valSvcs := reflect.ValueOf(element)
|
||||||
|
|
||||||
|
key := valSvcs.MapKeys()[0]
|
||||||
|
valueSvcRoot := valSvcs.MapIndex(key).Elem()
|
||||||
|
|
||||||
|
var svcFieldNames []string
|
||||||
|
for i := 0; i < valueSvcRoot.NumField(); i++ {
|
||||||
|
svcFieldNames = append(svcFieldNames, valueSvcRoot.Type().Field(i).Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(svcFieldNames)
|
||||||
|
|
||||||
|
for i, fieldName := range svcFieldNames {
|
||||||
|
v := reflect.New(valueSvcRoot.Type())
|
||||||
|
v.Elem().FieldByName(fieldName).Set(valueSvcRoot.FieldByName(fieldName))
|
||||||
|
|
||||||
|
valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s%.2d", valueSvcRoot.Type().Name(), i+1)), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s0", valueSvcRoot.Type().Name())), reflect.Value{})
|
||||||
|
valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s1", valueSvcRoot.Type().Name())), reflect.Value{})
|
||||||
|
}
|
||||||
|
|
||||||
func genStaticConfDoc(outputFile, prefix string, encodeFn func(interface{}) ([]parser.Flat, error)) {
|
func genStaticConfDoc(outputFile, prefix string, encodeFn func(interface{}) ([]parser.Flat, error)) {
|
||||||
logger := log.With().Str("file", outputFile).Logger()
|
logger := log.With().Str("file", outputFile).Logger()
|
||||||
|
|
||||||
|
@ -117,6 +314,7 @@ func genKVDynConfDoc(outputFile string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
store := storeWriter{data: map[string]string{}}
|
store := storeWriter{data: map[string]string{}}
|
||||||
|
|
||||||
c := client{store: store}
|
c := client{store: store}
|
||||||
err = c.load("traefik", conf)
|
err = c.load("traefik", conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -130,6 +328,12 @@ func genKVDynConfDoc(outputFile string) {
|
||||||
|
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
_, _ = fmt.Fprintf(file, `<!--
|
||||||
|
CODE GENERATED AUTOMATICALLY
|
||||||
|
THIS FILE MUST NOT BE EDITED BY HAND
|
||||||
|
-->
|
||||||
|
`)
|
||||||
|
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
_, _ = fmt.Fprintf(file, "| `%s` | `%s` |\n", k, store.data[k])
|
_, _ = fmt.Fprintf(file, "| `%s` | `%s` |\n", k, store.data[k])
|
||||||
}
|
}
|
||||||
|
|
66
internal/parser.go
Normal file
66
internal/parser.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/traefik/paerser/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
func encodeNode(labels map[string]string, root string, node *parser.Node) {
|
||||||
|
for _, child := range node.Children {
|
||||||
|
if child.Disabled {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var sep string
|
||||||
|
if child.Name[0] != '[' {
|
||||||
|
sep = "."
|
||||||
|
}
|
||||||
|
|
||||||
|
childName := root + sep + child.Name
|
||||||
|
|
||||||
|
if child.RawValue != nil {
|
||||||
|
encodeRawValue(labels, childName, child.RawValue)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(child.Tag.Get(parser.TagLabel), parser.TagLabelAllowEmpty) {
|
||||||
|
labels[childName] = "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(child.Children) > 0 {
|
||||||
|
encodeNode(labels, childName, child)
|
||||||
|
} else if len(child.Name) > 0 {
|
||||||
|
labels[childName] = child.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeRawValue(labels map[string]string, root string, rawValue interface{}) {
|
||||||
|
if rawValue == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tValue := reflect.TypeOf(rawValue)
|
||||||
|
|
||||||
|
if tValue.Kind() == reflect.Map && tValue.Elem().Kind() == reflect.Interface {
|
||||||
|
r := reflect.ValueOf(rawValue).
|
||||||
|
Convert(reflect.TypeOf((map[string]interface{})(nil))).
|
||||||
|
Interface().(map[string]interface{})
|
||||||
|
|
||||||
|
for k, v := range r {
|
||||||
|
switch tv := v.(type) {
|
||||||
|
case string:
|
||||||
|
labels[root+"."+k] = tv
|
||||||
|
case []interface{}:
|
||||||
|
for i, e := range tv {
|
||||||
|
encodeRawValue(labels, fmt.Sprintf("%s.%s[%d]", root, k, i), e)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
encodeRawValue(labels, root+"."+k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
541
pkg/cli/deprecation.go
Normal file
541
pkg/cli/deprecation.go
Normal file
|
@ -0,0 +1,541 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/traefik/paerser/cli"
|
||||||
|
"github.com/traefik/paerser/flag"
|
||||||
|
"github.com/traefik/paerser/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeprecationLoader struct{}
|
||||||
|
|
||||||
|
func (d DeprecationLoader) Load(args []string, cmd *cli.Command) (bool, error) {
|
||||||
|
if logDeprecation(cmd.Configuration, args) {
|
||||||
|
return true, errors.New("incompatible deprecated static option found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// logDeprecation prints deprecation hints and returns whether incompatible deprecated options need to be removed.
|
||||||
|
func logDeprecation(traefikConfiguration interface{}, args []string) bool {
|
||||||
|
// This part doesn't handle properly a flag defined like this:
|
||||||
|
// --accesslog true
|
||||||
|
// where `true` could be considered as a new argument.
|
||||||
|
// This is not really an issue with the deprecation loader since it will filter the unknown nodes later in this
|
||||||
|
// function.
|
||||||
|
for i, arg := range args {
|
||||||
|
if !strings.Contains(arg, "=") {
|
||||||
|
args[i] = arg + "=true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
labels, err := flag.Parse(args, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("deprecated static options analysis failed")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
node, err := parser.DecodeToNode(labels, "traefik")
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("deprecated static options analysis failed")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if node != nil && len(node.Children) > 0 {
|
||||||
|
config := &configuration{}
|
||||||
|
filterUnknownNodes(reflect.TypeOf(config), node)
|
||||||
|
|
||||||
|
if len(node.Children) > 0 {
|
||||||
|
// Telling parser to look for the label struct tag to allow empty values.
|
||||||
|
err = parser.AddMetadata(config, node, parser.MetadataOpts{TagName: "label"})
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("deprecated static options analysis failed")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
err = parser.Fill(config, node, parser.FillerOpts{})
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("deprecated static options analysis failed")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.deprecationNotice(log.With().Str("loader", "FLAG").Logger()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// No further deprecation parsing and logging,
|
||||||
|
// as args configuration contains at least one deprecated option.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE
|
||||||
|
ref, err := flag.Parse(args, traefikConfiguration)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("deprecated static options analysis failed")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
configFileFlag := "traefik.configfile"
|
||||||
|
if _, ok := ref["traefik.configFile"]; ok {
|
||||||
|
configFileFlag = "traefik.configFile"
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &configuration{}
|
||||||
|
_, err = loadConfigFiles(ref[configFileFlag], config)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
if config.deprecationNotice(log.With().Str("loader", "FILE").Logger()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config = &configuration{}
|
||||||
|
l := EnvLoader{}
|
||||||
|
_, err = l.Load(os.Args, &cli.Command{
|
||||||
|
Configuration: config,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
if config.deprecationNotice(log.With().Str("loader", "ENV").Logger()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterUnknownNodes(fType reflect.Type, node *parser.Node) bool {
|
||||||
|
var children []*parser.Node
|
||||||
|
for _, child := range node.Children {
|
||||||
|
if hasKnownNodes(fType, child) {
|
||||||
|
children = append(children, child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.Children = children
|
||||||
|
return len(node.Children) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasKnownNodes(rootType reflect.Type, node *parser.Node) bool {
|
||||||
|
rType := rootType
|
||||||
|
if rootType.Kind() == reflect.Pointer {
|
||||||
|
rType = rootType.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// unstructured type fitting anything, considering the current node as known.
|
||||||
|
if rType.Kind() == reflect.Map && rType.Elem().Kind() == reflect.Interface {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// unstructured type fitting anything, considering the current node as known.
|
||||||
|
if rType.Kind() == reflect.Interface {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// find matching field in struct type.
|
||||||
|
field, b := findTypedField(rType, node)
|
||||||
|
if !b {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(node.Children) > 0 {
|
||||||
|
return filterUnknownNodes(field.Type, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func findTypedField(rType reflect.Type, node *parser.Node) (reflect.StructField, bool) {
|
||||||
|
// avoid panicking.
|
||||||
|
if rType.Kind() != reflect.Struct {
|
||||||
|
return reflect.StructField{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < rType.NumField(); i++ {
|
||||||
|
cField := rType.Field(i)
|
||||||
|
|
||||||
|
// ignore unexported fields.
|
||||||
|
if cField.PkgPath == "" {
|
||||||
|
if strings.EqualFold(cField.Name, node.Name) {
|
||||||
|
node.FieldName = cField.Name
|
||||||
|
return cField, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflect.StructField{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// configuration holds the static configuration removed/deprecated options.
|
||||||
|
type configuration struct {
|
||||||
|
Experimental *experimental `json:"experimental,omitempty" toml:"experimental,omitempty" yaml:"experimental,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Pilot map[string]any `json:"pilot,omitempty" toml:"pilot,omitempty" yaml:"pilot,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Providers *providers `json:"providers,omitempty" toml:"providers,omitempty" yaml:"providers,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Tracing *tracing `json:"tracing,omitempty" toml:"tracing,omitempty" yaml:"tracing,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *configuration) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if c == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var incompatible bool
|
||||||
|
if c.Pilot != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Pilot configuration has been removed in v3, please remove all Pilot-related static configuration for Traefik to start." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#pilot")
|
||||||
|
}
|
||||||
|
|
||||||
|
incompatibleExperimental := c.Experimental.deprecationNotice(logger)
|
||||||
|
incompatibleProviders := c.Providers.deprecationNotice(logger)
|
||||||
|
incompatibleTracing := c.Tracing.deprecationNotice(logger)
|
||||||
|
return incompatible || incompatibleExperimental || incompatibleProviders || incompatibleTracing
|
||||||
|
}
|
||||||
|
|
||||||
|
type providers struct {
|
||||||
|
Docker *docker `json:"docker,omitempty" toml:"docker,omitempty" yaml:"docker,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Swarm *swarm `json:"swarm,omitempty" toml:"swarm,omitempty" yaml:"swarm,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Consul *consul `json:"consul,omitempty" toml:"consul,omitempty" yaml:"consul,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
ConsulCatalog *consulCatalog `json:"consulCatalog,omitempty" toml:"consulCatalog,omitempty" yaml:"consulCatalog,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Nomad *nomad `json:"nomad,omitempty" toml:"nomad,omitempty" yaml:"nomad,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Marathon map[string]any `json:"marathon,omitempty" toml:"marathon,omitempty" yaml:"marathon,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Rancher map[string]any `json:"rancher,omitempty" toml:"rancher,omitempty" yaml:"rancher,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
ETCD *etcd `json:"etcd,omitempty" toml:"etcd,omitempty" yaml:"etcd,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Redis *redis `json:"redis,omitempty" toml:"redis,omitempty" yaml:"redis,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
HTTP *http `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *providers) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if p == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var incompatible bool
|
||||||
|
|
||||||
|
if p.Marathon != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Marathon provider has been removed in v3, please remove all Marathon-related static configuration for Traefik to start." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#marathon-provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Rancher != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Rancher provider has been removed in v3, please remove all Rancher-related static configuration for Traefik to start." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#rancher-v1-provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerIncompatible := p.Docker.deprecationNotice(logger)
|
||||||
|
consulIncompatible := p.Consul.deprecationNotice(logger)
|
||||||
|
consulCatalogIncompatible := p.ConsulCatalog.deprecationNotice(logger)
|
||||||
|
nomadIncompatible := p.Nomad.deprecationNotice(logger)
|
||||||
|
swarmIncompatible := p.Swarm.deprecationNotice(logger)
|
||||||
|
etcdIncompatible := p.ETCD.deprecationNotice(logger)
|
||||||
|
redisIncompatible := p.Redis.deprecationNotice(logger)
|
||||||
|
httpIncompatible := p.HTTP.deprecationNotice(logger)
|
||||||
|
return incompatible ||
|
||||||
|
dockerIncompatible ||
|
||||||
|
consulIncompatible ||
|
||||||
|
consulCatalogIncompatible ||
|
||||||
|
nomadIncompatible ||
|
||||||
|
swarmIncompatible ||
|
||||||
|
etcdIncompatible ||
|
||||||
|
redisIncompatible ||
|
||||||
|
httpIncompatible
|
||||||
|
}
|
||||||
|
|
||||||
|
type tls struct {
|
||||||
|
CAOptional *bool `json:"caOptional,omitempty" toml:"caOptional,omitempty" yaml:"caOptional,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type docker struct {
|
||||||
|
SwarmMode *bool `json:"swarmMode,omitempty" toml:"swarmMode,omitempty" yaml:"swarmMode,omitempty"`
|
||||||
|
TLS *tls `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *docker) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if d == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var incompatible bool
|
||||||
|
|
||||||
|
if d.SwarmMode != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Docker provider `swarmMode` option has been removed in v3, please use the Swarm Provider instead." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#docker-docker-swarm")
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.TLS != nil && d.TLS.CAOptional != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Docker provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634)." +
|
||||||
|
"Please remove all occurrences from the static configuration for Traefik to start." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tlscaoptional")
|
||||||
|
}
|
||||||
|
|
||||||
|
return incompatible
|
||||||
|
}
|
||||||
|
|
||||||
|
type swarm struct {
|
||||||
|
TLS *tls `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *swarm) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if s == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var incompatible bool
|
||||||
|
|
||||||
|
if s.TLS != nil && s.TLS.CAOptional != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Swarm provider `tls.CAOptional` option does not exist, as TLS client authentication is a server side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634)." +
|
||||||
|
"Please remove all occurrences from the static configuration for Traefik to start.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return incompatible
|
||||||
|
}
|
||||||
|
|
||||||
|
type etcd struct {
|
||||||
|
TLS *tls `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *etcd) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if e == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var incompatible bool
|
||||||
|
|
||||||
|
if e.TLS != nil && e.TLS.CAOptional != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("ETCD provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634)." +
|
||||||
|
"Please remove all occurrences from the static configuration for Traefik to start." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tlscaoptional_3")
|
||||||
|
}
|
||||||
|
|
||||||
|
return incompatible
|
||||||
|
}
|
||||||
|
|
||||||
|
type redis struct {
|
||||||
|
TLS *tls `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *redis) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if r == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var incompatible bool
|
||||||
|
|
||||||
|
if r.TLS != nil && r.TLS.CAOptional != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Redis provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634)." +
|
||||||
|
"Please remove all occurrences from the static configuration for Traefik to start." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tlscaoptional_4")
|
||||||
|
}
|
||||||
|
|
||||||
|
return incompatible
|
||||||
|
}
|
||||||
|
|
||||||
|
type consul struct {
|
||||||
|
Namespace *string `json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||||
|
TLS *tls `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *consul) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if c == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var incompatible bool
|
||||||
|
|
||||||
|
if c.Namespace != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Consul provider `namespace` option has been removed, please use the `namespaces` option instead." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#consul-provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TLS != nil && c.TLS.CAOptional != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Consul provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634)." +
|
||||||
|
"Please remove all occurrences from the static configuration for Traefik to start." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tlscaoptional_1")
|
||||||
|
}
|
||||||
|
|
||||||
|
return incompatible
|
||||||
|
}
|
||||||
|
|
||||||
|
type consulCatalog struct {
|
||||||
|
Namespace *string `json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||||
|
Endpoint *endpointConfig `json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type endpointConfig struct {
|
||||||
|
TLS *tls `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *consulCatalog) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if c == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var incompatible bool
|
||||||
|
|
||||||
|
if c.Namespace != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("ConsulCatalog provider `namespace` option has been removed, please use the `namespaces` option instead." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#consulcatalog-provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Endpoint != nil && c.Endpoint.TLS != nil && c.Endpoint.TLS.CAOptional != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("ConsulCatalog provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634)." +
|
||||||
|
"Please remove all occurrences from the static configuration for Traefik to start." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#endpointtlscaoptional")
|
||||||
|
}
|
||||||
|
|
||||||
|
return incompatible
|
||||||
|
}
|
||||||
|
|
||||||
|
type nomad struct {
|
||||||
|
Namespace *string `json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||||
|
Endpoint *endpointConfig `json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *nomad) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if n == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var incompatible bool
|
||||||
|
|
||||||
|
if n.Namespace != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Nomad provider `namespace` option has been removed, please use the `namespaces` option instead." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#nomad-provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.Endpoint != nil && n.Endpoint.TLS != nil && n.Endpoint.TLS.CAOptional != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Nomad provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634)." +
|
||||||
|
"Please remove all occurrences from the static configuration for Traefik to start." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#endpointtlscaoptional_1")
|
||||||
|
}
|
||||||
|
|
||||||
|
return incompatible
|
||||||
|
}
|
||||||
|
|
||||||
|
type http struct {
|
||||||
|
TLS *tls `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *http) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if h == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var incompatible bool
|
||||||
|
|
||||||
|
if h.TLS != nil && h.TLS.CAOptional != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("HTTP provider `tls.CAOptional` option has been removed in v3, as TLS client authentication is a server side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634)." +
|
||||||
|
"Please remove all occurrences from the static configuration for Traefik to start." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tlscaoptional_2")
|
||||||
|
}
|
||||||
|
|
||||||
|
return incompatible
|
||||||
|
}
|
||||||
|
|
||||||
|
type experimental struct {
|
||||||
|
HTTP3 *bool `json:"http3,omitempty" toml:"http3,omitempty" yaml:"http3,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *experimental) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if e == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.HTTP3 != nil {
|
||||||
|
logger.Error().Msg("HTTP3 is not an experimental feature in v3 and the associated enablement has been removed." +
|
||||||
|
"Please remove its usage from the static configuration for Traefik to start." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#http3-experimental-configuration")
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type tracing struct {
|
||||||
|
SpanNameLimit *int `json:"spanNameLimit,omitempty" toml:"spanNameLimit,omitempty" yaml:"spanNameLimit,omitempty"`
|
||||||
|
Jaeger map[string]any `json:"jaeger,omitempty" toml:"jaeger,omitempty" yaml:"jaeger,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Zipkin map[string]any `json:"zipkin,omitempty" toml:"zipkin,omitempty" yaml:"zipkin,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Datadog map[string]any `json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Instana map[string]any `json:"instana,omitempty" toml:"instana,omitempty" yaml:"instana,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Haystack map[string]any `json:"haystack,omitempty" toml:"haystack,omitempty" yaml:"haystack,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
Elastic map[string]any `json:"elastic,omitempty" toml:"elastic,omitempty" yaml:"elastic,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tracing) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
if t == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var incompatible bool
|
||||||
|
if t.SpanNameLimit != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("SpanNameLimit option for Tracing has been removed in v3, as Span names are now of a fixed length." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tracing")
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Jaeger != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Jaeger Tracing backend has been removed in v3, please remove all Jaeger-related Tracing static configuration for Traefik to start." +
|
||||||
|
"In v3, Open Telemetry replaces specific tracing backend implementations, and an collector/exporter can be used to export metrics in a vendor specific format." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tracing")
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Zipkin != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Zipkin Tracing backend has been removed in v3, please remove all Zipkin-related Tracing static configuration for Traefik to start." +
|
||||||
|
"In v3, Open Telemetry replaces specific tracing backend implementations, and an collector/exporter can be used to export metrics in a vendor specific format." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tracing")
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Datadog != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Datadog Tracing backend has been removed in v3, please remove all Datadog-related Tracing static configuration for Traefik to start." +
|
||||||
|
"In v3, Open Telemetry replaces specific tracing backend implementations, and an collector/exporter can be used to export metrics in a vendor specific format." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tracing")
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Instana != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Instana Tracing backend has been removed in v3, please remove all Instana-related Tracing static configuration for Traefik to start." +
|
||||||
|
"In v3, Open Telemetry replaces specific tracing backend implementations, and an collector/exporter can be used to export metrics in a vendor specific format." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tracing")
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Haystack != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Haystack Tracing backend has been removed in v3, please remove all Haystack-related Tracing static configuration for Traefik to start." +
|
||||||
|
"In v3, Open Telemetry replaces specific tracing backend implementations, and an collector/exporter can be used to export metrics in a vendor specific format." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tracing")
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Elastic != nil {
|
||||||
|
incompatible = true
|
||||||
|
logger.Error().Msg("Elastic Tracing backend has been removed in v3, please remove all Elastic-related Tracing static configuration for Traefik to start." +
|
||||||
|
"In v3, Open Telemetry replaces specific tracing backend implementations, and an collector/exporter can be used to export metrics in a vendor specific format." +
|
||||||
|
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#tracing")
|
||||||
|
}
|
||||||
|
|
||||||
|
return incompatible
|
||||||
|
}
|
404
pkg/cli/deprecation_test.go
Normal file
404
pkg/cli/deprecation_test.go
Normal file
|
@ -0,0 +1,404 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/traefik/paerser/cli"
|
||||||
|
"github.com/traefik/traefik/v3/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ptr[T any](t T) *T {
|
||||||
|
return &t
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeprecationNotice(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
config configuration
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Docker provider swarmMode option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
Docker: &docker{
|
||||||
|
SwarmMode: ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Docker provider tls.CAOptional option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
Docker: &docker{
|
||||||
|
TLS: &tls{
|
||||||
|
CAOptional: ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Swarm provider tls.CAOptional option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
Swarm: &swarm{
|
||||||
|
TLS: &tls{
|
||||||
|
CAOptional: ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Consul provider namespace option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
Consul: &consul{
|
||||||
|
Namespace: ptr("foobar"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Consul provider tls.CAOptional option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
Consul: &consul{
|
||||||
|
TLS: &tls{
|
||||||
|
CAOptional: ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "ConsulCatalog provider namespace option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
ConsulCatalog: &consulCatalog{
|
||||||
|
Namespace: ptr("foobar"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "ConsulCatalog provider tls.CAOptional option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
ConsulCatalog: &consulCatalog{
|
||||||
|
Endpoint: &endpointConfig{
|
||||||
|
TLS: &tls{
|
||||||
|
CAOptional: ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Nomad provider namespace option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
Nomad: &nomad{
|
||||||
|
Namespace: ptr("foobar"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Nomad provider tls.CAOptional option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
Nomad: &nomad{
|
||||||
|
Endpoint: &endpointConfig{
|
||||||
|
TLS: &tls{
|
||||||
|
CAOptional: ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Marathon configuration is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
Marathon: map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Rancher configuration is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
Rancher: map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "ETCD provider tls.CAOptional option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
ETCD: &etcd{
|
||||||
|
TLS: &tls{
|
||||||
|
CAOptional: ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Redis provider tls.CAOptional option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
Redis: &redis{
|
||||||
|
TLS: &tls{
|
||||||
|
CAOptional: ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTP provider tls.CAOptional option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Providers: &providers{
|
||||||
|
HTTP: &http{
|
||||||
|
TLS: &tls{
|
||||||
|
CAOptional: ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Pilot configuration is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Pilot: map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Experimental HTTP3 enablement configuration is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Experimental: &experimental{
|
||||||
|
HTTP3: ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Tracing SpanNameLimit option is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Tracing: &tracing{
|
||||||
|
SpanNameLimit: ptr(42),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Tracing Jaeger configuration is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Tracing: &tracing{
|
||||||
|
Jaeger: map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Tracing Zipkin configuration is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Tracing: &tracing{
|
||||||
|
Zipkin: map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Tracing Datadog configuration is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Tracing: &tracing{
|
||||||
|
Datadog: map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Tracing Instana configuration is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Tracing: &tracing{
|
||||||
|
Instana: map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Tracing Haystack configuration is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Tracing: &tracing{
|
||||||
|
Haystack: map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Tracing Elastic configuration is incompatible",
|
||||||
|
config: configuration{
|
||||||
|
Tracing: &tracing{
|
||||||
|
Elastic: map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var gotLog bool
|
||||||
|
var gotLevel zerolog.Level
|
||||||
|
testHook := zerolog.HookFunc(func(e *zerolog.Event, level zerolog.Level, message string) {
|
||||||
|
gotLog = true
|
||||||
|
gotLevel = level
|
||||||
|
})
|
||||||
|
|
||||||
|
logger := log.With().Logger().Hook(testHook)
|
||||||
|
assert.True(t, test.config.deprecationNotice(logger))
|
||||||
|
assert.True(t, gotLog)
|
||||||
|
assert.Equal(t, zerolog.ErrorLevel, gotLevel)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoad(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
args []string
|
||||||
|
env map[string]string
|
||||||
|
wantDeprecated bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Empty",
|
||||||
|
args: []string{},
|
||||||
|
wantDeprecated: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "[FLAG] providers.marathon is deprecated",
|
||||||
|
args: []string{
|
||||||
|
"--access-log",
|
||||||
|
"--log.level=DEBUG",
|
||||||
|
"--entrypoints.test.http.tls",
|
||||||
|
"--providers.nomad.endpoint.tls.insecureskipverify=true",
|
||||||
|
"--providers.marathon",
|
||||||
|
},
|
||||||
|
wantDeprecated: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "[FLAG] multiple deprecated",
|
||||||
|
args: []string{
|
||||||
|
"--access-log",
|
||||||
|
"--log.level=DEBUG",
|
||||||
|
"--entrypoints.test.http.tls",
|
||||||
|
"--providers.marathon",
|
||||||
|
"--pilot.token=XXX",
|
||||||
|
},
|
||||||
|
wantDeprecated: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "[FLAG] no deprecated",
|
||||||
|
args: []string{
|
||||||
|
"--access-log",
|
||||||
|
"--log.level=DEBUG",
|
||||||
|
"--entrypoints.test.http.tls",
|
||||||
|
"--providers.docker",
|
||||||
|
},
|
||||||
|
wantDeprecated: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "[ENV] providers.marathon is deprecated",
|
||||||
|
env: map[string]string{
|
||||||
|
"TRAEFIK_ACCESS_LOG": "",
|
||||||
|
"TRAEFIK_LOG_LEVEL": "DEBUG",
|
||||||
|
"TRAEFIK_ENTRYPOINT_TEST_HTTP_TLS": "true",
|
||||||
|
"TRAEFIK_PROVIDERS_MARATHON": "true",
|
||||||
|
},
|
||||||
|
wantDeprecated: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "[ENV] multiple deprecated",
|
||||||
|
env: map[string]string{
|
||||||
|
"TRAEFIK_ACCESS_LOG": "true",
|
||||||
|
"TRAEFIK_LOG_LEVEL": "DEBUG",
|
||||||
|
"TRAEFIK_ENTRYPOINT_TEST_HTTP_TLS": "true",
|
||||||
|
"TRAEFIK_PROVIDERS_MARATHON": "true",
|
||||||
|
"TRAEFIK_PILOT_TOKEN": "xxx",
|
||||||
|
},
|
||||||
|
wantDeprecated: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "[ENV] no deprecated",
|
||||||
|
env: map[string]string{
|
||||||
|
"TRAEFIK_ACCESS_LOG": "true",
|
||||||
|
"TRAEFIK_LOG_LEVEL": "DEBUG",
|
||||||
|
"TRAEFIK_ENTRYPOINT_TEST_HTTP_TLS": "true",
|
||||||
|
},
|
||||||
|
|
||||||
|
wantDeprecated: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "[FILE] providers.marathon is deprecated",
|
||||||
|
args: []string{
|
||||||
|
"--configfile=./fixtures/traefik_deprecated.toml",
|
||||||
|
},
|
||||||
|
wantDeprecated: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "[FILE] multiple deprecated",
|
||||||
|
args: []string{
|
||||||
|
"--configfile=./fixtures/traefik_multiple_deprecated.toml",
|
||||||
|
},
|
||||||
|
wantDeprecated: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "[FILE] no deprecated",
|
||||||
|
args: []string{
|
||||||
|
"--configfile=./fixtures/traefik_no_deprecated.toml",
|
||||||
|
},
|
||||||
|
wantDeprecated: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
tconfig := cmd.NewTraefikConfiguration()
|
||||||
|
c := &cli.Command{Configuration: tconfig}
|
||||||
|
l := DeprecationLoader{}
|
||||||
|
|
||||||
|
for name, val := range test.env {
|
||||||
|
t.Setenv(name, val)
|
||||||
|
}
|
||||||
|
deprecated, err := l.Load(test.args, c)
|
||||||
|
assert.Equal(t, test.wantDeprecated, deprecated)
|
||||||
|
if !test.wantDeprecated {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
5
pkg/cli/fixtures/traefik_deprecated.toml
Normal file
5
pkg/cli/fixtures/traefik_deprecated.toml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[accesslog]
|
||||||
|
|
||||||
|
[entrypoints.test.http.tls]
|
||||||
|
|
||||||
|
[providers.marathon]
|
8
pkg/cli/fixtures/traefik_multiple_deprecated.toml
Normal file
8
pkg/cli/fixtures/traefik_multiple_deprecated.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[accesslog]
|
||||||
|
|
||||||
|
[entrypoints.test.http.tls]
|
||||||
|
|
||||||
|
[providers.marathon]
|
||||||
|
|
||||||
|
[pilot]
|
||||||
|
token="xxx"
|
3
pkg/cli/fixtures/traefik_no_deprecated.toml
Normal file
3
pkg/cli/fixtures/traefik_no_deprecated.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[accesslog]
|
||||||
|
|
||||||
|
[entrypoints.test.http.tls]
|
|
@ -5,13 +5,14 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/collector/hydratation"
|
||||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_createBody(t *testing.T) {
|
func Test_createBody(t *testing.T) {
|
||||||
var staticConfiguration static.Configuration
|
var staticConfiguration static.Configuration
|
||||||
|
|
||||||
err := hydrate(&staticConfiguration)
|
err := hydratation.Hydrate(&staticConfiguration)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
buffer, err := createBody(&staticConfiguration)
|
buffer, err := createBody(&staticConfiguration)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package collector
|
package hydratation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -17,7 +17,8 @@ const (
|
||||||
defaultMapKeyPrefix = "name"
|
defaultMapKeyPrefix = "name"
|
||||||
)
|
)
|
||||||
|
|
||||||
func hydrate(element interface{}) error {
|
// Hydrate hydrates a configuration.
|
||||||
|
func Hydrate(element interface{}) error {
|
||||||
field := reflect.ValueOf(element)
|
field := reflect.ValueOf(element)
|
||||||
return fill(field)
|
return fill(field)
|
||||||
}
|
}
|
||||||
|
@ -41,9 +42,7 @@ func fill(field reflect.Value) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
if err := fill(field.Elem()); err != nil {
|
setTyped(field, defaultString)
|
||||||
return err
|
|
||||||
}
|
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
setTyped(field, defaultString)
|
setTyped(field, defaultString)
|
||||||
case reflect.Int:
|
case reflect.Int:
|
||||||
|
@ -118,7 +117,7 @@ func makeKeyName(typ reflect.Type) string {
|
||||||
case reflect.String,
|
case reflect.String,
|
||||||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||||
reflect.Bool, reflect.Float32, reflect.Float64:
|
reflect.Bool, reflect.Float32, reflect.Float64, reflect.Interface:
|
||||||
return defaultMapKeyPrefix
|
return defaultMapKeyPrefix
|
||||||
default:
|
default:
|
||||||
return typ.Name()
|
return typ.Name()
|
|
@ -24,7 +24,7 @@ type Configuration struct {
|
||||||
HTTP *HTTPConfiguration `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" export:"true"`
|
HTTP *HTTPConfiguration `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" export:"true"`
|
||||||
TCP *TCPConfiguration `json:"tcp,omitempty" toml:"tcp,omitempty" yaml:"tcp,omitempty" export:"true"`
|
TCP *TCPConfiguration `json:"tcp,omitempty" toml:"tcp,omitempty" yaml:"tcp,omitempty" export:"true"`
|
||||||
UDP *UDPConfiguration `json:"udp,omitempty" toml:"udp,omitempty" yaml:"udp,omitempty" export:"true"`
|
UDP *UDPConfiguration `json:"udp,omitempty" toml:"udp,omitempty" yaml:"udp,omitempty" export:"true"`
|
||||||
TLS *TLSConfiguration `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
TLS *TLSConfiguration `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"-" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
|
@ -37,8 +37,9 @@ type HTTPConfiguration struct {
|
||||||
|
|
||||||
// Model is a set of default router's values.
|
// Model is a set of default router's values.
|
||||||
type Model struct {
|
type Model struct {
|
||||||
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
||||||
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
||||||
|
DefaultRuleSyntax string `json:"-" toml:"-" yaml:"-" label:"-" file:"-" kv:"-" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
@ -59,6 +60,7 @@ type Router struct {
|
||||||
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
||||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
||||||
Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"`
|
Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"`
|
||||||
|
RuleSyntax string `json:"ruleSyntax,omitempty" toml:"ruleSyntax,omitempty" yaml:"ruleSyntax,omitempty" export:"true"`
|
||||||
Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty" export:"true"`
|
Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty" export:"true"`
|
||||||
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
||||||
DefaultRule bool `json:"-" toml:"-" yaml:"-" label:"-" file:"-"`
|
DefaultRule bool `json:"-" toml:"-" yaml:"-" label:"-" file:"-"`
|
||||||
|
@ -155,6 +157,10 @@ type Cookie struct {
|
||||||
// SameSite defines the same site policy.
|
// SameSite defines the same site policy.
|
||||||
// More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
|
// More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
|
||||||
SameSite string `json:"sameSite,omitempty" toml:"sameSite,omitempty" yaml:"sameSite,omitempty" export:"true"`
|
SameSite string `json:"sameSite,omitempty" toml:"sameSite,omitempty" yaml:"sameSite,omitempty" export:"true"`
|
||||||
|
// MaxAge indicates the number of seconds until the cookie expires.
|
||||||
|
// When set to a negative number, the cookie expires immediately.
|
||||||
|
// When set to zero, the cookie never expires.
|
||||||
|
MaxAge int `json:"maxAge,omitempty" toml:"maxAge,omitempty" yaml:"maxAge,omitempty" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
@ -221,6 +227,7 @@ func (r *ResponseForwarding) SetDefaults() {
|
||||||
// Server holds the server configuration.
|
// Server holds the server configuration.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
URL string `json:"url,omitempty" toml:"url,omitempty" yaml:"url,omitempty" label:"-"`
|
URL string `json:"url,omitempty" toml:"url,omitempty" yaml:"url,omitempty" label:"-"`
|
||||||
|
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty" label:"weight"`
|
||||||
Scheme string `json:"-" toml:"-" yaml:"-" file:"-"`
|
Scheme string `json:"-" toml:"-" yaml:"-" file:"-"`
|
||||||
Port string `json:"-" toml:"-" yaml:"-" file:"-"`
|
Port string `json:"-" toml:"-" yaml:"-" file:"-"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,8 @@ type Compress struct {
|
||||||
// ExcludedContentTypes defines the list of content types to compare the Content-Type header of the incoming requests and responses before compressing.
|
// ExcludedContentTypes defines the list of content types to compare the Content-Type header of the incoming requests and responses before compressing.
|
||||||
// `application/grpc` is always excluded.
|
// `application/grpc` is always excluded.
|
||||||
ExcludedContentTypes []string `json:"excludedContentTypes,omitempty" toml:"excludedContentTypes,omitempty" yaml:"excludedContentTypes,omitempty" export:"true"`
|
ExcludedContentTypes []string `json:"excludedContentTypes,omitempty" toml:"excludedContentTypes,omitempty" yaml:"excludedContentTypes,omitempty" export:"true"`
|
||||||
|
// IncludedContentTypes defines the list of content types to compare the Content-Type header of the responses before compressing.
|
||||||
|
IncludedContentTypes []string `json:"includedContentTypes,omitempty" toml:"includedContentTypes,omitempty" yaml:"includedContentTypes,omitempty" export:"true"`
|
||||||
// MinResponseBodyBytes defines the minimum amount of bytes a response body must have to be compressed.
|
// MinResponseBodyBytes defines the minimum amount of bytes a response body must have to be compressed.
|
||||||
// Default: 1024.
|
// Default: 1024.
|
||||||
MinResponseBodyBytes int `json:"minResponseBodyBytes,omitempty" toml:"minResponseBodyBytes,omitempty" yaml:"minResponseBodyBytes,omitempty" export:"true"`
|
MinResponseBodyBytes int `json:"minResponseBodyBytes,omitempty" toml:"minResponseBodyBytes,omitempty" yaml:"minResponseBodyBytes,omitempty" export:"true"`
|
||||||
|
@ -223,6 +225,8 @@ type ForwardAuth struct {
|
||||||
// AuthRequestHeaders defines the list of the headers to copy from the request to the authentication server.
|
// AuthRequestHeaders defines the list of the headers to copy from the request to the authentication server.
|
||||||
// If not set or empty then all request headers are passed.
|
// If not set or empty then all request headers are passed.
|
||||||
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty" toml:"authRequestHeaders,omitempty" yaml:"authRequestHeaders,omitempty" export:"true"`
|
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty" toml:"authRequestHeaders,omitempty" yaml:"authRequestHeaders,omitempty" export:"true"`
|
||||||
|
// AddAuthCookiesToResponse defines the list of cookies to copy from the authentication server response to the response.
|
||||||
|
AddAuthCookiesToResponse []string `json:"addAuthCookiesToResponse,omitempty" toml:"addAuthCookiesToResponse,omitempty" yaml:"addAuthCookiesToResponse,omitempty" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
|
@ -16,11 +16,19 @@ type TCPConfiguration struct {
|
||||||
Routers map[string]*TCPRouter `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty" export:"true"`
|
Routers map[string]*TCPRouter `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty" export:"true"`
|
||||||
Services map[string]*TCPService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
|
Services map[string]*TCPService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
|
||||||
Middlewares map[string]*TCPMiddleware `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
Middlewares map[string]*TCPMiddleware `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
||||||
|
Models map[string]*TCPModel `json:"-" toml:"-" yaml:"-" label:"-" file:"-" kv:"-" export:"true"`
|
||||||
ServersTransports map[string]*TCPServersTransport `json:"serversTransports,omitempty" toml:"serversTransports,omitempty" yaml:"serversTransports,omitempty" label:"-" export:"true"`
|
ServersTransports map[string]*TCPServersTransport `json:"serversTransports,omitempty" toml:"serversTransports,omitempty" yaml:"serversTransports,omitempty" label:"-" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
|
// TCPModel is a set of default router's values.
|
||||||
|
type TCPModel struct {
|
||||||
|
DefaultRuleSyntax string `json:"-" toml:"-" yaml:"-" label:"-" file:"-" kv:"-" export:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
// TCPService holds a tcp service configuration (can only be of one type at the same time).
|
// TCPService holds a tcp service configuration (can only be of one type at the same time).
|
||||||
type TCPService struct {
|
type TCPService struct {
|
||||||
LoadBalancer *TCPServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
|
LoadBalancer *TCPServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
|
||||||
|
@ -56,6 +64,7 @@ type TCPRouter struct {
|
||||||
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
||||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
||||||
Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"`
|
Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"`
|
||||||
|
RuleSyntax string `json:"ruleSyntax,omitempty" toml:"ruleSyntax,omitempty" yaml:"ruleSyntax,omitempty" export:"true"`
|
||||||
Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty" export:"true"`
|
Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty" export:"true"`
|
||||||
TLS *RouterTCPTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
TLS *RouterTCPTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,6 +132,11 @@ func (in *Compress) DeepCopyInto(out *Compress) {
|
||||||
*out = make([]string, len(*in))
|
*out = make([]string, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
|
if in.IncludedContentTypes != nil {
|
||||||
|
in, out := &in.IncludedContentTypes, &out.IncludedContentTypes
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,6 +329,11 @@ func (in *ForwardAuth) DeepCopyInto(out *ForwardAuth) {
|
||||||
*out = make([]string, len(*in))
|
*out = make([]string, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
|
if in.AddAuthCookiesToResponse != nil {
|
||||||
|
in, out := &in.AddAuthCookiesToResponse, &out.AddAuthCookiesToResponse
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1118,6 +1128,11 @@ func (in *RouterTLSConfig) DeepCopy() *RouterTLSConfig {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Server) DeepCopyInto(out *Server) {
|
func (in *Server) DeepCopyInto(out *Server) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.Weight != nil {
|
||||||
|
in, out := &in.Weight, &out.Weight
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1170,7 +1185,9 @@ func (in *ServersLoadBalancer) DeepCopyInto(out *ServersLoadBalancer) {
|
||||||
if in.Servers != nil {
|
if in.Servers != nil {
|
||||||
in, out := &in.Servers, &out.Servers
|
in, out := &in.Servers, &out.Servers
|
||||||
*out = make([]Server, len(*in))
|
*out = make([]Server, len(*in))
|
||||||
copy(*out, *in)
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if in.HealthCheck != nil {
|
if in.HealthCheck != nil {
|
||||||
in, out := &in.HealthCheck, &out.HealthCheck
|
in, out := &in.HealthCheck, &out.HealthCheck
|
||||||
|
@ -1427,6 +1444,21 @@ func (in *TCPConfiguration) DeepCopyInto(out *TCPConfiguration) {
|
||||||
(*out)[key] = outVal
|
(*out)[key] = outVal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.Models != nil {
|
||||||
|
in, out := &in.Models, &out.Models
|
||||||
|
*out = make(map[string]*TCPModel, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
var outVal *TCPModel
|
||||||
|
if val == nil {
|
||||||
|
(*out)[key] = nil
|
||||||
|
} else {
|
||||||
|
in, out := &val, &outVal
|
||||||
|
*out = new(TCPModel)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
(*out)[key] = outVal
|
||||||
|
}
|
||||||
|
}
|
||||||
if in.ServersTransports != nil {
|
if in.ServersTransports != nil {
|
||||||
in, out := &in.ServersTransports, &out.ServersTransports
|
in, out := &in.ServersTransports, &out.ServersTransports
|
||||||
*out = make(map[string]*TCPServersTransport, len(*in))
|
*out = make(map[string]*TCPServersTransport, len(*in))
|
||||||
|
@ -1544,6 +1576,22 @@ func (in *TCPMiddleware) DeepCopy() *TCPMiddleware {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *TCPModel) DeepCopyInto(out *TCPModel) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCPModel.
|
||||||
|
func (in *TCPModel) DeepCopy() *TCPModel {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(TCPModel)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *TCPRouter) DeepCopyInto(out *TCPRouter) {
|
func (in *TCPRouter) DeepCopyInto(out *TCPRouter) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
|
|
@ -1334,6 +1334,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Name": "foobar",
|
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Name": "foobar",
|
||||||
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.HTTPOnly": "true",
|
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.HTTPOnly": "true",
|
||||||
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Secure": "false",
|
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Secure": "false",
|
||||||
|
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.MaxAge": "0",
|
||||||
"traefik.HTTP.Services.Service0.LoadBalancer.ServersTransport": "foobar",
|
"traefik.HTTP.Services.Service0.LoadBalancer.ServersTransport": "foobar",
|
||||||
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name0": "foobar",
|
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name0": "foobar",
|
||||||
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name1": "foobar",
|
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name1": "foobar",
|
||||||
|
|
|
@ -71,11 +71,23 @@ 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"`
|
||||||
|
|
||||||
Experimental *Experimental `description:"experimental features." json:"experimental,omitempty" toml:"experimental,omitempty" yaml:"experimental,omitempty" export:"true"`
|
Experimental *Experimental `description:"Experimental features." json:"experimental,omitempty" toml:"experimental,omitempty" yaml:"experimental,omitempty" export:"true"`
|
||||||
|
|
||||||
|
Core *Core `description:"Core controls." json:"core,omitempty" toml:"core,omitempty" yaml:"core,omitempty" export:"true"`
|
||||||
|
|
||||||
Spiffe *SpiffeClientConfig `description:"SPIFFE integration configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" export:"true"`
|
Spiffe *SpiffeClientConfig `description:"SPIFFE integration configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Core configures Traefik core behavior.
|
||||||
|
type Core struct {
|
||||||
|
DefaultRuleSyntax string `description:"Defines the rule parser default syntax (v2 or v3)" json:"defaultRuleSyntax,omitempty" toml:"defaultRuleSyntax,omitempty" yaml:"defaultRuleSyntax,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaults sets the default values.
|
||||||
|
func (c *Core) SetDefaults() {
|
||||||
|
c.DefaultRuleSyntax = "v3"
|
||||||
|
}
|
||||||
|
|
||||||
// SpiffeClientConfig defines the SPIFFE client configuration.
|
// SpiffeClientConfig defines the SPIFFE client configuration.
|
||||||
type SpiffeClientConfig struct {
|
type SpiffeClientConfig struct {
|
||||||
WorkloadAPIAddr string `description:"Defines the workload API address." json:"workloadAPIAddr,omitempty" toml:"workloadAPIAddr,omitempty" yaml:"workloadAPIAddr,omitempty"`
|
WorkloadAPIAddr string `description:"Defines the workload API address." json:"workloadAPIAddr,omitempty" toml:"workloadAPIAddr,omitempty" yaml:"workloadAPIAddr,omitempty"`
|
||||||
|
@ -317,6 +329,17 @@ func (c *Configuration) ValidateConfiguration() error {
|
||||||
acmeEmail = resolver.ACME.Email
|
acmeEmail = resolver.ACME.Email
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Core != nil {
|
||||||
|
switch c.Core.DefaultRuleSyntax {
|
||||||
|
case "v3": // NOOP
|
||||||
|
case "v2":
|
||||||
|
// TODO: point to migration guide.
|
||||||
|
log.Warn().Msgf("v2 rules syntax is now deprecated, please use v3 instead...")
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported default rule syntax configuration: %q", c.Core.DefaultRuleSyntax)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if c.Tracing != nil && c.Tracing.OTLP != nil {
|
if c.Tracing != nil && c.Tracing.OTLP != nil {
|
||||||
if c.Tracing.OTLP.HTTP == nil && c.Tracing.OTLP.GRPC == nil {
|
if c.Tracing.OTLP.HTTP == nil && c.Tracing.OTLP.GRPC == nil {
|
||||||
return errors.New("tracing OTLP: at least one of HTTP and gRPC options should be defined")
|
return errors.New("tracing OTLP: at least one of HTTP and gRPC options should be defined")
|
||||||
|
|
|
@ -13,12 +13,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDatadog(t *testing.T) {
|
func TestDatadog(t *testing.T) {
|
||||||
|
t.Cleanup(StopDatadog)
|
||||||
|
|
||||||
udp.SetAddr(":18125")
|
udp.SetAddr(":18125")
|
||||||
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
|
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
|
||||||
udp.Timeout = 5 * time.Second
|
udp.Timeout = 5 * time.Second
|
||||||
|
|
||||||
datadogRegistry := RegisterDatadog(context.Background(), &types.Datadog{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
|
datadogRegistry := RegisterDatadog(context.Background(), &types.Datadog{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
|
||||||
defer StopDatadog()
|
|
||||||
|
|
||||||
if !datadogRegistry.IsEpEnabled() || !datadogRegistry.IsRouterEnabled() || !datadogRegistry.IsSvcEnabled() {
|
if !datadogRegistry.IsEpEnabled() || !datadogRegistry.IsRouterEnabled() || !datadogRegistry.IsSvcEnabled() {
|
||||||
t.Errorf("DatadogRegistry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()")
|
t.Errorf("DatadogRegistry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()")
|
||||||
|
@ -27,9 +28,7 @@ func TestDatadog(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDatadogWithPrefix(t *testing.T) {
|
func TestDatadogWithPrefix(t *testing.T) {
|
||||||
t.Cleanup(func() {
|
t.Cleanup(StopDatadog)
|
||||||
StopDatadog()
|
|
||||||
})
|
|
||||||
|
|
||||||
udp.SetAddr(":18125")
|
udp.SetAddr(":18125")
|
||||||
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
|
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -26,7 +25,6 @@ func TestInfluxDB2(t *testing.T) {
|
||||||
c <- &bodyStr
|
c <- &bodyStr
|
||||||
_, _ = fmt.Fprintln(w, "ok")
|
_, _ = fmt.Fprintln(w, "ok")
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
influxDB2Registry := RegisterInfluxDB2(context.Background(),
|
influxDB2Registry := RegisterInfluxDB2(context.Background(),
|
||||||
&types.InfluxDB2{
|
&types.InfluxDB2{
|
||||||
|
@ -39,7 +37,11 @@ func TestInfluxDB2(t *testing.T) {
|
||||||
AddRoutersLabels: true,
|
AddRoutersLabels: true,
|
||||||
AddServicesLabels: true,
|
AddServicesLabels: true,
|
||||||
})
|
})
|
||||||
defer StopInfluxDB2()
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
StopInfluxDB2()
|
||||||
|
ts.Close()
|
||||||
|
})
|
||||||
|
|
||||||
if !influxDB2Registry.IsEpEnabled() || !influxDB2Registry.IsRouterEnabled() || !influxDB2Registry.IsSvcEnabled() {
|
if !influxDB2Registry.IsEpEnabled() || !influxDB2Registry.IsRouterEnabled() || !influxDB2Registry.IsSvcEnabled() {
|
||||||
t.Fatalf("InfluxDB2Registry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()")
|
t.Fatalf("InfluxDB2Registry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()")
|
||||||
|
@ -137,14 +139,3 @@ func TestInfluxDB2(t *testing.T) {
|
||||||
|
|
||||||
assertMessage(t, *msgServiceRetries, expectedServiceRetries)
|
assertMessage(t, *msgServiceRetries, expectedServiceRetries)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertMessage(t *testing.T, msg string, patterns []string) {
|
|
||||||
t.Helper()
|
|
||||||
for _, pattern := range patterns {
|
|
||||||
re := regexp.MustCompile(pattern)
|
|
||||||
match := re.FindStringSubmatch(msg)
|
|
||||||
if len(match) != 2 {
|
|
||||||
t.Errorf("Got %q %v, want %q", msg, match, pattern)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,10 +4,12 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -287,10 +289,8 @@ func TestOpenTelemetry_GaugeCollectorSet(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOpenTelemetry(t *testing.T) {
|
func TestOpenTelemetry(t *testing.T) {
|
||||||
t.Parallel()
|
c := make(chan *string, 5)
|
||||||
|
|
||||||
c := make(chan *string)
|
|
||||||
defer close(c)
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
gzr, err := gzip.NewReader(r.Body)
|
gzr, err := gzip.NewReader(r.Body)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -310,7 +310,11 @@ func TestOpenTelemetry(t *testing.T) {
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
StopOpenTelemetry()
|
||||||
|
ts.Close()
|
||||||
|
})
|
||||||
|
|
||||||
sURL, err := url.Parse(ts.URL)
|
sURL, err := url.Parse(ts.URL)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -333,57 +337,53 @@ func TestOpenTelemetry(t *testing.T) {
|
||||||
`({"key":"service.name","value":{"stringValue":"traefik"}})`,
|
`({"key":"service.name","value":{"stringValue":"traefik"}})`,
|
||||||
`({"key":"service.version","value":{"stringValue":"` + version.Version + `"}})`,
|
`({"key":"service.version","value":{"stringValue":"` + version.Version + `"}})`,
|
||||||
}
|
}
|
||||||
msgMisc := <-c
|
|
||||||
|
|
||||||
assertMessage(t, *msgMisc, expected)
|
tryAssertMessage(t, c, expected)
|
||||||
|
|
||||||
// TODO: the len of startUnixNano is no supposed to be 20, it should be 19
|
// TODO: the len of startUnixNano is no supposed to be 20, it should be 19
|
||||||
expected = append(expected,
|
expectedConfig := []string{
|
||||||
`({"name":"traefik_config_reloads_total","description":"Config reloads","unit":"1","sum":{"dataPoints":\[{"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_config_reloads_total","description":"Config reloads","unit":"1","sum":{"dataPoints":\[{"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
`({"name":"traefik_config_last_reload_success","description":"Last config reload success","unit":"ms","gauge":{"dataPoints":\[{"timeUnixNano":"[\d]{19}","asDouble":1}\]}})`,
|
`({"name":"traefik_config_last_reload_success","description":"Last config reload success","unit":"ms","gauge":{"dataPoints":\[{"timeUnixNano":"[\d]{19}","asDouble":1}\]}})`,
|
||||||
`({"name":"traefik_open_connections","description":"How many open connections exist, by entryPoint and protocol","unit":"1","gauge":{"dataPoints":\[{"attributes":\[{"key":"entrypoint","value":{"stringValue":"test"}},{"key":"protocol","value":{"stringValue":"TCP"}}\],"timeUnixNano":"[\d]{19}","asDouble":1}\]}})`,
|
`({"name":"traefik_open_connections","description":"How many open connections exist, by entryPoint and protocol","unit":"1","gauge":{"dataPoints":\[{"attributes":\[{"key":"entrypoint","value":{"stringValue":"test"}},{"key":"protocol","value":{"stringValue":"TCP"}}\],"timeUnixNano":"[\d]{19}","asDouble":1}\]}})`,
|
||||||
)
|
}
|
||||||
|
|
||||||
registry.ConfigReloadsCounter().Add(1)
|
registry.ConfigReloadsCounter().Add(1)
|
||||||
registry.LastConfigReloadSuccessGauge().Set(1)
|
registry.LastConfigReloadSuccessGauge().Set(1)
|
||||||
registry.OpenConnectionsGauge().With("entrypoint", "test", "protocol", "TCP").Set(1)
|
registry.OpenConnectionsGauge().With("entrypoint", "test", "protocol", "TCP").Set(1)
|
||||||
msgServer := <-c
|
|
||||||
|
|
||||||
assertMessage(t, *msgServer, expected)
|
tryAssertMessage(t, c, expectedConfig)
|
||||||
|
|
||||||
expected = append(expected,
|
expectedTLSCerts := []string{
|
||||||
`({"name":"traefik_tls_certs_not_after","description":"Certificate expiration timestamp","unit":"ms","gauge":{"dataPoints":\[{"attributes":\[{"key":"key","value":{"stringValue":"value"}}\],"timeUnixNano":"[\d]{19}","asDouble":1}\]}})`,
|
`({"name":"traefik_tls_certs_not_after","description":"Certificate expiration timestamp","unit":"ms","gauge":{"dataPoints":\[{"attributes":\[{"key":"key","value":{"stringValue":"value"}}\],"timeUnixNano":"[\d]{19}","asDouble":1}\]}})`,
|
||||||
)
|
}
|
||||||
|
|
||||||
registry.TLSCertsNotAfterTimestampGauge().With("key", "value").Set(1)
|
registry.TLSCertsNotAfterTimestampGauge().With("key", "value").Set(1)
|
||||||
msgTLS := <-c
|
|
||||||
|
|
||||||
assertMessage(t, *msgTLS, expected)
|
tryAssertMessage(t, c, expectedTLSCerts)
|
||||||
|
|
||||||
expected = append(expected,
|
expectedEntryPoints := []string{
|
||||||
`({"name":"traefik_entrypoint_requests_total","description":"How many HTTP requests processed on an entrypoint, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"entrypoint","value":{"stringValue":"test1"}},{"key":"method","value":{"stringValue":"GET"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_entrypoint_requests_total","description":"How many HTTP requests processed on an entrypoint, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"entrypoint","value":{"stringValue":"test1"}},{"key":"method","value":{"stringValue":"GET"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
`({"name":"traefik_entrypoint_requests_tls_total","description":"How many HTTP requests with TLS processed on an entrypoint, partitioned by TLS Version and TLS cipher Used.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"entrypoint","value":{"stringValue":"test2"}},{"key":"tls_cipher","value":{"stringValue":"bar"}},{"key":"tls_version","value":{"stringValue":"foo"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_entrypoint_requests_tls_total","description":"How many HTTP requests with TLS processed on an entrypoint, partitioned by TLS Version and TLS cipher Used.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"entrypoint","value":{"stringValue":"test2"}},{"key":"tls_cipher","value":{"stringValue":"bar"}},{"key":"tls_version","value":{"stringValue":"foo"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
`({"name":"traefik_entrypoint_request_duration_seconds","description":"How long it took to process the request on an entrypoint, partitioned by status code, protocol, and method.","unit":"ms","histogram":{"dataPoints":\[{"attributes":\[{"key":"entrypoint","value":{"stringValue":"test3"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","count":"1","sum":10000,"bucketCounts":\["0","0","0","0","0","0","0","0","0","0","0","1"\],"explicitBounds":\[0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10\],"min":10000,"max":10000}\],"aggregationTemporality":2}})`,
|
`({"name":"traefik_entrypoint_request_duration_seconds","description":"How long it took to process the request on an entrypoint, partitioned by status code, protocol, and method.","unit":"ms","histogram":{"dataPoints":\[{"attributes":\[{"key":"entrypoint","value":{"stringValue":"test3"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","count":"1","sum":10000,"bucketCounts":\["0","0","0","0","0","0","0","0","0","0","0","1"\],"explicitBounds":\[0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10\],"min":10000,"max":10000}\],"aggregationTemporality":2}})`,
|
||||||
`({"name":"traefik_entrypoint_requests_bytes_total","description":"The total size of requests in bytes handled by an entrypoint, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"entrypoint","value":{"stringValue":"test1"}},{"key":"method","value":{"stringValue":"GET"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_entrypoint_requests_bytes_total","description":"The total size of requests in bytes handled by an entrypoint, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"entrypoint","value":{"stringValue":"test1"}},{"key":"method","value":{"stringValue":"GET"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
`({"name":"traefik_entrypoint_responses_bytes_total","description":"The total size of responses in bytes handled by an entrypoint, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"entrypoint","value":{"stringValue":"test1"}},{"key":"method","value":{"stringValue":"GET"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_entrypoint_responses_bytes_total","description":"The total size of responses in bytes handled by an entrypoint, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"entrypoint","value":{"stringValue":"test1"}},{"key":"method","value":{"stringValue":"GET"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
)
|
}
|
||||||
|
|
||||||
registry.EntryPointReqsCounter().With(nil, "entrypoint", "test1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
|
registry.EntryPointReqsCounter().With(nil, "entrypoint", "test1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
|
||||||
registry.EntryPointReqsTLSCounter().With("entrypoint", "test2", "tls_version", "foo", "tls_cipher", "bar").Add(1)
|
registry.EntryPointReqsTLSCounter().With("entrypoint", "test2", "tls_version", "foo", "tls_cipher", "bar").Add(1)
|
||||||
registry.EntryPointReqDurationHistogram().With("entrypoint", "test3").Observe(10000)
|
registry.EntryPointReqDurationHistogram().With("entrypoint", "test3").Observe(10000)
|
||||||
registry.EntryPointReqsBytesCounter().With("entrypoint", "test1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
|
registry.EntryPointReqsBytesCounter().With("entrypoint", "test1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
|
||||||
registry.EntryPointRespsBytesCounter().With("entrypoint", "test1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
|
registry.EntryPointRespsBytesCounter().With("entrypoint", "test1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
|
||||||
msgEntrypoint := <-c
|
|
||||||
|
|
||||||
assertMessage(t, *msgEntrypoint, expected)
|
tryAssertMessage(t, c, expectedEntryPoints)
|
||||||
|
|
||||||
expected = append(expected,
|
expectedRouters := []string{
|
||||||
`({"name":"traefik_router_requests_total","description":"How many HTTP requests are processed on a router, partitioned by service, status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"router","value":{"stringValue":"RouterReqsCounter"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1},{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"router","value":{"stringValue":"RouterReqsCounter"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_router_requests_total","description":"How many HTTP requests are processed on a router, partitioned by service, status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"router","value":{"stringValue":"RouterReqsCounter"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1},{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"router","value":{"stringValue":"RouterReqsCounter"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
`({"name":"traefik_router_requests_tls_total","description":"How many HTTP requests with TLS are processed on a router, partitioned by service, TLS Version, and TLS cipher Used.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"router","value":{"stringValue":"demo"}},{"key":"service","value":{"stringValue":"test"}},{"key":"tls_cipher","value":{"stringValue":"bar"}},{"key":"tls_version","value":{"stringValue":"foo"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_router_requests_tls_total","description":"How many HTTP requests with TLS are processed on a router, partitioned by service, TLS Version, and TLS cipher Used.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"router","value":{"stringValue":"demo"}},{"key":"service","value":{"stringValue":"test"}},{"key":"tls_cipher","value":{"stringValue":"bar"}},{"key":"tls_version","value":{"stringValue":"foo"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
`({"name":"traefik_router_request_duration_seconds","description":"How long it took to process the request on a router, partitioned by service, status code, protocol, and method.","unit":"ms","histogram":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"router","value":{"stringValue":"demo"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","count":"1","sum":10000,"bucketCounts":\["0","0","0","0","0","0","0","0","0","0","0","1"\],"explicitBounds":\[0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10\],"min":10000,"max":10000}\],"aggregationTemporality":2}})`,
|
`({"name":"traefik_router_request_duration_seconds","description":"How long it took to process the request on a router, partitioned by service, status code, protocol, and method.","unit":"ms","histogram":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"router","value":{"stringValue":"demo"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","count":"1","sum":10000,"bucketCounts":\["0","0","0","0","0","0","0","0","0","0","0","1"\],"explicitBounds":\[0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10\],"min":10000,"max":10000}\],"aggregationTemporality":2}})`,
|
||||||
`({"name":"traefik_router_requests_bytes_total","description":"The total size of requests in bytes handled by a router, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"404"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"router","value":{"stringValue":"RouterReqsCounter"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_router_requests_bytes_total","description":"The total size of requests in bytes handled by a router, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"404"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"router","value":{"stringValue":"RouterReqsCounter"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
`({"name":"traefik_router_responses_bytes_total","description":"The total size of responses in bytes handled by a router, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"404"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"router","value":{"stringValue":"RouterReqsCounter"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_router_responses_bytes_total","description":"The total size of responses in bytes handled by a router, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"404"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"router","value":{"stringValue":"RouterReqsCounter"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
)
|
}
|
||||||
|
|
||||||
registry.RouterReqsCounter().With(nil, "router", "RouterReqsCounter", "service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
registry.RouterReqsCounter().With(nil, "router", "RouterReqsCounter", "service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
||||||
registry.RouterReqsCounter().With(nil, "router", "RouterReqsCounter", "service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
|
registry.RouterReqsCounter().With(nil, "router", "RouterReqsCounter", "service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
|
||||||
|
@ -391,18 +391,17 @@ func TestOpenTelemetry(t *testing.T) {
|
||||||
registry.RouterReqDurationHistogram().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
|
registry.RouterReqDurationHistogram().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
|
||||||
registry.RouterReqsBytesCounter().With("router", "RouterReqsCounter", "service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
registry.RouterReqsBytesCounter().With("router", "RouterReqsCounter", "service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
||||||
registry.RouterRespsBytesCounter().With("router", "RouterReqsCounter", "service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
registry.RouterRespsBytesCounter().With("router", "RouterReqsCounter", "service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
||||||
msgRouter := <-c
|
|
||||||
|
|
||||||
assertMessage(t, *msgRouter, expected)
|
tryAssertMessage(t, c, expectedRouters)
|
||||||
|
|
||||||
expected = append(expected,
|
expectedServices := []string{
|
||||||
`({"name":"traefik_service_requests_total","description":"How many HTTP requests processed on a service, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"service","value":{"stringValue":"ServiceReqsCounter"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1},{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"service","value":{"stringValue":"ServiceReqsCounter"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_service_requests_total","description":"How many HTTP requests processed on a service, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"service","value":{"stringValue":"ServiceReqsCounter"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1},{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"service","value":{"stringValue":"ServiceReqsCounter"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
`({"name":"traefik_service_requests_tls_total","description":"How many HTTP requests with TLS processed on a service, partitioned by TLS version and TLS cipher.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"service","value":{"stringValue":"test"}},{"key":"tls_cipher","value":{"stringValue":"bar"}},{"key":"tls_version","value":{"stringValue":"foo"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_service_requests_tls_total","description":"How many HTTP requests with TLS processed on a service, partitioned by TLS version and TLS cipher.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"service","value":{"stringValue":"test"}},{"key":"tls_cipher","value":{"stringValue":"bar"}},{"key":"tls_version","value":{"stringValue":"foo"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
`({"name":"traefik_service_request_duration_seconds","description":"How long it took to process the request on a service, partitioned by status code, protocol, and method.","unit":"ms","histogram":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","count":"1","sum":10000,"bucketCounts":\["0","0","0","0","0","0","0","0","0","0","0","1"\],"explicitBounds":\[0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10\],"min":10000,"max":10000}\],"aggregationTemporality":2}})`,
|
`({"name":"traefik_service_request_duration_seconds","description":"How long it took to process the request on a service, partitioned by status code, protocol, and method.","unit":"ms","histogram":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","count":"1","sum":10000,"bucketCounts":\["0","0","0","0","0","0","0","0","0","0","0","1"\],"explicitBounds":\[0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10\],"min":10000,"max":10000}\],"aggregationTemporality":2}})`,
|
||||||
`({"name":"traefik_service_server_up","description":"service server is up, described by gauge value of 0 or 1.","unit":"1","gauge":{"dataPoints":\[{"attributes":\[{"key":"service","value":{"stringValue":"test"}},{"key":"url","value":{"stringValue":"http://127.0.0.1"}}\],"timeUnixNano":"[\d]{19}","asDouble":1}\]}})`,
|
`({"name":"traefik_service_server_up","description":"service server is up, described by gauge value of 0 or 1.","unit":"1","gauge":{"dataPoints":\[{"attributes":\[{"key":"service","value":{"stringValue":"test"}},{"key":"url","value":{"stringValue":"http://127.0.0.1"}}\],"timeUnixNano":"[\d]{19}","asDouble":1}\]}})`,
|
||||||
`({"name":"traefik_service_requests_bytes_total","description":"The total size of requests in bytes received by a service, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"404"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"service","value":{"stringValue":"ServiceReqsCounter"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_service_requests_bytes_total","description":"The total size of requests in bytes received by a service, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"404"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"service","value":{"stringValue":"ServiceReqsCounter"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
`({"name":"traefik_service_responses_bytes_total","description":"The total size of responses in bytes returned by a service, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"404"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"service","value":{"stringValue":"ServiceReqsCounter"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
`({"name":"traefik_service_responses_bytes_total","description":"The total size of responses in bytes returned by a service, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"404"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"service","value":{"stringValue":"ServiceReqsCounter"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`,
|
||||||
)
|
}
|
||||||
|
|
||||||
registry.ServiceReqsCounter().With(nil, "service", "ServiceReqsCounter", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
|
registry.ServiceReqsCounter().With(nil, "service", "ServiceReqsCounter", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
|
||||||
registry.ServiceReqsCounter().With(nil, "service", "ServiceReqsCounter", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
registry.ServiceReqsCounter().With(nil, "service", "ServiceReqsCounter", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
||||||
|
@ -411,21 +410,19 @@ func TestOpenTelemetry(t *testing.T) {
|
||||||
registry.ServiceServerUpGauge().With("service", "test", "url", "http://127.0.0.1").Set(1)
|
registry.ServiceServerUpGauge().With("service", "test", "url", "http://127.0.0.1").Set(1)
|
||||||
registry.ServiceReqsBytesCounter().With("service", "ServiceReqsCounter", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
registry.ServiceReqsBytesCounter().With("service", "ServiceReqsCounter", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
||||||
registry.ServiceRespsBytesCounter().With("service", "ServiceReqsCounter", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
registry.ServiceRespsBytesCounter().With("service", "ServiceReqsCounter", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
|
||||||
msgService := <-c
|
|
||||||
|
|
||||||
assertMessage(t, *msgService, expected)
|
tryAssertMessage(t, c, expectedServices)
|
||||||
|
|
||||||
expected = append(expected,
|
expectedServicesRetries := []string{
|
||||||
`({"attributes":\[{"key":"service","value":{"stringValue":"foobar"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1})`,
|
`({"attributes":\[{"key":"service","value":{"stringValue":"foobar"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1})`,
|
||||||
`({"attributes":\[{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":2})`,
|
`({"attributes":\[{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":2})`,
|
||||||
)
|
}
|
||||||
|
|
||||||
registry.ServiceRetriesCounter().With("service", "test").Add(1)
|
registry.ServiceRetriesCounter().With("service", "test").Add(1)
|
||||||
registry.ServiceRetriesCounter().With("service", "test").Add(1)
|
registry.ServiceRetriesCounter().With("service", "test").Add(1)
|
||||||
registry.ServiceRetriesCounter().With("service", "foobar").Add(1)
|
registry.ServiceRetriesCounter().With("service", "foobar").Add(1)
|
||||||
msgServiceRetries := <-c
|
|
||||||
|
|
||||||
assertMessage(t, *msgServiceRetries, expected)
|
tryAssertMessage(t, c, expectedServicesRetries)
|
||||||
|
|
||||||
// We cannot rely on the previous expected pattern,
|
// We cannot rely on the previous expected pattern,
|
||||||
// because this pattern was for matching only one dataPoint in the histogram,
|
// because this pattern was for matching only one dataPoint in the histogram,
|
||||||
|
@ -437,14 +434,46 @@ func TestOpenTelemetry(t *testing.T) {
|
||||||
|
|
||||||
registry.EntryPointReqDurationHistogram().With("entrypoint", "myEntrypoint").Observe(10000)
|
registry.EntryPointReqDurationHistogram().With("entrypoint", "myEntrypoint").Observe(10000)
|
||||||
registry.EntryPointReqDurationHistogram().With("entrypoint", "myEntrypoint").Observe(20000)
|
registry.EntryPointReqDurationHistogram().With("entrypoint", "myEntrypoint").Observe(20000)
|
||||||
msgEntryPointReqDurationHistogram := <-c
|
|
||||||
|
|
||||||
assertMessage(t, *msgEntryPointReqDurationHistogram, expectedEntryPointReqDuration)
|
tryAssertMessage(t, c, expectedEntryPointReqDuration)
|
||||||
|
}
|
||||||
// We need to unlock the HTTP Server for the last export call when stopping
|
|
||||||
// OpenTelemetry.
|
func assertMessage(t *testing.T, msg string, expected []string) {
|
||||||
go func() {
|
t.Helper()
|
||||||
<-c
|
errs := verifyMessage(msg, expected)
|
||||||
}()
|
for _, err := range errs {
|
||||||
StopOpenTelemetry()
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func tryAssertMessage(t *testing.T, c chan *string, expected []string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
var errs []error
|
||||||
|
timeout := time.After(1 * time.Second)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-timeout:
|
||||||
|
for _, err := range errs {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
case msg := <-c:
|
||||||
|
errs = verifyMessage(*msg, expected)
|
||||||
|
if len(errs) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyMessage(msg string, expected []string) []error {
|
||||||
|
var errs []error
|
||||||
|
for _, pattern := range expected {
|
||||||
|
re := regexp.MustCompile(pattern)
|
||||||
|
match := re.FindStringSubmatch(msg)
|
||||||
|
if len(match) != 2 {
|
||||||
|
errs = append(errs, fmt.Errorf("Got %q %v, want %q", msg, match, pattern))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errs
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,19 +48,26 @@ type forwardAuth struct {
|
||||||
client http.Client
|
client http.Client
|
||||||
trustForwardHeader bool
|
trustForwardHeader bool
|
||||||
authRequestHeaders []string
|
authRequestHeaders []string
|
||||||
|
addAuthCookiesToResponse map[string]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewForward creates a forward auth middleware.
|
// NewForward creates a forward auth middleware.
|
||||||
func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAuth, name string) (http.Handler, error) {
|
func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAuth, name string) (http.Handler, error) {
|
||||||
middlewares.GetLogger(ctx, name, typeNameForward).Debug().Msg("Creating middleware")
|
middlewares.GetLogger(ctx, name, typeNameForward).Debug().Msg("Creating middleware")
|
||||||
|
|
||||||
|
addAuthCookiesToResponse := make(map[string]struct{})
|
||||||
|
for _, cookieName := range config.AddAuthCookiesToResponse {
|
||||||
|
addAuthCookiesToResponse[cookieName] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
fa := &forwardAuth{
|
fa := &forwardAuth{
|
||||||
address: config.Address,
|
address: config.Address,
|
||||||
authResponseHeaders: config.AuthResponseHeaders,
|
authResponseHeaders: config.AuthResponseHeaders,
|
||||||
next: next,
|
next: next,
|
||||||
name: name,
|
name: name,
|
||||||
trustForwardHeader: config.TrustForwardHeader,
|
trustForwardHeader: config.TrustForwardHeader,
|
||||||
authRequestHeaders: config.AuthRequestHeaders,
|
authRequestHeaders: config.AuthRequestHeaders,
|
||||||
|
addAuthCookiesToResponse: addAuthCookiesToResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure our request client does not follow redirects
|
// Ensure our request client does not follow redirects
|
||||||
|
@ -211,7 +218,35 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
tracing.LogResponseCode(forwardSpan, forwardResponse.StatusCode, trace.SpanKindClient)
|
tracing.LogResponseCode(forwardSpan, forwardResponse.StatusCode, trace.SpanKindClient)
|
||||||
|
|
||||||
req.RequestURI = req.URL.RequestURI()
|
req.RequestURI = req.URL.RequestURI()
|
||||||
fa.next.ServeHTTP(rw, req)
|
|
||||||
|
authCookies := forwardResponse.Cookies()
|
||||||
|
if len(authCookies) == 0 {
|
||||||
|
fa.next.ServeHTTP(rw, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fa.next.ServeHTTP(middlewares.NewResponseModifier(rw, req, fa.buildModifier(authCookies)), req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fa *forwardAuth) buildModifier(authCookies []*http.Cookie) func(res *http.Response) error {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
cookies := res.Cookies()
|
||||||
|
res.Header.Del("Set-Cookie")
|
||||||
|
|
||||||
|
for _, cookie := range cookies {
|
||||||
|
if _, found := fa.addAuthCookiesToResponse[cookie.Name]; !found {
|
||||||
|
res.Header.Add("Set-Cookie", cookie.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cookie := range authCookies {
|
||||||
|
if _, found := fa.addAuthCookiesToResponse[cookie.Name]; found {
|
||||||
|
res.Header.Add("Set-Cookie", cookie.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeHeader(req, forwardReq *http.Request, trustForwardHeader bool, allowedHeaders []string) {
|
func writeHeader(req, forwardReq *http.Request, trustForwardHeader bool, allowedHeaders []string) {
|
||||||
|
|
|
@ -66,6 +66,8 @@ func TestForwardAuthSuccess(t *testing.T) {
|
||||||
w.Header().Add("X-Auth-Group", "group1")
|
w.Header().Add("X-Auth-Group", "group1")
|
||||||
w.Header().Add("X-Auth-Group", "group2")
|
w.Header().Add("X-Auth-Group", "group2")
|
||||||
w.Header().Add("Foo-Bar", "auth-value")
|
w.Header().Add("Foo-Bar", "auth-value")
|
||||||
|
w.Header().Add("Set-Cookie", "authCookie=Auth")
|
||||||
|
w.Header().Add("Set-Cookie", "authCookieNotAdded=Auth")
|
||||||
fmt.Fprintln(w, "Success")
|
fmt.Fprintln(w, "Success")
|
||||||
}))
|
}))
|
||||||
t.Cleanup(server.Close)
|
t.Cleanup(server.Close)
|
||||||
|
@ -76,6 +78,9 @@ func TestForwardAuthSuccess(t *testing.T) {
|
||||||
assert.Equal(t, []string{"group1", "group2"}, r.Header["X-Auth-Group"])
|
assert.Equal(t, []string{"group1", "group2"}, r.Header["X-Auth-Group"])
|
||||||
assert.Equal(t, "auth-value", r.Header.Get("Foo-Bar"))
|
assert.Equal(t, "auth-value", r.Header.Get("Foo-Bar"))
|
||||||
assert.Empty(t, r.Header.Get("Foo-Baz"))
|
assert.Empty(t, r.Header.Get("Foo-Baz"))
|
||||||
|
w.Header().Add("Set-Cookie", "authCookie=Backend")
|
||||||
|
w.Header().Add("Set-Cookie", "backendCookie=Backend")
|
||||||
|
w.Header().Add("Other-Header", "BackendHeaderValue")
|
||||||
fmt.Fprintln(w, "traefik")
|
fmt.Fprintln(w, "traefik")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -83,6 +88,7 @@ func TestForwardAuthSuccess(t *testing.T) {
|
||||||
Address: server.URL,
|
Address: server.URL,
|
||||||
AuthResponseHeaders: []string{"X-Auth-User", "X-Auth-Group"},
|
AuthResponseHeaders: []string{"X-Auth-User", "X-Auth-Group"},
|
||||||
AuthResponseHeadersRegex: "^Foo-",
|
AuthResponseHeadersRegex: "^Foo-",
|
||||||
|
AddAuthCookiesToResponse: []string{"authCookie"},
|
||||||
}
|
}
|
||||||
middleware, err := NewForward(context.Background(), next, auth, "authTest")
|
middleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -97,6 +103,8 @@ func TestForwardAuthSuccess(t *testing.T) {
|
||||||
res, err := http.DefaultClient.Do(req)
|
res, err := http.DefaultClient.Do(req)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, http.StatusOK, res.StatusCode)
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
||||||
|
assert.Equal(t, []string{"backendCookie=Backend", "authCookie=Auth"}, res.Header["Set-Cookie"])
|
||||||
|
assert.Equal(t, []string{"BackendHeaderValue"}, res.Header["Other-Header"])
|
||||||
|
|
||||||
body, err := io.ReadAll(res.Body)
|
body, err := io.ReadAll(res.Body)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -22,7 +22,11 @@ const (
|
||||||
// Config is the Brotli handler configuration.
|
// Config is the Brotli handler configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// ExcludedContentTypes is the list of content types for which we should not compress.
|
// ExcludedContentTypes is the list of content types for which we should not compress.
|
||||||
|
// Mutually exclusive with the IncludedContentTypes option.
|
||||||
ExcludedContentTypes []string
|
ExcludedContentTypes []string
|
||||||
|
// IncludedContentTypes is the list of content types for which compression should be exclusively enabled.
|
||||||
|
// Mutually exclusive with the ExcludedContentTypes option.
|
||||||
|
IncludedContentTypes []string
|
||||||
// MinSize is the minimum size (in bytes) required to enable compression.
|
// MinSize is the minimum size (in bytes) required to enable compression.
|
||||||
MinSize int
|
MinSize int
|
||||||
}
|
}
|
||||||
|
@ -33,14 +37,28 @@ func NewWrapper(cfg Config) (func(http.Handler) http.HandlerFunc, error) {
|
||||||
return nil, fmt.Errorf("minimum size must be greater than or equal to zero")
|
return nil, fmt.Errorf("minimum size must be greater than or equal to zero")
|
||||||
}
|
}
|
||||||
|
|
||||||
var contentTypes []parsedContentType
|
if len(cfg.ExcludedContentTypes) > 0 && len(cfg.IncludedContentTypes) > 0 {
|
||||||
|
return nil, fmt.Errorf("excludedContentTypes and includedContentTypes options are mutually exclusive")
|
||||||
|
}
|
||||||
|
|
||||||
|
var excludedContentTypes []parsedContentType
|
||||||
for _, v := range cfg.ExcludedContentTypes {
|
for _, v := range cfg.ExcludedContentTypes {
|
||||||
mediaType, params, err := mime.ParseMediaType(v)
|
mediaType, params, err := mime.ParseMediaType(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parsing media type: %w", err)
|
return nil, fmt.Errorf("parsing excluded media type: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
contentTypes = append(contentTypes, parsedContentType{mediaType, params})
|
excludedContentTypes = append(excludedContentTypes, parsedContentType{mediaType, params})
|
||||||
|
}
|
||||||
|
|
||||||
|
var includedContentTypes []parsedContentType
|
||||||
|
for _, v := range cfg.IncludedContentTypes {
|
||||||
|
mediaType, params, err := mime.ParseMediaType(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing included media type: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
includedContentTypes = append(includedContentTypes, parsedContentType{mediaType, params})
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(h http.Handler) http.HandlerFunc {
|
return func(h http.Handler) http.HandlerFunc {
|
||||||
|
@ -52,7 +70,8 @@ func NewWrapper(cfg Config) (func(http.Handler) http.HandlerFunc, error) {
|
||||||
bw: brotli.NewWriter(rw),
|
bw: brotli.NewWriter(rw),
|
||||||
minSize: cfg.MinSize,
|
minSize: cfg.MinSize,
|
||||||
statusCode: http.StatusOK,
|
statusCode: http.StatusOK,
|
||||||
excludedContentTypes: contentTypes,
|
excludedContentTypes: excludedContentTypes,
|
||||||
|
includedContentTypes: includedContentTypes,
|
||||||
}
|
}
|
||||||
defer brw.close()
|
defer brw.close()
|
||||||
|
|
||||||
|
@ -69,6 +88,7 @@ type responseWriter struct {
|
||||||
|
|
||||||
minSize int
|
minSize int
|
||||||
excludedContentTypes []parsedContentType
|
excludedContentTypes []parsedContentType
|
||||||
|
includedContentTypes []parsedContentType
|
||||||
|
|
||||||
buf []byte
|
buf []byte
|
||||||
hijacked bool
|
hijacked bool
|
||||||
|
@ -121,11 +141,25 @@ func (r *responseWriter) Write(p []byte) (int, error) {
|
||||||
return r.rw.Write(p)
|
return r.rw.Write(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable compression according to user wishes in excludedContentTypes.
|
// Disable compression according to user wishes in excludedContentTypes or includedContentTypes.
|
||||||
if ct := r.rw.Header().Get(contentType); ct != "" {
|
if ct := r.rw.Header().Get(contentType); ct != "" {
|
||||||
mediaType, params, err := mime.ParseMediaType(ct)
|
mediaType, params, err := mime.ParseMediaType(ct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("parsing media type: %w", err)
|
return 0, fmt.Errorf("parsing content-type media type: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.includedContentTypes) > 0 {
|
||||||
|
var found bool
|
||||||
|
for _, includedContentType := range r.includedContentTypes {
|
||||||
|
if includedContentType.equals(mediaType, params) {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
r.compressionDisabled = true
|
||||||
|
return r.rw.Write(p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, excludedContentType := range r.excludedContentTypes {
|
for _, excludedContentType := range r.excludedContentTypes {
|
||||||
|
|
|
@ -291,10 +291,9 @@ func Test_ExcludedContentTypes(t *testing.T) {
|
||||||
expCompression bool
|
expCompression bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "Always compress when content types are empty",
|
desc: "Always compress when content types are empty",
|
||||||
contentType: "",
|
contentType: "",
|
||||||
excludedContentTypes: []string{},
|
expCompression: true,
|
||||||
expCompression: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "MIME match",
|
desc: "MIME match",
|
||||||
|
@ -389,6 +388,111 @@ func Test_ExcludedContentTypes(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_IncludedContentTypes(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
contentType string
|
||||||
|
includedContentTypes []string
|
||||||
|
expCompression bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Always compress when content types are empty",
|
||||||
|
contentType: "",
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match",
|
||||||
|
contentType: "application/json",
|
||||||
|
includedContentTypes: []string{"application/json"},
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME no match",
|
||||||
|
contentType: "text/xml",
|
||||||
|
includedContentTypes: []string{"application/json"},
|
||||||
|
expCompression: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match with no other directive ignores non-MIME directives",
|
||||||
|
contentType: "application/json; charset=utf-8",
|
||||||
|
includedContentTypes: []string{"application/json"},
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match with other directives requires all directives be equal, different charset",
|
||||||
|
contentType: "application/json; charset=ascii",
|
||||||
|
includedContentTypes: []string{"application/json; charset=utf-8"},
|
||||||
|
expCompression: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match with other directives requires all directives be equal, same charset",
|
||||||
|
contentType: "application/json; charset=utf-8",
|
||||||
|
includedContentTypes: []string{"application/json; charset=utf-8"},
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match with other directives requires all directives be equal, missing charset",
|
||||||
|
contentType: "application/json",
|
||||||
|
includedContentTypes: []string{"application/json; charset=ascii"},
|
||||||
|
expCompression: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match case insensitive",
|
||||||
|
contentType: "Application/Json",
|
||||||
|
includedContentTypes: []string{"application/json"},
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match ignore whitespace",
|
||||||
|
contentType: "application/json;charset=utf-8",
|
||||||
|
includedContentTypes: []string{"application/json; charset=utf-8"},
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cfg := Config{
|
||||||
|
MinSize: 1024,
|
||||||
|
IncludedContentTypes: test.includedContentTypes,
|
||||||
|
}
|
||||||
|
h := mustNewWrapper(t, cfg)(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
rw.Header().Set(contentType, test.contentType)
|
||||||
|
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
_, err := rw.Write(bigTestBody)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}))
|
||||||
|
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, "/whatever", nil)
|
||||||
|
req.Header.Set(acceptEncoding, "br")
|
||||||
|
|
||||||
|
rw := httptest.NewRecorder()
|
||||||
|
h.ServeHTTP(rw, req)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, rw.Code)
|
||||||
|
|
||||||
|
if test.expCompression {
|
||||||
|
assert.Equal(t, "br", rw.Header().Get(contentEncoding))
|
||||||
|
|
||||||
|
got, err := io.ReadAll(brotli.NewReader(rw.Body))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, bigTestBody, got)
|
||||||
|
} else {
|
||||||
|
assert.NotEqual(t, "br", rw.Header().Get("Content-Encoding"))
|
||||||
|
|
||||||
|
got, err := io.ReadAll(rw.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, bigTestBody, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_FlushExcludedContentTypes(t *testing.T) {
|
func Test_FlushExcludedContentTypes(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
@ -397,10 +501,9 @@ func Test_FlushExcludedContentTypes(t *testing.T) {
|
||||||
expCompression bool
|
expCompression bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "Always compress when content types are empty",
|
desc: "Always compress when content types are empty",
|
||||||
contentType: "",
|
contentType: "",
|
||||||
excludedContentTypes: []string{},
|
expCompression: true,
|
||||||
expCompression: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "MIME match",
|
desc: "MIME match",
|
||||||
|
@ -509,6 +612,125 @@ func Test_FlushExcludedContentTypes(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_FlushIncludedContentTypes(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
contentType string
|
||||||
|
includedContentTypes []string
|
||||||
|
expCompression bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Always compress when content types are empty",
|
||||||
|
contentType: "",
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match",
|
||||||
|
contentType: "application/json",
|
||||||
|
includedContentTypes: []string{"application/json"},
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME no match",
|
||||||
|
contentType: "text/xml",
|
||||||
|
includedContentTypes: []string{"application/json"},
|
||||||
|
expCompression: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match with no other directive ignores non-MIME directives",
|
||||||
|
contentType: "application/json; charset=utf-8",
|
||||||
|
includedContentTypes: []string{"application/json"},
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match with other directives requires all directives be equal, different charset",
|
||||||
|
contentType: "application/json; charset=ascii",
|
||||||
|
includedContentTypes: []string{"application/json; charset=utf-8"},
|
||||||
|
expCompression: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match with other directives requires all directives be equal, same charset",
|
||||||
|
contentType: "application/json; charset=utf-8",
|
||||||
|
includedContentTypes: []string{"application/json; charset=utf-8"},
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match with other directives requires all directives be equal, missing charset",
|
||||||
|
contentType: "application/json",
|
||||||
|
includedContentTypes: []string{"application/json; charset=ascii"},
|
||||||
|
expCompression: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match case insensitive",
|
||||||
|
contentType: "Application/Json",
|
||||||
|
includedContentTypes: []string{"application/json"},
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME match ignore whitespace",
|
||||||
|
contentType: "application/json;charset=utf-8",
|
||||||
|
includedContentTypes: []string{"application/json; charset=utf-8"},
|
||||||
|
expCompression: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cfg := Config{
|
||||||
|
MinSize: 1024,
|
||||||
|
IncludedContentTypes: test.includedContentTypes,
|
||||||
|
}
|
||||||
|
h := mustNewWrapper(t, cfg)(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
rw.Header().Set(contentType, test.contentType)
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
tb := bigTestBody
|
||||||
|
for len(tb) > 0 {
|
||||||
|
// Write 100 bytes per run
|
||||||
|
// Detection should not be affected (we send 100 bytes)
|
||||||
|
toWrite := 100
|
||||||
|
if toWrite > len(tb) {
|
||||||
|
toWrite = len(tb)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := rw.Write(tb[:toWrite])
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Flush between each write
|
||||||
|
rw.(http.Flusher).Flush()
|
||||||
|
tb = tb[toWrite:]
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, "/whatever", nil)
|
||||||
|
req.Header.Set(acceptEncoding, "br")
|
||||||
|
|
||||||
|
// This doesn't allow checking flushes, but we validate if content is correct.
|
||||||
|
rw := httptest.NewRecorder()
|
||||||
|
h.ServeHTTP(rw, req)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, rw.Code)
|
||||||
|
|
||||||
|
if test.expCompression {
|
||||||
|
assert.Equal(t, "br", rw.Header().Get(contentEncoding))
|
||||||
|
|
||||||
|
got, err := io.ReadAll(brotli.NewReader(rw.Body))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, bigTestBody, got)
|
||||||
|
} else {
|
||||||
|
assert.NotEqual(t, "br", rw.Header().Get(contentEncoding))
|
||||||
|
|
||||||
|
got, err := io.ReadAll(rw.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, bigTestBody, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func mustNewWrapper(t *testing.T, cfg Config) func(http.Handler) http.HandlerFunc {
|
func mustNewWrapper(t *testing.T, cfg Config) func(http.Handler) http.HandlerFunc {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ type compress struct {
|
||||||
next http.Handler
|
next http.Handler
|
||||||
name string
|
name string
|
||||||
excludes []string
|
excludes []string
|
||||||
|
includes []string
|
||||||
minSize int
|
minSize int
|
||||||
|
|
||||||
brotliHandler http.Handler
|
brotliHandler http.Handler
|
||||||
|
@ -36,16 +37,30 @@ type compress struct {
|
||||||
func New(ctx context.Context, next http.Handler, conf dynamic.Compress, name string) (http.Handler, error) {
|
func New(ctx context.Context, next http.Handler, conf dynamic.Compress, name string) (http.Handler, error) {
|
||||||
middlewares.GetLogger(ctx, name, typeName).Debug().Msg("Creating middleware")
|
middlewares.GetLogger(ctx, name, typeName).Debug().Msg("Creating middleware")
|
||||||
|
|
||||||
|
if len(conf.ExcludedContentTypes) > 0 && len(conf.IncludedContentTypes) > 0 {
|
||||||
|
return nil, fmt.Errorf("excludedContentTypes and includedContentTypes options are mutually exclusive")
|
||||||
|
}
|
||||||
|
|
||||||
excludes := []string{"application/grpc"}
|
excludes := []string{"application/grpc"}
|
||||||
for _, v := range conf.ExcludedContentTypes {
|
for _, v := range conf.ExcludedContentTypes {
|
||||||
mediaType, _, err := mime.ParseMediaType(v)
|
mediaType, _, err := mime.ParseMediaType(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("parsing excluded media type: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
excludes = append(excludes, mediaType)
|
excludes = append(excludes, mediaType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var includes []string
|
||||||
|
for _, v := range conf.IncludedContentTypes {
|
||||||
|
mediaType, _, err := mime.ParseMediaType(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing included media type: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
includes = append(includes, mediaType)
|
||||||
|
}
|
||||||
|
|
||||||
minSize := DefaultMinSize
|
minSize := DefaultMinSize
|
||||||
if conf.MinResponseBodyBytes > 0 {
|
if conf.MinResponseBodyBytes > 0 {
|
||||||
minSize = conf.MinResponseBodyBytes
|
minSize = conf.MinResponseBodyBytes
|
||||||
|
@ -55,6 +70,7 @@ func New(ctx context.Context, next http.Handler, conf dynamic.Compress, name str
|
||||||
next: next,
|
next: next,
|
||||||
name: name,
|
name: name,
|
||||||
excludes: excludes,
|
excludes: excludes,
|
||||||
|
includes: includes,
|
||||||
minSize: minSize,
|
minSize: minSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,11 +108,11 @@ func (c *compress) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client allows us to do whatever we want, so we br compress.
|
// Client doesn't specify a preferred encoding, for compatibility don't encode the request
|
||||||
// See https://www.rfc-editor.org/rfc/rfc9110.html#section-12.5.3
|
// See https://github.com/traefik/traefik/issues/9734
|
||||||
acceptEncoding, ok := req.Header["Accept-Encoding"]
|
acceptEncoding, ok := req.Header["Accept-Encoding"]
|
||||||
if !ok {
|
if !ok {
|
||||||
c.brotliHandler.ServeHTTP(rw, req)
|
c.next.ServeHTTP(rw, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,10 +134,21 @@ func (c *compress) GetTracingInformation() (string, string, trace.SpanKind) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compress) newGzipHandler() (http.Handler, error) {
|
func (c *compress) newGzipHandler() (http.Handler, error) {
|
||||||
wrapper, err := gzhttp.NewWrapper(
|
var wrapper func(http.Handler) http.HandlerFunc
|
||||||
gzhttp.ExceptContentTypes(c.excludes),
|
var err error
|
||||||
gzhttp.MinSize(c.minSize),
|
|
||||||
)
|
if len(c.includes) > 0 {
|
||||||
|
wrapper, err = gzhttp.NewWrapper(
|
||||||
|
gzhttp.ContentTypes(c.includes),
|
||||||
|
gzhttp.MinSize(c.minSize),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
wrapper, err = gzhttp.NewWrapper(
|
||||||
|
gzhttp.ExceptContentTypes(c.excludes),
|
||||||
|
gzhttp.MinSize(c.minSize),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("new gzip wrapper: %w", err)
|
return nil, fmt.Errorf("new gzip wrapper: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -130,9 +157,11 @@ func (c *compress) newGzipHandler() (http.Handler, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compress) newBrotliHandler() (http.Handler, error) {
|
func (c *compress) newBrotliHandler() (http.Handler, error) {
|
||||||
cfg := brotli.Config{
|
cfg := brotli.Config{MinSize: c.minSize}
|
||||||
ExcludedContentTypes: c.excludes,
|
if len(c.includes) > 0 {
|
||||||
MinSize: c.minSize,
|
cfg.IncludedContentTypes = c.includes
|
||||||
|
} else {
|
||||||
|
cfg.ExcludedContentTypes = c.excludes
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapper, err := brotli.NewWrapper(cfg)
|
wrapper, err := brotli.NewWrapper(cfg)
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/andybalholm/brotli"
|
|
||||||
"github.com/klauspost/compress/gzhttp"
|
"github.com/klauspost/compress/gzhttp"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -35,7 +34,7 @@ func TestNegotiation(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "no accept header",
|
desc: "no accept header",
|
||||||
expEncoding: "br",
|
expEncoding: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "unsupported accept header",
|
desc: "unsupported accept header",
|
||||||
|
@ -151,7 +150,7 @@ func TestShouldNotCompressWhenContentEncodingHeader(t *testing.T) {
|
||||||
assert.EqualValues(t, rw.Body.Bytes(), fakeCompressedBody)
|
assert.EqualValues(t, rw.Body.Bytes(), fakeCompressedBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldCompressWhenNoAcceptEncodingHeader(t *testing.T) {
|
func TestShouldNotCompressWhenNoAcceptEncodingHeader(t *testing.T) {
|
||||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
||||||
|
|
||||||
fakeBody := generateBytes(gzhttp.DefaultMinSize)
|
fakeBody := generateBytes(gzhttp.DefaultMinSize)
|
||||||
|
@ -167,12 +166,9 @@ func TestShouldCompressWhenNoAcceptEncodingHeader(t *testing.T) {
|
||||||
rw := httptest.NewRecorder()
|
rw := httptest.NewRecorder()
|
||||||
handler.ServeHTTP(rw, req)
|
handler.ServeHTTP(rw, req)
|
||||||
|
|
||||||
assert.Equal(t, brotliValue, rw.Header().Get(contentEncodingHeader))
|
assert.Empty(t, rw.Header().Get(contentEncodingHeader))
|
||||||
assert.Equal(t, acceptEncodingHeader, rw.Header().Get(varyHeader))
|
assert.Empty(t, rw.Header().Get(varyHeader))
|
||||||
|
assert.EqualValues(t, rw.Body.Bytes(), fakeBody)
|
||||||
got, err := io.ReadAll(brotli.NewReader(rw.Body))
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, got, fakeBody)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldNotCompressWhenIdentityAcceptEncodingHeader(t *testing.T) {
|
func TestShouldNotCompressWhenIdentityAcceptEncodingHeader(t *testing.T) {
|
||||||
|
@ -275,7 +271,28 @@ func TestShouldNotCompressWhenSpecificContentType(t *testing.T) {
|
||||||
respContentType: "text/event-stream",
|
respContentType: "text/event-stream",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "application/grpc",
|
desc: "Include Response Content-Type",
|
||||||
|
conf: dynamic.Compress{
|
||||||
|
IncludedContentTypes: []string{"text/plain"},
|
||||||
|
},
|
||||||
|
respContentType: "text/html",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Ignoring application/grpc with exclude option",
|
||||||
|
conf: dynamic.Compress{
|
||||||
|
ExcludedContentTypes: []string{"application/json"},
|
||||||
|
},
|
||||||
|
reqContentType: "application/grpc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Ignoring application/grpc with include option",
|
||||||
|
conf: dynamic.Compress{
|
||||||
|
IncludedContentTypes: []string{"application/json"},
|
||||||
|
},
|
||||||
|
reqContentType: "application/grpc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Ignoring application/grpc with no option",
|
||||||
conf: dynamic.Compress{},
|
conf: dynamic.Compress{},
|
||||||
reqContentType: "application/grpc",
|
reqContentType: "application/grpc",
|
||||||
},
|
},
|
||||||
|
@ -316,6 +333,52 @@ func TestShouldNotCompressWhenSpecificContentType(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShouldCompressWhenSpecificContentType(t *testing.T) {
|
||||||
|
baseBody := generateBytes(gzhttp.DefaultMinSize)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
conf dynamic.Compress
|
||||||
|
respContentType string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Include Response Content-Type",
|
||||||
|
conf: dynamic.Compress{
|
||||||
|
IncludedContentTypes: []string{"text/html"},
|
||||||
|
},
|
||||||
|
respContentType: "text/html",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
||||||
|
req.Header.Add(acceptEncodingHeader, gzipValue)
|
||||||
|
|
||||||
|
next := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
rw.Header().Set(contentTypeHeader, test.respContentType)
|
||||||
|
|
||||||
|
if _, err := rw.Write(baseBody); err != nil {
|
||||||
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
handler, err := New(context.Background(), next, test.conf, "test")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
rw := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(rw, req)
|
||||||
|
|
||||||
|
assert.Equal(t, gzipValue, rw.Header().Get(contentEncodingHeader))
|
||||||
|
assert.Equal(t, acceptEncodingHeader, rw.Header().Get(varyHeader))
|
||||||
|
assert.NotEqualValues(t, rw.Body.Bytes(), baseBody)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIntegrationShouldNotCompress(t *testing.T) {
|
func TestIntegrationShouldNotCompress(t *testing.T) {
|
||||||
fakeCompressedBody := generateBytes(100000)
|
fakeCompressedBody := generateBytes(100000)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/middlewares"
|
||||||
"github.com/vulcand/oxy/v2/forward"
|
"github.com/vulcand/oxy/v2/forward"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ func (s *Header) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
// If there is a next, call it.
|
// If there is a next, call it.
|
||||||
if s.next != nil {
|
if s.next != nil {
|
||||||
s.next.ServeHTTP(newResponseModifier(rw, req, s.PostRequestModifyResponseHeaders), req)
|
s.next.ServeHTTP(middlewares.NewResponseModifier(rw, req, s.PostRequestModifyResponseHeaders), req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/middlewares"
|
||||||
"github.com/unrolled/secure"
|
"github.com/unrolled/secure"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,6 +46,6 @@ func newSecure(next http.Handler, cfg dynamic.Headers, contextKey string) *secur
|
||||||
|
|
||||||
func (s secureHeader) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
func (s secureHeader) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
s.secure.HandlerFuncWithNextForRequestOnly(rw, req, func(writer http.ResponseWriter, request *http.Request) {
|
s.secure.HandlerFuncWithNextForRequestOnly(rw, req, func(writer http.ResponseWriter, request *http.Request) {
|
||||||
s.next.ServeHTTP(newResponseModifier(writer, request, s.secure.ModifyResponseHeaders), request)
|
s.next.ServeHTTP(middlewares.NewResponseModifier(writer, request, s.secure.ModifyResponseHeaders), request)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package headers
|
package middlewares
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
@ -9,7 +9,8 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type responseModifier struct {
|
// ResponseModifier is a ResponseWriter to modify the response headers before sending them.
|
||||||
|
type ResponseModifier struct {
|
||||||
req *http.Request
|
req *http.Request
|
||||||
rw http.ResponseWriter
|
rw http.ResponseWriter
|
||||||
|
|
||||||
|
@ -21,9 +22,10 @@ type responseModifier struct {
|
||||||
modifierErr error // returned by modifier call
|
modifierErr error // returned by modifier call
|
||||||
}
|
}
|
||||||
|
|
||||||
// modifier can be nil.
|
// NewResponseModifier returns a new ResponseModifier instance.
|
||||||
func newResponseModifier(w http.ResponseWriter, r *http.Request, modifier func(*http.Response) error) http.ResponseWriter {
|
// The given modifier can be nil.
|
||||||
return &responseModifier{
|
func NewResponseModifier(w http.ResponseWriter, r *http.Request, modifier func(*http.Response) error) http.ResponseWriter {
|
||||||
|
return &ResponseModifier{
|
||||||
req: r,
|
req: r,
|
||||||
rw: w,
|
rw: w,
|
||||||
modifier: modifier,
|
modifier: modifier,
|
||||||
|
@ -33,7 +35,7 @@ func newResponseModifier(w http.ResponseWriter, r *http.Request, modifier func(*
|
||||||
|
|
||||||
// WriteHeader is, in the specific case of 1xx status codes, a direct call to the wrapped ResponseWriter, without marking headers as sent,
|
// WriteHeader is, in the specific case of 1xx status codes, a direct call to the wrapped ResponseWriter, without marking headers as sent,
|
||||||
// allowing so further calls.
|
// allowing so further calls.
|
||||||
func (r *responseModifier) WriteHeader(code int) {
|
func (r *ResponseModifier) WriteHeader(code int) {
|
||||||
if r.headersSent {
|
if r.headersSent {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -73,11 +75,11 @@ func (r *responseModifier) WriteHeader(code int) {
|
||||||
r.rw.WriteHeader(code)
|
r.rw.WriteHeader(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *responseModifier) Header() http.Header {
|
func (r *ResponseModifier) Header() http.Header {
|
||||||
return r.rw.Header()
|
return r.rw.Header()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *responseModifier) Write(b []byte) (int, error) {
|
func (r *ResponseModifier) Write(b []byte) (int, error) {
|
||||||
r.WriteHeader(r.code)
|
r.WriteHeader(r.code)
|
||||||
if r.modifierErr != nil {
|
if r.modifierErr != nil {
|
||||||
return 0, r.modifierErr
|
return 0, r.modifierErr
|
||||||
|
@ -87,7 +89,7 @@ func (r *responseModifier) Write(b []byte) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hijack hijacks the connection.
|
// Hijack hijacks the connection.
|
||||||
func (r *responseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
func (r *ResponseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
if h, ok := r.rw.(http.Hijacker); ok {
|
if h, ok := r.rw.(http.Hijacker); ok {
|
||||||
return h.Hijack()
|
return h.Hijack()
|
||||||
}
|
}
|
||||||
|
@ -96,7 +98,7 @@ func (r *responseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush sends any buffered data to the client.
|
// Flush sends any buffered data to the client.
|
||||||
func (r *responseModifier) Flush() {
|
func (r *ResponseModifier) Flush() {
|
||||||
if flusher, ok := r.rw.(http.Flusher); ok {
|
if flusher, ok := r.rw.(http.Flusher); ok {
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
}
|
}
|
|
@ -73,7 +73,7 @@ func TestClientIPMatcher(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -147,7 +147,7 @@ func TestMethodMatcher(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -265,7 +265,7 @@ func TestHostMatcher(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -365,7 +365,7 @@ func TestHostRegexpMatcher(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -439,7 +439,7 @@ func TestPathMatcher(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -532,7 +532,7 @@ func TestPathRegexpMatcher(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -604,7 +604,7 @@ func TestPathPrefixMatcher(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -692,7 +692,7 @@ func TestHeaderMatcher(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -800,7 +800,7 @@ func TestHeaderRegexpMatcher(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -889,7 +889,7 @@ func TestQueryMatcher(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -1003,7 +1003,7 @@ func TestQueryRegexpMatcher(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
|
226
pkg/muxer/http/matcher_v2.go
Normal file
226
pkg/muxer/http/matcher_v2.go
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/ip"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/middlewares/requestdecorator"
|
||||||
|
)
|
||||||
|
|
||||||
|
var httpFuncsV2 = map[string]func(*matchersTree, ...string) error{
|
||||||
|
"Host": hostV2,
|
||||||
|
"HostHeader": hostV2,
|
||||||
|
"HostRegexp": hostRegexpV2,
|
||||||
|
"ClientIP": clientIPV2,
|
||||||
|
"Path": pathV2,
|
||||||
|
"PathPrefix": pathPrefixV2,
|
||||||
|
"Method": methodsV2,
|
||||||
|
"Headers": headersV2,
|
||||||
|
"HeadersRegexp": headersRegexpV2,
|
||||||
|
"Query": queryV2,
|
||||||
|
}
|
||||||
|
|
||||||
|
func pathV2(tree *matchersTree, paths ...string) error {
|
||||||
|
for _, path := range paths {
|
||||||
|
if !strings.HasPrefix(path, "/") {
|
||||||
|
return fmt.Errorf("path %q does not start with a '/'", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(req *http.Request) bool {
|
||||||
|
for _, path := range paths {
|
||||||
|
if req.URL.Path == path {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func pathPrefixV2(tree *matchersTree, paths ...string) error {
|
||||||
|
for _, path := range paths {
|
||||||
|
if !strings.HasPrefix(path, "/") {
|
||||||
|
return fmt.Errorf("path %q does not start with a '/'", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(req *http.Request) bool {
|
||||||
|
for _, path := range paths {
|
||||||
|
if strings.HasPrefix(req.URL.Path, path) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hostV2(tree *matchersTree, hosts ...string) error {
|
||||||
|
for i, host := range hosts {
|
||||||
|
if !IsASCII(host) {
|
||||||
|
return fmt.Errorf("invalid value %q for \"Host\" matcher, non-ASCII characters are not allowed", host)
|
||||||
|
}
|
||||||
|
|
||||||
|
hosts[i] = strings.ToLower(host)
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(req *http.Request) bool {
|
||||||
|
reqHost := requestdecorator.GetCanonizedHost(req.Context())
|
||||||
|
if len(reqHost) == 0 {
|
||||||
|
// If the request is an HTTP/1.0 request, then a Host may not be defined.
|
||||||
|
if req.ProtoAtLeast(1, 1) {
|
||||||
|
log.Ctx(req.Context()).Warn().Msgf("Could not retrieve CanonizedHost, rejecting %s", req.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
flatH := requestdecorator.GetCNAMEFlatten(req.Context())
|
||||||
|
if len(flatH) > 0 {
|
||||||
|
for _, host := range hosts {
|
||||||
|
if strings.EqualFold(reqHost, host) || strings.EqualFold(flatH, host) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
log.Ctx(req.Context()).Debug().Msgf("CNAMEFlattening: request %s which resolved to %s, is not matched to route %s", reqHost, flatH, host)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, host := range hosts {
|
||||||
|
if reqHost == host {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for match on trailing period on host
|
||||||
|
if last := len(host) - 1; last >= 0 && host[last] == '.' {
|
||||||
|
h := host[:last]
|
||||||
|
if reqHost == h {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for match on trailing period on request
|
||||||
|
if last := len(reqHost) - 1; last >= 0 && reqHost[last] == '.' {
|
||||||
|
h := reqHost[:last]
|
||||||
|
if h == host {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientIPV2(tree *matchersTree, clientIPs ...string) error {
|
||||||
|
checker, err := ip.NewChecker(clientIPs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not initialize IP Checker for \"ClientIP\" matcher: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
strategy := ip.RemoteAddrStrategy{}
|
||||||
|
|
||||||
|
tree.matcher = func(req *http.Request) bool {
|
||||||
|
ok, err := checker.Contains(strategy.GetIP(req))
|
||||||
|
if err != nil {
|
||||||
|
log.Ctx(req.Context()).Warn().Err(err).Msg("\"ClientIP\" matcher: could not match remote address")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func methodsV2(tree *matchersTree, methods ...string) error {
|
||||||
|
route := mux.NewRouter().NewRoute()
|
||||||
|
route.Methods(methods...)
|
||||||
|
if err := route.GetError(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(req *http.Request) bool {
|
||||||
|
return route.Match(req, &mux.RouteMatch{})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func headersV2(tree *matchersTree, headers ...string) error {
|
||||||
|
route := mux.NewRouter().NewRoute()
|
||||||
|
route.Headers(headers...)
|
||||||
|
if err := route.GetError(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(req *http.Request) bool {
|
||||||
|
return route.Match(req, &mux.RouteMatch{})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryV2(tree *matchersTree, query ...string) error {
|
||||||
|
var queries []string
|
||||||
|
for _, elem := range query {
|
||||||
|
queries = append(queries, strings.SplitN(elem, "=", 2)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
route := mux.NewRouter().NewRoute()
|
||||||
|
route.Queries(queries...)
|
||||||
|
if err := route.GetError(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(req *http.Request) bool {
|
||||||
|
return route.Match(req, &mux.RouteMatch{})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hostRegexpV2(tree *matchersTree, hosts ...string) error {
|
||||||
|
router := mux.NewRouter()
|
||||||
|
|
||||||
|
for _, host := range hosts {
|
||||||
|
if !IsASCII(host) {
|
||||||
|
return fmt.Errorf("invalid value %q for HostRegexp matcher, non-ASCII characters are not allowed", host)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpRt := router.Host(host)
|
||||||
|
if tmpRt.GetError() != nil {
|
||||||
|
return tmpRt.GetError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(req *http.Request) bool {
|
||||||
|
return router.Match(req, &mux.RouteMatch{})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func headersRegexpV2(tree *matchersTree, headers ...string) error {
|
||||||
|
route := mux.NewRouter().NewRoute()
|
||||||
|
route.HeadersRegexp(headers...)
|
||||||
|
if err := route.GetError(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(req *http.Request) bool {
|
||||||
|
return route.Match(req, &mux.RouteMatch{})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
1535
pkg/muxer/http/matcher_v2_test.go
Normal file
1535
pkg/muxer/http/matcher_v2_test.go
Normal file
File diff suppressed because it is too large
Load diff
|
@ -12,8 +12,9 @@ import (
|
||||||
|
|
||||||
// Muxer handles routing with rules.
|
// Muxer handles routing with rules.
|
||||||
type Muxer struct {
|
type Muxer struct {
|
||||||
routes routes
|
routes routes
|
||||||
parser predicate.Parser
|
parser predicate.Parser
|
||||||
|
parserV2 predicate.Parser
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMuxer returns a new muxer instance.
|
// NewMuxer returns a new muxer instance.
|
||||||
|
@ -28,8 +29,19 @@ func NewMuxer() (*Muxer, error) {
|
||||||
return nil, fmt.Errorf("error while creating parser: %w", err)
|
return nil, fmt.Errorf("error while creating parser: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var matchersV2 []string
|
||||||
|
for matcher := range httpFuncsV2 {
|
||||||
|
matchersV2 = append(matchersV2, matcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
parserV2, err := rules.NewParser(matchersV2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error while creating v2 parser: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &Muxer{
|
return &Muxer{
|
||||||
parser: parser,
|
parser: parser,
|
||||||
|
parserV2: parserV2,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,10 +65,26 @@ func GetRulePriority(rule string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRoute add a new route to the router.
|
// AddRoute add a new route to the router.
|
||||||
func (m *Muxer) AddRoute(rule string, priority int, handler http.Handler) error {
|
func (m *Muxer) AddRoute(rule string, syntax string, priority int, handler http.Handler) error {
|
||||||
parse, err := m.parser.Parse(rule)
|
var parse interface{}
|
||||||
if err != nil {
|
var err error
|
||||||
return fmt.Errorf("error while parsing rule %s: %w", rule, err)
|
var matcherFuncs map[string]func(*matchersTree, ...string) error
|
||||||
|
|
||||||
|
switch syntax {
|
||||||
|
case "v2":
|
||||||
|
parse, err = m.parserV2.Parse(rule)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while parsing rule %s: %w", rule, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
matcherFuncs = httpFuncsV2
|
||||||
|
default:
|
||||||
|
parse, err = m.parser.Parse(rule)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while parsing rule %s: %w", rule, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
matcherFuncs = httpFuncs
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTree, ok := parse.(rules.TreeBuilder)
|
buildTree, ok := parse.(rules.TreeBuilder)
|
||||||
|
@ -65,7 +93,7 @@ func (m *Muxer) AddRoute(rule string, priority int, handler http.Handler) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var matchers matchersTree
|
var matchers matchersTree
|
||||||
err = matchers.addRule(buildTree())
|
err = matchers.addRule(buildTree(), matcherFuncs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error while adding rule %s: %w", rule, err)
|
return fmt.Errorf("error while adding rule %s: %w", rule, err)
|
||||||
}
|
}
|
||||||
|
@ -87,6 +115,9 @@ func ParseDomains(rule string) ([]string, error) {
|
||||||
for matcher := range httpFuncs {
|
for matcher := range httpFuncs {
|
||||||
matchers = append(matchers, matcher)
|
matchers = append(matchers, matcher)
|
||||||
}
|
}
|
||||||
|
for matcher := range httpFuncsV2 {
|
||||||
|
matchers = append(matchers, matcher)
|
||||||
|
}
|
||||||
|
|
||||||
parser, err := rules.NewParser(matchers)
|
parser, err := rules.NewParser(matchers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -166,25 +197,27 @@ func (m *matchersTree) match(req *http.Request) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *matchersTree) addRule(rule *rules.Tree) error {
|
type matcherFuncs map[string]func(*matchersTree, ...string) error
|
||||||
|
|
||||||
|
func (m *matchersTree) addRule(rule *rules.Tree, funcs matcherFuncs) error {
|
||||||
switch rule.Matcher {
|
switch rule.Matcher {
|
||||||
case "and", "or":
|
case "and", "or":
|
||||||
m.operator = rule.Matcher
|
m.operator = rule.Matcher
|
||||||
m.left = &matchersTree{}
|
m.left = &matchersTree{}
|
||||||
err := m.left.addRule(rule.RuleLeft)
|
err := m.left.addRule(rule.RuleLeft, funcs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error while adding rule %s: %w", rule.Matcher, err)
|
return fmt.Errorf("error while adding rule %s: %w", rule.Matcher, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.right = &matchersTree{}
|
m.right = &matchersTree{}
|
||||||
return m.right.addRule(rule.RuleRight)
|
return m.right.addRule(rule.RuleRight, funcs)
|
||||||
default:
|
default:
|
||||||
err := rules.CheckRule(rule)
|
err := rules.CheckRule(rule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error while checking rule %s: %w", rule.Matcher, err)
|
return fmt.Errorf("error while checking rule %s: %w", rule.Matcher, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = httpFuncs[rule.Matcher](m, rule.Value...)
|
err = funcs[rule.Matcher](m, rule.Value...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error while adding rule %s: %w", rule.Matcher, err)
|
return fmt.Errorf("error while adding rule %s: %w", rule.Matcher, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ func TestMuxer(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.expectedError {
|
if test.expectedError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -394,7 +394,7 @@ func Test_addRoutePriority(t *testing.T) {
|
||||||
route.priority = GetRulePriority(route.rule)
|
route.priority = GetRulePriority(route.rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := muxer.AddRoute(route.rule, route.priority, handler)
|
err := muxer.AddRoute(route.rule, "", route.priority, handler)
|
||||||
require.NoError(t, err, route.rule)
|
require.NoError(t, err, route.rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,7 +519,7 @@ func TestEmptyHost(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, handler)
|
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// RequestDecorator is necessary for the host rule
|
// RequestDecorator is necessary for the host rule
|
||||||
|
|
|
@ -38,7 +38,7 @@ func Test_HostSNICatchAll(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
|
err = muxer.AddRoute(test.rule, "", 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
handler, catchAll := muxer.Match(ConnData{
|
handler, catchAll := muxer.Match(ConnData{
|
||||||
|
@ -144,7 +144,7 @@ func Test_HostSNI(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
|
err = muxer.AddRoute(test.rule, "", 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
|
||||||
if test.buildErr {
|
if test.buildErr {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -227,7 +227,7 @@ func Test_HostSNIRegexp(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
|
err = muxer.AddRoute(test.rule, "", 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
|
||||||
if test.buildErr {
|
if test.buildErr {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -299,7 +299,7 @@ func Test_ClientIP(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
|
err = muxer.AddRoute(test.rule, "", 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
|
||||||
if test.buildErr {
|
if test.buildErr {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -363,7 +363,7 @@ func Test_ALPN(t *testing.T) {
|
||||||
muxer, err := NewMuxer()
|
muxer, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = muxer.AddRoute(test.rule, 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
|
err = muxer.AddRoute(test.rule, "", 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
|
||||||
if test.buildErr {
|
if test.buildErr {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
|
240
pkg/muxer/tcp/matcher_v2.go
Normal file
240
pkg/muxer/tcp/matcher_v2.go
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
package tcp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/challenge/tlsalpn01"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/ip"
|
||||||
|
)
|
||||||
|
|
||||||
|
var tcpFuncsV2 = map[string]func(*matchersTree, ...string) error{
|
||||||
|
"ALPN": alpnV2,
|
||||||
|
"ClientIP": clientIPV2,
|
||||||
|
"HostSNI": hostSNIV2,
|
||||||
|
"HostSNIRegexp": hostSNIRegexpV2,
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientIPV2(tree *matchersTree, clientIPs ...string) error {
|
||||||
|
checker, err := ip.NewChecker(clientIPs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not initialize IP Checker for \"ClientIP\" matcher: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(meta ConnData) bool {
|
||||||
|
if meta.remoteIP == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := checker.Contains(meta.remoteIP)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Msg("ClientIP matcher: could not match remote address")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// alpnV2 checks if any of the connection ALPN protocols matches one of the matcher protocols.
|
||||||
|
func alpnV2(tree *matchersTree, protos ...string) error {
|
||||||
|
if len(protos) == 0 {
|
||||||
|
return errors.New("empty value for \"ALPN\" matcher is not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, proto := range protos {
|
||||||
|
if proto == tlsalpn01.ACMETLS1Protocol {
|
||||||
|
return fmt.Errorf("invalid protocol value for \"ALPN\" matcher, %q is not allowed", proto)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(meta ConnData) bool {
|
||||||
|
for _, proto := range meta.alpnProtos {
|
||||||
|
for _, filter := range protos {
|
||||||
|
if proto == filter {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hostSNIV2 checks if the SNI Host of the connection match the matcher host.
|
||||||
|
func hostSNIV2(tree *matchersTree, hosts ...string) error {
|
||||||
|
if len(hosts) == 0 {
|
||||||
|
return errors.New("empty value for \"HostSNI\" matcher is not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, host := range hosts {
|
||||||
|
// Special case to allow global wildcard
|
||||||
|
if host == "*" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hostOrIP.MatchString(host) {
|
||||||
|
return fmt.Errorf("invalid value for \"HostSNI\" matcher, %q is not a valid hostname or IP", host)
|
||||||
|
}
|
||||||
|
|
||||||
|
hosts[i] = strings.ToLower(host)
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(meta ConnData) bool {
|
||||||
|
// Since a HostSNI(`*`) rule has been provided as catchAll for non-TLS TCP,
|
||||||
|
// it allows matching with an empty serverName.
|
||||||
|
// Which is why we make sure to take that case into account before
|
||||||
|
// checking meta.serverName.
|
||||||
|
if hosts[0] == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if meta.serverName == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, host := range hosts {
|
||||||
|
if host == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if host == meta.serverName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim trailing period in case of FQDN
|
||||||
|
host = strings.TrimSuffix(host, ".")
|
||||||
|
if host == meta.serverName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hostSNIRegexpV2 checks if the SNI Host of the connection matches the matcher host regexp.
|
||||||
|
func hostSNIRegexpV2(tree *matchersTree, templates ...string) error {
|
||||||
|
if len(templates) == 0 {
|
||||||
|
return fmt.Errorf("empty value for \"HostSNIRegexp\" matcher is not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
var regexps []*regexp.Regexp
|
||||||
|
|
||||||
|
for _, template := range templates {
|
||||||
|
preparedPattern, err := preparePattern(template)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid pattern value for \"HostSNIRegexp\" matcher, %q is not a valid pattern: %w", template, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
regexp, err := regexp.Compile(preparedPattern)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
regexps = append(regexps, regexp)
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.matcher = func(meta ConnData) bool {
|
||||||
|
for _, regexp := range regexps {
|
||||||
|
if regexp.MatchString(meta.serverName) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// preparePattern builds a regexp pattern from the initial user defined expression.
|
||||||
|
// This function reuses the code dedicated to host matching of the newRouteRegexp func from the gorilla/mux library.
|
||||||
|
// https://github.com/containous/mux/tree/8ffa4f6d063c1e2b834a73be6a1515cca3992618.
|
||||||
|
func preparePattern(template string) (string, error) {
|
||||||
|
// Check if it is well-formed.
|
||||||
|
idxs, errBraces := braceIndices(template)
|
||||||
|
if errBraces != nil {
|
||||||
|
return "", errBraces
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultPattern := "[^.]+"
|
||||||
|
pattern := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
// Host SNI matching is case-insensitive
|
||||||
|
_, _ = fmt.Fprint(pattern, "(?i)")
|
||||||
|
|
||||||
|
pattern.WriteByte('^')
|
||||||
|
var end int
|
||||||
|
for i := 0; i < len(idxs); i += 2 {
|
||||||
|
// Set all values we are interested in.
|
||||||
|
raw := template[end:idxs[i]]
|
||||||
|
end = idxs[i+1]
|
||||||
|
parts := strings.SplitN(template[idxs[i]+1:end-1], ":", 2)
|
||||||
|
name := parts[0]
|
||||||
|
|
||||||
|
patt := defaultPattern
|
||||||
|
if len(parts) == 2 {
|
||||||
|
patt = parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name or pattern can't be empty.
|
||||||
|
if name == "" || patt == "" {
|
||||||
|
return "", fmt.Errorf("mux: missing name or pattern in %q",
|
||||||
|
template[idxs[i]:end])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the regexp pattern.
|
||||||
|
_, _ = fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the remaining.
|
||||||
|
raw := template[end:]
|
||||||
|
pattern.WriteString(regexp.QuoteMeta(raw))
|
||||||
|
pattern.WriteByte('$')
|
||||||
|
|
||||||
|
return pattern.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// varGroupName builds a capturing group name for the indexed variable.
|
||||||
|
// This function is a copy of varGroupName func from the gorilla/mux library.
|
||||||
|
// https://github.com/containous/mux/tree/8ffa4f6d063c1e2b834a73be6a1515cca3992618.
|
||||||
|
func varGroupName(idx int) string {
|
||||||
|
return "v" + strconv.Itoa(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// braceIndices returns the first level curly brace indices from a string.
|
||||||
|
// This function is a copy of braceIndices func from the gorilla/mux library.
|
||||||
|
// https://github.com/containous/mux/tree/8ffa4f6d063c1e2b834a73be6a1515cca3992618.
|
||||||
|
func braceIndices(s string) ([]int, error) {
|
||||||
|
var level, idx int
|
||||||
|
var idxs []int
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
switch s[i] {
|
||||||
|
case '{':
|
||||||
|
if level++; level == 1 {
|
||||||
|
idx = i
|
||||||
|
}
|
||||||
|
case '}':
|
||||||
|
if level--; level == 0 {
|
||||||
|
idxs = append(idxs, idx, i+1)
|
||||||
|
} else if level < 0 {
|
||||||
|
return nil, fmt.Errorf("mux: unbalanced braces in %q", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if level != 0 {
|
||||||
|
return nil, fmt.Errorf("mux: unbalanced braces in %q", s)
|
||||||
|
}
|
||||||
|
return idxs, nil
|
||||||
|
}
|
1008
pkg/muxer/tcp/matcher_v2_test.go
Normal file
1008
pkg/muxer/tcp/matcher_v2_test.go
Normal file
File diff suppressed because it is too large
Load diff
|
@ -41,8 +41,9 @@ func NewConnData(serverName string, conn tcp.WriteCloser, alpnProtos []string) (
|
||||||
|
|
||||||
// Muxer defines a muxer that handles TCP routing with rules.
|
// Muxer defines a muxer that handles TCP routing with rules.
|
||||||
type Muxer struct {
|
type Muxer struct {
|
||||||
routes routes
|
routes routes
|
||||||
parser predicate.Parser
|
parser predicate.Parser
|
||||||
|
parserV2 predicate.Parser
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMuxer returns a TCP muxer.
|
// NewMuxer returns a TCP muxer.
|
||||||
|
@ -57,7 +58,20 @@ func NewMuxer() (*Muxer, error) {
|
||||||
return nil, fmt.Errorf("error while creating rules parser: %w", err)
|
return nil, fmt.Errorf("error while creating rules parser: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Muxer{parser: parser}, nil
|
var matchersV2 []string
|
||||||
|
for matcher := range tcpFuncsV2 {
|
||||||
|
matchersV2 = append(matchersV2, matcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
parserV2, err := rules.NewParser(matchersV2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error while creating v2 rules parser: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Muxer{
|
||||||
|
parser: parser,
|
||||||
|
parserV2: parserV2,
|
||||||
|
}, 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,
|
||||||
|
@ -106,10 +120,26 @@ func GetRulePriority(rule string) int {
|
||||||
|
|
||||||
// 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, syntax string, priority int, handler tcp.Handler) error {
|
||||||
parse, err := m.parser.Parse(rule)
|
var parse interface{}
|
||||||
if err != nil {
|
var err error
|
||||||
return fmt.Errorf("error while parsing rule %s: %w", rule, err)
|
var matcherFuncs map[string]func(*matchersTree, ...string) error
|
||||||
|
|
||||||
|
switch syntax {
|
||||||
|
case "v2":
|
||||||
|
parse, err = m.parserV2.Parse(rule)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while parsing rule %s: %w", rule, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
matcherFuncs = tcpFuncsV2
|
||||||
|
default:
|
||||||
|
parse, err = m.parser.Parse(rule)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while parsing rule %s: %w", rule, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
matcherFuncs = tcpFuncs
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTree, ok := parse.(rules.TreeBuilder)
|
buildTree, ok := parse.(rules.TreeBuilder)
|
||||||
|
@ -120,7 +150,7 @@ func (m *Muxer) AddRoute(rule string, priority int, handler tcp.Handler) error {
|
||||||
ruleTree := buildTree()
|
ruleTree := buildTree()
|
||||||
|
|
||||||
var matchers matchersTree
|
var matchers matchersTree
|
||||||
err = matchers.addRule(ruleTree)
|
err = matchers.addRule(ruleTree, matcherFuncs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error while adding rule %s: %w", rule, err)
|
return fmt.Errorf("error while adding rule %s: %w", rule, err)
|
||||||
}
|
}
|
||||||
|
@ -155,6 +185,9 @@ func ParseHostSNI(rule string) ([]string, error) {
|
||||||
for matcher := range tcpFuncs {
|
for matcher := range tcpFuncs {
|
||||||
matchers = append(matchers, matcher)
|
matchers = append(matchers, matcher)
|
||||||
}
|
}
|
||||||
|
for matcher := range tcpFuncsV2 {
|
||||||
|
matchers = append(matchers, matcher)
|
||||||
|
}
|
||||||
|
|
||||||
parser, err := rules.NewParser(matchers)
|
parser, err := rules.NewParser(matchers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -237,25 +270,27 @@ func (m *matchersTree) match(meta ConnData) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *matchersTree) addRule(rule *rules.Tree) error {
|
type matcherFuncs map[string]func(*matchersTree, ...string) error
|
||||||
|
|
||||||
|
func (m *matchersTree) addRule(rule *rules.Tree, funcs matcherFuncs) error {
|
||||||
switch rule.Matcher {
|
switch rule.Matcher {
|
||||||
case "and", "or":
|
case "and", "or":
|
||||||
m.operator = rule.Matcher
|
m.operator = rule.Matcher
|
||||||
m.left = &matchersTree{}
|
m.left = &matchersTree{}
|
||||||
err := m.left.addRule(rule.RuleLeft)
|
err := m.left.addRule(rule.RuleLeft, funcs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.right = &matchersTree{}
|
m.right = &matchersTree{}
|
||||||
return m.right.addRule(rule.RuleRight)
|
return m.right.addRule(rule.RuleRight, funcs)
|
||||||
default:
|
default:
|
||||||
err := rules.CheckRule(rule)
|
err := rules.CheckRule(rule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tcpFuncs[rule.Matcher](m, rule.Value...)
|
err = funcs[rule.Matcher](m, rule.Value...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -277,7 +277,7 @@ func Test_addTCPRoute(t *testing.T) {
|
||||||
router, err := NewMuxer()
|
router, err := NewMuxer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = router.AddRoute(test.rule, 0, handler)
|
err = router.AddRoute(test.rule, "", 0, handler)
|
||||||
if test.routeErr {
|
if test.routeErr {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -447,7 +447,7 @@ func Test_Priority(t *testing.T) {
|
||||||
matchedRule := ""
|
matchedRule := ""
|
||||||
for rule, priority := range test.rules {
|
for rule, priority := range test.rules {
|
||||||
rule := rule
|
rule := rule
|
||||||
err := muxer.AddRoute(rule, priority, tcp.HandlerFunc(func(conn tcp.WriteCloser) {
|
err := muxer.AddRoute(rule, "", priority, tcp.HandlerFunc(func(conn tcp.WriteCloser) {
|
||||||
matchedRule = rule
|
matchedRule = rule
|
||||||
}))
|
}))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -731,6 +731,7 @@ func createForwardAuthMiddleware(k8sClient Client, namespace string, auth *traef
|
||||||
AuthResponseHeaders: auth.AuthResponseHeaders,
|
AuthResponseHeaders: auth.AuthResponseHeaders,
|
||||||
AuthResponseHeadersRegex: auth.AuthResponseHeadersRegex,
|
AuthResponseHeadersRegex: auth.AuthResponseHeadersRegex,
|
||||||
AuthRequestHeaders: auth.AuthRequestHeaders,
|
AuthRequestHeaders: auth.AuthRequestHeaders,
|
||||||
|
AddAuthCookiesToResponse: auth.AddAuthCookiesToResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
if auth.TLS == nil {
|
if auth.TLS == nil {
|
||||||
|
|
|
@ -112,6 +112,7 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
|
||||||
r := &dynamic.Router{
|
r := &dynamic.Router{
|
||||||
Middlewares: mds,
|
Middlewares: mds,
|
||||||
Priority: route.Priority,
|
Priority: route.Priority,
|
||||||
|
RuleSyntax: route.Syntax,
|
||||||
EntryPoints: ingressRoute.Spec.EntryPoints,
|
EntryPoints: ingressRoute.Spec.EntryPoints,
|
||||||
Rule: route.Match,
|
Rule: route.Match,
|
||||||
Service: serviceName,
|
Service: serviceName,
|
||||||
|
|
|
@ -102,6 +102,7 @@ func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client
|
||||||
Middlewares: mds,
|
Middlewares: mds,
|
||||||
Rule: route.Match,
|
Rule: route.Match,
|
||||||
Priority: route.Priority,
|
Priority: route.Priority,
|
||||||
|
RuleSyntax: route.Syntax,
|
||||||
Service: serviceName,
|
Service: serviceName,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,9 @@ type Route struct {
|
||||||
// Priority defines the router's priority.
|
// Priority defines the router's priority.
|
||||||
// More info: https://doc.traefik.io/traefik/v3.0/routing/routers/#priority
|
// More info: https://doc.traefik.io/traefik/v3.0/routing/routers/#priority
|
||||||
Priority int `json:"priority,omitempty"`
|
Priority int `json:"priority,omitempty"`
|
||||||
|
// Syntax defines the router's rule syntax.
|
||||||
|
// More info: https://doc.traefik.io/traefik/v3.0/routing/routers/#rulesyntax
|
||||||
|
Syntax string `json:"syntax,omitempty"`
|
||||||
// Services defines the list of Service.
|
// Services defines the list of Service.
|
||||||
// It can contain any combination of TraefikService and/or reference to a Kubernetes Service.
|
// It can contain any combination of TraefikService and/or reference to a Kubernetes Service.
|
||||||
Services []Service `json:"services,omitempty"`
|
Services []Service `json:"services,omitempty"`
|
||||||
|
|
|
@ -29,6 +29,9 @@ type RouteTCP struct {
|
||||||
// Priority defines the router's priority.
|
// Priority defines the router's priority.
|
||||||
// More info: https://doc.traefik.io/traefik/v3.0/routing/routers/#priority_1
|
// More info: https://doc.traefik.io/traefik/v3.0/routing/routers/#priority_1
|
||||||
Priority int `json:"priority,omitempty"`
|
Priority int `json:"priority,omitempty"`
|
||||||
|
// Syntax defines the router's rule syntax.
|
||||||
|
// More info: https://doc.traefik.io/traefik/v3.0/routing/routers/#rulesyntax_1
|
||||||
|
Syntax string `json:"syntax,omitempty"`
|
||||||
// Services defines the list of TCP services.
|
// Services defines the list of TCP services.
|
||||||
Services []ServiceTCP `json:"services,omitempty"`
|
Services []ServiceTCP `json:"services,omitempty"`
|
||||||
// Middlewares defines the list of references to MiddlewareTCP resources.
|
// Middlewares defines the list of references to MiddlewareTCP resources.
|
||||||
|
|
|
@ -157,6 +157,8 @@ type ForwardAuth struct {
|
||||||
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty"`
|
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty"`
|
||||||
// TLS defines the configuration used to secure the connection to the authentication server.
|
// TLS defines the configuration used to secure the connection to the authentication server.
|
||||||
TLS *ClientTLS `json:"tls,omitempty"`
|
TLS *ClientTLS `json:"tls,omitempty"`
|
||||||
|
// AddAuthCookiesToResponse defines the list of cookies to copy from the authentication server response to the response.
|
||||||
|
AddAuthCookiesToResponse []string `json:"addAuthCookiesToResponse,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientTLS holds the client TLS configuration.
|
// ClientTLS holds the client TLS configuration.
|
||||||
|
|
|
@ -215,6 +215,11 @@ func (in *ForwardAuth) DeepCopyInto(out *ForwardAuth) {
|
||||||
*out = new(ClientTLS)
|
*out = new(ClientTLS)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
|
if in.AddAuthCookiesToResponse != nil {
|
||||||
|
in, out := &in.AddAuthCookiesToResponse, &out.AddAuthCookiesToResponse
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -230,6 +230,7 @@ func (p *Provider) loadConfigurationFromGateway(ctx context.Context, client Clie
|
||||||
err := client.UpdateGatewayClassStatus(gatewayClass, metav1.Condition{
|
err := client.UpdateGatewayClassStatus(gatewayClass, metav1.Condition{
|
||||||
Type: string(gatev1.GatewayClassConditionStatusAccepted),
|
Type: string(gatev1.GatewayClassConditionStatusAccepted),
|
||||||
Status: metav1.ConditionTrue,
|
Status: metav1.ConditionTrue,
|
||||||
|
ObservedGeneration: gatewayClass.Generation,
|
||||||
Reason: "Handled",
|
Reason: "Handled",
|
||||||
Message: "Handled by Traefik controller",
|
Message: "Handled by Traefik controller",
|
||||||
LastTransitionTime: metav1.Now(),
|
LastTransitionTime: metav1.Now(),
|
||||||
|
@ -587,7 +588,16 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listenerStatuses [
|
||||||
Type: string(gatev1.GatewayConditionAccepted),
|
Type: string(gatev1.GatewayConditionAccepted),
|
||||||
Status: metav1.ConditionTrue,
|
Status: metav1.ConditionTrue,
|
||||||
ObservedGeneration: gateway.Generation,
|
ObservedGeneration: gateway.Generation,
|
||||||
Reason: string(gatev1.GatewayConditionAccepted),
|
Reason: string(gatev1.GatewayReasonAccepted),
|
||||||
|
Message: "Gateway successfully scheduled",
|
||||||
|
LastTransitionTime: metav1.Now(),
|
||||||
|
},
|
||||||
|
// update "Programmed" status with "Programmed" reason
|
||||||
|
metav1.Condition{
|
||||||
|
Type: string(gatev1.GatewayConditionProgrammed),
|
||||||
|
Status: metav1.ConditionTrue,
|
||||||
|
ObservedGeneration: gateway.Generation,
|
||||||
|
Reason: string(gatev1.GatewayReasonProgrammed),
|
||||||
Message: "Gateway successfully scheduled",
|
Message: "Gateway successfully scheduled",
|
||||||
LastTransitionTime: metav1.Now(),
|
LastTransitionTime: metav1.Now(),
|
||||||
},
|
},
|
||||||
|
@ -760,6 +770,7 @@ func (p *Provider) gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, li
|
||||||
|
|
||||||
router := dynamic.Router{
|
router := dynamic.Router{
|
||||||
Rule: rule,
|
Rule: rule,
|
||||||
|
RuleSyntax: "v3",
|
||||||
EntryPoints: []string{ep},
|
EntryPoints: []string{ep},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -898,6 +909,7 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener gatev1.Li
|
||||||
router := dynamic.TCPRouter{
|
router := dynamic.TCPRouter{
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
EntryPoints: []string{ep},
|
EntryPoints: []string{ep},
|
||||||
|
RuleSyntax: "v3",
|
||||||
}
|
}
|
||||||
|
|
||||||
if listener.Protocol == gatev1.TLSProtocolType && listener.TLS != nil {
|
if listener.Protocol == gatev1.TLSProtocolType && listener.TLS != nil {
|
||||||
|
@ -1062,6 +1074,7 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener gatev1.Li
|
||||||
|
|
||||||
router := dynamic.TCPRouter{
|
router := dynamic.TCPRouter{
|
||||||
Rule: rule,
|
Rule: rule,
|
||||||
|
RuleSyntax: "v3",
|
||||||
EntryPoints: []string{ep},
|
EntryPoints: []string{ep},
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: listener.TLS.Mode != nil && *listener.TLS.Mode == gatev1.TLSModePassthrough,
|
Passthrough: listener.TLS.Mode != nil && *listener.TLS.Mode == gatev1.TLSModePassthrough,
|
||||||
|
@ -1385,7 +1398,7 @@ func extractHeaderRules(headers []gatev1.HTTPHeaderMatch) ([]string, error) {
|
||||||
|
|
||||||
switch *header.Type {
|
switch *header.Type {
|
||||||
case gatev1.HeaderMatchExact:
|
case gatev1.HeaderMatchExact:
|
||||||
headerRules = append(headerRules, fmt.Sprintf("Headers(`%s`,`%s`)", header.Name, header.Value))
|
headerRules = append(headerRules, fmt.Sprintf("Header(`%s`,`%s`)", header.Name, header.Value))
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported header match type %s", *header.Type)
|
return nil, fmt.Errorf("unsupported header match type %s", *header.Type)
|
||||||
}
|
}
|
||||||
|
|
|
@ -550,6 +550,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
||||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
@ -609,6 +610,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "api@internal",
|
Service: "api@internal",
|
||||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
@ -641,6 +643,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
||||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
@ -704,6 +707,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"websecure"},
|
EntryPoints: []string{"websecure"},
|
||||||
Service: "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-wrr",
|
Service: "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-wrr",
|
||||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTLSConfig{},
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -773,6 +777,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-web-66e726cd8903b49727ae-wrr",
|
Service: "default-http-app-1-my-gateway-web-66e726cd8903b49727ae-wrr",
|
||||||
Rule: "(Host(`foo.com`) || Host(`bar.com`)) && PathPrefix(`/`)",
|
Rule: "(Host(`foo.com`) || Host(`bar.com`)) && PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
@ -832,6 +837,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-web-3b78e2feb3295ddd87f0-wrr",
|
Service: "default-http-app-1-my-gateway-web-3b78e2feb3295ddd87f0-wrr",
|
||||||
Rule: "(Host(`foo.com`) || HostRegexp(`^[a-zA-Z0-9-]+\\.bar\\.com$`)) && PathPrefix(`/`)",
|
Rule: "(Host(`foo.com`) || HostRegexp(`^[a-zA-Z0-9-]+\\.bar\\.com$`)) && PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
@ -891,6 +897,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-web-b0521a61fb43068694b4-wrr",
|
Service: "default-http-app-1-my-gateway-web-b0521a61fb43068694b4-wrr",
|
||||||
Rule: "(Host(`foo.com`) || HostRegexp(`^[a-zA-Z0-9-]+\\.foo\\.com$`)) && PathPrefix(`/`)",
|
Rule: "(Host(`foo.com`) || HostRegexp(`^[a-zA-Z0-9-]+\\.foo\\.com$`)) && PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
@ -949,11 +956,13 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": {
|
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
||||||
},
|
},
|
||||||
"default-http-app-1-my-gateway-web-d737b4933fa88e68ab8a": {
|
"default-http-app-1-my-gateway-web-d737b4933fa88e68ab8a": {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Rule: "Host(`foo.com`) && Path(`/bir`)",
|
Rule: "Host(`foo.com`) && Path(`/bir`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
Service: "default-http-app-1-my-gateway-web-d737b4933fa88e68ab8a-wrr",
|
Service: "default-http-app-1-my-gateway-web-d737b4933fa88e68ab8a-wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1039,6 +1048,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": {
|
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1124,11 +1134,13 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-http-web-1c0cf64bde37d9d0df06-wrr",
|
Service: "default-http-app-1-my-gateway-http-web-1c0cf64bde37d9d0df06-wrr",
|
||||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-http-app-1-my-gateway-https-websecure-1c0cf64bde37d9d0df06": {
|
"default-http-app-1-my-gateway-https-websecure-1c0cf64bde37d9d0df06": {
|
||||||
EntryPoints: []string{"websecure"},
|
EntryPoints: []string{"websecure"},
|
||||||
Service: "default-http-app-1-my-gateway-https-websecure-1c0cf64bde37d9d0df06-wrr",
|
Service: "default-http-app-1-my-gateway-https-websecure-1c0cf64bde37d9d0df06-wrr",
|
||||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTLSConfig{},
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1213,11 +1225,13 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
||||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06": {
|
"default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06": {
|
||||||
EntryPoints: []string{"websecure"},
|
EntryPoints: []string{"websecure"},
|
||||||
Service: "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-wrr",
|
Service: "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-wrr",
|
||||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTLSConfig{},
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1293,20 +1307,22 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
},
|
},
|
||||||
HTTP: &dynamic.HTTPConfiguration{
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
Routers: map[string]*dynamic.Router{
|
Routers: map[string]*dynamic.Router{
|
||||||
"default-http-app-1-my-gateway-web-330d644a7f2079e8f454": {
|
"default-http-app-1-my-gateway-web-4a1b73e6f83804949a37": {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-web-330d644a7f2079e8f454-wrr",
|
Service: "default-http-app-1-my-gateway-web-4a1b73e6f83804949a37-wrr",
|
||||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`) && Headers(`my-header`,`foo`) && Headers(`my-header2`,`bar`)",
|
Rule: "Host(`foo.com`) && PathPrefix(`/bar`) && Header(`my-header`,`foo`) && Header(`my-header2`,`bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-http-app-1-my-gateway-web-fe80e69a38713941ea22": {
|
"default-http-app-1-my-gateway-web-aaba0f24fd26e1ca2276": {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-web-fe80e69a38713941ea22-wrr",
|
Service: "default-http-app-1-my-gateway-web-aaba0f24fd26e1ca2276-wrr",
|
||||||
Rule: "Host(`foo.com`) && Path(`/bar`) && Headers(`my-header`,`bar`)",
|
Rule: "Host(`foo.com`) && Path(`/bar`) && Header(`my-header`,`bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default-http-app-1-my-gateway-web-330d644a7f2079e8f454-wrr": {
|
"default-http-app-1-my-gateway-web-4a1b73e6f83804949a37-wrr": {
|
||||||
Weighted: &dynamic.WeightedRoundRobin{
|
Weighted: &dynamic.WeightedRoundRobin{
|
||||||
Services: []dynamic.WRRService{
|
Services: []dynamic.WRRService{
|
||||||
{
|
{
|
||||||
|
@ -1316,7 +1332,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"default-http-app-1-my-gateway-web-fe80e69a38713941ea22-wrr": {
|
"default-http-app-1-my-gateway-web-aaba0f24fd26e1ca2276-wrr": {
|
||||||
Weighted: &dynamic.WeightedRoundRobin{
|
Weighted: &dynamic.WeightedRoundRobin{
|
||||||
Services: []dynamic.WRRService{
|
Services: []dynamic.WRRService{
|
||||||
{
|
{
|
||||||
|
@ -1371,6 +1387,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-default-my-gateway-web-efde1997778109a1f6eb-wrr",
|
Service: "default-http-app-default-my-gateway-web-efde1997778109a1f6eb-wrr",
|
||||||
Rule: "Host(`foo.com`) && Path(`/foo`)",
|
Rule: "Host(`foo.com`) && Path(`/foo`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
@ -1430,11 +1447,13 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-default-my-gateway-web-efde1997778109a1f6eb-wrr",
|
Service: "default-http-app-default-my-gateway-web-efde1997778109a1f6eb-wrr",
|
||||||
Rule: "Host(`foo.com`) && Path(`/foo`)",
|
Rule: "Host(`foo.com`) && Path(`/foo`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597": {
|
"bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597": {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597-wrr",
|
Service: "bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597-wrr",
|
||||||
Rule: "Host(`bar.com`) && Path(`/bar`)",
|
Rule: "Host(`bar.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
@ -1520,6 +1539,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597-wrr",
|
Service: "bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597-wrr",
|
||||||
Rule: "Host(`bar.com`) && Path(`/bar`)",
|
Rule: "Host(`bar.com`) && Path(`/bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
@ -1579,6 +1599,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr",
|
Service: "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr",
|
||||||
Rule: "Host(`example.org`) && PathPrefix(`/`)",
|
Rule: "Host(`example.org`) && PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
Middlewares: []string{"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestredirect-0"},
|
Middlewares: []string{"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestredirect-0"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1647,6 +1668,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr",
|
Service: "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr",
|
||||||
Rule: "Host(`example.org`) && PathPrefix(`/`)",
|
Rule: "Host(`example.org`) && PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
Middlewares: []string{"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestredirect-0"},
|
Middlewares: []string{"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestredirect-0"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1912,6 +1934,7 @@ func TestLoadTCPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tcp-app-1-my-tcp-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-1-my-tcp-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||||
|
@ -1969,11 +1992,13 @@ func TestLoadTCPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp-1"},
|
EntryPoints: []string{"tcp-1"},
|
||||||
Service: "default-tcp-app-1-my-tcp-gateway-tcp-1-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-1-my-tcp-gateway-tcp-1-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-tcp-app-2-my-tcp-gateway-tcp-2-e3b0c44298fc1c149afb": {
|
"default-tcp-app-2-my-tcp-gateway-tcp-2-e3b0c44298fc1c149afb": {
|
||||||
EntryPoints: []string{"tcp-2"},
|
EntryPoints: []string{"tcp-2"},
|
||||||
Service: "default-tcp-app-2-my-tcp-gateway-tcp-2-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-2-my-tcp-gateway-tcp-2-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||||
|
@ -2053,6 +2078,7 @@ func TestLoadTCPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp-1"},
|
EntryPoints: []string{"tcp-1"},
|
||||||
Service: "default-tcp-app-my-tcp-gateway-tcp-1-e3b0c44298fc1c149afb-wrr",
|
Service: "default-tcp-app-my-tcp-gateway-tcp-1-e3b0c44298fc1c149afb-wrr",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||||
|
@ -2144,6 +2170,7 @@ func TestLoadTCPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tcp-app-1-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-1-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||||
|
@ -2203,6 +2230,7 @@ func TestLoadTCPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "default-tcp-app-1-my-gateway-tls-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-1-my-gateway-tls-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -2266,6 +2294,7 @@ func TestLoadTCPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tcp-app-default-my-tcp-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-default-my-tcp-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||||
|
@ -2321,11 +2350,13 @@ func TestLoadTCPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tcp-app-default-my-tcp-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-default-my-tcp-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"bar-tcp-app-bar-my-tcp-gateway-tcp-e3b0c44298fc1c149afb": {
|
"bar-tcp-app-bar-my-tcp-gateway-tcp-e3b0c44298fc1c149afb": {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "bar-tcp-app-bar-my-tcp-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "bar-tcp-app-bar-my-tcp-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||||
|
@ -2403,6 +2434,7 @@ func TestLoadTCPRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "bar-tcp-app-bar-my-tcp-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "bar-tcp-app-bar-my-tcp-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||||
|
@ -2696,6 +2728,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tcp-app-1-my-tls-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-1-my-tls-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -2761,6 +2794,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tcp-app-1-my-tls-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-1-my-tls-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -2819,6 +2853,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tls-app-1-my-tls-gateway-tcp-f0dd0dd89f82eae1c270-wrr-0",
|
Service: "default-tls-app-1-my-tls-gateway-tcp-f0dd0dd89f82eae1c270-wrr-0",
|
||||||
Rule: "HostSNI(`foo.example.com`)",
|
Rule: "HostSNI(`foo.example.com`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -2878,12 +2913,14 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "default-tcp-app-1-my-tls-gateway-tls-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-1-my-tls-gateway-tls-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||||
},
|
},
|
||||||
"default-tls-app-1-my-tls-gateway-tcp-673acf455cb2dab0b43a": {
|
"default-tls-app-1-my-tls-gateway-tcp-673acf455cb2dab0b43a": {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tls-app-1-my-tls-gateway-tcp-673acf455cb2dab0b43a-wrr-0",
|
Service: "default-tls-app-1-my-tls-gateway-tcp-673acf455cb2dab0b43a-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -2973,6 +3010,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "default-tcp-app-1-my-gateway-tls-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-1-my-gateway-tls-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3042,6 +3080,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0",
|
Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0",
|
||||||
Rule: "HostSNI(`foo.example.com`)",
|
Rule: "HostSNI(`foo.example.com`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -3100,6 +3139,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0",
|
Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0",
|
||||||
Rule: "HostSNI(`foo.example.com`)",
|
Rule: "HostSNI(`foo.example.com`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -3158,6 +3198,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0",
|
Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0",
|
||||||
Rule: "HostSNI(`foo.example.com`)",
|
Rule: "HostSNI(`foo.example.com`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -3216,6 +3257,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "default-tls-app-1-my-gateway-tls-d5342d75658583f03593-wrr-0",
|
Service: "default-tls-app-1-my-gateway-tls-d5342d75658583f03593-wrr-0",
|
||||||
Rule: "HostSNI(`foo.example.com`) || HostSNI(`bar.example.com`)",
|
Rule: "HostSNI(`foo.example.com`) || HostSNI(`bar.example.com`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -3274,6 +3316,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0",
|
Service: "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0",
|
||||||
Rule: "HostSNI(`foo.default`)",
|
Rule: "HostSNI(`foo.default`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -3332,6 +3375,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0",
|
Service: "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0",
|
||||||
Rule: "HostSNI(`foo.default`)",
|
Rule: "HostSNI(`foo.default`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -3340,6 +3384,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0",
|
Service: "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0",
|
||||||
Rule: "HostSNI(`foo.bar`)",
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -3420,6 +3465,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0",
|
Service: "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0",
|
||||||
Rule: "HostSNI(`foo.bar`)",
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -3478,6 +3524,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp-1"},
|
EntryPoints: []string{"tcp-1"},
|
||||||
Service: "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr",
|
Service: "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -3702,17 +3749,20 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tcp-app-1-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-1-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-tcp-app-1-my-gateway-tls-1-e3b0c44298fc1c149afb": {
|
"default-tcp-app-1-my-gateway-tls-1-e3b0c44298fc1c149afb": {
|
||||||
EntryPoints: []string{"tls-1"},
|
EntryPoints: []string{"tls-1"},
|
||||||
Service: "default-tcp-app-1-my-gateway-tls-1-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-1-my-gateway-tls-1-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||||
},
|
},
|
||||||
"default-tls-app-1-my-gateway-tls-2-59130f7db6718b7700c1": {
|
"default-tls-app-1-my-gateway-tls-2-59130f7db6718b7700c1": {
|
||||||
EntryPoints: []string{"tls-2"},
|
EntryPoints: []string{"tls-2"},
|
||||||
Service: "default-tls-app-1-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
|
Service: "default-tls-app-1-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
|
||||||
Rule: "HostSNI(`pass.tls.foo.example.com`)",
|
Rule: "HostSNI(`pass.tls.foo.example.com`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -3771,11 +3821,13 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-1-my-gateway-web-a431b128267aabc954fd-wrr",
|
Service: "default-http-app-1-my-gateway-web-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-http-app-1-my-gateway-websecure-a431b128267aabc954fd": {
|
"default-http-app-1-my-gateway-websecure-a431b128267aabc954fd": {
|
||||||
EntryPoints: []string{"websecure"},
|
EntryPoints: []string{"websecure"},
|
||||||
Service: "default-http-app-1-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
Service: "default-http-app-1-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTLSConfig{},
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3881,17 +3933,20 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tcp-app-default-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-default-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-tcp-app-default-my-gateway-tls-1-e3b0c44298fc1c149afb": {
|
"default-tcp-app-default-my-gateway-tls-1-e3b0c44298fc1c149afb": {
|
||||||
EntryPoints: []string{"tls-1"},
|
EntryPoints: []string{"tls-1"},
|
||||||
Service: "default-tcp-app-default-my-gateway-tls-1-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-default-my-gateway-tls-1-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||||
},
|
},
|
||||||
"default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1": {
|
"default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1": {
|
||||||
EntryPoints: []string{"tls-2"},
|
EntryPoints: []string{"tls-2"},
|
||||||
Service: "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
|
Service: "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
|
||||||
Rule: "HostSNI(`pass.tls.foo.example.com`)",
|
Rule: "HostSNI(`pass.tls.foo.example.com`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -3950,11 +4005,13 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-default-my-gateway-web-a431b128267aabc954fd-wrr",
|
Service: "default-http-app-default-my-gateway-web-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-http-app-default-my-gateway-websecure-a431b128267aabc954fd": {
|
"default-http-app-default-my-gateway-websecure-a431b128267aabc954fd": {
|
||||||
EntryPoints: []string{"websecure"},
|
EntryPoints: []string{"websecure"},
|
||||||
Service: "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
Service: "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTLSConfig{},
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4032,17 +4089,20 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tcp-app-default-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-default-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-tcp-app-default-my-gateway-tls-1-e3b0c44298fc1c149afb": {
|
"default-tcp-app-default-my-gateway-tls-1-e3b0c44298fc1c149afb": {
|
||||||
EntryPoints: []string{"tls-1"},
|
EntryPoints: []string{"tls-1"},
|
||||||
Service: "default-tcp-app-default-my-gateway-tls-1-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-default-my-gateway-tls-1-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||||
},
|
},
|
||||||
"default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1": {
|
"default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1": {
|
||||||
EntryPoints: []string{"tls-2"},
|
EntryPoints: []string{"tls-2"},
|
||||||
Service: "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
|
Service: "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
|
||||||
Rule: "HostSNI(`pass.tls.foo.example.com`)",
|
Rule: "HostSNI(`pass.tls.foo.example.com`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -4051,11 +4111,13 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "bar-tcp-app-bar-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "bar-tcp-app-bar-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"bar-tcp-app-bar-my-gateway-tls-1-e3b0c44298fc1c149afb": {
|
"bar-tcp-app-bar-my-gateway-tls-1-e3b0c44298fc1c149afb": {
|
||||||
EntryPoints: []string{"tls-1"},
|
EntryPoints: []string{"tls-1"},
|
||||||
Service: "bar-tcp-app-bar-my-gateway-tls-1-e3b0c44298fc1c149afb-wrr-0",
|
Service: "bar-tcp-app-bar-my-gateway-tls-1-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4144,22 +4206,26 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-default-my-gateway-web-a431b128267aabc954fd-wrr",
|
Service: "default-http-app-default-my-gateway-web-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-http-app-default-my-gateway-websecure-a431b128267aabc954fd": {
|
"default-http-app-default-my-gateway-websecure-a431b128267aabc954fd": {
|
||||||
EntryPoints: []string{"websecure"},
|
EntryPoints: []string{"websecure"},
|
||||||
Service: "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
Service: "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTLSConfig{},
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
},
|
},
|
||||||
"bar-http-app-bar-my-gateway-web-a431b128267aabc954fd": {
|
"bar-http-app-bar-my-gateway-web-a431b128267aabc954fd": {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "bar-http-app-bar-my-gateway-web-a431b128267aabc954fd-wrr",
|
Service: "bar-http-app-bar-my-gateway-web-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd": {
|
"bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd": {
|
||||||
EntryPoints: []string{"websecure"},
|
EntryPoints: []string{"websecure"},
|
||||||
Service: "bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
Service: "bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTLSConfig{},
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4273,17 +4339,20 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "bar-tcp-app-bar-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "bar-tcp-app-bar-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"bar-tcp-app-bar-my-gateway-tls-1-e3b0c44298fc1c149afb": {
|
"bar-tcp-app-bar-my-gateway-tls-1-e3b0c44298fc1c149afb": {
|
||||||
EntryPoints: []string{"tls-1"},
|
EntryPoints: []string{"tls-1"},
|
||||||
Service: "bar-tcp-app-bar-my-gateway-tls-1-e3b0c44298fc1c149afb-wrr-0",
|
Service: "bar-tcp-app-bar-my-gateway-tls-1-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||||
},
|
},
|
||||||
"bar-tls-app-bar-my-gateway-tls-2-59130f7db6718b7700c1": {
|
"bar-tls-app-bar-my-gateway-tls-2-59130f7db6718b7700c1": {
|
||||||
EntryPoints: []string{"tls-2"},
|
EntryPoints: []string{"tls-2"},
|
||||||
Service: "bar-tls-app-bar-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
|
Service: "bar-tls-app-bar-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
|
||||||
Rule: "HostSNI(`pass.tls.foo.example.com`)",
|
Rule: "HostSNI(`pass.tls.foo.example.com`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{
|
TLS: &dynamic.RouterTCPTLSConfig{
|
||||||
Passthrough: true,
|
Passthrough: true,
|
||||||
},
|
},
|
||||||
|
@ -4342,11 +4411,13 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "bar-http-app-bar-my-gateway-web-a431b128267aabc954fd-wrr",
|
Service: "bar-http-app-bar-my-gateway-web-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd": {
|
"bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd": {
|
||||||
EntryPoints: []string{"websecure"},
|
EntryPoints: []string{"websecure"},
|
||||||
Service: "bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
Service: "bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTLSConfig{},
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4423,11 +4494,13 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"tcp"},
|
EntryPoints: []string{"tcp"},
|
||||||
Service: "default-tcp-app-default-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-default-my-gateway-tcp-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-tcp-app-default-my-gateway-tls-e3b0c44298fc1c149afb": {
|
"default-tcp-app-default-my-gateway-tls-e3b0c44298fc1c149afb": {
|
||||||
EntryPoints: []string{"tls"},
|
EntryPoints: []string{"tls"},
|
||||||
Service: "default-tcp-app-default-my-gateway-tls-e3b0c44298fc1c149afb-wrr-0",
|
Service: "default-tcp-app-default-my-gateway-tls-e3b0c44298fc1c149afb-wrr-0",
|
||||||
Rule: "HostSNI(`*`)",
|
Rule: "HostSNI(`*`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4474,11 +4547,13 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "default-http-app-default-my-gateway-web-a431b128267aabc954fd-wrr",
|
Service: "default-http-app-default-my-gateway-web-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
},
|
},
|
||||||
"default-http-app-default-my-gateway-websecure-a431b128267aabc954fd": {
|
"default-http-app-default-my-gateway-websecure-a431b128267aabc954fd": {
|
||||||
EntryPoints: []string{"websecure"},
|
EntryPoints: []string{"websecure"},
|
||||||
Service: "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
Service: "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd-wrr",
|
||||||
Rule: "PathPrefix(`/`)",
|
Rule: "PathPrefix(`/`)",
|
||||||
|
RuleSyntax: "v3",
|
||||||
TLS: &dynamic.RouterTLSConfig{},
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4807,7 +4882,7 @@ func Test_extractRule(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedRule: "Path(`/foo/`) || Headers(`my-header`,`foo`)",
|
expectedRule: "Path(`/foo/`) || Header(`my-header`,`foo`)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Path && Header rules",
|
desc: "Path && Header rules",
|
||||||
|
@ -4828,7 +4903,7 @@ func Test_extractRule(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedRule: "Path(`/foo/`) && Headers(`my-header`,`foo`)",
|
expectedRule: "Path(`/foo/`) && Header(`my-header`,`foo`)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Host && Path && Header rules",
|
desc: "Host && Path && Header rules",
|
||||||
|
@ -4850,7 +4925,7 @@ func Test_extractRule(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedRule: "Host(`foo.com`) && Path(`/foo/`) && Headers(`my-header`,`foo`)",
|
expectedRule: "Host(`foo.com`) && Path(`/foo/`) && Header(`my-header`,`foo`)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Host && (Path || Header) rules",
|
desc: "Host && (Path || Header) rules",
|
||||||
|
@ -4874,7 +4949,7 @@ func Test_extractRule(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedRule: "Host(`foo.com`) && (Path(`/foo/`) || Headers(`my-header`,`foo`))",
|
expectedRule: "Host(`foo.com`) && (Path(`/foo/`) || Header(`my-header`,`foo`))",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,11 @@
|
||||||
"priority": 2147483645
|
"priority": 2147483645
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"services": {
|
||||||
|
"api": {},
|
||||||
|
"dashboard": {},
|
||||||
|
"noop": {}
|
||||||
|
},
|
||||||
"middlewares": {
|
"middlewares": {
|
||||||
"dashboard_redirect": {
|
"dashboard_redirect": {
|
||||||
"redirectRegex": {
|
"redirectRegex": {
|
||||||
|
@ -38,11 +43,6 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"services": {
|
|
||||||
"api": {},
|
|
||||||
"dashboard": {},
|
|
||||||
"noop": {}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tcp": {},
|
"tcp": {},
|
||||||
|
|
|
@ -54,6 +54,14 @@
|
||||||
"priority": 2147483647
|
"priority": 2147483647
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"services": {
|
||||||
|
"api": {},
|
||||||
|
"dashboard": {},
|
||||||
|
"noop": {},
|
||||||
|
"ping": {},
|
||||||
|
"prometheus": {},
|
||||||
|
"rest": {}
|
||||||
|
},
|
||||||
"middlewares": {
|
"middlewares": {
|
||||||
"dashboard_redirect": {
|
"dashboard_redirect": {
|
||||||
"redirectRegex": {
|
"redirectRegex": {
|
||||||
|
@ -70,14 +78,6 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"services": {
|
|
||||||
"api": {},
|
|
||||||
"dashboard": {},
|
|
||||||
"noop": {},
|
|
||||||
"ping": {},
|
|
||||||
"prometheus": {},
|
|
||||||
"rest": {}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tcp": {},
|
"tcp": {},
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
"rule": "HostRegexp(`^.+$`)"
|
"rule": "HostRegexp(`^.+$`)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"services": {
|
||||||
|
"noop": {}
|
||||||
|
},
|
||||||
"middlewares": {
|
"middlewares": {
|
||||||
"redirect-web-to-websecure": {
|
"redirect-web-to-websecure": {
|
||||||
"redirectScheme": {
|
"redirectScheme": {
|
||||||
|
@ -20,11 +23,8 @@
|
||||||
"permanent": true
|
"permanent": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"services": {
|
|
||||||
"noop": {}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tcp": {},
|
"tcp": {},
|
||||||
"tls": {}
|
"tls": {}
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue