Merge branch v3.3 into master
This commit is contained in:
commit
786d9f3272
63 changed files with 1660 additions and 4548 deletions
1
.github/workflows/build.yaml
vendored
1
.github/workflows/build.yaml
vendored
|
@ -61,6 +61,7 @@ jobs:
|
||||||
ImageOS: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.goarm }}
|
ImageOS: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.goarm }}
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: Artifact webui
|
- name: Artifact webui
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
|
|
1
.github/workflows/experimental.yaml
vendored
1
.github/workflows/experimental.yaml
vendored
|
@ -33,6 +33,7 @@ jobs:
|
||||||
ImageOS: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.goarm }}
|
ImageOS: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.goarm }}
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make generate binary
|
run: make generate binary
|
||||||
|
|
1
.github/workflows/release.yaml
vendored
1
.github/workflows/release.yaml
vendored
|
@ -41,6 +41,7 @@ jobs:
|
||||||
ImageOS: ${{ matrix.os }}
|
ImageOS: ${{ matrix.os }}
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: Artifact webui
|
- name: Artifact webui
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
|
|
2
.github/workflows/test-integration.yaml
vendored
2
.github/workflows/test-integration.yaml
vendored
|
@ -28,6 +28,7 @@ jobs:
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: Avoid generating webui
|
- name: Avoid generating webui
|
||||||
run: touch webui/static/index.html
|
run: touch webui/static/index.html
|
||||||
|
@ -55,6 +56,7 @@ jobs:
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: Avoid generating webui
|
- name: Avoid generating webui
|
||||||
run: touch webui/static/index.html
|
run: touch webui/static/index.html
|
||||||
|
|
1
.github/workflows/test-unit.yaml
vendored
1
.github/workflows/test-unit.yaml
vendored
|
@ -27,6 +27,7 @@ jobs:
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: Avoid generating webui
|
- name: Avoid generating webui
|
||||||
run: touch webui/static/index.html
|
run: touch webui/static/index.html
|
||||||
|
|
3
.github/workflows/validate.yaml
vendored
3
.github/workflows/validate.yaml
vendored
|
@ -25,6 +25,7 @@ jobs:
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v6
|
uses: golangci/golangci-lint-action@v6
|
||||||
|
@ -44,6 +45,7 @@ jobs:
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: Install misspell ${{ env.MISSPELL_VERSION }}
|
- name: Install misspell ${{ env.MISSPELL_VERSION }}
|
||||||
run: curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSPELL_VERSION}
|
run: curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSPELL_VERSION}
|
||||||
|
@ -67,6 +69,7 @@ jobs:
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: go generate
|
- name: go generate
|
||||||
run: |
|
run: |
|
||||||
|
|
49
CHANGELOG.md
49
CHANGELOG.md
|
@ -1,3 +1,52 @@
|
||||||
|
## [v3.3.3](https://github.com/traefik/traefik/tree/v3.3.3) (2025-01-31)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v3.3.2...v3.3.3)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[api]** Do not create observability model by default ([#11476](https://github.com/traefik/traefik/pull/11476) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- **[fastproxy]** Fix content-length header assertion ([#11498](https://github.com/traefik/traefik/pull/11498) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- **[fastproxy]** Handle responses without content length header ([#11458](https://github.com/traefik/traefik/pull/11458) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- **[k8s/crd,k8s]** Add missing headerField in Middleware CRD ([#11499](https://github.com/traefik/traefik/pull/11499) by [jspdown](https://github.com/jspdown))
|
||||||
|
- **[tracing,accesslogs]** Bring back TraceID and SpanID fields in access logs ([#11450](https://github.com/traefik/traefik/pull/11450) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
|
||||||
|
**Misc:**
|
||||||
|
- Merge branch v2.11 into v3.3 ([#11502](https://github.com/traefik/traefik/pull/11502) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- Merge branch v2.11 into v3.3 ([#11491](https://github.com/traefik/traefik/pull/11491) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
|
||||||
|
## [v2.11.20](https://github.com/traefik/traefik/tree/v2.11.20) (2025-01-31)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v2.11.19...v2.11.20)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[acme]** Graceful shutdown for ACME JSON write operation ([#11497](https://github.com/traefik/traefik/pull/11497) by [juliens](https://github.com/juliens))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- Change docker-compose to docker compose ([#11496](https://github.com/traefik/traefik/pull/11496) by [khai-pi](https://github.com/khai-pi))
|
||||||
|
|
||||||
|
## [v2.11.19](https://github.com/traefik/traefik/tree/v2.11.19) (2025-01-29)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v2.11.18...v2.11.19)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[middleware]** Changing log message when client cert is not available to debug ([#11453](https://github.com/traefik/traefik/pull/11453) by [Nelwhix](https://github.com/Nelwhix))
|
||||||
|
- **[service]** Do not create a logger instance for each proxy ([#11487](https://github.com/traefik/traefik/pull/11487) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- **[webui]** Fix auto refresh not clearing on component unmount ([#11477](https://github.com/traefik/traefik/pull/11477) by [DoubleREW](https://github.com/DoubleREW))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- Remove awesome.traefik.io reference in documentation section ([#11435](https://github.com/traefik/traefik/pull/11435) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
|
||||||
|
## [v3.3.2](https://github.com/traefik/traefik/tree/v3.3.2) (2025-01-14)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v3.3.1...v3.3.2)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[fastproxy]** Do not read response body for HEAD requests ([#11442](https://github.com/traefik/traefik/pull/11442) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- **[metrics,tracing,accesslogs]** Fix observability configuration on EntryPoints ([#11446](https://github.com/traefik/traefik/pull/11446) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- **[webui]** Set content-type when serving webui index ([#11428](https://github.com/traefik/traefik/pull/11428) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- **[acme]** Fix deprecated dnsChallenge propagation logging and documentation ([#11433](https://github.com/traefik/traefik/pull/11433) by [thomscode](https://github.com/thomscode))
|
||||||
|
- **[acme]** Add missing trailing s to propagation.delayBeforeCheck option ([#11417](https://github.com/traefik/traefik/pull/11417) by [jspiers](https://github.com/jspiers))
|
||||||
|
|
||||||
|
**Misc:**
|
||||||
|
- Merge branch v2.11 into v3.3 ([#11419](https://github.com/traefik/traefik/pull/11419) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
|
||||||
## [v3.3.1](https://github.com/traefik/traefik/tree/v3.3.1) (2025-01-07)
|
## [v3.3.1](https://github.com/traefik/traefik/tree/v3.3.1) (2025-01-07)
|
||||||
[All Commits](https://github.com/traefik/traefik/compare/v3.3.0...v3.3.1)
|
[All Commits](https://github.com/traefik/traefik/compare/v3.3.0...v3.3.1)
|
||||||
|
|
||||||
|
|
|
@ -90,8 +90,6 @@ You can access the simple HTML frontend of Traefik.
|
||||||
|
|
||||||
You can find the complete documentation of Traefik v3 at [https://doc.traefik.io/traefik/](https://doc.traefik.io/traefik/).
|
You can find the complete documentation of Traefik v3 at [https://doc.traefik.io/traefik/](https://doc.traefik.io/traefik/).
|
||||||
|
|
||||||
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
|
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
To get community support, you can:
|
To get community support, you can:
|
||||||
|
|
|
@ -192,7 +192,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
acmeProviders := initACMEProvider(staticConfiguration, providerAggregator, tlsManager, httpChallengeProvider, tlsChallengeProvider)
|
acmeProviders := initACMEProvider(staticConfiguration, providerAggregator, tlsManager, httpChallengeProvider, tlsChallengeProvider, routinesPool)
|
||||||
|
|
||||||
// Tailscale
|
// Tailscale
|
||||||
|
|
||||||
|
@ -444,7 +444,7 @@ func switchRouter(routerFactory *server.RouterFactory, serverEntryPointsTCP serv
|
||||||
}
|
}
|
||||||
|
|
||||||
// initACMEProvider creates and registers acme.Provider instances corresponding to the configured ACME certificate resolvers.
|
// initACMEProvider creates and registers acme.Provider instances corresponding to the configured ACME certificate resolvers.
|
||||||
func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.ProviderAggregator, tlsManager *traefiktls.Manager, httpChallengeProvider, tlsChallengeProvider challenge.Provider) []*acme.Provider {
|
func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.ProviderAggregator, tlsManager *traefiktls.Manager, httpChallengeProvider, tlsChallengeProvider challenge.Provider, routinesPool *safe.Pool) []*acme.Provider {
|
||||||
localStores := map[string]*acme.LocalStore{}
|
localStores := map[string]*acme.LocalStore{}
|
||||||
|
|
||||||
var resolvers []*acme.Provider
|
var resolvers []*acme.Provider
|
||||||
|
@ -454,7 +454,7 @@ func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.Pr
|
||||||
}
|
}
|
||||||
|
|
||||||
if localStores[resolver.ACME.Storage] == nil {
|
if localStores[resolver.ACME.Storage] == nil {
|
||||||
localStores[resolver.ACME.Storage] = acme.NewLocalStore(resolver.ACME.Storage)
|
localStores[resolver.ACME.Storage] = acme.NewLocalStore(resolver.ACME.Storage, routinesPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &acme.Provider{
|
p := &acme.Provider{
|
||||||
|
|
|
@ -38,7 +38,7 @@ services:
|
||||||
Start your `reverse-proxy` with the following command:
|
Start your `reverse-proxy` with the following command:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker-compose up -d reverse-proxy
|
docker compose up -d reverse-proxy
|
||||||
```
|
```
|
||||||
|
|
||||||
You can open a browser and go to `http://localhost:8080/api/rawdata` to see Traefik's API rawdata (you'll go back there once you have launched a service in step 2).
|
You can open a browser and go to `http://localhost:8080/api/rawdata` to see Traefik's API rawdata (you'll go back there once you have launched a service in step 2).
|
||||||
|
@ -68,7 +68,7 @@ The above defines `whoami`: a web service that outputs information about the mac
|
||||||
Start the `whoami` service with the following command:
|
Start the `whoami` service with the following command:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker-compose up -d whoami
|
docker compose up -d whoami
|
||||||
```
|
```
|
||||||
|
|
||||||
Browse `http://localhost:8080/api/rawdata` and see that Traefik has automatically detected the new container and updated its own configuration.
|
Browse `http://localhost:8080/api/rawdata` and see that Traefik has automatically detected the new container and updated its own configuration.
|
||||||
|
@ -92,7 +92,7 @@ IP: 172.27.0.3
|
||||||
Run more instances of your `whoami` service with the following command:
|
Run more instances of your `whoami` service with the following command:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker-compose up -d --scale whoami=2
|
docker compose up -d --scale whoami=2
|
||||||
```
|
```
|
||||||
|
|
||||||
Browse to `http://localhost:8080/api/rawdata` and see that Traefik has automatically detected the new instance of the container.
|
Browse to `http://localhost:8080/api/rawdata` and see that Traefik has automatically detected the new instance of the container.
|
||||||
|
|
|
@ -503,7 +503,7 @@ certificatesResolvers:
|
||||||
|
|
||||||
By default, the `provider` verifies the TXT record _before_ letting ACME verify.
|
By default, the `provider` verifies the TXT record _before_ letting ACME verify.
|
||||||
|
|
||||||
You can delay this operation by specifying a delay (in seconds) with `delayBeforeCheck` (value must be greater than zero).
|
You can delay this operation by specifying a delay (in seconds) with `delayBeforeChecks` (value must be greater than zero).
|
||||||
|
|
||||||
This option is useful when internal networks block external DNS queries.
|
This option is useful when internal networks block external DNS queries.
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ please use the `traefik.swarm.network` and `traefik.swarm.lbswarm` labels instea
|
||||||
### ACME DNS Certificate Resolver
|
### ACME DNS Certificate Resolver
|
||||||
|
|
||||||
In `v3.3`, the `acme.dnsChallenge.delaybeforecheck` and `acme.dnsChallenge.disablepropagationcheck` options of the ACME certificate resolver are deprecated,
|
In `v3.3`, the `acme.dnsChallenge.delaybeforecheck` and `acme.dnsChallenge.disablepropagationcheck` options of the ACME certificate resolver are deprecated,
|
||||||
please use respectively `acme.dnsChallenge.propagation.delayBeforeChecks` and `acme.dnsChallenge.propagation.disableAllChecks` options instead.
|
please use respectively `acme.dnsChallenge.propagation.delayBeforeChecks` and `acme.dnsChallenge.propagation.disableChecks` options instead.
|
||||||
|
|
||||||
### Tracing Global Attributes
|
### Tracing Global Attributes
|
||||||
|
|
||||||
|
|
|
@ -1238,6 +1238,11 @@ spec:
|
||||||
description: ForwardBody defines whether to send the request body
|
description: ForwardBody defines whether to send the request body
|
||||||
to the authentication server.
|
to the authentication server.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
headerField:
|
||||||
|
description: |-
|
||||||
|
HeaderField defines a header field to store the authenticated user.
|
||||||
|
More info: https://doc.traefik.io/traefik/v3.3/middlewares/http/forwardauth/#headerfield
|
||||||
|
type: string
|
||||||
maxBodySize:
|
maxBodySize:
|
||||||
description: MaxBodySize defines the maximum body size in bytes
|
description: MaxBodySize defines the maximum body size in bytes
|
||||||
allowed to be forwarded to the authentication server.
|
allowed to be forwarded to the authentication server.
|
||||||
|
|
|
@ -496,6 +496,11 @@ spec:
|
||||||
description: ForwardBody defines whether to send the request body
|
description: ForwardBody defines whether to send the request body
|
||||||
to the authentication server.
|
to the authentication server.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
headerField:
|
||||||
|
description: |-
|
||||||
|
HeaderField defines a header field to store the authenticated user.
|
||||||
|
More info: https://doc.traefik.io/traefik/v3.3/middlewares/http/forwardauth/#headerfield
|
||||||
|
type: string
|
||||||
maxBodySize:
|
maxBodySize:
|
||||||
description: MaxBodySize defines the maximum body size in bytes
|
description: MaxBodySize defines the maximum body size in bytes
|
||||||
allowed to be forwarded to the authentication server.
|
allowed to be forwarded to the authentication server.
|
||||||
|
|
|
@ -31,7 +31,7 @@ Our starting point is the docker-compose configuration file, to start the k3s cl
|
||||||
You can start it with:
|
You can start it with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose -f k3s.yml up
|
docker compose -f k3s.yml up
|
||||||
```
|
```
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|
|
@ -46,7 +46,7 @@ For the DNS challenge, you'll need:
|
||||||
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
|
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Run `docker-compose up -d` within the folder where you created the previous file.
|
- Run `docker compose up -d` within the folder where you created the previous file.
|
||||||
- Wait a bit and visit `https://your_own_domain` to confirm everything went fine.
|
- Wait a bit and visit `https://your_own_domain` to confirm everything went fine.
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
|
|
|
@ -32,7 +32,7 @@ For the HTTP challenge you will need:
|
||||||
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
|
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Run `docker-compose up -d` within the folder where you created the previous file.
|
- Run `docker compose up -d` within the folder where you created the previous file.
|
||||||
- Wait a bit and visit `https://your_own_domain` to confirm everything went fine.
|
- Wait a bit and visit `https://your_own_domain` to confirm everything went fine.
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
|
|
|
@ -32,7 +32,7 @@ For the TLS challenge you will need:
|
||||||
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
|
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Run `docker-compose up -d` within the folder where you created the previous file.
|
- Run `docker compose up -d` within the folder where you created the previous file.
|
||||||
- Wait a bit and visit `https://your_own_domain` to confirm everything went fine.
|
- Wait a bit and visit `https://your_own_domain` to confirm everything went fine.
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
|
|
|
@ -46,7 +46,7 @@ Create a `docker-compose.yml` file with the following content:
|
||||||
|
|
||||||
Replace `whoami.localhost` by your **own domain** within the `traefik.http.routers.whoami.rule` label of the `whoami` service.
|
Replace `whoami.localhost` by your **own domain** within the `traefik.http.routers.whoami.rule` label of the `whoami` service.
|
||||||
|
|
||||||
Now run `docker-compose up -d` within the folder where you created the previous file.
|
Now run `docker compose up -d` within the folder where you created the previous file.
|
||||||
This will start Docker Compose in background mode.
|
This will start Docker Compose in background mode.
|
||||||
|
|
||||||
!!! info "This can take a moment"
|
!!! info "This can take a moment"
|
||||||
|
|
|
@ -10,24 +10,24 @@
|
||||||
# Use certificate in net/internal/testcert.go
|
# Use certificate in net/internal/testcert.go
|
||||||
rootCAs = [ """
|
rootCAs = [ """
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
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
|
||||||
WkBKOclmOV2xlTVuPw==
|
rF7r4gUnKeC7mYIH1zypY7laskopiLFAfe96Kg==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
"""]
|
"""]
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
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
|
||||||
WkBKOclmOV2xlTVuPw==
|
rF7r4gUnKeC7mYIH1zypY7laskopiLFAfe96Kg==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1238,6 +1238,11 @@ spec:
|
||||||
description: ForwardBody defines whether to send the request body
|
description: ForwardBody defines whether to send the request body
|
||||||
to the authentication server.
|
to the authentication server.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
headerField:
|
||||||
|
description: |-
|
||||||
|
HeaderField defines a header field to store the authenticated user.
|
||||||
|
More info: https://doc.traefik.io/traefik/v3.3/middlewares/http/forwardauth/#headerfield
|
||||||
|
type: string
|
||||||
maxBodySize:
|
maxBodySize:
|
||||||
description: MaxBodySize defines the maximum body size in bytes
|
description: MaxBodySize defines the maximum body size in bytes
|
||||||
allowed to be forwarded to the authentication server.
|
allowed to be forwarded to the authentication server.
|
||||||
|
|
20
integration/testdata/rawdata-consul.json
vendored
20
integration/testdata/rawdata-consul.json
vendored
|
@ -12,6 +12,11 @@
|
||||||
"rule": "Host(`kv1.localhost`)",
|
"rule": "Host(`kv1.localhost`)",
|
||||||
"priority": 42,
|
"priority": 42,
|
||||||
"tls": {},
|
"tls": {},
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -42,6 +47,11 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -55,6 +65,11 @@
|
||||||
"rule": "PathPrefix(`/api`)",
|
"rule": "PathPrefix(`/api`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775806,
|
"priority": 9223372036854775806,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -72,6 +87,11 @@
|
||||||
"rule": "PathPrefix(`/`)",
|
"rule": "PathPrefix(`/`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775805,
|
"priority": 9223372036854775805,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
|
|
@ -7,6 +7,11 @@
|
||||||
"service": "api@internal",
|
"service": "api@internal",
|
||||||
"rule": "PathPrefix(`/api`)",
|
"rule": "PathPrefix(`/api`)",
|
||||||
"priority": 18,
|
"priority": 18,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -22,6 +27,11 @@
|
||||||
"tls": {
|
"tls": {
|
||||||
"options": "default-mytlsoption"
|
"options": "default-mytlsoption"
|
||||||
},
|
},
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
|
30
integration/testdata/rawdata-crd.json
vendored
30
integration/testdata/rawdata-crd.json
vendored
|
@ -7,6 +7,11 @@
|
||||||
"service": "api@internal",
|
"service": "api@internal",
|
||||||
"rule": "PathPrefix(`/api`)",
|
"rule": "PathPrefix(`/api`)",
|
||||||
"priority": 18,
|
"priority": 18,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -22,6 +27,11 @@
|
||||||
"tls": {
|
"tls": {
|
||||||
"options": "default-mytlsoption"
|
"options": "default-mytlsoption"
|
||||||
},
|
},
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -37,6 +47,11 @@
|
||||||
"service": "default-test2-route-23c7f4c450289ee29016",
|
"service": "default-test2-route-23c7f4c450289ee29016",
|
||||||
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/tobestripped`)",
|
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/tobestripped`)",
|
||||||
"priority": 46,
|
"priority": 46,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -49,6 +64,11 @@
|
||||||
"service": "default-wrr1",
|
"service": "default-wrr1",
|
||||||
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/wrr1`)",
|
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/wrr1`)",
|
||||||
"priority": 38,
|
"priority": 38,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -61,6 +81,11 @@
|
||||||
"service": "default-testst-route-60ad45fcb5fc1f5f3629",
|
"service": "default-testst-route-60ad45fcb5fc1f5f3629",
|
||||||
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/serverstransport`)",
|
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/serverstransport`)",
|
||||||
"priority": 50,
|
"priority": 50,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -73,6 +98,11 @@
|
||||||
"service": "other-ns-wrr3",
|
"service": "other-ns-wrr3",
|
||||||
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/c`)",
|
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/c`)",
|
||||||
"priority": 35,
|
"priority": 35,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"error": [
|
"error": [
|
||||||
"the service \"other-ns-wrr3@kubernetescrd\" does not exist"
|
"the service \"other-ns-wrr3@kubernetescrd\" does not exist"
|
||||||
],
|
],
|
||||||
|
|
20
integration/testdata/rawdata-etcd.json
vendored
20
integration/testdata/rawdata-etcd.json
vendored
|
@ -12,6 +12,11 @@
|
||||||
"rule": "Host(`kv1.localhost`)",
|
"rule": "Host(`kv1.localhost`)",
|
||||||
"priority": 42,
|
"priority": 42,
|
||||||
"tls": {},
|
"tls": {},
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -42,6 +47,11 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -55,6 +65,11 @@
|
||||||
"rule": "PathPrefix(`/api`)",
|
"rule": "PathPrefix(`/api`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775806,
|
"priority": 9223372036854775806,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -72,6 +87,11 @@
|
||||||
"rule": "PathPrefix(`/`)",
|
"rule": "PathPrefix(`/`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775805,
|
"priority": 9223372036854775805,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
|
20
integration/testdata/rawdata-gateway.json
vendored
20
integration/testdata/rawdata-gateway.json
vendored
|
@ -8,6 +8,11 @@
|
||||||
"rule": "PathPrefix(`/api`)",
|
"rule": "PathPrefix(`/api`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775806,
|
"priority": 9223372036854775806,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -25,6 +30,11 @@
|
||||||
"rule": "PathPrefix(`/`)",
|
"rule": "PathPrefix(`/`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775805,
|
"priority": 9223372036854775805,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -38,6 +48,11 @@
|
||||||
"rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)",
|
"rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 100008,
|
"priority": 100008,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -52,6 +67,11 @@
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 100008,
|
"priority": 100008,
|
||||||
"tls": {},
|
"tls": {},
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"websecure"
|
"websecure"
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
"rule": "PathPrefix(`/api`)",
|
"rule": "PathPrefix(`/api`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775806,
|
"priority": 9223372036854775806,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -25,6 +30,11 @@
|
||||||
"rule": "PathPrefix(`/`)",
|
"rule": "PathPrefix(`/`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775805,
|
"priority": 9223372036854775805,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -37,6 +47,11 @@
|
||||||
"service": "default-whoami-http",
|
"service": "default-whoami-http",
|
||||||
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
|
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||||
"priority": 44,
|
"priority": 44,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
|
30
integration/testdata/rawdata-ingress.json
vendored
30
integration/testdata/rawdata-ingress.json
vendored
|
@ -8,6 +8,11 @@
|
||||||
"rule": "PathPrefix(`/api`)",
|
"rule": "PathPrefix(`/api`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775806,
|
"priority": 9223372036854775806,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -25,6 +30,11 @@
|
||||||
"rule": "PathPrefix(`/`)",
|
"rule": "PathPrefix(`/`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775805,
|
"priority": 9223372036854775805,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -37,6 +47,11 @@
|
||||||
"service": "default-whoami-http",
|
"service": "default-whoami-http",
|
||||||
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
|
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||||
"priority": 50,
|
"priority": 50,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -49,6 +64,11 @@
|
||||||
"service": "default-whoami-http",
|
"service": "default-whoami-http",
|
||||||
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
|
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||||
"priority": 44,
|
"priority": 44,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -61,6 +81,11 @@
|
||||||
"service": "default-whoami-80",
|
"service": "default-whoami-80",
|
||||||
"rule": "Host(`whoami.test.drop`) \u0026\u0026 PathPrefix(`/drop`)",
|
"rule": "Host(`whoami.test.drop`) \u0026\u0026 PathPrefix(`/drop`)",
|
||||||
"priority": 47,
|
"priority": 47,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -73,6 +98,11 @@
|
||||||
"service": "default-whoami-80",
|
"service": "default-whoami-80",
|
||||||
"rule": "Host(`whoami.test.keep`) \u0026\u0026 PathPrefix(`/keep`)",
|
"rule": "Host(`whoami.test.keep`) \u0026\u0026 PathPrefix(`/keep`)",
|
||||||
"priority": 47,
|
"priority": 47,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
"rule": "PathPrefix(`/api`)",
|
"rule": "PathPrefix(`/api`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775806,
|
"priority": 9223372036854775806,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -25,6 +30,11 @@
|
||||||
"rule": "PathPrefix(`/`)",
|
"rule": "PathPrefix(`/`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775805,
|
"priority": 9223372036854775805,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
|
15
integration/testdata/rawdata-ingressclass.json
vendored
15
integration/testdata/rawdata-ingressclass.json
vendored
|
@ -8,6 +8,11 @@
|
||||||
"rule": "PathPrefix(`/api`)",
|
"rule": "PathPrefix(`/api`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775806,
|
"priority": 9223372036854775806,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -25,6 +30,11 @@
|
||||||
"rule": "PathPrefix(`/`)",
|
"rule": "PathPrefix(`/`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775805,
|
"priority": 9223372036854775805,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -37,6 +47,11 @@
|
||||||
"service": "default-whoami-80",
|
"service": "default-whoami-80",
|
||||||
"rule": "Host(`whoami.test.keep`) \u0026\u0026 PathPrefix(`/keep`)",
|
"rule": "Host(`whoami.test.keep`) \u0026\u0026 PathPrefix(`/keep`)",
|
||||||
"priority": 47,
|
"priority": 47,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
|
20
integration/testdata/rawdata-redis.json
vendored
20
integration/testdata/rawdata-redis.json
vendored
|
@ -12,6 +12,11 @@
|
||||||
"rule": "Host(`kv1.localhost`)",
|
"rule": "Host(`kv1.localhost`)",
|
||||||
"priority": 42,
|
"priority": 42,
|
||||||
"tls": {},
|
"tls": {},
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -42,6 +47,11 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -55,6 +65,11 @@
|
||||||
"rule": "PathPrefix(`/api`)",
|
"rule": "PathPrefix(`/api`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775806,
|
"priority": 9223372036854775806,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -72,6 +87,11 @@
|
||||||
"rule": "PathPrefix(`/`)",
|
"rule": "PathPrefix(`/`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775805,
|
"priority": 9223372036854775805,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
|
20
integration/testdata/rawdata-zk.json
vendored
20
integration/testdata/rawdata-zk.json
vendored
|
@ -12,6 +12,11 @@
|
||||||
"rule": "Host(`kv1.localhost`)",
|
"rule": "Host(`kv1.localhost`)",
|
||||||
"priority": 42,
|
"priority": 42,
|
||||||
"tls": {},
|
"tls": {},
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -42,6 +47,11 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"web"
|
"web"
|
||||||
|
@ -55,6 +65,11 @@
|
||||||
"rule": "PathPrefix(`/api`)",
|
"rule": "PathPrefix(`/api`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775806,
|
"priority": 9223372036854775806,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
@ -72,6 +87,11 @@
|
||||||
"rule": "PathPrefix(`/`)",
|
"rule": "PathPrefix(`/`)",
|
||||||
"ruleSyntax": "v3",
|
"ruleSyntax": "v3",
|
||||||
"priority": 9223372036854775805,
|
"priority": 9223372036854775805,
|
||||||
|
"observability": {
|
||||||
|
"accessLogs": true,
|
||||||
|
"tracing": true,
|
||||||
|
"metrics": true
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"using": [
|
"using": [
|
||||||
"traefik"
|
"traefik"
|
||||||
|
|
|
@ -29,14 +29,10 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
assets = webui.FS
|
assets = webui.FS
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow iframes from traefik domains only
|
// Allow iframes from traefik domains only.
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
|
||||||
w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")
|
w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")
|
||||||
|
|
||||||
// The content type must be guessed by the file server.
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
|
|
||||||
w.Header().Del("Content-Type")
|
|
||||||
|
|
||||||
if r.RequestURI == "/" {
|
if r.RequestURI == "/" {
|
||||||
indexTemplate, err := template.ParseFS(assets, "index.html")
|
indexTemplate, err := template.ParseFS(assets, "index.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -45,6 +41,8 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
|
||||||
apiPath := strings.TrimSuffix(h.BasePath, "/") + "/api/"
|
apiPath := strings.TrimSuffix(h.BasePath, "/") + "/api/"
|
||||||
if err = indexTemplate.Execute(w, indexTemplateData{APIUrl: apiPath}); err != nil {
|
if err = indexTemplate.Execute(w, indexTemplateData{APIUrl: apiPath}); err != nil {
|
||||||
log.Error().Err(err).Msg("Unable to render index template")
|
log.Error().Err(err).Msg("Unable to render index template")
|
||||||
|
@ -55,6 +53,10 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The content type must be guessed by the file server.
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
|
||||||
|
w.Header().Del("Content-Type")
|
||||||
|
|
||||||
http.FileServerFS(assets).ServeHTTP(w, r)
|
http.FileServerFS(assets).ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,13 +86,11 @@ func Append(router *mux.Router, basePath string, customAssets fs.FS) error {
|
||||||
router.Methods(http.MethodGet).
|
router.Methods(http.MethodGet).
|
||||||
Path(dashboardPath).
|
Path(dashboardPath).
|
||||||
HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// allow iframes from our domains only
|
// Allow iframes from our domains only.
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
|
||||||
w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")
|
w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")
|
||||||
|
|
||||||
// The content type must be guessed by the file server.
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
|
|
||||||
w.Header().Del("Content-Type")
|
|
||||||
|
|
||||||
apiPath := strings.TrimSuffix(basePath, "/") + "/api/"
|
apiPath := strings.TrimSuffix(basePath, "/") + "/api/"
|
||||||
if err = indexTemplate.Execute(w, indexTemplateData{APIUrl: apiPath}); err != nil {
|
if err = indexTemplate.Execute(w, indexTemplateData{APIUrl: apiPath}); err != nil {
|
||||||
|
@ -103,7 +103,7 @@ func Append(router *mux.Router, basePath string, customAssets fs.FS) error {
|
||||||
router.Methods(http.MethodGet).
|
router.Methods(http.MethodGet).
|
||||||
PathPrefix(dashboardPath).
|
PathPrefix(dashboardPath).
|
||||||
HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// allow iframes from traefik domains only
|
// Allow iframes from traefik domains only.
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
|
||||||
w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")
|
w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")
|
||||||
|
|
||||||
|
@ -113,5 +113,6 @@ func Append(router *mux.Router, basePath string, customAssets fs.FS) error {
|
||||||
|
|
||||||
http.StripPrefix(dashboardPath, http.FileServerFS(assets)).ServeHTTP(w, r)
|
http.StripPrefix(dashboardPath, http.FileServerFS(assets)).ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,7 +252,7 @@ type ForwardAuth struct {
|
||||||
// AddAuthCookiesToResponse defines the list of cookies to copy from the authentication server response to the response.
|
// 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"`
|
AddAuthCookiesToResponse []string `json:"addAuthCookiesToResponse,omitempty" toml:"addAuthCookiesToResponse,omitempty" yaml:"addAuthCookiesToResponse,omitempty" export:"true"`
|
||||||
// HeaderField defines a header field to store the authenticated user.
|
// HeaderField defines a header field to store the authenticated user.
|
||||||
// More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/forwardauth/#headerfield
|
// More info: https://doc.traefik.io/traefik/v3.3/middlewares/http/forwardauth/#headerfield
|
||||||
HeaderField string `json:"headerField,omitempty" toml:"headerField,omitempty" yaml:"headerField,omitempty" export:"true"`
|
HeaderField string `json:"headerField,omitempty" toml:"headerField,omitempty" yaml:"headerField,omitempty" export:"true"`
|
||||||
// ForwardBody defines whether to send the request body to the authentication server.
|
// ForwardBody defines whether to send the request body to the authentication server.
|
||||||
ForwardBody bool `json:"forwardBody,omitempty" toml:"forwardBody,omitempty" yaml:"forwardBody,omitempty" export:"true"`
|
ForwardBody bool `json:"forwardBody,omitempty" toml:"forwardBody,omitempty" yaml:"forwardBody,omitempty" export:"true"`
|
||||||
|
|
|
@ -60,8 +60,6 @@ func (ep *EntryPoint) SetDefaults() {
|
||||||
ep.HTTP.SetDefaults()
|
ep.HTTP.SetDefaults()
|
||||||
ep.HTTP2 = &HTTP2Config{}
|
ep.HTTP2 = &HTTP2Config{}
|
||||||
ep.HTTP2.SetDefaults()
|
ep.HTTP2.SetDefaults()
|
||||||
ep.Observability = &ObservabilityConfig{}
|
|
||||||
ep.Observability.SetDefaults()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPConfig is the HTTP configuration of an entry point.
|
// HTTPConfig is the HTTP configuration of an entry point.
|
||||||
|
@ -164,14 +162,15 @@ func (u *UDPConfig) SetDefaults() {
|
||||||
|
|
||||||
// ObservabilityConfig holds the observability configuration for an entry point.
|
// ObservabilityConfig holds the observability configuration for an entry point.
|
||||||
type ObservabilityConfig struct {
|
type ObservabilityConfig struct {
|
||||||
AccessLogs bool `json:"accessLogs,omitempty" toml:"accessLogs,omitempty" yaml:"accessLogs,omitempty" export:"true"`
|
AccessLogs *bool `json:"accessLogs,omitempty" toml:"accessLogs,omitempty" yaml:"accessLogs,omitempty" export:"true"`
|
||||||
Tracing bool `json:"tracing,omitempty" toml:"tracing,omitempty" yaml:"tracing,omitempty" export:"true"`
|
Tracing *bool `json:"tracing,omitempty" toml:"tracing,omitempty" yaml:"tracing,omitempty" export:"true"`
|
||||||
Metrics bool `json:"metrics,omitempty" toml:"metrics,omitempty" yaml:"metrics,omitempty" export:"true"`
|
Metrics *bool `json:"metrics,omitempty" toml:"metrics,omitempty" yaml:"metrics,omitempty" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaults sets the default values.
|
// SetDefaults sets the default values.
|
||||||
func (o *ObservabilityConfig) SetDefaults() {
|
func (o *ObservabilityConfig) SetDefaults() {
|
||||||
o.AccessLogs = true
|
defaultValue := true
|
||||||
o.Tracing = true
|
o.AccessLogs = &defaultValue
|
||||||
o.Metrics = true
|
o.Tracing = &defaultValue
|
||||||
|
o.Metrics = &defaultValue
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,7 +321,7 @@ func (c *Configuration) SetEffectiveConfiguration() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if resolver.ACME.DNSChallenge.DisablePropagationCheck {
|
if resolver.ACME.DNSChallenge.DisablePropagationCheck {
|
||||||
log.Warn().Msgf("disablePropagationCheck is now deprecated, please use propagation.disableAllChecks instead.")
|
log.Warn().Msgf("disablePropagationCheck is now deprecated, please use propagation.disableChecks instead.")
|
||||||
|
|
||||||
if resolver.ACME.DNSChallenge.Propagation == nil {
|
if resolver.ACME.DNSChallenge.Propagation == nil {
|
||||||
resolver.ACME.DNSChallenge.Propagation = &acmeprovider.Propagation{}
|
resolver.ACME.DNSChallenge.Propagation = &acmeprovider.Propagation{}
|
||||||
|
|
|
@ -77,11 +77,6 @@ func TestConfiguration_SetEffectiveConfiguration(t *testing.T) {
|
||||||
UDP: &UDPConfig{
|
UDP: &UDPConfig{
|
||||||
Timeout: 3000000000,
|
Timeout: 3000000000,
|
||||||
},
|
},
|
||||||
Observability: &ObservabilityConfig{
|
|
||||||
AccessLogs: true,
|
|
||||||
Tracing: true,
|
|
||||||
Metrics: true,
|
|
||||||
},
|
|
||||||
}},
|
}},
|
||||||
Providers: &Providers{},
|
Providers: &Providers{},
|
||||||
},
|
},
|
||||||
|
@ -127,11 +122,6 @@ func TestConfiguration_SetEffectiveConfiguration(t *testing.T) {
|
||||||
UDP: &UDPConfig{
|
UDP: &UDPConfig{
|
||||||
Timeout: 3000000000,
|
Timeout: 3000000000,
|
||||||
},
|
},
|
||||||
Observability: &ObservabilityConfig{
|
|
||||||
AccessLogs: true,
|
|
||||||
Tracing: true,
|
|
||||||
Metrics: true,
|
|
||||||
},
|
|
||||||
}},
|
}},
|
||||||
Providers: &Providers{},
|
Providers: &Providers{},
|
||||||
CertificatesResolvers: map[string]CertificateResolver{
|
CertificatesResolvers: map[string]CertificateResolver{
|
||||||
|
@ -188,11 +178,6 @@ func TestConfiguration_SetEffectiveConfiguration(t *testing.T) {
|
||||||
UDP: &UDPConfig{
|
UDP: &UDPConfig{
|
||||||
Timeout: 3000000000,
|
Timeout: 3000000000,
|
||||||
},
|
},
|
||||||
Observability: &ObservabilityConfig{
|
|
||||||
AccessLogs: true,
|
|
||||||
Tracing: true,
|
|
||||||
Metrics: true,
|
|
||||||
},
|
|
||||||
}},
|
}},
|
||||||
Providers: &Providers{},
|
Providers: &Providers{},
|
||||||
CertificatesResolvers: map[string]CertificateResolver{
|
CertificatesResolvers: map[string]CertificateResolver{
|
||||||
|
@ -253,11 +238,6 @@ func TestConfiguration_SetEffectiveConfiguration(t *testing.T) {
|
||||||
UDP: &UDPConfig{
|
UDP: &UDPConfig{
|
||||||
Timeout: 3000000000,
|
Timeout: 3000000000,
|
||||||
},
|
},
|
||||||
Observability: &ObservabilityConfig{
|
|
||||||
AccessLogs: true,
|
|
||||||
Tracing: true,
|
|
||||||
Metrics: true,
|
|
||||||
},
|
|
||||||
}},
|
}},
|
||||||
Providers: &Providers{},
|
Providers: &Providers{},
|
||||||
CertificatesResolvers: map[string]CertificateResolver{
|
CertificatesResolvers: map[string]CertificateResolver{
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||||
"github.com/traefik/traefik/v3/pkg/types"
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
"go.opentelemetry.io/contrib/bridges/otellogrus"
|
"go.opentelemetry.io/contrib/bridges/otellogrus"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type key string
|
type key string
|
||||||
|
@ -209,6 +210,12 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if span := trace.SpanFromContext(req.Context()); span != nil {
|
||||||
|
spanContext := span.SpanContext()
|
||||||
|
logDataTable.Core[TraceID] = spanContext.TraceID().String()
|
||||||
|
logDataTable.Core[SpanID] = spanContext.SpanID().String()
|
||||||
|
}
|
||||||
|
|
||||||
reqWithDataTable := req.WithContext(context.WithValue(req.Context(), DataTableKey, logDataTable))
|
reqWithDataTable := req.WithContext(context.WithValue(req.Context(), DataTableKey, logDataTable))
|
||||||
|
|
||||||
core[RequestCount] = nextRequestCount()
|
core[RequestCount] = nextRequestCount()
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/types"
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
"go.opentelemetry.io/collector/pdata/plog/plogotlp"
|
"go.opentelemetry.io/collector/pdata/plog/plogotlp"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
"go.opentelemetry.io/otel/trace/noop"
|
||||||
)
|
)
|
||||||
|
|
||||||
const delta float64 = 1e-10
|
const delta float64 = 1e-10
|
||||||
|
@ -409,6 +410,8 @@ func TestLoggerJSON(t *testing.T) {
|
||||||
"time": assertNotEmpty(),
|
"time": assertNotEmpty(),
|
||||||
"StartLocal": assertNotEmpty(),
|
"StartLocal": assertNotEmpty(),
|
||||||
"StartUTC": assertNotEmpty(),
|
"StartUTC": assertNotEmpty(),
|
||||||
|
TraceID: assertNotEmpty(),
|
||||||
|
SpanID: assertNotEmpty(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -452,6 +455,8 @@ func TestLoggerJSON(t *testing.T) {
|
||||||
"time": assertNotEmpty(),
|
"time": assertNotEmpty(),
|
||||||
StartLocal: assertNotEmpty(),
|
StartLocal: assertNotEmpty(),
|
||||||
StartUTC: assertNotEmpty(),
|
StartUTC: assertNotEmpty(),
|
||||||
|
TraceID: assertNotEmpty(),
|
||||||
|
SpanID: assertNotEmpty(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -627,6 +632,8 @@ func TestLogger_AbortedRequest(t *testing.T) {
|
||||||
"downstream_Content-Type": assertString("text/plain"),
|
"downstream_Content-Type": assertString("text/plain"),
|
||||||
"downstream_Transfer-Encoding": assertString("chunked"),
|
"downstream_Transfer-Encoding": assertString("chunked"),
|
||||||
"downstream_Cache-Control": assertString("no-cache"),
|
"downstream_Cache-Control": assertString("no-cache"),
|
||||||
|
TraceID: assertNotEmpty(),
|
||||||
|
SpanID: assertNotEmpty(),
|
||||||
}
|
}
|
||||||
|
|
||||||
config := &types.AccessLog{
|
config := &types.AccessLog{
|
||||||
|
@ -945,6 +952,10 @@ func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracer := noop.Tracer{}
|
||||||
|
spanCtx, _ := tracer.Start(req.Context(), "test")
|
||||||
|
req = req.WithContext(spanCtx)
|
||||||
|
|
||||||
chain := alice.New()
|
chain := alice.New()
|
||||||
chain = chain.Append(capture.Wrap)
|
chain = chain.Append(capture.Wrap)
|
||||||
chain = chain.Append(WrapHandler(logger))
|
chain = chain.Append(WrapHandler(logger))
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/containous/alice"
|
"github.com/containous/alice"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/traefik/traefik/v3/pkg/middlewares"
|
"github.com/traefik/traefik/v3/pkg/middlewares"
|
||||||
"github.com/traefik/traefik/v3/pkg/middlewares/accesslog"
|
|
||||||
"github.com/traefik/traefik/v3/pkg/tracing"
|
"github.com/traefik/traefik/v3/pkg/tracing"
|
||||||
"go.opentelemetry.io/otel/attribute"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
@ -63,12 +62,6 @@ func (e *entryPointTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
||||||
|
|
||||||
e.tracer.CaptureServerRequest(span, req)
|
e.tracer.CaptureServerRequest(span, req)
|
||||||
|
|
||||||
if logData := accesslog.GetLogData(req); logData != nil {
|
|
||||||
spanContext := span.SpanContext()
|
|
||||||
logData.Core[accesslog.TraceID] = spanContext.TraceID().String()
|
|
||||||
logData.Core[accesslog.SpanID] = spanContext.SpanID().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
recorder := newStatusCodeRecorder(rw, http.StatusOK)
|
recorder := newStatusCodeRecorder(rw, http.StatusOK)
|
||||||
e.next.ServeHTTP(recorder, req)
|
e.next.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/traefik/traefik/v3/pkg/middlewares/accesslog"
|
|
||||||
"github.com/traefik/traefik/v3/pkg/tracing"
|
"github.com/traefik/traefik/v3/pkg/tracing"
|
||||||
"go.opentelemetry.io/otel/attribute"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
)
|
)
|
||||||
|
@ -79,27 +78,3 @@ func TestEntryPointMiddleware_tracing(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEntryPointMiddleware_tracingInfoIntoLog(t *testing.T) {
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "http://www.test.com/", http.NoBody)
|
|
||||||
req = req.WithContext(
|
|
||||||
context.WithValue(
|
|
||||||
req.Context(),
|
|
||||||
accesslog.DataTableKey,
|
|
||||||
&accesslog.LogData{Core: accesslog.CoreLogData{}},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
next := http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {})
|
|
||||||
|
|
||||||
tracer := &mockTracer{}
|
|
||||||
|
|
||||||
handler := newEntryPoint(context.Background(), tracing.NewTracer(tracer, []string{}, []string{}, []string{}), "test", next)
|
|
||||||
handler.ServeHTTP(httptest.NewRecorder(), req)
|
|
||||||
|
|
||||||
expectedSpanCtx := tracer.spans[0].SpanContext()
|
|
||||||
|
|
||||||
logData := accesslog.GetLogData(req)
|
|
||||||
assert.Equal(t, expectedSpanCtx.TraceID().String(), logData.Core[accesslog.TraceID])
|
|
||||||
assert.Equal(t, expectedSpanCtx.SpanID().String(), logData.Core[accesslog.SpanID])
|
|
||||||
}
|
|
||||||
|
|
|
@ -151,7 +151,7 @@ func (p *passTLSClientCert) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
||||||
if req.TLS != nil && len(req.TLS.PeerCertificates) > 0 {
|
if req.TLS != nil && len(req.TLS.PeerCertificates) > 0 {
|
||||||
req.Header.Set(xForwardedTLSClientCert, getCertificates(ctx, req.TLS.PeerCertificates))
|
req.Header.Set(xForwardedTLSClientCert, getCertificates(ctx, req.TLS.PeerCertificates))
|
||||||
} else {
|
} else {
|
||||||
logger.Warn().Msg("Tried to extract a certificate on a request without mutual TLS")
|
logger.Debug().Msg("Tried to extract a certificate on a request without mutual TLS")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ func (p *passTLSClientCert) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
||||||
headerContent := p.getCertInfo(ctx, req.TLS.PeerCertificates)
|
headerContent := p.getCertInfo(ctx, req.TLS.PeerCertificates)
|
||||||
req.Header.Set(xForwardedTLSClientCertInfo, url.QueryEscape(headerContent))
|
req.Header.Set(xForwardedTLSClientCertInfo, url.QueryEscape(headerContent))
|
||||||
} else {
|
} else {
|
||||||
logger.Warn().Msg("Tried to extract a certificate on a request without mutual TLS")
|
logger.Debug().Msg("Tried to extract a certificate on a request without mutual TLS")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package acme
|
package acme
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -23,9 +24,9 @@ type LocalStore struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLocalStore initializes a new LocalStore with a file name.
|
// NewLocalStore initializes a new LocalStore with a file name.
|
||||||
func NewLocalStore(filename string) *LocalStore {
|
func NewLocalStore(filename string, routinesPool *safe.Pool) *LocalStore {
|
||||||
store := &LocalStore{filename: filename, saveDataChan: make(chan map[string]*StoredData)}
|
store := &LocalStore{filename: filename, saveDataChan: make(chan map[string]*StoredData)}
|
||||||
store.listenSaveAction()
|
store.listenSaveAction(routinesPool)
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,10 +101,22 @@ func (s *LocalStore) get(resolverName string) (*StoredData, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// listenSaveAction listens to a chan to store ACME data in json format into `LocalStore.filename`.
|
// listenSaveAction listens to a chan to store ACME data in json format into `LocalStore.filename`.
|
||||||
func (s *LocalStore) listenSaveAction() {
|
func (s *LocalStore) listenSaveAction(routinesPool *safe.Pool) {
|
||||||
safe.Go(func() {
|
routinesPool.GoCtx(func(ctx context.Context) {
|
||||||
logger := log.With().Str(logs.ProviderName, "acme").Logger()
|
logger := log.With().Str(logs.ProviderName, "acme").Logger()
|
||||||
for object := range s.saveDataChan {
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
|
||||||
|
case object := <-s.saveDataChan:
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
// Stop handling events because Traefik is shutting down.
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
data, err := json.MarshalIndent(object, "", " ")
|
data, err := json.MarshalIndent(object, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Err(err).Send()
|
logger.Error().Err(err).Send()
|
||||||
|
@ -114,6 +127,7 @@ func (s *LocalStore) listenSaveAction() {
|
||||||
logger.Error().Err(err).Send()
|
logger.Error().Err(err).Send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package acme
|
package acme
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -9,6 +10,7 @@ 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/safe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLocalStore_GetAccount(t *testing.T) {
|
func TestLocalStore_GetAccount(t *testing.T) {
|
||||||
|
@ -45,7 +47,7 @@ func TestLocalStore_GetAccount(t *testing.T) {
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
s := NewLocalStore(test.filename)
|
s := NewLocalStore(test.filename, safe.NewPool(context.Background()))
|
||||||
|
|
||||||
account, err := s.GetAccount("test")
|
account, err := s.GetAccount("test")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -58,7 +60,7 @@ func TestLocalStore_GetAccount(t *testing.T) {
|
||||||
func TestLocalStore_SaveAccount(t *testing.T) {
|
func TestLocalStore_SaveAccount(t *testing.T) {
|
||||||
acmeFile := filepath.Join(t.TempDir(), "acme.json")
|
acmeFile := filepath.Join(t.TempDir(), "acme.json")
|
||||||
|
|
||||||
s := NewLocalStore(acmeFile)
|
s := NewLocalStore(acmeFile, safe.NewPool(context.Background()))
|
||||||
|
|
||||||
email := "some@email.com"
|
email := "some@email.com"
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ type DNSChallenge struct {
|
||||||
|
|
||||||
// Deprecated: please use Propagation.DelayBeforeChecks instead.
|
// Deprecated: please use Propagation.DelayBeforeChecks instead.
|
||||||
DelayBeforeCheck ptypes.Duration `description:"(Deprecated) Assume DNS propagates after a delay in seconds rather than finding and querying nameservers." json:"delayBeforeCheck,omitempty" toml:"delayBeforeCheck,omitempty" yaml:"delayBeforeCheck,omitempty" export:"true"`
|
DelayBeforeCheck ptypes.Duration `description:"(Deprecated) Assume DNS propagates after a delay in seconds rather than finding and querying nameservers." json:"delayBeforeCheck,omitempty" toml:"delayBeforeCheck,omitempty" yaml:"delayBeforeCheck,omitempty" export:"true"`
|
||||||
// Deprecated: please use Propagation.DisableAllChecks instead.
|
// Deprecated: please use Propagation.DisableChecks instead.
|
||||||
DisablePropagationCheck bool `description:"(Deprecated) Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended]" json:"disablePropagationCheck,omitempty" toml:"disablePropagationCheck,omitempty" yaml:"disablePropagationCheck,omitempty" export:"true"`
|
DisablePropagationCheck bool `description:"(Deprecated) Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended]" json:"disablePropagationCheck,omitempty" toml:"disablePropagationCheck,omitempty" yaml:"disablePropagationCheck,omitempty" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
forwardAuth:
|
forwardAuth:
|
||||||
address: test.com
|
address: test.com
|
||||||
|
headerField: X-Header-Field
|
||||||
tls:
|
tls:
|
||||||
certSecret: tlssecret
|
certSecret: tlssecret
|
||||||
caSecret: casecret
|
caSecret: casecret
|
||||||
|
|
|
@ -789,6 +789,7 @@ func createForwardAuthMiddleware(k8sClient Client, namespace string, auth *traef
|
||||||
AuthResponseHeadersRegex: auth.AuthResponseHeadersRegex,
|
AuthResponseHeadersRegex: auth.AuthResponseHeadersRegex,
|
||||||
AuthRequestHeaders: auth.AuthRequestHeaders,
|
AuthRequestHeaders: auth.AuthRequestHeaders,
|
||||||
AddAuthCookiesToResponse: auth.AddAuthCookiesToResponse,
|
AddAuthCookiesToResponse: auth.AddAuthCookiesToResponse,
|
||||||
|
HeaderField: auth.HeaderField,
|
||||||
ForwardBody: auth.ForwardBody,
|
ForwardBody: auth.ForwardBody,
|
||||||
PreserveLocationHeader: auth.PreserveLocationHeader,
|
PreserveLocationHeader: auth.PreserveLocationHeader,
|
||||||
PreserveRequestMethod: auth.PreserveRequestMethod,
|
PreserveRequestMethod: auth.PreserveRequestMethod,
|
||||||
|
|
|
@ -3961,6 +3961,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
ForwardAuth: &dynamic.ForwardAuth{
|
ForwardAuth: &dynamic.ForwardAuth{
|
||||||
Address: "test.com",
|
Address: "test.com",
|
||||||
MaxBodySize: pointer(int64(-1)),
|
MaxBodySize: pointer(int64(-1)),
|
||||||
|
HeaderField: "X-Header-Field",
|
||||||
TLS: &dynamic.ClientTLS{
|
TLS: &dynamic.ClientTLS{
|
||||||
CA: "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----",
|
CA: "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----",
|
||||||
Cert: "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----",
|
Cert: "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----",
|
||||||
|
|
|
@ -161,6 +161,9 @@ type ForwardAuth struct {
|
||||||
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 defines the list of cookies to copy from the authentication server response to the response.
|
||||||
AddAuthCookiesToResponse []string `json:"addAuthCookiesToResponse,omitempty"`
|
AddAuthCookiesToResponse []string `json:"addAuthCookiesToResponse,omitempty"`
|
||||||
|
// HeaderField defines a header field to store the authenticated user.
|
||||||
|
// More info: https://doc.traefik.io/traefik/v3.3/middlewares/http/forwardauth/#headerfield
|
||||||
|
HeaderField string `json:"headerField,omitempty"`
|
||||||
// ForwardBody defines whether to send the request body to the authentication server.
|
// ForwardBody defines whether to send the request body to the authentication server.
|
||||||
ForwardBody bool `json:"forwardBody,omitempty"`
|
ForwardBody bool `json:"forwardBody,omitempty"`
|
||||||
// MaxBodySize defines the maximum body size in bytes allowed to be forwarded to the authentication server.
|
// MaxBodySize defines the maximum body size in bytes allowed to be forwarded to the authentication server.
|
||||||
|
|
|
@ -229,33 +229,32 @@ func (i *Provider) entryPointModels(cfg *dynamic.Configuration) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ep.HTTP.Middlewares) == 0 && ep.HTTP.TLS == nil && defaultRuleSyntax == "" {
|
if len(ep.HTTP.Middlewares) == 0 && ep.HTTP.TLS == nil && defaultRuleSyntax == "" && ep.Observability == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
m := &dynamic.Model{
|
httpModel := &dynamic.Model{
|
||||||
|
DefaultRuleSyntax: defaultRuleSyntax,
|
||||||
Middlewares: ep.HTTP.Middlewares,
|
Middlewares: ep.HTTP.Middlewares,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ep.Observability != nil {
|
if ep.Observability != nil {
|
||||||
m.Observability = dynamic.RouterObservabilityConfig{
|
httpModel.Observability = dynamic.RouterObservabilityConfig{
|
||||||
AccessLogs: &ep.Observability.AccessLogs,
|
AccessLogs: ep.Observability.AccessLogs,
|
||||||
Tracing: &ep.Observability.Tracing,
|
Tracing: ep.Observability.Tracing,
|
||||||
Metrics: &ep.Observability.Metrics,
|
Metrics: ep.Observability.Metrics,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ep.HTTP.TLS != nil {
|
if ep.HTTP.TLS != nil {
|
||||||
m.TLS = &dynamic.RouterTLSConfig{
|
httpModel.TLS = &dynamic.RouterTLSConfig{
|
||||||
Options: ep.HTTP.TLS.Options,
|
Options: ep.HTTP.TLS.Options,
|
||||||
CertResolver: ep.HTTP.TLS.CertResolver,
|
CertResolver: ep.HTTP.TLS.CertResolver,
|
||||||
Domains: ep.HTTP.TLS.Domains,
|
Domains: ep.HTTP.TLS.Domains,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.DefaultRuleSyntax = defaultRuleSyntax
|
cfg.HTTP.Models[name] = httpModel
|
||||||
|
|
||||||
cfg.HTTP.Models[name] = m
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ import (
|
||||||
|
|
||||||
var updateExpected = flag.Bool("update_expected", false, "Update expected files in fixtures")
|
var updateExpected = flag.Bool("update_expected", false, "Update expected files in fixtures")
|
||||||
|
|
||||||
|
func pointer[T any](v T) *T { return &v }
|
||||||
|
|
||||||
func Test_createConfiguration(t *testing.T) {
|
func Test_createConfiguration(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
@ -185,9 +187,9 @@ func Test_createConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Observability: &static.ObservabilityConfig{
|
Observability: &static.ObservabilityConfig{
|
||||||
AccessLogs: false,
|
AccessLogs: pointer(false),
|
||||||
Tracing: false,
|
Tracing: pointer(false),
|
||||||
Metrics: false,
|
Metrics: pointer(false),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
// rwWithUpgrade contains a ResponseWriter and an upgradeHandler,
|
// rwWithUpgrade contains a ResponseWriter and an upgradeHandler,
|
||||||
// used to upgrade the connection (e.g. Websockets).
|
// used to upgrade the connection (e.g. Websockets).
|
||||||
type rwWithUpgrade struct {
|
type rwWithUpgrade struct {
|
||||||
|
ReqMethod string
|
||||||
RW http.ResponseWriter
|
RW http.ResponseWriter
|
||||||
Upgrade upgradeHandler
|
Upgrade upgradeHandler
|
||||||
}
|
}
|
||||||
|
@ -178,7 +179,6 @@ func (c *conn) handleResponse(r rwWithUpgrade) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
res.Reset()
|
res.Reset()
|
||||||
res.Header.Reset()
|
|
||||||
res.Header.SetNoDefaultContentType(true)
|
res.Header.SetNoDefaultContentType(true)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
@ -211,7 +211,13 @@ func (c *conn) handleResponse(r rwWithUpgrade) error {
|
||||||
|
|
||||||
r.RW.WriteHeader(res.StatusCode())
|
r.RW.WriteHeader(res.StatusCode())
|
||||||
|
|
||||||
if res.Header.ContentLength() == 0 {
|
if noResponseBodyExpected(r.ReqMethod) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
hasContentLength := len(res.Header.Peek("Content-Length")) > 0
|
||||||
|
|
||||||
|
if hasContentLength && res.Header.ContentLength() == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,6 +227,20 @@ func (c *conn) handleResponse(r rwWithUpgrade) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !hasContentLength {
|
||||||
|
b := c.bufferPool.Get()
|
||||||
|
if b == nil {
|
||||||
|
b = make([]byte, bufferSize)
|
||||||
|
}
|
||||||
|
defer c.bufferPool.Put(b)
|
||||||
|
|
||||||
|
if _, err := io.CopyBuffer(r.RW, c.br, b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Chunked response, Content-Length is set to -1 by FastProxy when "Transfer-Encoding: chunked" header is received.
|
// Chunked response, Content-Length is set to -1 by FastProxy when "Transfer-Encoding: chunked" header is received.
|
||||||
if res.Header.ContentLength() == -1 {
|
if res.Header.ContentLength() == -1 {
|
||||||
cbr := httputil.NewChunkedReader(c.br)
|
cbr := httputil.NewChunkedReader(c.br)
|
||||||
|
@ -444,8 +464,8 @@ func (c *connPool) askForNewConn(errCh chan<- error) {
|
||||||
c.releaseConn(newConn)
|
c.releaseConn(newConn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isBodyAllowedForStatus reports whether a given response status code
|
// isBodyAllowedForStatus reports whether a given response status code permits a body.
|
||||||
// permits a body. See RFC 7230, section 3.3.
|
// See RFC 7230, section 3.3.
|
||||||
// From https://github.com/golang/go/blame/master/src/net/http/transfer.go#L459
|
// From https://github.com/golang/go/blame/master/src/net/http/transfer.go#L459
|
||||||
func isBodyAllowedForStatus(status int) bool {
|
func isBodyAllowedForStatus(status int) bool {
|
||||||
switch {
|
switch {
|
||||||
|
@ -458,3 +478,9 @@ func isBodyAllowedForStatus(status int) bool {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// noResponseBodyExpected reports whether a given request method permits a body.
|
||||||
|
// From https://github.com/golang/go/blame/master/src/net/http/transfer.go#L250
|
||||||
|
func noResponseBodyExpected(requestMethod string) bool {
|
||||||
|
return requestMethod == "HEAD"
|
||||||
|
}
|
||||||
|
|
|
@ -284,6 +284,7 @@ func (p *ReverseProxy) roundTrip(rw http.ResponseWriter, req *http.Request, outR
|
||||||
|
|
||||||
// Sending the responseWriter unlocks the connection readLoop, to handle the response.
|
// Sending the responseWriter unlocks the connection readLoop, to handle the response.
|
||||||
co.RWCh <- rwWithUpgrade{
|
co.RWCh <- rwWithUpgrade{
|
||||||
|
ReqMethod: req.Method,
|
||||||
RW: rw,
|
RW: rw,
|
||||||
Upgrade: upgradeResponseHandler(req.Context(), reqUpType),
|
Upgrade: upgradeResponseHandler(req.Context(), reqUpType),
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,6 +278,74 @@ func TestPreservePath(t *testing.T) {
|
||||||
assert.Equal(t, http.StatusOK, res.Code)
|
assert.Equal(t, http.StatusOK, res.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHeadRequest(t *testing.T) {
|
||||||
|
var callCount int
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
callCount++
|
||||||
|
|
||||||
|
assert.Equal(t, http.MethodHead, req.Method)
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Length", "42")
|
||||||
|
}))
|
||||||
|
t.Cleanup(server.Close)
|
||||||
|
|
||||||
|
builder := NewProxyBuilder(&transportManagerMock{}, static.FastProxyConfig{})
|
||||||
|
|
||||||
|
serverURL, err := url.JoinPath(server.URL)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
proxyHandler, err := builder.Build("", testhelpers.MustParseURL(serverURL), true, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodHead, "/", http.NoBody)
|
||||||
|
res := httptest.NewRecorder()
|
||||||
|
|
||||||
|
proxyHandler.ServeHTTP(res, req)
|
||||||
|
|
||||||
|
assert.Equal(t, 1, callCount)
|
||||||
|
assert.Equal(t, http.StatusOK, res.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoContentLengthResponse(t *testing.T) {
|
||||||
|
backendListener, err := net.Listen("tcp", ":0")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
_ = backendListener.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
conn, err := backendListener.Accept()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = conn.Write([]byte("HTTP/1.1 200 OK\r\n\r\nfoo"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// CloseWrite the connection to signal the end of the response.
|
||||||
|
if v, ok := conn.(interface{ CloseWrite() error }); ok {
|
||||||
|
err = v.CloseWrite()
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
builder := NewProxyBuilder(&transportManagerMock{}, static.FastProxyConfig{})
|
||||||
|
|
||||||
|
serverURL := "http://" + backendListener.Addr().String()
|
||||||
|
|
||||||
|
proxyHandler, err := builder.Build("", testhelpers.MustParseURL(serverURL), true, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/", http.NoBody)
|
||||||
|
res := httptest.NewRecorder()
|
||||||
|
|
||||||
|
proxyHandler.ServeHTTP(res, req)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, res.Code)
|
||||||
|
assert.Equal(t, "foo", res.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
func newCertificate(t *testing.T, domain string) *tls.Certificate {
|
func newCertificate(t *testing.T, domain string) *tls.Certificate {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
|
|
@ -191,14 +191,14 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
||||||
cp.Observability.AccessLogs = m.Observability.AccessLogs
|
cp.Observability.AccessLogs = m.Observability.AccessLogs
|
||||||
}
|
}
|
||||||
|
|
||||||
if cp.Observability.Tracing == nil {
|
|
||||||
cp.Observability.Tracing = m.Observability.Tracing
|
|
||||||
}
|
|
||||||
|
|
||||||
if cp.Observability.Metrics == nil {
|
if cp.Observability.Metrics == nil {
|
||||||
cp.Observability.Metrics = m.Observability.Metrics
|
cp.Observability.Metrics = m.Observability.Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cp.Observability.Tracing == nil {
|
||||||
|
cp.Observability.Tracing = m.Observability.Tracing
|
||||||
|
}
|
||||||
|
|
||||||
rtName := name
|
rtName := name
|
||||||
if len(eps) > 1 {
|
if len(eps) > 1 {
|
||||||
rtName = epName + "-" + name
|
rtName = epName + "-" + name
|
||||||
|
@ -215,6 +215,9 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
||||||
cfg.HTTP.Routers = rts
|
cfg.HTTP.Routers = rts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply default observability model to HTTP routers.
|
||||||
|
applyDefaultObservabilityModel(cfg)
|
||||||
|
|
||||||
if cfg.TCP == nil || len(cfg.TCP.Models) == 0 {
|
if cfg.TCP == nil || len(cfg.TCP.Models) == 0 {
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
@ -238,3 +241,38 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// applyDefaultObservabilityModel applies the default observability model to the configuration.
|
||||||
|
// This function is used to ensure that the observability configuration is set for all routers,
|
||||||
|
// and make sure it is serialized and available in the API.
|
||||||
|
// We could have introduced a "default" model, but it would have been more complex to manage for now.
|
||||||
|
// This could be generalized in the future.
|
||||||
|
func applyDefaultObservabilityModel(cfg dynamic.Configuration) {
|
||||||
|
if cfg.HTTP != nil {
|
||||||
|
for _, router := range cfg.HTTP.Routers {
|
||||||
|
if router.Observability == nil {
|
||||||
|
router.Observability = &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if router.Observability.AccessLogs == nil {
|
||||||
|
router.Observability.AccessLogs = pointer(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if router.Observability.Tracing == nil {
|
||||||
|
router.Observability.Tracing = pointer(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if router.Observability.Metrics == nil {
|
||||||
|
router.Observability.Metrics = pointer(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pointer[T any](v T) *T { return &v }
|
||||||
|
|
|
@ -9,8 +9,6 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/tls"
|
"github.com/traefik/traefik/v3/pkg/tls"
|
||||||
)
|
)
|
||||||
|
|
||||||
func pointer[T any](v T) *T { return &v }
|
|
||||||
|
|
||||||
func Test_mergeConfiguration(t *testing.T) {
|
func Test_mergeConfiguration(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
@ -508,6 +506,33 @@ func Test_applyModel(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "without model, one router",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{"test": {}},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"test": {
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "with model, not used",
|
desc: "with model, not used",
|
||||||
input: dynamic.Configuration{
|
input: dynamic.Configuration{
|
||||||
|
@ -563,7 +588,11 @@ func Test_applyModel(t *testing.T) {
|
||||||
EntryPoints: []string{"websecure"},
|
EntryPoints: []string{"websecure"},
|
||||||
Middlewares: []string{"test"},
|
Middlewares: []string{"test"},
|
||||||
TLS: &dynamic.RouterTLSConfig{},
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
Observability: &dynamic.RouterObservabilityConfig{},
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: make(map[string]*dynamic.Middleware),
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
@ -659,9 +688,9 @@ func Test_applyModel(t *testing.T) {
|
||||||
Middlewares: []string{"test"},
|
Middlewares: []string{"test"},
|
||||||
TLS: &dynamic.RouterTLSConfig{CertResolver: "router"},
|
TLS: &dynamic.RouterTLSConfig{CertResolver: "router"},
|
||||||
Observability: &dynamic.RouterObservabilityConfig{
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
AccessLogs: nil,
|
AccessLogs: pointer(true),
|
||||||
Tracing: nil,
|
Metrics: pointer(true),
|
||||||
Metrics: nil,
|
Tracing: pointer(true),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -700,12 +729,21 @@ func Test_applyModel(t *testing.T) {
|
||||||
Routers: map[string]*dynamic.Router{
|
Routers: map[string]*dynamic.Router{
|
||||||
"test": {
|
"test": {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"websecure-test": {
|
"websecure-test": {
|
||||||
EntryPoints: []string{"websecure"},
|
EntryPoints: []string{"websecure"},
|
||||||
Middlewares: []string{"test"},
|
Middlewares: []string{"test"},
|
||||||
TLS: &dynamic.RouterTLSConfig{},
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
Observability: &dynamic.RouterObservabilityConfig{},
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Middlewares: make(map[string]*dynamic.Middleware),
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
|
|
@ -84,7 +84,8 @@ func TestNewConfigurationWatcher(t *testing.T) {
|
||||||
th.WithRouters(
|
th.WithRouters(
|
||||||
th.WithRouter("test@mock",
|
th.WithRouter("test@mock",
|
||||||
th.WithEntryPoints("e"),
|
th.WithEntryPoints("e"),
|
||||||
th.WithServiceName("scv"))),
|
th.WithServiceName("scv"),
|
||||||
|
th.WithObservability())),
|
||||||
th.WithMiddlewares(),
|
th.WithMiddlewares(),
|
||||||
th.WithLoadBalancerServices(),
|
th.WithLoadBalancerServices(),
|
||||||
),
|
),
|
||||||
|
@ -175,7 +176,7 @@ func TestIgnoreTransientConfiguration(t *testing.T) {
|
||||||
|
|
||||||
expectedConfig := dynamic.Configuration{
|
expectedConfig := dynamic.Configuration{
|
||||||
HTTP: th.BuildConfiguration(
|
HTTP: th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("foo@mock", th.WithEntryPoints("ep"))),
|
th.WithRouters(th.WithRouter("foo@mock", th.WithEntryPoints("ep"), th.WithObservability())),
|
||||||
th.WithLoadBalancerServices(th.WithService("bar@mock")),
|
th.WithLoadBalancerServices(th.WithService("bar@mock")),
|
||||||
th.WithMiddlewares(),
|
th.WithMiddlewares(),
|
||||||
),
|
),
|
||||||
|
@ -200,7 +201,7 @@ func TestIgnoreTransientConfiguration(t *testing.T) {
|
||||||
|
|
||||||
expectedConfig3 := dynamic.Configuration{
|
expectedConfig3 := dynamic.Configuration{
|
||||||
HTTP: th.BuildConfiguration(
|
HTTP: th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("foo@mock", th.WithEntryPoints("ep"))),
|
th.WithRouters(th.WithRouter("foo@mock", th.WithEntryPoints("ep"), th.WithObservability())),
|
||||||
th.WithLoadBalancerServices(th.WithService("bar-config3@mock")),
|
th.WithLoadBalancerServices(th.WithService("bar-config3@mock")),
|
||||||
th.WithMiddlewares(),
|
th.WithMiddlewares(),
|
||||||
),
|
),
|
||||||
|
@ -447,7 +448,7 @@ func TestListenProvidersDoesNotSkipFlappingConfiguration(t *testing.T) {
|
||||||
|
|
||||||
expected := dynamic.Configuration{
|
expected := dynamic.Configuration{
|
||||||
HTTP: th.BuildConfiguration(
|
HTTP: th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("foo@mock", th.WithEntryPoints("ep"))),
|
th.WithRouters(th.WithRouter("foo@mock", th.WithEntryPoints("ep"), th.WithObservability())),
|
||||||
th.WithLoadBalancerServices(th.WithService("bar@mock")),
|
th.WithLoadBalancerServices(th.WithService("bar@mock")),
|
||||||
th.WithMiddlewares(),
|
th.WithMiddlewares(),
|
||||||
),
|
),
|
||||||
|
@ -538,7 +539,7 @@ func TestListenProvidersIgnoreSameConfig(t *testing.T) {
|
||||||
|
|
||||||
expected := dynamic.Configuration{
|
expected := dynamic.Configuration{
|
||||||
HTTP: th.BuildConfiguration(
|
HTTP: th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("foo@mock", th.WithEntryPoints("ep"))),
|
th.WithRouters(th.WithRouter("foo@mock", th.WithEntryPoints("ep"), th.WithObservability())),
|
||||||
th.WithLoadBalancerServices(th.WithService("bar@mock")),
|
th.WithLoadBalancerServices(th.WithService("bar@mock")),
|
||||||
th.WithMiddlewares(),
|
th.WithMiddlewares(),
|
||||||
),
|
),
|
||||||
|
@ -674,7 +675,7 @@ func TestListenProvidersIgnoreIntermediateConfigs(t *testing.T) {
|
||||||
|
|
||||||
expected := dynamic.Configuration{
|
expected := dynamic.Configuration{
|
||||||
HTTP: th.BuildConfiguration(
|
HTTP: th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("final@mock", th.WithEntryPoints("ep"))),
|
th.WithRouters(th.WithRouter("final@mock", th.WithEntryPoints("ep"), th.WithObservability())),
|
||||||
th.WithLoadBalancerServices(th.WithService("final@mock")),
|
th.WithLoadBalancerServices(th.WithService("final@mock")),
|
||||||
th.WithMiddlewares(),
|
th.WithMiddlewares(),
|
||||||
),
|
),
|
||||||
|
@ -738,8 +739,8 @@ func TestListenProvidersPublishesConfigForEachProvider(t *testing.T) {
|
||||||
expected := dynamic.Configuration{
|
expected := dynamic.Configuration{
|
||||||
HTTP: th.BuildConfiguration(
|
HTTP: th.BuildConfiguration(
|
||||||
th.WithRouters(
|
th.WithRouters(
|
||||||
th.WithRouter("foo@mock", th.WithEntryPoints("ep")),
|
th.WithRouter("foo@mock", th.WithEntryPoints("ep"), th.WithObservability()),
|
||||||
th.WithRouter("foo@mock2", th.WithEntryPoints("ep")),
|
th.WithRouter("foo@mock2", th.WithEntryPoints("ep"), th.WithObservability()),
|
||||||
),
|
),
|
||||||
th.WithLoadBalancerServices(
|
th.WithLoadBalancerServices(
|
||||||
th.WithService("bar@mock"),
|
th.WithService("bar@mock"),
|
||||||
|
|
|
@ -110,7 +110,7 @@ func (o *ObservabilityMgr) ShouldAddAccessLogs(serviceName string, observability
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return observabilityConfig == nil || observabilityConfig.AccessLogs != nil && *observabilityConfig.AccessLogs
|
return observabilityConfig == nil || observabilityConfig.AccessLogs == nil || *observabilityConfig.AccessLogs
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShouldAddMetrics returns whether the metrics should be enabled for the given resource and the observability config.
|
// ShouldAddMetrics returns whether the metrics should be enabled for the given resource and the observability config.
|
||||||
|
@ -127,7 +127,7 @@ func (o *ObservabilityMgr) ShouldAddMetrics(serviceName string, observabilityCon
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return observabilityConfig == nil || observabilityConfig.Metrics != nil && *observabilityConfig.Metrics
|
return observabilityConfig == nil || observabilityConfig.Metrics == nil || *observabilityConfig.Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShouldAddTracing returns whether the tracing should be enabled for the given serviceName and the observability config.
|
// ShouldAddTracing returns whether the tracing should be enabled for the given serviceName and the observability config.
|
||||||
|
@ -144,7 +144,7 @@ func (o *ObservabilityMgr) ShouldAddTracing(serviceName string, observabilityCon
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return observabilityConfig == nil || observabilityConfig.Tracing != nil && *observabilityConfig.Tracing
|
return observabilityConfig == nil || observabilityConfig.Tracing == nil || *observabilityConfig.Tracing
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetricsRegistry is an accessor to the metrics registry.
|
// MetricsRegistry is an accessor to the metrics registry.
|
||||||
|
|
|
@ -53,6 +53,17 @@ func WithServiceName(serviceName string) func(*dynamic.Router) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithObservability is a helper to create a configuration.
|
||||||
|
func WithObservability() func(*dynamic.Router) {
|
||||||
|
return func(r *dynamic.Router) {
|
||||||
|
r.Observability = &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithLoadBalancerServices is a helper to create a configuration.
|
// WithLoadBalancerServices is a helper to create a configuration.
|
||||||
func WithLoadBalancerServices(opts ...func(service *dynamic.ServersLoadBalancer) string) func(*dynamic.HTTPConfiguration) {
|
func WithLoadBalancerServices(opts ...func(service *dynamic.ServersLoadBalancer) string) func(*dynamic.HTTPConfiguration) {
|
||||||
return func(c *dynamic.HTTPConfiguration) {
|
return func(c *dynamic.HTTPConfiguration) {
|
||||||
|
@ -149,3 +160,5 @@ func WithSticky(cookieName string) func(*dynamic.ServersLoadBalancer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pointer[T any](v T) *T { return &v }
|
||||||
|
|
|
@ -4,11 +4,11 @@ RepositoryName = "traefik"
|
||||||
OutputType = "file"
|
OutputType = "file"
|
||||||
FileName = "traefik_changelog.md"
|
FileName = "traefik_changelog.md"
|
||||||
|
|
||||||
# example new bugfix v3.3.1
|
# example new bugfix v3.3.3
|
||||||
CurrentRef = "v3.3"
|
CurrentRef = "v3.3"
|
||||||
PreviousRef = "v3.3.0"
|
PreviousRef = "v3.3.2"
|
||||||
BaseBranch = "v3.3"
|
BaseBranch = "v3.3"
|
||||||
FutureCurrentRefName = "v3.3.1"
|
FutureCurrentRefName = "v3.3.3"
|
||||||
|
|
||||||
ThresholdPreviousRef = 10
|
ThresholdPreviousRef = 10
|
||||||
ThresholdCurrentRef = 10
|
ThresholdCurrentRef = 10
|
||||||
|
|
|
@ -67,7 +67,7 @@ export default function PaginationMixin (opts = {}) {
|
||||||
this.fetchMore()
|
this.fetchMore()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeUnmount () {
|
||||||
clearInterval(this.pollingInterval)
|
clearInterval(this.pollingInterval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue