Compare commits

..

No commits in common. "ca45770bbd517004302a3e067ce1e405312a4b36" and "fa154de4a2787765060ce48581e5f5f816edd112" have entirely different histories.

124 changed files with 1279 additions and 7606 deletions

View file

@ -1,5 +1,5 @@
dist/ dist/
!dist/**/traefik !dist/traefik
site/ site/
vendor/ vendor/
.idea/ .idea/

1
.gitignore vendored
View file

@ -19,4 +19,3 @@ plugins-storage/
plugins-local/ plugins-local/
traefik_changelog.md traefik_changelog.md
integration/tailscale.secret integration/tailscale.secret
integration/conformance-reports/

View file

@ -280,9 +280,3 @@ 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

View file

@ -1,13 +1,6 @@
# syntax=docker/dockerfile:1.2 FROM scratch
FROM alpine:3.19 COPY script/ca-certificates.crt /etc/ssl/certs/
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
View file

@ -7,22 +7,8 @@ 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: generate binary default: binary
## Create the "dist" directory ## Create the "dist" directory
dist: dist:
@ -49,68 +35,43 @@ 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 dist binary: generate-webui
@echo SHA: $(VERSION) $(CODENAME) $(DATE) ./script/make.sh generate binary
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
binary-linux-arm64: export GOOS := linux ## Build the linux binary locally
binary-linux-arm64: export GOARCH := arm64 .PHONY: binary-debug
binary-linux-arm64: binary-debug: generate-webui
@$(MAKE) binary GOOS=linux ./script/make.sh 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 generate-webui crossbinary-default: generate-webui
$(CURDIR)/script/crossbinary-default.sh ./script/make.sh generate crossbinary-default
## 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-unit test-integration test:
./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:
GOOS=$(GOOS) GOARCH=$(GOARCH) go test -cover "-coverprofile=cover.out" -v $(TESTFLAGS) ./pkg/... ./cmd/... ./script/make.sh generate test-unit
## Run the integration tests ## Run the integration tests
.PHONY: test-integration .PHONY: test-integration
test-integration: binary test-integration:
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -test.timeout=20m -failfast -v $(TESTFLAGS) ./script/make.sh generate binary test-integration
## Run the conformance tests ## Pull all images for integration 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 \
@ -119,47 +80,38 @@ pull-images:
| uniq \ | uniq \
| xargs -P 6 -n 1 docker pull | xargs -P 6 -n 1 docker pull
## Lint run golangci-lint EXECUTABLES = misspell shellcheck
.PHONY: lint
lint:
golangci-lint run
## Validate code and docs ## Validate code and docs
.PHONY: validate-files .PHONY: validate-files
validate-files: lint validate-files:
$(foreach exec,$(LINT_EXECUTABLES),\ $(foreach exec,$(EXECUTABLES),\
$(if $(shell which $(exec)),,$(error "No $(exec) in PATH"))) $(if $(shell which $(exec)),,$(error "No $(exec) in PATH")))
$(CURDIR)/script/validate-misspell.sh ./script/make.sh generate validate-lint validate-misspell
$(CURDIR)/script/validate-shell-script.sh bash $(CURDIR)/script/validate-shell-script.sh
## Validate code, docs, and vendor ## Validate code, docs, and vendor
.PHONY: validate .PHONY: validate
validate: lint validate:
$(foreach exec,$(EXECUTABLES),\ $(foreach exec,$(EXECUTABLES),\
$(if $(shell which $(exec)),,$(error "No $(exec) in PATH"))) $(if $(shell which $(exec)),,$(error "No $(exec) in PATH")))
$(CURDIR)/script/validate-vendor.sh ./script/make.sh generate validate-lint validate-misspell validate-vendor
$(CURDIR)/script/validate-misspell.sh bash $(CURDIR)/script/validate-shell-script.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: export DOCKER_BUILDX_ARGS := --load build-image: clean-webui binary
build-image: export DOCKER_BUILD_PLATFORMS := linux/$(GOARCH) docker build -t $(TRAEFIK_IMAGE) .
build-image: clean-webui
@$(MAKE) multi-arch-image-latest
## Build a Docker Traefik image without re-building the webui when it's already built ## Build a Docker Traefik image without re-building the webui
.PHONY: build-image-dirty .PHONY: build-image-dirty
build-image-dirty: export DOCKER_BUILDX_ARGS := --load build-image-dirty: binary
build-image-dirty: export DOCKER_BUILD_PLATFORMS := linux/$(GOARCH) docker build -t $(TRAEFIK_IMAGE) .
build-image-dirty:
@$(MAKE) multi-arch-image-latest ## Locally build traefik for linux, then shove it an alpine image, with basic tools.
.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
@ -189,9 +141,30 @@ 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
$(CURDIR)/script/release-packages.sh rm -rf dist
@- $(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

37
build.Dockerfile Normal file
View file

@ -0,0 +1,37 @@
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

View file

@ -53,7 +53,7 @@ func main() {
// traefik config inits // traefik config inits
tConfig := cmd.NewTraefikConfiguration() tConfig := cmd.NewTraefikConfiguration()
loaders := []cli.ResourceLoader{&tcli.DeprecationLoader{}, &tcli.FileLoader{}, &tcli.FlagLoader{}, &tcli.EnvLoader{}} loaders := []cli.ResourceLoader{&tcli.FileLoader{}, &tcli.FlagLoader{}, &tcli.EnvLoader{}}
cmdTraefik := &cli.Command{ cmdTraefik := &cli.Command{
Name: "traefik", Name: "traefik",

10
debug.Dockerfile Normal file
View file

@ -0,0 +1,10 @@
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"]

View file

@ -58,12 +58,10 @@ Once you've set up your go environment and cloned the source repository, you can
```bash ```bash
$ make binary $ make binary
SHA: 8fddfe118288bb5280eb5e77fa952f52def360b4 cheddar 2024-01-11_03:14:57PM ./script/make.sh generate binary
CGO_ENABLED=0 GOGC=off GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w \ ---> Making bundle: generate (in .)
-X github.com/traefik/traefik/v2/pkg/version.Version=8fddfe118288bb5280eb5e77fa952f52def360b4 \
-X github.com/traefik/traefik/v2/pkg/version.Codename=cheddar \ ---> Making bundle: binary (in .)
-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*
@ -79,7 +77,10 @@ Run all tests (unit and integration) using the `test` target.
```bash ```bash
$ make test-unit $ make test-unit
GOOS=darwin GOARCH=arm64 go test -cover "-coverprofile=cover.out" -v ./pkg/... ./cmd/... ./script/make.sh generate test-unit
---> 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

View file

@ -25,7 +25,7 @@ The main features include dynamic configuration, automatic service discovery, an
## Edge Router ## Edge Router
Traefik is an *Edge Router*; this means that it's the door to your platform, and that it intercepts and routes every incoming request: Traefik is an *Edge Router*, it 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")
This means that when a service is deployed, Traefik detects it immediately and updates the routing rules in real time. It 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.

View file

@ -19,7 +19,7 @@ version: '3'
services: services:
reverse-proxy: reverse-proxy:
# The official v3 Traefik docker image # The official v2 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

View file

@ -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, the response won't be encoded. If the `Accept-Encoding` request header is absent, it is meant as br compression is requested.
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), or is one among the [includedContentTypes options](#includedcontenttypes). * The response`Content-Type` header is not one among the [excludedContentTypes options](#excludedcontenttypes).
* 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,10 +73,6 @@ 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.
@ -121,59 +117,6 @@ 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_

View file

@ -285,55 +285,6 @@ 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_

View file

@ -19,8 +19,6 @@ 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)
@ -45,7 +43,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.
@ -66,35 +64,7 @@ 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
``` ```
#### TLS.CAOptional ### HTTP3 Experimental Configuration
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.
@ -116,14 +86,12 @@ 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.
@ -143,7 +111,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.
@ -164,36 +132,8 @@ 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.
@ -213,7 +153,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.
@ -234,37 +174,8 @@ 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.
@ -284,7 +195,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.
@ -305,33 +216,6 @@ 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/),
@ -387,90 +271,6 @@ 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/).
@ -526,16 +326,21 @@ All Pilot related configuration should be removed from the static configuration.
## Dynamic configuration ## Dynamic configuration
### Router Rule Matchers ### IPWhiteList
In v3, a new rule matchers syntax has been introduced for HTTP and TCP routers. In v3, we renamed the `IPWhiteList` middleware to `IPAllowList` without changing anything to the configuration.
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.
#### New V3 Syntax Notable Changes ### Deprecated Options Removal
The `Headers` and `HeadersRegexp` matchers have been renamed to `Header` and `HeaderRegexp` respectively. - 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.
### 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.
@ -550,87 +355,6 @@ 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.
@ -691,5 +415,3 @@ 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.

View file

@ -1,138 +1,128 @@
## CODE GENERATED AUTOMATICALLY - "traefik.http.middlewares.middleware00.addprefix.prefix=foobar"
## THIS FILE MUST NOT BE EDITED BY HAND - "traefik.http.middlewares.middleware01.basicauth.headerfield=foobar"
- "traefik.http.middlewares.middleware01.addprefix.prefix=foobar" - "traefik.http.middlewares.middleware01.basicauth.realm=foobar"
- "traefik.http.middlewares.middleware02.basicauth.headerfield=foobar" - "traefik.http.middlewares.middleware01.basicauth.removeheader=true"
- "traefik.http.middlewares.middleware02.basicauth.realm=foobar" - "traefik.http.middlewares.middleware01.basicauth.users=foobar, foobar"
- "traefik.http.middlewares.middleware02.basicauth.removeheader=true" - "traefik.http.middlewares.middleware01.basicauth.usersfile=foobar"
- "traefik.http.middlewares.middleware02.basicauth.users=foobar, foobar" - "traefik.http.middlewares.middleware02.buffering.maxrequestbodybytes=42"
- "traefik.http.middlewares.middleware02.basicauth.usersfile=foobar" - "traefik.http.middlewares.middleware02.buffering.maxresponsebodybytes=42"
- "traefik.http.middlewares.middleware03.buffering.maxrequestbodybytes=42" - "traefik.http.middlewares.middleware02.buffering.memrequestbodybytes=42"
- "traefik.http.middlewares.middleware03.buffering.maxresponsebodybytes=42" - "traefik.http.middlewares.middleware02.buffering.memresponsebodybytes=42"
- "traefik.http.middlewares.middleware03.buffering.memrequestbodybytes=42" - "traefik.http.middlewares.middleware02.buffering.retryexpression=foobar"
- "traefik.http.middlewares.middleware03.buffering.memresponsebodybytes=42" - "traefik.http.middlewares.middleware03.chain.middlewares=foobar, foobar"
- "traefik.http.middlewares.middleware03.buffering.retryexpression=foobar" - "traefik.http.middlewares.middleware04.circuitbreaker.expression=foobar"
- "traefik.http.middlewares.middleware04.chain.middlewares=foobar, foobar" - "traefik.http.middlewares.middleware04.circuitbreaker.checkperiod=42s"
- "traefik.http.middlewares.middleware05.circuitbreaker.checkperiod=42s" - "traefik.http.middlewares.middleware04.circuitbreaker.fallbackduration=42s"
- "traefik.http.middlewares.middleware05.circuitbreaker.expression=foobar" - "traefik.http.middlewares.middleware04.circuitbreaker.recoveryduration=42s"
- "traefik.http.middlewares.middleware05.circuitbreaker.fallbackduration=42s" - "traefik.http.middlewares.middleware05.compress=true"
- "traefik.http.middlewares.middleware05.circuitbreaker.recoveryduration=42s" - "traefik.http.middlewares.middleware05.compress.excludedcontenttypes=foobar, foobar"
- "traefik.http.middlewares.middleware06.compress=true" - "traefik.http.middlewares.middleware05.compress.minresponsebodybytes=42"
- "traefik.http.middlewares.middleware06.compress.excludedcontenttypes=foobar, foobar" - "traefik.http.middlewares.middleware06.contenttype=true"
- "traefik.http.middlewares.middleware06.compress.includedcontenttypes=foobar, foobar" - "traefik.http.middlewares.middleware07.digestauth.headerfield=foobar"
- "traefik.http.middlewares.middleware06.compress.minresponsebodybytes=42" - "traefik.http.middlewares.middleware07.digestauth.realm=foobar"
- "traefik.http.middlewares.middleware07.contenttype=true" - "traefik.http.middlewares.middleware07.digestauth.removeheader=true"
- "traefik.http.middlewares.middleware08.digestauth.headerfield=foobar" - "traefik.http.middlewares.middleware07.digestauth.users=foobar, foobar"
- "traefik.http.middlewares.middleware08.digestauth.realm=foobar" - "traefik.http.middlewares.middleware07.digestauth.usersfile=foobar"
- "traefik.http.middlewares.middleware08.digestauth.removeheader=true" - "traefik.http.middlewares.middleware08.errors.query=foobar"
- "traefik.http.middlewares.middleware08.digestauth.users=foobar, foobar" - "traefik.http.middlewares.middleware08.errors.service=foobar"
- "traefik.http.middlewares.middleware08.digestauth.usersfile=foobar" - "traefik.http.middlewares.middleware08.errors.status=foobar, foobar"
- "traefik.http.middlewares.middleware09.errors.query=foobar" - "traefik.http.middlewares.middleware09.forwardauth.address=foobar"
- "traefik.http.middlewares.middleware09.errors.service=foobar" - "traefik.http.middlewares.middleware09.forwardauth.authresponseheaders=foobar, foobar"
- "traefik.http.middlewares.middleware09.errors.status=foobar, foobar" - "traefik.http.middlewares.middleware09.forwardauth.authresponseheadersregex=foobar"
- "traefik.http.middlewares.middleware10.forwardauth.addauthcookiestoresponse=foobar, foobar" - "traefik.http.middlewares.middleware09.forwardauth.authrequestheaders=foobar, foobar"
- "traefik.http.middlewares.middleware10.forwardauth.address=foobar" - "traefik.http.middlewares.middleware09.forwardauth.tls.ca=foobar"
- "traefik.http.middlewares.middleware10.forwardauth.authrequestheaders=foobar, foobar" - "traefik.http.middlewares.middleware09.forwardauth.tls.cert=foobar"
- "traefik.http.middlewares.middleware10.forwardauth.authresponseheaders=foobar, foobar" - "traefik.http.middlewares.middleware09.forwardauth.tls.insecureskipverify=true"
- "traefik.http.middlewares.middleware10.forwardauth.authresponseheadersregex=foobar" - "traefik.http.middlewares.middleware09.forwardauth.tls.key=foobar"
- "traefik.http.middlewares.middleware10.forwardauth.tls.ca=foobar" - "traefik.http.middlewares.middleware09.forwardauth.trustforwardheader=true"
- "traefik.http.middlewares.middleware10.forwardauth.tls.cert=foobar" - "traefik.http.middlewares.middleware10.headers.accesscontrolallowcredentials=true"
- "traefik.http.middlewares.middleware10.forwardauth.tls.insecureskipverify=true" - "traefik.http.middlewares.middleware10.headers.accesscontrolallowheaders=foobar, foobar"
- "traefik.http.middlewares.middleware10.forwardauth.tls.key=foobar" - "traefik.http.middlewares.middleware10.headers.accesscontrolallowmethods=foobar, foobar"
- "traefik.http.middlewares.middleware10.forwardauth.trustforwardheader=true" - "traefik.http.middlewares.middleware10.headers.accesscontrolalloworiginlist=foobar, foobar"
- "traefik.http.middlewares.middleware11.grpcweb.alloworigins=foobar, foobar" - "traefik.http.middlewares.middleware10.headers.accesscontrolalloworiginlistregex=foobar, foobar"
- "traefik.http.middlewares.middleware12.headers.accesscontrolallowcredentials=true" - "traefik.http.middlewares.middleware10.headers.accesscontrolexposeheaders=foobar, foobar"
- "traefik.http.middlewares.middleware12.headers.accesscontrolallowheaders=foobar, foobar" - "traefik.http.middlewares.middleware10.headers.accesscontrolmaxage=42"
- "traefik.http.middlewares.middleware12.headers.accesscontrolallowmethods=foobar, foobar" - "traefik.http.middlewares.middleware10.headers.addvaryheader=true"
- "traefik.http.middlewares.middleware12.headers.accesscontrolalloworiginlist=foobar, foobar" - "traefik.http.middlewares.middleware10.headers.allowedhosts=foobar, foobar"
- "traefik.http.middlewares.middleware12.headers.accesscontrolalloworiginlistregex=foobar, foobar" - "traefik.http.middlewares.middleware10.headers.browserxssfilter=true"
- "traefik.http.middlewares.middleware12.headers.accesscontrolexposeheaders=foobar, foobar" - "traefik.http.middlewares.middleware10.headers.contentsecuritypolicy=foobar"
- "traefik.http.middlewares.middleware12.headers.accesscontrolmaxage=42" - "traefik.http.middlewares.middleware10.headers.contenttypenosniff=true"
- "traefik.http.middlewares.middleware12.headers.addvaryheader=true" - "traefik.http.middlewares.middleware10.headers.custombrowserxssvalue=foobar"
- "traefik.http.middlewares.middleware12.headers.allowedhosts=foobar, foobar" - "traefik.http.middlewares.middleware10.headers.customframeoptionsvalue=foobar"
- "traefik.http.middlewares.middleware12.headers.browserxssfilter=true" - "traefik.http.middlewares.middleware10.headers.customrequestheaders.name0=foobar"
- "traefik.http.middlewares.middleware12.headers.contentsecuritypolicy=foobar" - "traefik.http.middlewares.middleware10.headers.customrequestheaders.name1=foobar"
- "traefik.http.middlewares.middleware12.headers.contenttypenosniff=true" - "traefik.http.middlewares.middleware10.headers.customresponseheaders.name0=foobar"
- "traefik.http.middlewares.middleware12.headers.custombrowserxssvalue=foobar" - "traefik.http.middlewares.middleware10.headers.customresponseheaders.name1=foobar"
- "traefik.http.middlewares.middleware12.headers.customframeoptionsvalue=foobar" - "traefik.http.middlewares.middleware10.headers.forcestsheader=true"
- "traefik.http.middlewares.middleware12.headers.customrequestheaders.name0=foobar" - "traefik.http.middlewares.middleware10.headers.framedeny=true"
- "traefik.http.middlewares.middleware12.headers.customrequestheaders.name1=foobar" - "traefik.http.middlewares.middleware10.headers.hostsproxyheaders=foobar, foobar"
- "traefik.http.middlewares.middleware12.headers.customresponseheaders.name0=foobar" - "traefik.http.middlewares.middleware10.headers.isdevelopment=true"
- "traefik.http.middlewares.middleware12.headers.customresponseheaders.name1=foobar" - "traefik.http.middlewares.middleware10.headers.permissionspolicy=foobar"
- "traefik.http.middlewares.middleware12.headers.forcestsheader=true" - "traefik.http.middlewares.middleware10.headers.publickey=foobar"
- "traefik.http.middlewares.middleware12.headers.framedeny=true" - "traefik.http.middlewares.middleware10.headers.referrerpolicy=foobar"
- "traefik.http.middlewares.middleware12.headers.hostsproxyheaders=foobar, foobar" - "traefik.http.middlewares.middleware10.headers.sslproxyheaders.name0=foobar"
- "traefik.http.middlewares.middleware12.headers.isdevelopment=true" - "traefik.http.middlewares.middleware10.headers.sslproxyheaders.name1=foobar"
- "traefik.http.middlewares.middleware12.headers.permissionspolicy=foobar" - "traefik.http.middlewares.middleware10.headers.stsincludesubdomains=true"
- "traefik.http.middlewares.middleware12.headers.publickey=foobar" - "traefik.http.middlewares.middleware10.headers.stspreload=true"
- "traefik.http.middlewares.middleware12.headers.referrerpolicy=foobar" - "traefik.http.middlewares.middleware10.headers.stsseconds=42"
- "traefik.http.middlewares.middleware12.headers.sslproxyheaders.name0=foobar" - "traefik.http.middlewares.middleware11.ipwhitelist.ipstrategy.depth=42"
- "traefik.http.middlewares.middleware12.headers.sslproxyheaders.name1=foobar" - "traefik.http.middlewares.middleware11.ipwhitelist.ipstrategy.excludedips=foobar, foobar"
- "traefik.http.middlewares.middleware12.headers.stsincludesubdomains=true" - "traefik.http.middlewares.middleware12.ipwhitelist.sourcerange=foobar, foobar"
- "traefik.http.middlewares.middleware12.headers.stspreload=true" - "traefik.http.middlewares.middleware12.ipallowlist.ipstrategy.depth=42"
- "traefik.http.middlewares.middleware12.headers.stsseconds=42" - "traefik.http.middlewares.middleware12.ipallowlist.ipstrategy.excludedips=foobar, foobar"
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy=true" - "traefik.http.middlewares.middleware12.ipallowlist.sourcerange=foobar, foobar"
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy.depth=42" - "traefik.http.middlewares.middleware12.ipallowlist.rejectstatuscode=404"
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy.excludedips=foobar, foobar" - "traefik.http.middlewares.middleware13.inflightreq.amount=42"
- "traefik.http.middlewares.middleware13.ipallowlist.rejectstatuscode=42" - "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.ipstrategy.depth=42"
- "traefik.http.middlewares.middleware13.ipallowlist.sourcerange=foobar, foobar" - "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy=true" - "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.requestheadername=foobar"
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy.depth=42" - "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.requesthost=true"
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy.excludedips=foobar, foobar" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.commonname=true"
- "traefik.http.middlewares.middleware14.ipwhitelist.sourcerange=foobar, foobar" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.country=true"
- "traefik.http.middlewares.middleware15.inflightreq.amount=42" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.domaincomponent=true"
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.ipstrategy.depth=42" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.locality=true"
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.ipstrategy.excludedips=foobar, foobar" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.organization=true"
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.requestheadername=foobar" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.province=true"
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.requesthost=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.serialnumber=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.commonname=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.notafter=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.country=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.notbefore=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.domaincomponent=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.sans=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.locality=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.serialnumber=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.organization=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.commonname=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.province=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.country=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.serialnumber=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.domaincomponent=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.notafter=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.locality=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.notbefore=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.organization=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.sans=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.organizationalunit=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.serialnumber=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.province=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.commonname=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.serialnumber=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.country=true" - "traefik.http.middlewares.middleware14.passtlsclientcert.pem=true"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.domaincomponent=true" - "traefik.http.middlewares.middleware15.plugin.foobar.foo=bar"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.locality=true" - "traefik.http.middlewares.middleware16.ratelimit.average=42"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.organization=true" - "traefik.http.middlewares.middleware16.ratelimit.burst=42"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.organizationalunit=true" - "traefik.http.middlewares.middleware16.ratelimit.period=42"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.province=true" - "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.ipstrategy.depth=42"
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.subject.serialnumber=true" - "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
- "traefik.http.middlewares.middleware16.passtlsclientcert.pem=true" - "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.requestheadername=foobar"
- "traefik.http.middlewares.middleware17.plugin.pluginconf0.name0=foobar" - "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.requesthost=true"
- "traefik.http.middlewares.middleware17.plugin.pluginconf0.name1=foobar" - "traefik.http.middlewares.middleware17.redirectregex.permanent=true"
- "traefik.http.middlewares.middleware17.plugin.pluginconf1.name0=foobar" - "traefik.http.middlewares.middleware17.redirectregex.regex=foobar"
- "traefik.http.middlewares.middleware17.plugin.pluginconf1.name1=foobar" - "traefik.http.middlewares.middleware17.redirectregex.replacement=foobar"
- "traefik.http.middlewares.middleware18.ratelimit.average=42" - "traefik.http.middlewares.middleware18.redirectscheme.permanent=true"
- "traefik.http.middlewares.middleware18.ratelimit.burst=42" - "traefik.http.middlewares.middleware18.redirectscheme.port=foobar"
- "traefik.http.middlewares.middleware18.ratelimit.period=42s" - "traefik.http.middlewares.middleware18.redirectscheme.scheme=foobar"
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.ipstrategy.depth=42" - "traefik.http.middlewares.middleware19.replacepath.path=foobar"
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.ipstrategy.excludedips=foobar, foobar" - "traefik.http.middlewares.middleware20.replacepathregex.regex=foobar"
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.requestheadername=foobar" - "traefik.http.middlewares.middleware20.replacepathregex.replacement=foobar"
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.requesthost=true" - "traefik.http.middlewares.middleware21.retry.attempts=42"
- "traefik.http.middlewares.middleware19.redirectregex.permanent=true" - "traefik.http.middlewares.middleware21.retry.initialinterval=42"
- "traefik.http.middlewares.middleware19.redirectregex.regex=foobar" - "traefik.http.middlewares.middleware22.stripprefix.prefixes=foobar, foobar"
- "traefik.http.middlewares.middleware19.redirectregex.replacement=foobar" - "traefik.http.middlewares.middleware23.stripprefixregex.regex=foobar, foobar"
- "traefik.http.middlewares.middleware20.redirectscheme.permanent=true" - "traefik.http.middlewares.middleware24.grpcweb.alloworigins=foobar, foobar"
- "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"
@ -145,7 +135,6 @@
- "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"
@ -154,39 +143,35 @@
- "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.service02.loadbalancer.healthcheck.followredirects=true" - "traefik.http.services.service01.loadbalancer.healthcheck.followredirects=true"
- "traefik.http.services.service02.loadbalancer.healthcheck.headers.name0=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.headers.name0=foobar"
- "traefik.http.services.service02.loadbalancer.healthcheck.headers.name1=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.headers.name1=foobar"
- "traefik.http.services.service02.loadbalancer.healthcheck.hostname=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.hostname=foobar"
- "traefik.http.services.service02.loadbalancer.healthcheck.interval=42s" - "traefik.http.services.service01.loadbalancer.healthcheck.interval=foobar"
- "traefik.http.services.service02.loadbalancer.healthcheck.method=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.path=foobar"
- "traefik.http.services.service02.loadbalancer.healthcheck.mode=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.method=foobar"
- "traefik.http.services.service02.loadbalancer.healthcheck.path=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.status=42"
- "traefik.http.services.service02.loadbalancer.healthcheck.port=42" - "traefik.http.services.service01.loadbalancer.healthcheck.port=42"
- "traefik.http.services.service02.loadbalancer.healthcheck.scheme=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.scheme=foobar"
- "traefik.http.services.service02.loadbalancer.healthcheck.status=42" - "traefik.http.services.service01.loadbalancer.healthcheck.mode=foobar"
- "traefik.http.services.service02.loadbalancer.healthcheck.timeout=42s" - "traefik.http.services.service01.loadbalancer.healthcheck.timeout=foobar"
- "traefik.http.services.service02.loadbalancer.passhostheader=true" - "traefik.http.services.service01.loadbalancer.passhostheader=true"
- "traefik.http.services.service02.loadbalancer.responseforwarding.flushinterval=42s" - "traefik.http.services.service01.loadbalancer.responseforwarding.flushinterval=foobar"
- "traefik.http.services.service02.loadbalancer.serverstransport=foobar" - "traefik.http.services.service01.loadbalancer.serverstransport=foobar"
- "traefik.http.services.service02.loadbalancer.sticky=true" - "traefik.http.services.service01.loadbalancer.sticky.cookie=true"
- "traefik.http.services.service02.loadbalancer.sticky.cookie=true" - "traefik.http.services.service01.loadbalancer.sticky.cookie.httponly=true"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.httponly=true" - "traefik.http.services.service01.loadbalancer.sticky.cookie.name=foobar"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.maxage=42" - "traefik.http.services.service01.loadbalancer.sticky.cookie.samesite=foobar"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.name=foobar" - "traefik.http.services.service01.loadbalancer.sticky.cookie.secure=true"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.samesite=foobar" - "traefik.http.services.service01.loadbalancer.server.port=foobar"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.secure=true" - "traefik.http.services.service01.loadbalancer.server.scheme=foobar"
- "traefik.http.services.service02.loadbalancer.server.port=foobar" - "traefik.tcp.middlewares.tcpmiddleware00.inflightconn.amount=42"
- "traefik.http.services.service02.loadbalancer.server.scheme=foobar" - "traefik.tcp.middlewares.tcpmiddleware01.ipwhitelist.sourcerange=foobar, foobar"
- "traefik.http.services.service02.loadbalancer.server.weight=42" - "traefik.tcp.middlewares.tcpmiddleware02.ipallowlist.sourcerange=foobar, foobar"
- "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.priority=42"
- "traefik.tcp.routers.tcprouter0.rule=foobar" - "traefik.tcp.routers.tcprouter0.rule=foobar"
- "traefik.tcp.routers.tcprouter0.rulesyntax=foobar" - "traefik.tcp.routers.tcprouter0.priority=42"
- "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"
@ -198,9 +183,8 @@
- "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.priority=42"
- "traefik.tcp.routers.tcprouter1.rule=foobar" - "traefik.tcp.routers.tcprouter1.rule=foobar"
- "traefik.tcp.routers.tcprouter1.rulesyntax=foobar" - "traefik.tcp.routers.tcprouter1.priority=42"
- "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"
@ -210,13 +194,22 @@
- "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"

View file

@ -1,5 +1,3 @@
## CODE GENERATED AUTOMATICALLY
## THIS FILE MUST NOT BE EDITED BY HAND
[http] [http]
[http.routers] [http.routers]
[http.routers.Router0] [http.routers.Router0]
@ -7,7 +5,6 @@
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"
@ -25,7 +22,6 @@
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"
@ -40,30 +36,22 @@
sans = ["foobar", "foobar"] sans = ["foobar", "foobar"]
[http.services] [http.services]
[http.services.Service01] [http.services.Service01]
[http.services.Service01.failover] [http.services.Service01.loadBalancer]
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.Service02.loadBalancer.sticky] [http.services.Service01.loadBalancer.sticky]
[http.services.Service02.loadBalancer.sticky.cookie] [http.services.Service01.loadBalancer.sticky.cookie]
name = "foobar" name = "foobar"
secure = true secure = true
httpOnly = true httpOnly = true
sameSite = "foobar" sameSite = "foobar"
maxAge = 42
[[http.services.Service02.loadBalancer.servers]] [[http.services.Service01.loadBalancer.servers]]
url = "foobar" url = "foobar"
weight = 42
[[http.services.Service02.loadBalancer.servers]] [[http.services.Service01.loadBalancer.servers]]
url = "foobar" url = "foobar"
weight = 42 [http.services.Service01.loadBalancer.healthCheck]
[http.services.Service02.loadBalancer.healthCheck]
scheme = "foobar" scheme = "foobar"
mode = "foobar" mode = "foobar"
path = "foobar" path = "foobar"
@ -74,106 +62,107 @@
timeout = "42s" timeout = "42s"
hostname = "foobar" hostname = "foobar"
followRedirects = true followRedirects = true
[http.services.Service02.loadBalancer.healthCheck.headers] [http.services.Service01.loadBalancer.healthCheck.headers]
name0 = "foobar" name0 = "foobar"
name1 = "foobar" name1 = "foobar"
[http.services.Service02.loadBalancer.responseForwarding] [http.services.Service01.loadBalancer.responseForwarding]
flushInterval = "42s" flushInterval = "42s"
[http.services.Service03] [http.services.Service02]
[http.services.Service03.mirroring] [http.services.Service02.mirroring]
service = "foobar" service = "foobar"
maxBodySize = 42 maxBodySize = 42
[[http.services.Service03.mirroring.mirrors]] [http.services.Service02.mirroring.healthCheck]
[[http.services.Service02.mirroring.mirrors]]
name = "foobar" name = "foobar"
percent = 42 percent = 42
[[http.services.Service03.mirroring.mirrors]] [[http.services.Service02.mirroring.mirrors]]
name = "foobar" name = "foobar"
percent = 42 percent = 42
[http.services.Service03.mirroring.healthCheck] [http.services.Service03]
[http.services.Service04] [http.services.Service03.weighted]
[http.services.Service04.weighted] [http.services.Service03.weighted.healthCheck]
[[http.services.Service04.weighted.services]] [[http.services.Service03.weighted.services]]
name = "foobar" name = "foobar"
weight = 42 weight = 42
[[http.services.Service04.weighted.services]] [[http.services.Service03.weighted.services]]
name = "foobar" name = "foobar"
weight = 42 weight = 42
[http.services.Service04.weighted.sticky] [http.services.Service03.weighted.sticky]
[http.services.Service04.weighted.sticky.cookie] [http.services.Service03.weighted.sticky.cookie]
name = "foobar" name = "foobar"
secure = true secure = true
httpOnly = true httpOnly = true
sameSite = "foobar" sameSite = "foobar"
maxAge = 42 [http.services.Service04]
[http.services.Service04.weighted.healthCheck] [http.services.Service04.failover]
service = "foobar"
fallback = "foobar"
[http.services.Service04.failover.healthCheck]
[http.middlewares] [http.middlewares]
[http.middlewares.Middleware01] [http.middlewares.Middleware00]
[http.middlewares.Middleware01.addPrefix] [http.middlewares.Middleware00.addPrefix]
prefix = "foobar" prefix = "foobar"
[http.middlewares.Middleware02] [http.middlewares.Middleware01]
[http.middlewares.Middleware02.basicAuth] [http.middlewares.Middleware01.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.Middleware03] [http.middlewares.Middleware02]
[http.middlewares.Middleware03.buffering] [http.middlewares.Middleware02.buffering]
maxRequestBodyBytes = 42 maxRequestBodyBytes = 42
memRequestBodyBytes = 42 memRequestBodyBytes = 42
maxResponseBodyBytes = 42 maxResponseBodyBytes = 42
memResponseBodyBytes = 42 memResponseBodyBytes = 42
retryExpression = "foobar" retryExpression = "foobar"
[http.middlewares.Middleware04] [http.middlewares.Middleware03]
[http.middlewares.Middleware04.chain] [http.middlewares.Middleware03.chain]
middlewares = ["foobar", "foobar"] middlewares = ["foobar", "foobar"]
[http.middlewares.Middleware05] [http.middlewares.Middleware04]
[http.middlewares.Middleware05.circuitBreaker] [http.middlewares.Middleware04.circuitBreaker]
expression = "foobar" expression = "foobar"
checkPeriod = "42s" checkPeriod = "42s"
fallbackDuration = "42s" fallbackDuration = "42s"
recoveryDuration = "42s" recoveryDuration = "42s"
[http.middlewares.Middleware06] [http.middlewares.Middleware05]
[http.middlewares.Middleware06.compress] [http.middlewares.Middleware05.compress]
excludedContentTypes = ["foobar", "foobar"] excludedContentTypes = ["foobar", "foobar"]
includedContentTypes = ["foobar", "foobar"]
minResponseBodyBytes = 42 minResponseBodyBytes = 42
[http.middlewares.Middleware06]
[http.middlewares.Middleware06.contentType]
[http.middlewares.Middleware07] [http.middlewares.Middleware07]
[http.middlewares.Middleware07.contentType] [http.middlewares.Middleware07.digestAuth]
[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.Middleware09] [http.middlewares.Middleware08]
[http.middlewares.Middleware09.errors] [http.middlewares.Middleware08.errors]
status = ["foobar", "foobar"] status = ["foobar", "foobar"]
service = "foobar" service = "foobar"
query = "foobar" query = "foobar"
[http.middlewares.Middleware10] [http.middlewares.Middleware09]
[http.middlewares.Middleware10.forwardAuth] [http.middlewares.Middleware09.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"]
addAuthCookiesToResponse = ["foobar", "foobar"] [http.middlewares.Middleware09.forwardAuth.tls]
[http.middlewares.Middleware10.forwardAuth.tls]
ca = "foobar" ca = "foobar"
cert = "foobar" cert = "foobar"
key = "foobar" key = "foobar"
insecureSkipVerify = true insecureSkipVerify = true
[http.middlewares.Middleware11] [http.middlewares.Middleware10]
[http.middlewares.Middleware11.grpcWeb] [http.middlewares.Middleware10.headers]
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"]
@ -198,46 +187,46 @@
referrerPolicy = "foobar" referrerPolicy = "foobar"
permissionsPolicy = "foobar" permissionsPolicy = "foobar"
isDevelopment = true isDevelopment = true
[http.middlewares.Middleware12.headers.customRequestHeaders] [http.middlewares.Middleware10.headers.customRequestHeaders]
name0 = "foobar" name0 = "foobar"
name1 = "foobar" name1 = "foobar"
[http.middlewares.Middleware12.headers.customResponseHeaders] [http.middlewares.Middleware10.headers.customResponseHeaders]
name0 = "foobar" name0 = "foobar"
name1 = "foobar" name1 = "foobar"
[http.middlewares.Middleware12.headers.sslProxyHeaders] [http.middlewares.Middleware10.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.ipAllowList] [http.middlewares.Middleware13.inFlightReq]
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.Middleware15.inFlightReq.sourceCriterion] [http.middlewares.Middleware13.inFlightReq.sourceCriterion]
requestHeaderName = "foobar" requestHeaderName = "foobar"
requestHost = true requestHost = true
[http.middlewares.Middleware15.inFlightReq.sourceCriterion.ipStrategy] [http.middlewares.Middleware13.inFlightReq.sourceCriterion.ipStrategy]
depth = 42 depth = 42
excludedIPs = ["foobar", "foobar"] excludedIPs = ["foobar", "foobar"]
[http.middlewares.Middleware16] [http.middlewares.Middleware14]
[http.middlewares.Middleware16.passTLSClientCert] [http.middlewares.Middleware14.passTLSClientCert]
pem = true pem = true
[http.middlewares.Middleware16.passTLSClientCert.info] [http.middlewares.Middleware14.passTLSClientCert.info]
notAfter = true notAfter = true
notBefore = true notBefore = true
sans = true sans = true
serialNumber = true serialNumber = true
[http.middlewares.Middleware16.passTLSClientCert.info.subject] [http.middlewares.Middleware14.passTLSClientCert.info.subject]
country = true country = true
province = true province = true
locality = true locality = true
@ -246,7 +235,7 @@
commonName = true commonName = true
serialNumber = true serialNumber = true
domainComponent = true domainComponent = true
[http.middlewares.Middleware16.passTLSClientCert.info.issuer] [http.middlewares.Middleware14.passTLSClientCert.info.issuer]
country = true country = true
province = true province = true
locality = true locality = true
@ -254,52 +243,51 @@
commonName = true commonName = true
serialNumber = true serialNumber = true
domainComponent = true domainComponent = true
[http.middlewares.Middleware17] [http.middlewares.Middleware15]
[http.middlewares.Middleware17.plugin] [http.middlewares.Middleware15.plugin]
[http.middlewares.Middleware17.plugin.PluginConf0] [http.middlewares.Middleware15.plugin.PluginConf]
name0 = "foobar" foo = "bar"
name1 = "foobar" [http.middlewares.Middleware16]
[http.middlewares.Middleware17.plugin.PluginConf1] [http.middlewares.Middleware16.rateLimit]
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.Middleware18.rateLimit.sourceCriterion] [http.middlewares.Middleware16.rateLimit.sourceCriterion]
requestHeaderName = "foobar" requestHeaderName = "foobar"
requestHost = true requestHost = true
[http.middlewares.Middleware18.rateLimit.sourceCriterion.ipStrategy] [http.middlewares.Middleware16.rateLimit.sourceCriterion.ipStrategy]
depth = 42 depth = 42
excludedIPs = ["foobar", "foobar"] excludedIPs = ["foobar", "foobar"]
[http.middlewares.Middleware19] [http.middlewares.Middleware17]
[http.middlewares.Middleware19.redirectRegex] [http.middlewares.Middleware17.redirectRegex]
regex = "foobar" regex = "foobar"
replacement = "foobar" replacement = "foobar"
permanent = true permanent = true
[http.middlewares.Middleware20] [http.middlewares.Middleware18]
[http.middlewares.Middleware20.redirectScheme] [http.middlewares.Middleware18.redirectScheme]
scheme = "foobar" scheme = "foobar"
port = "foobar" port = "foobar"
permanent = true permanent = true
[http.middlewares.Middleware21] [http.middlewares.Middleware19]
[http.middlewares.Middleware21.replacePath] [http.middlewares.Middleware19.replacePath]
path = "foobar" path = "foobar"
[http.middlewares.Middleware22] [http.middlewares.Middleware20]
[http.middlewares.Middleware22.replacePathRegex] [http.middlewares.Middleware20.replacePathRegex]
regex = "foobar" regex = "foobar"
replacement = "foobar" replacement = "foobar"
[http.middlewares.Middleware23] [http.middlewares.Middleware21]
[http.middlewares.Middleware23.retry] [http.middlewares.Middleware21.retry]
attempts = 42 attempts = 42
initialInterval = "42s" initialInterval = "42s"
[http.middlewares.Middleware24] [http.middlewares.Middleware22]
[http.middlewares.Middleware24.stripPrefix] [http.middlewares.Middleware22.stripPrefix]
prefixes = ["foobar", "foobar"] prefixes = ["foobar", "foobar"]
[http.middlewares.Middleware25] [http.middlewares.Middleware23]
[http.middlewares.Middleware25.stripPrefixRegex] [http.middlewares.Middleware23.stripPrefixRegex]
regex = ["foobar", "foobar"] regex = ["foobar", "foobar"]
[http.middlewares.Middleware24]
[http.middlewares.Middleware24.grpcWeb]
allowOrigins = ["foobar", "foobar"]
[http.serversTransports] [http.serversTransports]
[http.serversTransports.ServersTransport0] [http.serversTransports.ServersTransport0]
serverName = "foobar" serverName = "foobar"
@ -316,15 +304,18 @@
[[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
@ -340,12 +331,14 @@
[[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"
@ -357,7 +350,6 @@
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
@ -376,7 +368,6 @@
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
@ -414,21 +405,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.ipAllowList] [tcp.middlewares.TCPMiddleware01.inFlightConn]
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]
dialKeepAlive = "42s"
dialTimeout = "42s" dialTimeout = "42s"
dialKeepAlive = "42s"
terminationDelay = "42s" terminationDelay = "42s"
[tcp.serversTransports.TCPServersTransport0.tls] [tcp.serversTransports.TCPServersTransport0.tls]
serverName = "foobar" serverName = "foobar"
insecureSkipVerify = true insecureSkipVerify = true
@ -442,13 +433,16 @@
[[tcp.serversTransports.TCPServersTransport0.tls.certificates]] [[tcp.serversTransports.TCPServersTransport0.tls.certificates]]
certFile = "foobar" certFile = "foobar"
keyFile = "foobar" keyFile = "foobar"
[tcp.serversTransports.TCPServersTransport0.tls.spiffe]
ids = ["foobar", "foobar"] [tcp.serversTransports.TCPServersTransport0.spiffe]
trustDomain = "foobar" ids = ["foobar", "foobar"]
trustDomain = "foobar"
[tcp.serversTransports.TCPServersTransport1] [tcp.serversTransports.TCPServersTransport1]
dialKeepAlive = "42s"
dialTimeout = "42s" dialTimeout = "42s"
dialKeepAlive = "42s"
terminationDelay = "42s" terminationDelay = "42s"
[tcp.serversTransports.TCPServersTransport1.tls] [tcp.serversTransports.TCPServersTransport1.tls]
serverName = "foobar" serverName = "foobar"
insecureSkipVerify = true insecureSkipVerify = true
@ -462,9 +456,10 @@
[[tcp.serversTransports.TCPServersTransport1.tls.certificates]] [[tcp.serversTransports.TCPServersTransport1.tls.certificates]]
certFile = "foobar" certFile = "foobar"
keyFile = "foobar" keyFile = "foobar"
[tcp.serversTransports.TCPServersTransport1.tls.spiffe]
ids = ["foobar", "foobar"] [tcp.serversTransports.TCPServersTransport1.spiffe]
trustDomain = "foobar" ids = ["foobar", "foobar"]
trustDomain = "foobar"
[udp] [udp]
[udp.routers] [udp.routers]

View file

@ -1,5 +1,3 @@
## CODE GENERATED AUTOMATICALLY
## THIS FILE MUST NOT BE EDITED BY HAND
http: http:
routers: routers:
Router0: Router0:
@ -11,7 +9,6 @@ http:
- foobar - foobar
service: foobar service: foobar
rule: foobar rule: foobar
ruleSyntax: foobar
priority: 42 priority: 42
tls: tls:
options: foobar options: foobar
@ -34,7 +31,6 @@ http:
- foobar - foobar
service: foobar service: foobar
rule: foobar rule: foobar
ruleSyntax: foobar
priority: 42 priority: 42
tls: tls:
options: foobar options: foobar
@ -50,11 +46,6 @@ http:
- foobar - foobar
services: services:
Service01: Service01:
failover:
service: foobar
fallback: foobar
healthCheck: {}
Service02:
loadBalancer: loadBalancer:
sticky: sticky:
cookie: cookie:
@ -62,12 +53,9 @@ 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
@ -86,18 +74,19 @@ http:
responseForwarding: responseForwarding:
flushInterval: 42s flushInterval: 42s
serversTransport: foobar serversTransport: foobar
Service03: Service02:
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
healthCheck: {} Service03:
Service04:
weighted: weighted:
healthCheck: {}
services: services:
- name: foobar - name: foobar
weight: 42 weight: 42
@ -109,13 +98,16 @@ http:
secure: true secure: true
httpOnly: true httpOnly: true
sameSite: foobar sameSite: foobar
maxAge: 42 Service04:
failover:
service: foobar
fallback: foobar
healthCheck: {} healthCheck: {}
middlewares: middlewares:
Middleware01: Middleware00:
addPrefix: addPrefix:
prefix: foobar prefix: foobar
Middleware02: Middleware01:
basicAuth: basicAuth:
users: users:
- foobar - foobar
@ -124,36 +116,33 @@ http:
realm: foobar realm: foobar
removeHeader: true removeHeader: true
headerField: foobar headerField: foobar
Middleware03: Middleware02:
buffering: buffering:
maxRequestBodyBytes: 42 maxRequestBodyBytes: 42
memRequestBodyBytes: 42 memRequestBodyBytes: 42
maxResponseBodyBytes: 42 maxResponseBodyBytes: 42
memResponseBodyBytes: 42 memResponseBodyBytes: 42
retryExpression: foobar retryExpression: foobar
Middleware04: Middleware03:
chain: chain:
middlewares: middlewares:
- foobar - foobar
- foobar - foobar
Middleware05: Middleware04:
circuitBreaker: circuitBreaker:
expression: foobar expression: foobar
checkPeriod: 42s checkPeriod: 42s
fallbackDuration: 42s fallbackDuration: 42s
recoveryDuration: 42s recoveryDuration: 42s
Middleware06: Middleware05:
compress: compress:
excludedContentTypes: excludedContentTypes:
- foobar - foobar
- foobar - foobar
includedContentTypes:
- foobar
- foobar
minResponseBodyBytes: 42 minResponseBodyBytes: 42
Middleware07: Middleware06:
contentType: {} contentType: {}
Middleware08: Middleware07:
digestAuth: digestAuth:
users: users:
- foobar - foobar
@ -162,14 +151,14 @@ http:
removeHeader: true removeHeader: true
realm: foobar realm: foobar
headerField: foobar headerField: foobar
Middleware09: Middleware08:
errors: errors:
status: status:
- foobar - foobar
- foobar - foobar
service: foobar service: foobar
query: foobar query: foobar
Middleware10: Middleware09:
forwardAuth: forwardAuth:
address: foobar address: foobar
tls: tls:
@ -185,15 +174,7 @@ http:
authRequestHeaders: authRequestHeaders:
- foobar - foobar
- foobar - foobar
addAuthCookiesToResponse: Middleware10:
- foobar
- foobar
Middleware11:
grpcWeb:
allowOrigins:
- foobar
- foobar
Middleware12:
headers: headers:
customRequestHeaders: customRequestHeaders:
name0: foobar name0: foobar
@ -242,18 +223,7 @@ http:
referrerPolicy: foobar referrerPolicy: foobar
permissionsPolicy: foobar permissionsPolicy: foobar
isDevelopment: true isDevelopment: true
Middleware13: Middleware11:
ipAllowList:
sourceRange:
- foobar
- foobar
ipStrategy:
depth: 42
excludedIPs:
- foobar
- foobar
rejectStatusCode: 42
Middleware14:
ipWhiteList: ipWhiteList:
sourceRange: sourceRange:
- foobar - foobar
@ -263,7 +233,18 @@ http:
excludedIPs: excludedIPs:
- foobar - foobar
- foobar - foobar
Middleware15: Middleware12:
ipAllowList:
rejectStatusCode: 404
sourceRange:
- foobar
- foobar
ipStrategy:
depth: 42
excludedIPs:
- foobar
- foobar
Middleware13:
inFlightReq: inFlightReq:
amount: 42 amount: 42
sourceCriterion: sourceCriterion:
@ -274,14 +255,13 @@ http:
- foobar - foobar
requestHeaderName: foobar requestHeaderName: foobar
requestHost: true requestHost: true
Middleware16: Middleware14:
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
@ -299,15 +279,12 @@ http:
commonName: true commonName: true
serialNumber: true serialNumber: true
domainComponent: true domainComponent: true
Middleware17: serialNumber: true
Middleware15:
plugin: plugin:
PluginConf0: PluginConf:
name0: foobar foo: bar
name1: foobar Middleware16:
PluginConf1:
name0: foobar
name1: foobar
Middleware18:
rateLimit: rateLimit:
average: 42 average: 42
period: 42s period: 42s
@ -320,37 +297,42 @@ http:
- foobar - foobar
requestHeaderName: foobar requestHeaderName: foobar
requestHost: true requestHost: true
Middleware19: Middleware17:
redirectRegex: redirectRegex:
regex: foobar regex: foobar
replacement: foobar replacement: foobar
permanent: true permanent: true
Middleware20: Middleware18:
redirectScheme: redirectScheme:
scheme: foobar scheme: foobar
port: foobar port: foobar
permanent: true permanent: true
Middleware21: Middleware19:
replacePath: replacePath:
path: foobar path: foobar
Middleware22: Middleware20:
replacePathRegex: replacePathRegex:
regex: foobar regex: foobar
replacement: foobar replacement: foobar
Middleware23: Middleware21:
retry: retry:
attempts: 42 attempts: 42
initialInterval: 42s initialInterval: 42s
Middleware24: Middleware22:
stripPrefix: stripPrefix:
prefixes: prefixes:
- foobar - foobar
- foobar - foobar
Middleware25: Middleware23:
stripPrefixRegex: stripPrefixRegex:
regex: regex:
- foobar - foobar
- foobar - foobar
Middleware24:
grpcWeb:
allowOrigins:
- foobar
- foobar
serversTransports: serversTransports:
ServersTransport0: ServersTransport0:
serverName: foobar serverName: foobar
@ -377,6 +359,7 @@ http:
- foobar - foobar
- foobar - foobar
trustDomain: foobar trustDomain: foobar
ServersTransport1: ServersTransport1:
serverName: foobar serverName: foobar
insecureSkipVerify: true insecureSkipVerify: true
@ -402,6 +385,7 @@ http:
- foobar - foobar
- foobar - foobar
trustDomain: foobar trustDomain: foobar
tcp: tcp:
routers: routers:
TCPRouter0: TCPRouter0:
@ -413,7 +397,6 @@ 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 +420,6 @@ tcp:
- foobar - foobar
service: foobar service: foobar
rule: foobar rule: foobar
ruleSyntax: foobar
priority: 42 priority: 42
tls: tls:
passthrough: true passthrough: true
@ -455,6 +437,7 @@ tcp:
services: services:
TCPService01: TCPService01:
loadBalancer: loadBalancer:
serversTransport: foobar
proxyProtocol: proxyProtocol:
version: 42 version: 42
servers: servers:
@ -462,7 +445,6 @@ tcp:
tls: true tls: true
- address: foobar - address: foobar
tls: true tls: true
serversTransport: foobar
TCPService02: TCPService02:
weighted: weighted:
services: services:
@ -471,23 +453,23 @@ tcp:
- name: foobar - name: foobar
weight: 42 weight: 42
middlewares: middlewares:
TCPMiddleware01: TCPMiddleware00:
ipAllowList: ipAllowList:
sourceRange: sourceRange:
- foobar - foobar
- foobar - foobar
TCPMiddleware01:
inFlightConn:
amount: 42
TCPMiddleware02: TCPMiddleware02:
ipWhiteList: ipAllowList:
sourceRange: sourceRange:
- foobar - foobar
- foobar - foobar
TCPMiddleware03:
inFlightConn:
amount: 42
serversTransports: serversTransports:
TCPServersTransport0: TCPServersTransport0:
dialKeepAlive: 42s
dialTimeout: 42s dialTimeout: 42s
dialKeepAlive: 42s
terminationDelay: 42s terminationDelay: 42s
tls: tls:
serverName: foobar serverName: foobar
@ -501,14 +483,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:
dialKeepAlive: 42s
dialTimeout: 42s dialTimeout: 42s
dialKeepAlive: 42s
terminationDelay: 42s terminationDelay: 42s
tls: tls:
serverName: foobar serverName: foobar
@ -522,11 +504,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:

View file

@ -160,12 +160,6 @@ 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
@ -195,10 +189,6 @@ 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
@ -406,10 +396,6 @@ 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
@ -764,13 +750,6 @@ 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:
@ -891,12 +870,6 @@ 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
@ -939,12 +912,6 @@ 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
@ -2178,12 +2145,6 @@ 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
@ -2275,12 +2236,6 @@ 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
@ -2388,12 +2343,6 @@ 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
@ -2433,12 +2382,6 @@ 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

View file

@ -1,164 +1,152 @@
<!-- | `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/basicAuth/removeHeader` | `true` |
| `traefik/http/middlewares/Middleware01/addPrefix/prefix` | `foobar` | | `traefik/http/middlewares/Middleware01/basicAuth/users/0` | `foobar` |
| `traefik/http/middlewares/Middleware02/basicAuth/headerField` | `foobar` | | `traefik/http/middlewares/Middleware01/basicAuth/users/1` | `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/0` | `foobar` | | `traefik/http/middlewares/Middleware02/buffering/maxResponseBodyBytes` | `42` |
| `traefik/http/middlewares/Middleware02/basicAuth/users/1` | `foobar` | | `traefik/http/middlewares/Middleware02/buffering/memRequestBodyBytes` | `42` |
| `traefik/http/middlewares/Middleware02/basicAuth/usersFile` | `foobar` | | `traefik/http/middlewares/Middleware02/buffering/memResponseBodyBytes` | `42` |
| `traefik/http/middlewares/Middleware03/buffering/maxRequestBodyBytes` | `42` | | `traefik/http/middlewares/Middleware02/buffering/retryExpression` | `foobar` |
| `traefik/http/middlewares/Middleware03/buffering/maxResponseBodyBytes` | `42` | | `traefik/http/middlewares/Middleware03/chain/middlewares/0` | `foobar` |
| `traefik/http/middlewares/Middleware03/buffering/memRequestBodyBytes` | `42` | | `traefik/http/middlewares/Middleware03/chain/middlewares/1` | `foobar` |
| `traefik/http/middlewares/Middleware03/buffering/memResponseBodyBytes` | `42` | | `traefik/http/middlewares/Middleware04/circuitBreaker/checkPeriod` | `42s` |
| `traefik/http/middlewares/Middleware03/buffering/retryExpression` | `foobar` | | `traefik/http/middlewares/Middleware04/circuitBreaker/expression` | `foobar` |
| `traefik/http/middlewares/Middleware04/chain/middlewares/0` | `foobar` | | `traefik/http/middlewares/Middleware04/circuitBreaker/fallbackDuration` | `42s` |
| `traefik/http/middlewares/Middleware04/chain/middlewares/1` | `foobar` | | `traefik/http/middlewares/Middleware04/circuitBreaker/recoveryDuration` | `42s` |
| `traefik/http/middlewares/Middleware05/circuitBreaker/checkPeriod` | `42s` | | `traefik/http/middlewares/Middleware05/compress/excludedContentTypes/0` | `foobar` |
| `traefik/http/middlewares/Middleware05/circuitBreaker/expression` | `foobar` | | `traefik/http/middlewares/Middleware05/compress/excludedContentTypes/1` | `foobar` |
| `traefik/http/middlewares/Middleware05/circuitBreaker/fallbackDuration` | `42s` | | `traefik/http/middlewares/Middleware05/compress/minResponseBodyBytes` | `42` |
| `traefik/http/middlewares/Middleware05/circuitBreaker/recoveryDuration` | `42s` | | `traefik/http/middlewares/Middleware06/contentType` | `` |
| `traefik/http/middlewares/Middleware06/compress/excludedContentTypes/0` | `foobar` | | `traefik/http/middlewares/Middleware07/digestAuth/headerField` | `foobar` |
| `traefik/http/middlewares/Middleware06/compress/excludedContentTypes/1` | `foobar` | | `traefik/http/middlewares/Middleware07/digestAuth/realm` | `foobar` |
| `traefik/http/middlewares/Middleware06/compress/includedContentTypes/0` | `foobar` | | `traefik/http/middlewares/Middleware07/digestAuth/removeHeader` | `true` |
| `traefik/http/middlewares/Middleware06/compress/includedContentTypes/1` | `foobar` | | `traefik/http/middlewares/Middleware07/digestAuth/users/0` | `foobar` |
| `traefik/http/middlewares/Middleware06/compress/minResponseBodyBytes` | `42` | | `traefik/http/middlewares/Middleware07/digestAuth/users/1` | `foobar` |
| `traefik/http/middlewares/Middleware07/contentType` | `` | | `traefik/http/middlewares/Middleware07/digestAuth/usersFile` | `foobar` |
| `traefik/http/middlewares/Middleware08/digestAuth/headerField` | `foobar` | | `traefik/http/middlewares/Middleware08/errors/query` | `foobar` |
| `traefik/http/middlewares/Middleware08/digestAuth/realm` | `foobar` | | `traefik/http/middlewares/Middleware08/errors/service` | `foobar` |
| `traefik/http/middlewares/Middleware08/digestAuth/removeHeader` | `true` | | `traefik/http/middlewares/Middleware08/errors/status/0` | `foobar` |
| `traefik/http/middlewares/Middleware08/digestAuth/users/0` | `foobar` | | `traefik/http/middlewares/Middleware08/errors/status/1` | `foobar` |
| `traefik/http/middlewares/Middleware08/digestAuth/users/1` | `foobar` | | `traefik/http/middlewares/Middleware09/forwardAuth/address` | `foobar` |
| `traefik/http/middlewares/Middleware08/digestAuth/usersFile` | `foobar` | | `traefik/http/middlewares/Middleware09/forwardAuth/authRequestHeaders/0` | `foobar` |
| `traefik/http/middlewares/Middleware09/errors/query` | `foobar` | | `traefik/http/middlewares/Middleware09/forwardAuth/authRequestHeaders/1` | `foobar` |
| `traefik/http/middlewares/Middleware09/errors/service` | `foobar` | | `traefik/http/middlewares/Middleware09/forwardAuth/authResponseHeaders/0` | `foobar` |
| `traefik/http/middlewares/Middleware09/errors/status/0` | `foobar` | | `traefik/http/middlewares/Middleware09/forwardAuth/authResponseHeaders/1` | `foobar` |
| `traefik/http/middlewares/Middleware09/errors/status/1` | `foobar` | | `traefik/http/middlewares/Middleware09/forwardAuth/authResponseHeadersRegex` | `foobar` |
| `traefik/http/middlewares/Middleware10/forwardAuth/addAuthCookiesToResponse/0` | `foobar` | | `traefik/http/middlewares/Middleware09/forwardAuth/tls/ca` | `foobar` |
| `traefik/http/middlewares/Middleware10/forwardAuth/addAuthCookiesToResponse/1` | `foobar` | | `traefik/http/middlewares/Middleware09/forwardAuth/tls/cert` | `foobar` |
| `traefik/http/middlewares/Middleware10/forwardAuth/address` | `foobar` | | `traefik/http/middlewares/Middleware09/forwardAuth/tls/insecureSkipVerify` | `true` |
| `traefik/http/middlewares/Middleware10/forwardAuth/authRequestHeaders/0` | `foobar` | | `traefik/http/middlewares/Middleware09/forwardAuth/tls/key` | `foobar` |
| `traefik/http/middlewares/Middleware10/forwardAuth/authRequestHeaders/1` | `foobar` | | `traefik/http/middlewares/Middleware09/forwardAuth/trustForwardHeader` | `true` |
| `traefik/http/middlewares/Middleware10/forwardAuth/authResponseHeaders/0` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/accessControlAllowCredentials` | `true` |
| `traefik/http/middlewares/Middleware10/forwardAuth/authResponseHeaders/1` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/accessControlAllowHeaders/0` | `foobar` |
| `traefik/http/middlewares/Middleware10/forwardAuth/authResponseHeadersRegex` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/accessControlAllowHeaders/1` | `foobar` |
| `traefik/http/middlewares/Middleware10/forwardAuth/tls/ca` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/accessControlAllowMethods/0` | `foobar` |
| `traefik/http/middlewares/Middleware10/forwardAuth/tls/cert` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/accessControlAllowMethods/1` | `foobar` |
| `traefik/http/middlewares/Middleware10/forwardAuth/tls/insecureSkipVerify` | `true` | | `traefik/http/middlewares/Middleware10/headers/accessControlAllowOriginList/0` | `foobar` |
| `traefik/http/middlewares/Middleware10/forwardAuth/tls/key` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/accessControlAllowOriginList/1` | `foobar` |
| `traefik/http/middlewares/Middleware10/forwardAuth/trustForwardHeader` | `true` | | `traefik/http/middlewares/Middleware10/headers/accessControlAllowOriginListRegex/0` | `foobar` |
| `traefik/http/middlewares/Middleware11/grpcWeb/allowOrigins/0` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/accessControlAllowOriginListRegex/1` | `foobar` |
| `traefik/http/middlewares/Middleware11/grpcWeb/allowOrigins/1` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/accessControlExposeHeaders/0` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowCredentials` | `true` | | `traefik/http/middlewares/Middleware10/headers/accessControlExposeHeaders/1` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowHeaders/0` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/accessControlMaxAge` | `42` |
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowHeaders/1` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/addVaryHeader` | `true` |
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowMethods/0` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/allowedHosts/0` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowMethods/1` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/allowedHosts/1` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowOriginList/0` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/browserXssFilter` | `true` |
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowOriginList/1` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/contentSecurityPolicy` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowOriginListRegex/0` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/contentTypeNosniff` | `true` |
| `traefik/http/middlewares/Middleware12/headers/accessControlAllowOriginListRegex/1` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/customBrowserXSSValue` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/accessControlExposeHeaders/0` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/customFrameOptionsValue` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/accessControlExposeHeaders/1` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/customRequestHeaders/name0` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/accessControlMaxAge` | `42` | | `traefik/http/middlewares/Middleware10/headers/customRequestHeaders/name1` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/addVaryHeader` | `true` | | `traefik/http/middlewares/Middleware10/headers/customResponseHeaders/name0` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/allowedHosts/0` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/customResponseHeaders/name1` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/allowedHosts/1` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/forceSTSHeader` | `true` |
| `traefik/http/middlewares/Middleware12/headers/browserXssFilter` | `true` | | `traefik/http/middlewares/Middleware10/headers/frameDeny` | `true` |
| `traefik/http/middlewares/Middleware12/headers/contentSecurityPolicy` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/hostsProxyHeaders/0` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/contentTypeNosniff` | `true` | | `traefik/http/middlewares/Middleware10/headers/hostsProxyHeaders/1` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/customBrowserXSSValue` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/isDevelopment` | `true` |
| `traefik/http/middlewares/Middleware12/headers/customFrameOptionsValue` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/permissionsPolicy` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/customRequestHeaders/name0` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/publicKey` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/customRequestHeaders/name1` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/referrerPolicy` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/customResponseHeaders/name0` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/sslProxyHeaders/name0` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/customResponseHeaders/name1` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/sslProxyHeaders/name1` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/forceSTSHeader` | `true` | | `traefik/http/middlewares/Middleware10/headers/stsIncludeSubdomains` | `true` |
| `traefik/http/middlewares/Middleware12/headers/frameDeny` | `true` | | `traefik/http/middlewares/Middleware10/headers/stsPreload` | `true` |
| `traefik/http/middlewares/Middleware12/headers/hostsProxyHeaders/0` | `foobar` | | `traefik/http/middlewares/Middleware10/headers/stsSeconds` | `42` |
| `traefik/http/middlewares/Middleware12/headers/hostsProxyHeaders/1` | `foobar` | | `traefik/http/middlewares/Middleware11/ipWhiteList/ipStrategy/depth` | `42` |
| `traefik/http/middlewares/Middleware12/headers/isDevelopment` | `true` | | `traefik/http/middlewares/Middleware11/ipWhiteList/ipStrategy/excludedIPs/0` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/permissionsPolicy` | `foobar` | | `traefik/http/middlewares/Middleware11/ipWhiteList/ipStrategy/excludedIPs/1` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/publicKey` | `foobar` | | `traefik/http/middlewares/Middleware11/ipWhiteList/sourceRange/0` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/referrerPolicy` | `foobar` | | `traefik/http/middlewares/Middleware11/ipWhiteList/sourceRange/1` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/sslProxyHeaders/name0` | `foobar` | | `traefik/http/middlewares/Middleware12/ipAllowList/ipStrategy/depth` | `42` |
| `traefik/http/middlewares/Middleware12/headers/sslProxyHeaders/name1` | `foobar` | | `traefik/http/middlewares/Middleware12/ipAllowList/ipStrategy/excludedIPs/0` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/stsIncludeSubdomains` | `true` | | `traefik/http/middlewares/Middleware12/ipAllowList/ipStrategy/excludedIPs/1` | `foobar` |
| `traefik/http/middlewares/Middleware12/headers/stsPreload` | `true` | | `traefik/http/middlewares/Middleware12/ipAllowList/rejectStatusCode` | `404` |
| `traefik/http/middlewares/Middleware12/headers/stsSeconds` | `42` | | `traefik/http/middlewares/Middleware12/ipAllowList/sourceRange/0` | `foobar` |
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/depth` | `42` | | `traefik/http/middlewares/Middleware12/ipAllowList/sourceRange/1` | `foobar` |
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/excludedIPs/0` | `foobar` | | `traefik/http/middlewares/Middleware13/inFlightReq/amount` | `42` |
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/excludedIPs/1` | `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/0` | `foobar` |
| `traefik/http/middlewares/Middleware13/ipAllowList/sourceRange/0` | `foobar` | | `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
| `traefik/http/middlewares/Middleware13/ipAllowList/sourceRange/1` | `foobar` | | `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/requestHeaderName` | `foobar` |
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/depth` | `42` | | `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/requestHost` | `true` |
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/excludedIPs/0` | `foobar` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/commonName` | `true` |
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/excludedIPs/1` | `foobar` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/country` | `true` |
| `traefik/http/middlewares/Middleware14/ipWhiteList/sourceRange/0` | `foobar` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/domainComponent` | `true` |
| `traefik/http/middlewares/Middleware14/ipWhiteList/sourceRange/1` | `foobar` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/locality` | `true` |
| `traefik/http/middlewares/Middleware15/inFlightReq/amount` | `42` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/organization` | `true` |
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/depth` | `42` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/province` | `true` |
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/serialNumber` | `true` |
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/notAfter` | `true` |
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/requestHeaderName` | `foobar` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/notBefore` | `true` |
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/requestHost` | `true` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/sans` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/commonName` | `true` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/serialNumber` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/country` | `true` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/commonName` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/domainComponent` | `true` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/country` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/locality` | `true` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/domainComponent` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/organization` | `true` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/locality` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/province` | `true` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/organization` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/serialNumber` | `true` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/organizationalUnit` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/notAfter` | `true` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/province` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/notBefore` | `true` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/serialNumber` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/sans` | `true` | | `traefik/http/middlewares/Middleware14/passTLSClientCert/pem` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/serialNumber` | `true` | | `traefik/http/middlewares/Middleware15/plugin/PluginConf/foo` | `bar` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/commonName` | `true` | | `traefik/http/middlewares/Middleware16/rateLimit/average` | `42` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/country` | `true` | | `traefik/http/middlewares/Middleware16/rateLimit/burst` | `42` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/domainComponent` | `true` | | `traefik/http/middlewares/Middleware16/rateLimit/period` | `42s` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/locality` | `true` | | `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/ipStrategy/depth` | `42` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/organization` | `true` | | `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/organizationalUnit` | `true` | | `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/province` | `true` | | `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/requestHeaderName` | `foobar` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/subject/serialNumber` | `true` | | `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/requestHost` | `true` |
| `traefik/http/middlewares/Middleware16/passTLSClientCert/pem` | `true` | | `traefik/http/middlewares/Middleware17/redirectRegex/permanent` | `true` |
| `traefik/http/middlewares/Middleware17/plugin/PluginConf0/name0` | `foobar` | | `traefik/http/middlewares/Middleware17/redirectRegex/regex` | `foobar` |
| `traefik/http/middlewares/Middleware17/plugin/PluginConf0/name1` | `foobar` | | `traefik/http/middlewares/Middleware17/redirectRegex/replacement` | `foobar` |
| `traefik/http/middlewares/Middleware17/plugin/PluginConf1/name0` | `foobar` | | `traefik/http/middlewares/Middleware18/redirectScheme/permanent` | `true` |
| `traefik/http/middlewares/Middleware17/plugin/PluginConf1/name1` | `foobar` | | `traefik/http/middlewares/Middleware18/redirectScheme/port` | `foobar` |
| `traefik/http/middlewares/Middleware18/rateLimit/average` | `42` | | `traefik/http/middlewares/Middleware18/redirectScheme/scheme` | `foobar` |
| `traefik/http/middlewares/Middleware18/rateLimit/burst` | `42` | | `traefik/http/middlewares/Middleware19/replacePath/path` | `foobar` |
| `traefik/http/middlewares/Middleware18/rateLimit/period` | `42s` | | `traefik/http/middlewares/Middleware20/replacePathRegex/regex` | `foobar` |
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/depth` | `42` | | `traefik/http/middlewares/Middleware20/replacePathRegex/replacement` | `foobar` |
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` | | `traefik/http/middlewares/Middleware21/retry/attempts` | `42` |
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` | | `traefik/http/middlewares/Middleware21/retry/initialInterval` | `42s` |
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/requestHeaderName` | `foobar` | | `traefik/http/middlewares/Middleware22/stripPrefix/prefixes/0` | `foobar` |
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/requestHost` | `true` | | `traefik/http/middlewares/Middleware22/stripPrefix/prefixes/1` | `foobar` |
| `traefik/http/middlewares/Middleware19/redirectRegex/permanent` | `true` | | `traefik/http/middlewares/Middleware23/stripPrefixRegex/regex/0` | `foobar` |
| `traefik/http/middlewares/Middleware19/redirectRegex/regex` | `foobar` | | `traefik/http/middlewares/Middleware23/stripPrefixRegex/regex/1` | `foobar` |
| `traefik/http/middlewares/Middleware19/redirectRegex/replacement` | `foobar` | | `traefik/http/middlewares/Middleware24/grpcWeb/allowOrigins/0` | `foobar` |
| `traefik/http/middlewares/Middleware20/redirectScheme/permanent` | `true` | | `traefik/http/middlewares/Middleware24/grpcWeb/allowOrigins/1` | `foobar` |
| `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` |
@ -174,7 +162,6 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `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` |
@ -222,62 +209,55 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `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/failover/fallback` | `foobar` | | `traefik/http/services/Service01/loadBalancer/healthCheck/followRedirects` | `true` |
| `traefik/http/services/Service01/failover/healthCheck` | `` | | `traefik/http/services/Service01/loadBalancer/healthCheck/headers/name0` | `foobar` |
| `traefik/http/services/Service01/failover/service` | `foobar` | | `traefik/http/services/Service01/loadBalancer/healthCheck/headers/name1` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/healthCheck/followRedirects` | `true` | | `traefik/http/services/Service01/loadBalancer/healthCheck/hostname` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/healthCheck/headers/name0` | `foobar` | | `traefik/http/services/Service01/loadBalancer/healthCheck/interval` | `42s` |
| `traefik/http/services/Service02/loadBalancer/healthCheck/headers/name1` | `foobar` | | `traefik/http/services/Service01/loadBalancer/healthCheck/method` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/healthCheck/hostname` | `foobar` | | `traefik/http/services/Service01/loadBalancer/healthCheck/mode` | `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/port` | `42` |
| `traefik/http/services/Service02/loadBalancer/healthCheck/mode` | `foobar` | | `traefik/http/services/Service01/loadBalancer/healthCheck/scheme` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/healthCheck/path` | `foobar` | | `traefik/http/services/Service01/loadBalancer/healthCheck/status` | `42` |
| `traefik/http/services/Service02/loadBalancer/healthCheck/port` | `42` | | `traefik/http/services/Service01/loadBalancer/healthCheck/timeout` | `42s` |
| `traefik/http/services/Service02/loadBalancer/healthCheck/scheme` | `foobar` | | `traefik/http/services/Service01/loadBalancer/passHostHeader` | `true` |
| `traefik/http/services/Service02/loadBalancer/healthCheck/status` | `42` | | `traefik/http/services/Service01/loadBalancer/responseForwarding/flushInterval` | `42s` |
| `traefik/http/services/Service02/loadBalancer/healthCheck/timeout` | `42s` | | `traefik/http/services/Service01/loadBalancer/servers/0/url` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/passHostHeader` | `true` | | `traefik/http/services/Service01/loadBalancer/servers/1/url` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/responseForwarding/flushInterval` | `42s` | | `traefik/http/services/Service01/loadBalancer/serversTransport` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/servers/0/url` | `foobar` | | `traefik/http/services/Service01/loadBalancer/sticky/cookie/httpOnly` | `true` |
| `traefik/http/services/Service02/loadBalancer/servers/0/weight` | `42` | | `traefik/http/services/Service01/loadBalancer/sticky/cookie/name` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/servers/1/url` | `foobar` | | `traefik/http/services/Service01/loadBalancer/sticky/cookie/sameSite` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/servers/1/weight` | `42` | | `traefik/http/services/Service01/loadBalancer/sticky/cookie/secure` | `true` |
| `traefik/http/services/Service02/loadBalancer/serversTransport` | `foobar` | | `traefik/http/services/Service02/mirroring/healthCheck` | `` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/httpOnly` | `true` | | `traefik/http/services/Service02/mirroring/maxBodySize` | `42` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/maxAge` | `42` | | `traefik/http/services/Service02/mirroring/mirrors/0/name` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/name` | `foobar` | | `traefik/http/services/Service02/mirroring/mirrors/0/percent` | `42` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/sameSite` | `foobar` | | `traefik/http/services/Service02/mirroring/mirrors/1/name` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/secure` | `true` | | `traefik/http/services/Service02/mirroring/mirrors/1/percent` | `42` |
| `traefik/http/services/Service03/mirroring/healthCheck` | `` | | `traefik/http/services/Service02/mirroring/service` | `foobar` |
| `traefik/http/services/Service03/mirroring/maxBodySize` | `42` | | `traefik/http/services/Service03/weighted/healthCheck` | `` |
| `traefik/http/services/Service03/mirroring/mirrors/0/name` | `foobar` | | `traefik/http/services/Service03/weighted/services/0/name` | `foobar` |
| `traefik/http/services/Service03/mirroring/mirrors/0/percent` | `42` | | `traefik/http/services/Service03/weighted/services/0/weight` | `42` |
| `traefik/http/services/Service03/mirroring/mirrors/1/name` | `foobar` | | `traefik/http/services/Service03/weighted/services/1/name` | `foobar` |
| `traefik/http/services/Service03/mirroring/mirrors/1/percent` | `42` | | `traefik/http/services/Service03/weighted/services/1/weight` | `42` |
| `traefik/http/services/Service03/mirroring/service` | `foobar` | | `traefik/http/services/Service03/weighted/sticky/cookie/httpOnly` | `true` |
| `traefik/http/services/Service04/weighted/healthCheck` | `` | | `traefik/http/services/Service03/weighted/sticky/cookie/name` | `foobar` |
| `traefik/http/services/Service04/weighted/services/0/name` | `foobar` | | `traefik/http/services/Service03/weighted/sticky/cookie/sameSite` | `foobar` |
| `traefik/http/services/Service04/weighted/services/0/weight` | `42` | | `traefik/http/services/Service03/weighted/sticky/cookie/secure` | `true` |
| `traefik/http/services/Service04/weighted/services/1/name` | `foobar` | | `traefik/http/services/Service04/failover/fallback` | `foobar` |
| `traefik/http/services/Service04/weighted/services/1/weight` | `42` | | `traefik/http/services/Service04/failover/healthCheck` | `` |
| `traefik/http/services/Service04/weighted/sticky/cookie/httpOnly` | `true` | | `traefik/http/services/Service04/failover/service` | `foobar` |
| `traefik/http/services/Service04/weighted/sticky/cookie/maxAge` | `42` | | `traefik/tcp/middlewares/TCPMiddleware00/ipAllowList/sourceRange/0` | `foobar` |
| `traefik/http/services/Service04/weighted/sticky/cookie/name` | `foobar` | | `traefik/tcp/middlewares/TCPMiddleware00/ipAllowList/sourceRange/1` | `foobar` |
| `traefik/http/services/Service04/weighted/sticky/cookie/sameSite` | `foobar` | | `traefik/tcp/middlewares/TCPMiddleware01/inFlightConn/amount` | `42` |
| `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` |
@ -294,7 +274,6 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `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` |
@ -307,6 +286,9 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `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` |
@ -317,11 +299,11 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `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` |
@ -332,9 +314,6 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `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` |

View file

@ -160,12 +160,6 @@ 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
@ -195,10 +189,6 @@ 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

View file

@ -129,10 +129,6 @@ 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

View file

@ -175,13 +175,6 @@ 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:
@ -302,12 +295,6 @@ 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
@ -350,12 +337,6 @@ 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

View file

@ -134,12 +134,6 @@ 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
@ -231,12 +225,6 @@ 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
@ -344,12 +332,6 @@ 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
@ -389,12 +371,6 @@ 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

View file

@ -105,9 +105,6 @@ 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```)

View file

@ -105,9 +105,6 @@ 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```)

View file

@ -1,5 +1,3 @@
## CODE GENERATED AUTOMATICALLY
## THIS FILE MUST NOT BE EDITED BY HAND
[global] [global]
checkNewVersion = true checkNewVersion = true
sendAnonymousUsage = true sendAnonymousUsage = true
@ -8,21 +6,26 @@
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]
dialKeepAlive = "42s"
dialTimeout = "42s" dialTimeout = "42s"
terminationDelay = "42s" dialKeepAlive = "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"
@ -32,8 +35,8 @@
address = "foobar" address = "foobar"
asDefault = true asDefault = true
[entryPoints.EntryPoint0.transport] [entryPoints.EntryPoint0.transport]
keepAliveMaxTime = "42s"
keepAliveMaxRequests = 42 keepAliveMaxRequests = 42
keepAliveMaxTime = "42s"
[entryPoints.EntryPoint0.transport.lifeCycle] [entryPoints.EntryPoint0.transport.lifeCycle]
requestAcceptGraceTimeout = "42s" requestAcceptGraceTimeout = "42s"
graceTimeOut = "42s" graceTimeOut = "42s"
@ -77,31 +80,31 @@
[providers] [providers]
providersThrottleDuration = "42s" providersThrottleDuration = "42s"
[providers.docker] [providers.docker]
exposedByDefault = true
constraints = "foobar" constraints = "foobar"
allowEmptyServices = true
network = "foobar"
useBindPortIP = true
watch = true watch = true
defaultRule = "foobar"
endpoint = "foobar" endpoint = "foobar"
defaultRule = "foobar"
exposedByDefault = true
useBindPortIP = true
network = "foobar"
httpClientTimeout = "42s" httpClientTimeout = "42s"
allowEmptyServices = true
[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]
exposedByDefault = true
constraints = "foobar" constraints = "foobar"
allowEmptyServices = true
network = "foobar"
useBindPortIP = true
watch = true watch = true
defaultRule = "foobar"
endpoint = "foobar" endpoint = "foobar"
httpClientTimeout = "42s" defaultRule = "foobar"
exposedByDefault = true
useBindPortIP = true
network = "foobar"
refreshSeconds = "42s" refreshSeconds = "42s"
httpClientTimeout = "42s"
allowEmptyServices = true
[providers.swarm.tls] [providers.swarm.tls]
ca = "foobar" ca = "foobar"
cert = "foobar" cert = "foobar"
@ -180,9 +183,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"
@ -200,11 +203,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"]
@ -262,18 +265,14 @@
key = "foobar" key = "foobar"
insecureSkipVerify = true insecureSkipVerify = true
[providers.plugin] [providers.plugin]
[providers.plugin.PluginConf0] [providers.plugin.Descriptor0]
name0 = "foobar" [providers.plugin.Descriptor1]
name1 = "foobar"
[providers.plugin.PluginConf1]
name0 = "foobar"
name1 = "foobar"
[api] [api]
insecure = true insecure = true
dashboard = true dashboard = true
debug = true debug = true
disableDashboardAd = true disabledashboardad = false
[metrics] [metrics]
[metrics.prometheus] [metrics.prometheus]
@ -284,8 +283,8 @@
entryPoint = "foobar" entryPoint = "foobar"
manualRouting = true manualRouting = true
[metrics.prometheus.headerLabels] [metrics.prometheus.headerLabels]
name0 = "foobar" label1 = "foobar"
name1 = "foobar" label2 = "foobar"
[metrics.datadog] [metrics.datadog]
address = "foobar" address = "foobar"
pushInterval = "42s" pushInterval = "42s"
@ -317,19 +316,20 @@
addEntryPointsLabels = true addEntryPointsLabels = true
addRoutersLabels = true addRoutersLabels = true
addServicesLabels = true addServicesLabels = true
explicitBoundaries = [42.0, 42.0]
insecure = true
path = "foobar"
pushInterval = "42s" pushInterval = "42s"
[metrics.openTelemetry.grpc] path = "foobar"
explicitBoundaries = [42.0, 42.0]
insecure = true
[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"
key = "foobar"
insecureSkipVerify = true insecureSkipVerify = true
key = "foobar"
[metrics.openTelemetry.grpc]
[ping] [ping]
entryPoint = "foobar" entryPoint = "foobar"
@ -342,8 +342,8 @@
noColor = true noColor = true
filePath = "foobar" filePath = "foobar"
maxSize = 42 maxSize = 42
maxAge = 42
maxBackups = 42 maxBackups = 42
maxAge = 42
compress = true compress = true
[accessLog] [accessLog]
@ -367,29 +367,28 @@
[tracing] [tracing]
serviceName = "foobar" serviceName = "foobar"
sampleRate = 42.0 sampleRate = 42
[tracing.headers] [tracing.headers]
name0 = "foobar" header1 = "foobar"
name1 = "foobar" header2 = "foobar"
[tracing.globalAttributes] [tracing.globalAttributes]
name0 = "foobar" attr1 = "foobar"
name1 = "foobar" attr2 = "foobar"
[tracing.otlp] [tracing.otlp.grpc]
[tracing.otlp.grpc] endpoint = "foobar"
endpoint = "foobar" insecure = true
insecure = true [tracing.otlp.grpc.tls]
[tracing.otlp.grpc.tls] ca = "foobar"
ca = "foobar" cert = "foobar"
cert = "foobar" key = "foobar"
key = "foobar" insecureSkipVerify = true
insecureSkipVerify = true [tracing.otlp.http]
[tracing.otlp.http] endpoint = "foobar"
endpoint = "foobar" [tracing.otlp.http.tls]
[tracing.otlp.http.tls] ca = "foobar"
ca = "foobar" cert = "foobar"
cert = "foobar" key = "foobar"
key = "foobar" insecureSkipVerify = true
insecureSkipVerify = true
[hostResolver] [hostResolver]
cnameFlattening = true cnameFlattening = true
@ -416,27 +415,7 @@
[certificatesResolvers.CertificateResolver0.acme.httpChallenge] [certificatesResolvers.CertificateResolver0.acme.httpChallenge]
entryPoint = "foobar" entryPoint = "foobar"
[certificatesResolvers.CertificateResolver0.acme.tlsChallenge] [certificatesResolvers.CertificateResolver0.acme.tlsChallenge]
[certificatesResolvers.CertificateResolver0.tailscale] [certificatesResolvers.CertificateResolver1.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
@ -448,13 +427,7 @@
moduleName = "foobar" moduleName = "foobar"
version = "foobar" version = "foobar"
[experimental.localPlugins] [experimental.localPlugins]
[experimental.localPlugins.LocalDescriptor0] [experimental.localPlugins.Descriptor0]
moduleName = "foobar" moduleName = "foobar"
[experimental.localPlugins.LocalDescriptor1] [experimental.localPlugins.Descriptor1]
moduleName = "foobar" moduleName = "foobar"
[core]
defaultRuleSyntax = "foobar"
[spiffe]
workloadAPIAddr = "foobar"

View file

@ -1,9 +1,7 @@
## CODE GENERATED AUTOMATICALLY
## THIS FILE MUST NOT BE EDITED BY HAND
global: global:
checkNewVersion: true checkNewVersion: true
sendAnonymousUsage: true sendAnonymousUsage: true
serversTransport: serversTransports:
insecureSkipVerify: true insecureSkipVerify: true
rootCAs: rootCAs:
- foobar - foobar
@ -13,15 +11,16 @@ serversTransport:
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:
dialKeepAlive: 42s
dialTimeout: 42s dialTimeout: 42s
terminationDelay: 42s dialKeepAlive: 42s
tls: tls:
insecureSkipVerify: true insecureSkipVerify: true
rootCAs: rootCAs:
@ -37,6 +36,8 @@ 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
@ -44,8 +45,6 @@ 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:
@ -57,6 +56,7 @@ entryPoints:
- foobar - foobar
- foobar - foobar
http: http:
encodeQuerySemicolons: true
redirections: redirections:
entryPoint: entryPoint:
to: foobar to: foobar
@ -78,7 +78,6 @@ entryPoints:
sans: sans:
- foobar - foobar
- foobar - foobar
encodeQuerySemicolons: true
http2: http2:
maxConcurrentStreams: 42 maxConcurrentStreams: 42
http3: http3:
@ -88,36 +87,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
defaultRule: foobar
endpoint: foobar endpoint: foobar
defaultRule: 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
defaultRule: foobar
endpoint: foobar endpoint: foobar
defaultRule: foobar
tls: tls:
ca: foobar ca: foobar
cert: foobar cert: foobar
key: foobar key: foobar
insecureSkipVerify: true insecureSkipVerify: true
httpClientTimeout: 42s exposedByDefault: true
useBindPortIP: true
network: foobar
refreshSeconds: 42s refreshSeconds: 42s
httpClientTimeout: 42s
allowEmptyServices: true
file: file:
directory: foobar directory: foobar
watch: true watch: true
@ -132,14 +131,14 @@ providers:
- foobar - foobar
labelSelector: foobar labelSelector: foobar
ingressClass: foobar ingressClass: foobar
ingressEndpoint:
ip: foobar
hostname: foobar
publishedService: foobar
throttleDuration: 42s throttleDuration: 42s
allowEmptyServices: true allowEmptyServices: true
allowExternalNameServices: true allowExternalNameServices: true
disableIngressClassLookup: true disableIngressClassLookup: true
ingressEndpoint:
ip: foobar
hostname: foobar
publishedService: foobar
kubernetesCRD: kubernetesCRD:
endpoint: foobar endpoint: foobar
token: foobar token: foobar
@ -166,20 +165,6 @@ 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
@ -194,26 +179,40 @@ providers:
namespaces: namespaces:
- foobar - foobar
- foobar - foobar
nomad:
defaultRule: foobar
constraints: foobar
endpoint: endpoint:
address: foobar address: foobar
region: foobar scheme: foobar
datacenter: 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 httpAuth:
username: foobar
password: foobar
nomad:
defaultRule: foobar
constraints: foobar
prefix: foobar prefix: foobar
stale: true stale: true
exposedByDefault: true
refreshInterval: 42s
namespaces: namespaces:
- foobar - foobar
- foobar - foobar
exposedByDefault: true
refreshInterval: 42s
endpoint:
address: foobar
region: foobar
token: foobar
endpointWaitTime: 42s
tls:
ca: foobar
cert: foobar
key: foobar
insecureSkipVerify: true
ecs: ecs:
constraints: foobar constraints: foobar
exposedByDefault: true exposedByDefault: true
@ -223,37 +222,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:
@ -266,14 +265,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
@ -295,17 +294,13 @@ providers:
key: foobar key: foobar
insecureSkipVerify: true insecureSkipVerify: true
plugin: plugin:
PluginConf0: Descriptor0: {}
name0: foobar Descriptor1: {}
name1: foobar
PluginConf1:
name0: foobar
name1: foobar
api: api:
insecure: true insecure: true
dashboard: true dashboard: true
debug: true debug: true
disableDashboardAd: true disabledashboardad: false
metrics: metrics:
prometheus: prometheus:
buckets: buckets:
@ -317,8 +312,8 @@ metrics:
entryPoint: foobar entryPoint: foobar
manualRouting: true manualRouting: true
headerLabels: headerLabels:
name0: foobar label1: foobar
name1: foobar label2: foobar
datadog: datadog:
address: foobar address: foobar
pushInterval: 42s pushInterval: 42s
@ -346,7 +341,6 @@ metrics:
name0: foobar name0: foobar
name1: foobar name1: foobar
openTelemetry: openTelemetry:
grpc: {}
address: foobar address: foobar
addEntryPointsLabels: true addEntryPointsLabels: true
addRoutersLabels: true addRoutersLabels: true
@ -362,9 +356,12 @@ metrics:
pushInterval: 42s pushInterval: 42s
tls: tls:
ca: foobar ca: foobar
caOptional: true
cert: foobar cert: foobar
key: foobar
insecureSkipVerify: true insecureSkipVerify: true
key: foobar
grpc: {}
ping: ping:
entryPoint: foobar entryPoint: foobar
manualRouting: true manualRouting: true
@ -375,8 +372,8 @@ log:
noColor: true noColor: true
filePath: foobar filePath: foobar
maxSize: 42 maxSize: 42
maxAge: 42
maxBackups: 42 maxBackups: 42
maxAge: 42
compress: true compress: true
accessLog: accessLog:
filePath: foobar filePath: foobar
@ -400,13 +397,13 @@ accessLog:
bufferingSize: 42 bufferingSize: 42
tracing: tracing:
serviceName: foobar serviceName: foobar
headers:
name0: foobar
name1: foobar
globalAttributes:
name0: foobar
name1: foobar
sampleRate: 42 sampleRate: 42
headers:
header1: foobar
header2: foobar
globalAttributes:
attr1: foobar
attr2: foobar
otlp: otlp:
grpc: grpc:
endpoint: foobar endpoint: foobar
@ -432,13 +429,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
@ -449,30 +446,10 @@ 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
@ -481,12 +458,7 @@ experimental:
moduleName: foobar moduleName: foobar
version: foobar version: foobar
localPlugins: localPlugins:
LocalDescriptor0: Descriptor0:
moduleName: foobar moduleName: foobar
LocalDescriptor1: Descriptor1:
moduleName: foobar moduleName: foobar
kubernetesGateway: true
core:
defaultRuleSyntax: foobar
spiffe:
workloadAPIAddr: foobar

View file

@ -273,14 +273,6 @@ 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.

View file

@ -376,14 +376,6 @@ 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.

View file

@ -275,14 +275,6 @@ 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.

View file

@ -348,7 +348,6 @@ 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]

View file

@ -351,14 +351,6 @@ 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+,

View file

@ -244,14 +244,6 @@ 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.
@ -314,12 +306,6 @@ 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).

View file

@ -265,14 +265,6 @@ 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.

View file

@ -515,60 +515,6 @@ 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.
@ -1215,60 +1161,6 @@ 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.

View file

@ -143,36 +143,6 @@ 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:
@ -217,13 +187,6 @@ 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.

47
exp.Dockerfile Normal file
View file

@ -0,0 +1,47 @@
# 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
View file

@ -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-20240122103822-8a4bd61caf74 github.com/hashicorp/nomad/api v0.0.0-20220506174431-b5665129cd1f
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,13 +85,12 @@ 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.4 k8s.io/api v0.28.3
k8s.io/apiextensions-apiserver v0.28.3 k8s.io/apiextensions-apiserver v0.28.3
k8s.io/apimachinery v0.28.4 k8s.io/apimachinery v0.28.3
k8s.io/client-go v0.28.4 k8s.io/client-go v0.28.3
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
) )
@ -163,7 +162,6 @@ 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
@ -198,7 +196,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.2 // indirect github.com/hashicorp/cronexpr v1.1.1 // 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
@ -238,7 +236,6 @@ 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
@ -257,6 +254,7 @@ 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
View file

@ -114,8 +114,6 @@ 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=
@ -304,8 +302,6 @@ 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=
@ -315,8 +311,6 @@ 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=
@ -362,8 +356,6 @@ 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=
@ -546,8 +538,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.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.1 h1:NJZDd87hGXjoZBdvyCF9mX4DCq5Wy7+A/w+A7q0wn6c=
github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/cronexpr v1.1.1/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=
@ -598,8 +590,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-20240122103822-8a4bd61caf74 h1:Q+WuGTnZkL2cJ7yNsg4Go4GNnRkcahGLiQP/WD41TTA= github.com/hashicorp/nomad/api v0.0.0-20220506174431-b5665129cd1f h1:jSBbBJcPca465gK6XfwdXRQnFCd63e0oJmqllZTsawI=
github.com/hashicorp/nomad/api v0.0.0-20240122103822-8a4bd61caf74/go.mod h1:ijDwa6o1uG1jFSq6kERiX2PamKGpZzTmo0XOFNeFZgw= github.com/hashicorp/nomad/api v0.0.0-20220506174431-b5665129cd1f/go.mod h1:b/AoT79m3PEpb6tKCFKva/M+q1rKJNUk5mdu1S8DymM=
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=
@ -802,8 +794,6 @@ 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=
@ -1014,9 +1004,8 @@ 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=
@ -1493,8 +1482,6 @@ 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=
@ -1629,14 +1616,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.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM=
k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc=
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.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A=
k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8=
k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY= k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4=
k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4= k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo=
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=
@ -1650,8 +1637,6 @@ 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=

View file

@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"io" "io"
"net/http" "net/http"
"strings"
"testing" "testing"
"time" "time"
@ -56,56 +55,6 @@ 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

View file

@ -160,12 +160,6 @@ 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
@ -195,10 +189,6 @@ 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
@ -406,10 +396,6 @@ 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
@ -764,13 +750,6 @@ 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:
@ -891,12 +870,6 @@ 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
@ -939,12 +912,6 @@ 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
@ -2178,12 +2145,6 @@ 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
@ -2275,12 +2236,6 @@ 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
@ -2388,12 +2343,6 @@ 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
@ -2433,12 +2382,6 @@ 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

View file

@ -1,21 +0,0 @@
[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]

View file

@ -1,41 +0,0 @@
[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]

View file

@ -1,38 +0,0 @@
[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]

View file

@ -1,35 +0,0 @@
[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 }}"

View file

@ -15,7 +15,6 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime"
"slices" "slices"
"strings" "strings"
"testing" "testing"
@ -35,13 +34,7 @@ import (
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
var ( var showLog = flag.Bool("tlog", false, "always show Traefik logs")
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"`
@ -63,6 +56,8 @@ 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
@ -105,11 +100,6 @@ 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
@ -135,7 +125,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(tailscaleSecretFilePath) s.setupVPN("tailscale.secret")
} }
} }
@ -318,13 +308,7 @@ func (s *BaseSuite) composeDown() {
} }
func (s *BaseSuite) cmdTraefik(args ...string) (*exec.Cmd, *bytes.Buffer) { func (s *BaseSuite) cmdTraefik(args ...string) (*exec.Cmd, *bytes.Buffer) {
binName := "traefik" cmd := exec.Command(traefikBinary, args...)
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)

View file

@ -1,229 +0,0 @@
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)
}

View file

@ -36,14 +36,3 @@ 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

View file

@ -659,66 +659,6 @@ 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{}{})
@ -809,49 +749,6 @@ 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")

View file

@ -34,7 +34,6 @@
], ],
"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": [
@ -47,7 +46,6 @@
], ],
"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",
@ -154,7 +152,6 @@
], ],
"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": [
@ -167,7 +164,6 @@
], ],
"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
@ -183,7 +179,6 @@
], ],
"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

View file

@ -1,13 +1,10 @@
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"os" "os"
"path" "path"
"path/filepath"
"reflect"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -19,65 +16,9 @@ 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)
}) })
@ -85,144 +26,6 @@ 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()
@ -314,7 +117,6 @@ 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 {
@ -328,12 +130,6 @@ 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])
} }

View file

@ -1,66 +0,0 @@
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)
}
}
}
}

View file

@ -1,541 +0,0 @@
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
}

View file

@ -1,404 +0,0 @@
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)
}
})
}
}

View file

@ -1,5 +0,0 @@
[accesslog]
[entrypoints.test.http.tls]
[providers.marathon]

View file

@ -1,8 +0,0 @@
[accesslog]
[entrypoints.test.http.tls]
[providers.marathon]
[pilot]
token="xxx"

View file

@ -1,3 +0,0 @@
[accesslog]
[entrypoints.test.http.tls]

View file

@ -5,14 +5,13 @@ 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 := hydratation.Hydrate(&staticConfiguration) err := hydrate(&staticConfiguration)
require.NoError(t, err) require.NoError(t, err)
buffer, err := createBody(&staticConfiguration) buffer, err := createBody(&staticConfiguration)

View file

@ -1,4 +1,4 @@
package hydratation package collector
import ( import (
"fmt" "fmt"
@ -17,8 +17,7 @@ const (
defaultMapKeyPrefix = "name" defaultMapKeyPrefix = "name"
) )
// Hydrate hydrates a configuration. func hydrate(element interface{}) error {
func Hydrate(element interface{}) error {
field := reflect.ValueOf(element) field := reflect.ValueOf(element)
return fill(field) return fill(field)
} }
@ -42,7 +41,9 @@ func fill(field reflect.Value) error {
return err return err
} }
case reflect.Interface: case reflect.Interface:
setTyped(field, defaultString) if err := fill(field.Elem()); err != nil {
return err
}
case reflect.String: case reflect.String:
setTyped(field, defaultString) setTyped(field, defaultString)
case reflect.Int: case reflect.Int:
@ -117,7 +118,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.Interface: reflect.Bool, reflect.Float32, reflect.Float64:
return defaultMapKeyPrefix return defaultMapKeyPrefix
default: default:
return typ.Name() return typ.Name()

View file

@ -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" label:"-" export:"true"` TLS *TLSConfiguration `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
} }
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true

View file

@ -37,9 +37,8 @@ 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
@ -60,7 +59,6 @@ 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:"-"`
@ -157,10 +155,6 @@ 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
@ -227,7 +221,6 @@ 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:"-"`
} }

View file

@ -159,8 +159,6 @@ 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"`
@ -225,8 +223,6 @@ 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

View file

@ -16,19 +16,11 @@ 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"`
@ -64,7 +56,6 @@ 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"`
} }

View file

@ -132,11 +132,6 @@ 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
} }
@ -329,11 +324,6 @@ 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
} }
@ -1128,11 +1118,6 @@ 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
} }
@ -1185,9 +1170,7 @@ 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))
for i := range *in { copy(*out, *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
@ -1444,21 +1427,6 @@ 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))
@ -1576,22 +1544,6 @@ 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

View file

@ -1334,7 +1334,6 @@ 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",

View file

@ -71,23 +71,11 @@ 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"`
@ -329,17 +317,6 @@ 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")

View file

@ -13,13 +13,12 @@ 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()")
@ -28,7 +27,9 @@ func TestDatadog(t *testing.T) {
} }
func TestDatadogWithPrefix(t *testing.T) { func TestDatadogWithPrefix(t *testing.T) {
t.Cleanup(StopDatadog) t.Cleanup(func() {
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

View file

@ -6,6 +6,7 @@ import (
"io" "io"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"regexp"
"strconv" "strconv"
"testing" "testing"
"time" "time"
@ -25,6 +26,7 @@ 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{
@ -37,11 +39,7 @@ 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()")
@ -139,3 +137,14 @@ 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)
}
}
}

View file

@ -4,12 +4,10 @@ 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"
@ -289,8 +287,10 @@ func TestOpenTelemetry_GaugeCollectorSet(t *testing.T) {
} }
func TestOpenTelemetry(t *testing.T) { func TestOpenTelemetry(t *testing.T) {
c := make(chan *string, 5) t.Parallel()
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,11 +310,7 @@ 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)
@ -337,53 +333,57 @@ 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
tryAssertMessage(t, c, expected) assertMessage(t, *msgMisc, 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
expectedConfig := []string{ expected = append(expected,
`({"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
tryAssertMessage(t, c, expectedConfig) assertMessage(t, *msgServer, expected)
expectedTLSCerts := []string{ expected = append(expected,
`({"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
tryAssertMessage(t, c, expectedTLSCerts) assertMessage(t, *msgTLS, expected)
expectedEntryPoints := []string{ expected = append(expected,
`({"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
tryAssertMessage(t, c, expectedEntryPoints) assertMessage(t, *msgEntrypoint, expected)
expectedRouters := []string{ expected = append(expected,
`({"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,17 +391,18 @@ 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
tryAssertMessage(t, c, expectedRouters) assertMessage(t, *msgRouter, expected)
expectedServices := []string{ expected = append(expected,
`({"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)
@ -410,19 +411,21 @@ 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
tryAssertMessage(t, c, expectedServices) assertMessage(t, *msgService, expected)
expectedServicesRetries := []string{ expected = append(expected,
`({"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
tryAssertMessage(t, c, expectedServicesRetries) assertMessage(t, *msgServiceRetries, expected)
// 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,
@ -434,46 +437,14 @@ 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
tryAssertMessage(t, c, expectedEntryPointReqDuration) assertMessage(t, *msgEntryPointReqDurationHistogram, expectedEntryPointReqDuration)
}
// We need to unlock the HTTP Server for the last export call when stopping
func assertMessage(t *testing.T, msg string, expected []string) { // OpenTelemetry.
t.Helper() go func() {
errs := verifyMessage(msg, expected) <-c
for _, err := range errs { }()
t.Error(err) StopOpenTelemetry()
}
}
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
} }

View file

@ -48,26 +48,19 @@ 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
@ -218,35 +211,7 @@ 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) {

View file

@ -66,8 +66,6 @@ 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)
@ -78,9 +76,6 @@ 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")
}) })
@ -88,7 +83,6 @@ 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)
@ -103,8 +97,6 @@ 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)

View file

@ -22,11 +22,7 @@ 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
} }
@ -37,28 +33,14 @@ 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")
} }
if len(cfg.ExcludedContentTypes) > 0 && len(cfg.IncludedContentTypes) > 0 { var contentTypes []parsedContentType
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 excluded media type: %w", err) return nil, fmt.Errorf("parsing media type: %w", err)
} }
excludedContentTypes = append(excludedContentTypes, parsedContentType{mediaType, params}) contentTypes = append(contentTypes, 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 {
@ -70,8 +52,7 @@ 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: excludedContentTypes, excludedContentTypes: contentTypes,
includedContentTypes: includedContentTypes,
} }
defer brw.close() defer brw.close()
@ -88,7 +69,6 @@ type responseWriter struct {
minSize int minSize int
excludedContentTypes []parsedContentType excludedContentTypes []parsedContentType
includedContentTypes []parsedContentType
buf []byte buf []byte
hijacked bool hijacked bool
@ -141,25 +121,11 @@ 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 or includedContentTypes. // Disable compression according to user wishes in excludedContentTypes.
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 content-type media type: %w", err) return 0, fmt.Errorf("parsing 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 {

View file

@ -291,9 +291,10 @@ 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: "",
expCompression: true, excludedContentTypes: []string{},
expCompression: true,
}, },
{ {
desc: "MIME match", desc: "MIME match",
@ -388,111 +389,6 @@ 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
@ -501,9 +397,10 @@ 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: "",
expCompression: true, excludedContentTypes: []string{},
expCompression: true,
}, },
{ {
desc: "MIME match", desc: "MIME match",
@ -612,125 +509,6 @@ 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()

View file

@ -26,7 +26,6 @@ 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
@ -37,30 +36,16 @@ 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, fmt.Errorf("parsing excluded media type: %w", err) return nil, 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
@ -70,7 +55,6 @@ 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,
} }
@ -108,11 +92,11 @@ func (c *compress) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return return
} }
// Client doesn't specify a preferred encoding, for compatibility don't encode the request // Client allows us to do whatever we want, so we br compress.
// See https://github.com/traefik/traefik/issues/9734 // See https://www.rfc-editor.org/rfc/rfc9110.html#section-12.5.3
acceptEncoding, ok := req.Header["Accept-Encoding"] acceptEncoding, ok := req.Header["Accept-Encoding"]
if !ok { if !ok {
c.next.ServeHTTP(rw, req) c.brotliHandler.ServeHTTP(rw, req)
return return
} }
@ -134,21 +118,10 @@ func (c *compress) GetTracingInformation() (string, string, trace.SpanKind) {
} }
func (c *compress) newGzipHandler() (http.Handler, error) { func (c *compress) newGzipHandler() (http.Handler, error) {
var wrapper func(http.Handler) http.HandlerFunc wrapper, err := gzhttp.NewWrapper(
var err error gzhttp.ExceptContentTypes(c.excludes),
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)
} }
@ -157,11 +130,9 @@ func (c *compress) newGzipHandler() (http.Handler, error) {
} }
func (c *compress) newBrotliHandler() (http.Handler, error) { func (c *compress) newBrotliHandler() (http.Handler, error) {
cfg := brotli.Config{MinSize: c.minSize} cfg := brotli.Config{
if len(c.includes) > 0 { ExcludedContentTypes: c.excludes,
cfg.IncludedContentTypes = c.includes MinSize: c.minSize,
} else {
cfg.ExcludedContentTypes = c.excludes
} }
wrapper, err := brotli.NewWrapper(cfg) wrapper, err := brotli.NewWrapper(cfg)

View file

@ -10,6 +10,7 @@ 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"
@ -34,7 +35,7 @@ func TestNegotiation(t *testing.T) {
}{ }{
{ {
desc: "no accept header", desc: "no accept header",
expEncoding: "", expEncoding: "br",
}, },
{ {
desc: "unsupported accept header", desc: "unsupported accept header",
@ -150,7 +151,7 @@ func TestShouldNotCompressWhenContentEncodingHeader(t *testing.T) {
assert.EqualValues(t, rw.Body.Bytes(), fakeCompressedBody) assert.EqualValues(t, rw.Body.Bytes(), fakeCompressedBody)
} }
func TestShouldNotCompressWhenNoAcceptEncodingHeader(t *testing.T) { func TestShouldCompressWhenNoAcceptEncodingHeader(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)
@ -166,9 +167,12 @@ func TestShouldNotCompressWhenNoAcceptEncodingHeader(t *testing.T) {
rw := httptest.NewRecorder() rw := httptest.NewRecorder()
handler.ServeHTTP(rw, req) handler.ServeHTTP(rw, req)
assert.Empty(t, rw.Header().Get(contentEncodingHeader)) assert.Equal(t, brotliValue, rw.Header().Get(contentEncodingHeader))
assert.Empty(t, rw.Header().Get(varyHeader)) assert.Equal(t, acceptEncodingHeader, 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) {
@ -271,28 +275,7 @@ func TestShouldNotCompressWhenSpecificContentType(t *testing.T) {
respContentType: "text/event-stream", respContentType: "text/event-stream",
}, },
{ {
desc: "Include Response Content-Type", desc: "application/grpc",
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",
}, },
@ -333,52 +316,6 @@ 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)

View file

@ -8,7 +8,6 @@ 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"
) )
@ -59,7 +58,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(middlewares.NewResponseModifier(rw, req, s.PostRequestModifyResponseHeaders), req) s.next.ServeHTTP(newResponseModifier(rw, req, s.PostRequestModifyResponseHeaders), req)
} }
} }

View file

@ -1,4 +1,4 @@
package middlewares package headers
import ( import (
"bufio" "bufio"
@ -9,8 +9,7 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
// ResponseModifier is a ResponseWriter to modify the response headers before sending them. type responseModifier struct {
type ResponseModifier struct {
req *http.Request req *http.Request
rw http.ResponseWriter rw http.ResponseWriter
@ -22,10 +21,9 @@ type ResponseModifier struct {
modifierErr error // returned by modifier call modifierErr error // returned by modifier call
} }
// NewResponseModifier returns a new ResponseModifier instance. // modifier can be nil.
// The given modifier can be nil. func newResponseModifier(w http.ResponseWriter, r *http.Request, modifier func(*http.Response) error) http.ResponseWriter {
func NewResponseModifier(w http.ResponseWriter, r *http.Request, modifier func(*http.Response) error) http.ResponseWriter { return &responseModifier{
return &ResponseModifier{
req: r, req: r,
rw: w, rw: w,
modifier: modifier, modifier: modifier,
@ -35,7 +33,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
} }
@ -75,11 +73,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
@ -89,7 +87,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()
} }
@ -98,7 +96,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()
} }

View file

@ -4,7 +4,6 @@ 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"
) )
@ -46,6 +45,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(middlewares.NewResponseModifier(writer, request, s.secure.ModifyResponseHeaders), request) s.next.ServeHTTP(newResponseModifier(writer, request, s.secure.ModifyResponseHeaders), request)
}) })
} }

View file

@ -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

View file

@ -1,226 +0,0 @@
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
}

File diff suppressed because it is too large Load diff

View file

@ -12,9 +12,8 @@ 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.
@ -29,19 +28,8 @@ 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
} }
@ -65,26 +53,10 @@ 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, syntax string, priority int, handler http.Handler) error { func (m *Muxer) AddRoute(rule string, priority int, handler http.Handler) error {
var parse interface{} parse, err := m.parser.Parse(rule)
var err error if err != nil {
var matcherFuncs map[string]func(*matchersTree, ...string) error return fmt.Errorf("error while parsing rule %s: %w", rule, err)
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)
@ -93,7 +65,7 @@ func (m *Muxer) AddRoute(rule string, syntax string, priority int, handler http.
} }
var matchers matchersTree var matchers matchersTree
err = matchers.addRule(buildTree(), matcherFuncs) err = matchers.addRule(buildTree())
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)
} }
@ -115,9 +87,6 @@ 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 {
@ -197,27 +166,25 @@ func (m *matchersTree) match(req *http.Request) bool {
} }
} }
type matcherFuncs map[string]func(*matchersTree, ...string) error func (m *matchersTree) addRule(rule *rules.Tree) 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, funcs) err := m.left.addRule(rule.RuleLeft)
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, funcs) return m.right.addRule(rule.RuleRight)
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 = funcs[rule.Matcher](m, rule.Value...) err = httpFuncs[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)
} }

View file

@ -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

View file

@ -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

View file

@ -1,240 +0,0 @@
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
}

File diff suppressed because it is too large Load diff

View file

@ -41,9 +41,8 @@ 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.
@ -58,20 +57,7 @@ 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)
} }
var matchersV2 []string return &Muxer{parser: parser}, nil
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,
@ -120,26 +106,10 @@ 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, syntax string, priority int, handler tcp.Handler) error { func (m *Muxer) AddRoute(rule string, priority int, handler tcp.Handler) error {
var parse interface{} parse, err := m.parser.Parse(rule)
var err error if err != nil {
var matcherFuncs map[string]func(*matchersTree, ...string) error return fmt.Errorf("error while parsing rule %s: %w", rule, err)
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)
@ -150,7 +120,7 @@ func (m *Muxer) AddRoute(rule string, syntax string, priority int, handler tcp.H
ruleTree := buildTree() ruleTree := buildTree()
var matchers matchersTree var matchers matchersTree
err = matchers.addRule(ruleTree, matcherFuncs) err = matchers.addRule(ruleTree)
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)
} }
@ -185,9 +155,6 @@ 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 {
@ -270,27 +237,25 @@ func (m *matchersTree) match(meta ConnData) bool {
} }
} }
type matcherFuncs map[string]func(*matchersTree, ...string) error func (m *matchersTree) addRule(rule *rules.Tree) 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, funcs) err := m.left.addRule(rule.RuleLeft)
if err != nil { if err != nil {
return err return err
} }
m.right = &matchersTree{} m.right = &matchersTree{}
return m.right.addRule(rule.RuleRight, funcs) return m.right.addRule(rule.RuleRight)
default: default:
err := rules.CheckRule(rule) err := rules.CheckRule(rule)
if err != nil { if err != nil {
return err return err
} }
err = funcs[rule.Matcher](m, rule.Value...) err = tcpFuncs[rule.Matcher](m, rule.Value...)
if err != nil { if err != nil {
return err return err
} }

View file

@ -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)

View file

@ -731,7 +731,6 @@ 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 {

View file

@ -112,7 +112,6 @@ 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,

View file

@ -102,7 +102,6 @@ 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,
} }

View file

@ -33,9 +33,6 @@ 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"`

View file

@ -29,9 +29,6 @@ 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.

View file

@ -157,8 +157,6 @@ 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.

View file

@ -215,11 +215,6 @@ 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
} }

View file

@ -230,7 +230,6 @@ 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(),
@ -588,16 +587,7 @@ 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.GatewayReasonAccepted), Reason: string(gatev1.GatewayConditionAccepted),
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(),
}, },
@ -770,7 +760,6 @@ 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},
} }
@ -909,7 +898,6 @@ 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 {
@ -1074,7 +1062,6 @@ 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,
@ -1398,7 +1385,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("Header(`%s`,`%s`)", header.Name, header.Value)) headerRules = append(headerRules, fmt.Sprintf("Headers(`%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)
} }

View file

@ -550,7 +550,6 @@ 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{},
@ -610,7 +609,6 @@ 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{},
@ -643,7 +641,6 @@ 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{},
@ -707,7 +704,6 @@ 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{},
}, },
}, },
@ -777,7 +773,6 @@ 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{},
@ -837,7 +832,6 @@ 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{},
@ -897,7 +891,6 @@ 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{},
@ -956,13 +949,11 @@ 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",
}, },
}, },
@ -1048,7 +1039,6 @@ 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",
}, },
}, },
@ -1134,13 +1124,11 @@ 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{},
}, },
}, },
@ -1225,13 +1213,11 @@ 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{},
}, },
}, },
@ -1307,22 +1293,20 @@ 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-4a1b73e6f83804949a37": { "default-http-app-1-my-gateway-web-330d644a7f2079e8f454": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-4a1b73e6f83804949a37-wrr", Service: "default-http-app-1-my-gateway-web-330d644a7f2079e8f454-wrr",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`) && Header(`my-header`,`foo`) && Header(`my-header2`,`bar`)", Rule: "Host(`foo.com`) && PathPrefix(`/bar`) && Headers(`my-header`,`foo`) && Headers(`my-header2`,`bar`)",
RuleSyntax: "v3",
}, },
"default-http-app-1-my-gateway-web-aaba0f24fd26e1ca2276": { "default-http-app-1-my-gateway-web-fe80e69a38713941ea22": {
EntryPoints: []string{"web"}, EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-aaba0f24fd26e1ca2276-wrr", Service: "default-http-app-1-my-gateway-web-fe80e69a38713941ea22-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`) && Header(`my-header`,`bar`)", Rule: "Host(`foo.com`) && Path(`/bar`) && Headers(`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-4a1b73e6f83804949a37-wrr": { "default-http-app-1-my-gateway-web-330d644a7f2079e8f454-wrr": {
Weighted: &dynamic.WeightedRoundRobin{ Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{ Services: []dynamic.WRRService{
{ {
@ -1332,7 +1316,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
}, },
}, },
}, },
"default-http-app-1-my-gateway-web-aaba0f24fd26e1ca2276-wrr": { "default-http-app-1-my-gateway-web-fe80e69a38713941ea22-wrr": {
Weighted: &dynamic.WeightedRoundRobin{ Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{ Services: []dynamic.WRRService{
{ {
@ -1387,7 +1371,6 @@ 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{},
@ -1447,13 +1430,11 @@ 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{},
@ -1539,7 +1520,6 @@ 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{},
@ -1599,7 +1579,6 @@ 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"},
}, },
}, },
@ -1668,7 +1647,6 @@ 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"},
}, },
}, },
@ -1934,7 +1912,6 @@ 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{},
@ -1992,13 +1969,11 @@ 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{},
@ -2078,7 +2053,6 @@ 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{},
@ -2170,7 +2144,6 @@ 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{},
@ -2230,7 +2203,6 @@ 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{},
}, },
}, },
@ -2294,7 +2266,6 @@ 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{},
@ -2350,13 +2321,11 @@ 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{},
@ -2434,7 +2403,6 @@ 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{},
@ -2728,7 +2696,6 @@ 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{},
}, },
}, },
@ -2794,7 +2761,6 @@ 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,
}, },
@ -2853,7 +2819,6 @@ 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,
}, },
@ -2913,14 +2878,12 @@ 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,
}, },
@ -3010,7 +2973,6 @@ 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{},
}, },
}, },
@ -3080,7 +3042,6 @@ 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,
}, },
@ -3139,7 +3100,6 @@ 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,
}, },
@ -3198,7 +3158,6 @@ 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,
}, },
@ -3257,7 +3216,6 @@ 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,
}, },
@ -3316,7 +3274,6 @@ 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,
}, },
@ -3375,7 +3332,6 @@ 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,
}, },
@ -3384,7 +3340,6 @@ 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,
}, },
@ -3465,7 +3420,6 @@ 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,
}, },
@ -3524,7 +3478,6 @@ 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,
}, },
@ -3749,20 +3702,17 @@ 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,
}, },
@ -3821,13 +3771,11 @@ 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{},
}, },
}, },
@ -3933,20 +3881,17 @@ 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,
}, },
@ -4005,13 +3950,11 @@ 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{},
}, },
}, },
@ -4089,20 +4032,17 @@ 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,
}, },
@ -4111,13 +4051,11 @@ 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{},
}, },
}, },
@ -4206,26 +4144,22 @@ 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{},
}, },
}, },
@ -4339,20 +4273,17 @@ 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,
}, },
@ -4411,13 +4342,11 @@ 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{},
}, },
}, },
@ -4494,13 +4423,11 @@ 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{},
}, },
}, },
@ -4547,13 +4474,11 @@ 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{},
}, },
}, },
@ -4882,7 +4807,7 @@ func Test_extractRule(t *testing.T) {
}, },
}, },
}, },
expectedRule: "Path(`/foo/`) || Header(`my-header`,`foo`)", expectedRule: "Path(`/foo/`) || Headers(`my-header`,`foo`)",
}, },
{ {
desc: "Path && Header rules", desc: "Path && Header rules",
@ -4903,7 +4828,7 @@ func Test_extractRule(t *testing.T) {
}, },
}, },
}, },
expectedRule: "Path(`/foo/`) && Header(`my-header`,`foo`)", expectedRule: "Path(`/foo/`) && Headers(`my-header`,`foo`)",
}, },
{ {
desc: "Host && Path && Header rules", desc: "Host && Path && Header rules",
@ -4925,7 +4850,7 @@ func Test_extractRule(t *testing.T) {
}, },
}, },
}, },
expectedRule: "Host(`foo.com`) && Path(`/foo/`) && Header(`my-header`,`foo`)", expectedRule: "Host(`foo.com`) && Path(`/foo/`) && Headers(`my-header`,`foo`)",
}, },
{ {
desc: "Host && (Path || Header) rules", desc: "Host && (Path || Header) rules",
@ -4949,7 +4874,7 @@ func Test_extractRule(t *testing.T) {
}, },
}, },
}, },
expectedRule: "Host(`foo.com`) && (Path(`/foo/`) || Header(`my-header`,`foo`))", expectedRule: "Host(`foo.com`) && (Path(`/foo/`) || Headers(`my-header`,`foo`))",
}, },
} }

View file

@ -22,11 +22,6 @@
"priority": 2147483645 "priority": 2147483645
} }
}, },
"services": {
"api": {},
"dashboard": {},
"noop": {}
},
"middlewares": { "middlewares": {
"dashboard_redirect": { "dashboard_redirect": {
"redirectRegex": { "redirectRegex": {
@ -43,6 +38,11 @@
] ]
} }
} }
},
"services": {
"api": {},
"dashboard": {},
"noop": {}
} }
}, },
"tcp": {}, "tcp": {},

View file

@ -54,14 +54,6 @@
"priority": 2147483647 "priority": 2147483647
} }
}, },
"services": {
"api": {},
"dashboard": {},
"noop": {},
"ping": {},
"prometheus": {},
"rest": {}
},
"middlewares": { "middlewares": {
"dashboard_redirect": { "dashboard_redirect": {
"redirectRegex": { "redirectRegex": {
@ -78,6 +70,14 @@
] ]
} }
} }
},
"services": {
"api": {},
"dashboard": {},
"noop": {},
"ping": {},
"prometheus": {},
"rest": {}
} }
}, },
"tcp": {}, "tcp": {},

View file

@ -12,9 +12,6 @@
"rule": "HostRegexp(`^.+$`)" "rule": "HostRegexp(`^.+$`)"
} }
}, },
"services": {
"noop": {}
},
"middlewares": { "middlewares": {
"redirect-web-to-websecure": { "redirect-web-to-websecure": {
"redirectScheme": { "redirectScheme": {
@ -23,8 +20,11 @@
"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