Compare commits

...

16 commits

Author SHA1 Message Date
86a7f8765b
Merge branch 'master' of github.com:traefik/traefik
All checks were successful
Build & Push / build-and-push (push) Successful in 10m37s
Signed-off-by: baalajimaestro <baalajimaestro@ptr.moe>
2024-09-08 09:22:14 +05:30
Michael
9dc2155e63
Fix sync docker images latest tag 2024-09-06 09:56:03 +02:00
Michael
c2cb4fac10
Sync docker images from docker hub to ghcr 2024-09-05 10:02:04 +02:00
weijiany
e8335a94a4
Record trace id and EntryPoint span id into access log 2024-09-03 16:40:04 +02:00
Romain
3eb7ecce19
Improve Kubernetes GatewayAPI TCPRoute and TLSRoute support 2024-09-03 12:10:04 +02:00
mmatur
0b34e0cdcb
Merge current v3.1 into master 2024-09-03 10:31:10 +02:00
Romain
cf2869407d
Wrap capture for services used by pieces of middleware 2024-09-03 10:30:08 +02:00
mmatur
8ca27b4a1d
Merge current v2.11 into v3.1 2024-09-03 10:00:38 +02:00
Michael
6009aaed87
Improve CI speed 2024-09-03 09:44:04 +02:00
Matteo Paier
eb99c8c785
Add mirrorBody option to HTTP mirroring 2024-09-02 16:36:06 +02:00
Ludovic Fernandez
bf71560515
Update go-acme/lego to v4.18.0 2024-09-02 15:42:05 +02:00
Michael
2714831a4e
fix: otlp doc + potential panic 2024-08-29 14:30:05 +02:00
Michael
1417da4a21
Update k8s quickstart permissions 2024-08-29 11:08:09 +02:00
Michael
3040f2659a
Upgrade paerser to v0.2.1 2024-08-29 10:54:05 +02:00
Edward Eastman
6b1a584c2b
Update quick-start-with-kubernetes.md to include required permissions 2024-08-29 10:50:06 +02:00
Patrick Evans
3a80aa172c
Give valid examples for exposing dashboard with default Helm values 2024-08-29 10:40:05 +02:00
46 changed files with 1031 additions and 615 deletions

View file

@ -99,38 +99,6 @@ helm install traefik traefik/traefik
- "--log.level=DEBUG"
```
### Exposing the Traefik dashboard
This Helm chart does not expose the Traefik dashboard by default, for security concerns.
Thus, there are multiple ways to expose the dashboard.
For instance, the dashboard access could be achieved through a port-forward:
```shell
kubectl port-forward $(kubectl get pods --selector "app.kubernetes.io/name=traefik" --output=name) 9000:9000
```
It can then be reached at: `http://127.0.0.1:9000/dashboard/`
Another way would be to apply your own configuration, for instance,
by defining and applying an IngressRoute CRD (`kubectl apply -f dashboard.yaml`):
```yaml
# dashboard.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: dashboard
spec:
entryPoints:
- web
routes:
- match: Host(`traefik.localhost`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
kind: Rule
services:
- name: api@internal
kind: TraefikService
```
## Use the Binary Distribution
Grab the latest binary from the [releases](https://github.com/traefik/traefik/releases) page.

View file

@ -36,6 +36,7 @@ rules:
resources:
- services
- secrets
- nodes
verbs:
- get
- list
@ -64,6 +65,23 @@ rules:
- ingresses/status
verbs:
- update
- apiGroups:
- traefik.io
resources:
- middlewares
- middlewaretcps
- ingressroutes
- traefikservices
- ingressroutetcps
- ingressrouteudps
- tlsoptions
- tlsstores
- serverstransports
- serverstransporttcps
verbs:
- get
- list
- watch
```
!!! info "You can find the reference for this file [there](../../reference/dynamic-configuration/kubernetes-crd/#rbac)."

View file

@ -341,6 +341,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [Derak Cloud](https://derak.cloud/) | `derak` | `DERAK_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/derak) |
| [deSEC](https://desec.io) | `desec` | `DESEC_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/desec) |
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/digitalocean) |
| [DirectAdmin](https://www.directadmin.com) | `directadmin` | `DIRECTADMIN_API_URL` , `DIRECTADMIN_USERNAME`, `DIRECTADMIN_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/directadmin) |
| [DNS Made Easy](https://dnsmadeeasy.com) | `dnsmadeeasy` | `DNSMADEEASY_API_KEY`, `DNSMADEEASY_API_SECRET`, `DNSMADEEASY_SANDBOX` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsmadeeasy) |
| [dnsHome.de](https://www.dnshome.de) | `dnsHomede` | `DNSHOMEDE_CREDENTIALS` | [Additional configuration](https://go-acme.github.io/lego/dns/dnshomede) |
| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsimple) |
@ -384,12 +385,15 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [Joker.com](https://joker.com) | `joker` | `JOKER_API_MODE` with `JOKER_API_KEY` or `JOKER_USERNAME`, `JOKER_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/joker) |
| [Liara](https://liara.ir) | `liara` | `LIARA_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/liara) |
| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/lightsail) |
| [Lima-City](https://www.lima-city.de) | `limacity` | `LIMACITY_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/limacity) |
| [Linode v4](https://www.linode.com) | `linode` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) |
| [Liquid Web](https://www.liquidweb.com/) | `liquidweb` | `LIQUID_WEB_PASSWORD`, `LIQUID_WEB_USERNAME`, `LIQUID_WEB_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/liquidweb) |
| [Loopia](https://loopia.com/) | `loopia` | `LOOPIA_API_PASSWORD`, `LOOPIA_API_USER` | [Additional configuration](https://go-acme.github.io/lego/dns/loopia) |
| [LuaDNS](https://luadns.com) | `luadns` | `LUADNS_API_USERNAME`, `LUADNS_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/luadns) |
| [Mail-in-a-Box](https://mailinabox.email) | `mailinabox` | `MAILINABOX_EMAIL`, `MAILINABOX_PASSWORD`, `MAILINABOX_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/mailinabox) |
| [Metaname](https://metaname.net) | `metaname` | `METANAME_ACCOUNT_REFERENCE`, `METANAME_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/metaname) |
| [mijn.host](https://mijn.host/) | `mijnhost` | `MIJNHOST_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/mijnhost) |
| [Mittwald](https://www.mittwald.de) | `mittwald` | `MITTWALD_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/mittwald) |
| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) |
| [Mythic Beasts](https://www.mythic-beasts.com) | `mythicbeasts` | `MYTHICBEASTS_USER_NAME`, `MYTHICBEASTS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mythicbeasts) |
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/namedotcom) |
@ -418,8 +422,8 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [Route 53](https://aws.amazon.com/route53/) | `route53` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `[AWS_REGION]`, `[AWS_HOSTED_ZONE_ID]` or a configured user/instance IAM profile. | [Additional configuration](https://go-acme.github.io/lego/dns/route53) |
| [Sakura Cloud](https://cloud.sakura.ad.jp/) | `sakuracloud` | `SAKURACLOUD_ACCESS_TOKEN`, `SAKURACLOUD_ACCESS_TOKEN_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/sakuracloud) |
| [Scaleway](https://www.scaleway.com) | `scaleway` | `SCW_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/scaleway) |
| [Selectel](https://selectel.ru/en/) | `selectel` | `SELECTEL_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/selectel) |
| [Selectel v2](https://selectel.ru/en/) | `selectelv2` | `SELECTELV2_ACCOUNT_ID`, `SELECTELV2_PASSWORD`, `SELECTELV2_PROJECT_ID`, `SELECTELV2_USERNAME` | [Additional configuration](https://go-acme.github.io/lego/dns/selectelv2) |
| [Selectel](https://selectel.ru/en/) | `selectel` | `SELECTEL_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/selectel) |
| [Servercow](https://servercow.de) | `servercow` | `SERVERCOW_USERNAME`, `SERVERCOW_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/servercow) |
| [Shellrent](https://www.shellrent.com) | `shellrent` | `SHELLRENT_USERNAME`, `SHELLRENT_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/shellrent) |
| [Simply.com](https://www.simply.com/en/domains/) | `simply` | `SIMPLY_ACCOUNT_NAME`, `SIMPLY_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/simply) |

View file

@ -250,6 +250,8 @@ accessLog:
| `TLSVersion` | The TLS version used by the connection (e.g. `1.2`) (if connection is TLS). |
| `TLSCipher` | The TLS cipher used by the connection (e.g. `TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA`) (if connection is TLS) |
| `TLSClientSubject` | The string representation of the TLS client certificate's Subject (e.g. `CN=username,O=organization`) |
| `TraceId` | A consistent identifier for tracking requests across services, including upstream ones managed by Traefik, shown as a 32-hex digit string |
| `SpanId` | A unique identifier for Traefik’s root span (EntryPoint) within a request trace, formatted as a 16-hex digit string. |
## Log Rotation

View file

@ -170,7 +170,6 @@ Defines the list of query parameters to not redact.
```yaml tab="File (YAML)"
tracing:
otlp:
safeQueryParams:
- bar
- buz
@ -178,10 +177,9 @@ tracing:
```toml tab="File (TOML)"
[tracing]
[tracing.otlp]
safeQueryParams = ["bar", "buz"]
```
```bash tab="CLI"
--tracing.otlp.safeQueryParams=bar,buz
--tracing.safeQueryParams=bar,buz
```

View file

@ -82,6 +82,7 @@
[http.services.Service03]
[http.services.Service03.mirroring]
service = "foobar"
mirrorBody = true
maxBodySize = 42
[[http.services.Service03.mirroring.mirrors]]

View file

@ -89,6 +89,7 @@ http:
Service03:
mirroring:
service: foobar
mirrorBody: true
maxBodySize: 42
mirrors:
- name: foobar

View file

@ -2506,6 +2506,11 @@ spec:
Default value is -1, which means unlimited size.
format: int64
type: integer
mirrorBody:
description: |-
MirrorBody defines whether the body of the request should be mirrored.
Default value is true.
type: boolean
mirrors:
description: Mirrors defines the list of mirrors where Traefik
will duplicate the traffic.

View file

@ -63,6 +63,7 @@ spec:
mirroring:
name: wrr2
kind: TraefikService
mirrorBody: true
# Optional
maxBodySize: 2000000000
mirrors:

View file

@ -264,6 +264,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/secure` | `true` |
| `traefik/http/services/Service03/mirroring/healthCheck` | `` |
| `traefik/http/services/Service03/mirroring/maxBodySize` | `42` |
| `traefik/http/services/Service03/mirroring/mirrorBody` | `true` |
| `traefik/http/services/Service03/mirroring/mirrors/0/name` | `foobar` |
| `traefik/http/services/Service03/mirroring/mirrors/0/percent` | `42` |
| `traefik/http/services/Service03/mirroring/mirrors/1/name` | `foobar` |

View file

@ -121,6 +121,11 @@ spec:
Default value is -1, which means unlimited size.
format: int64
type: integer
mirrorBody:
description: |-
MirrorBody defines whether the body of the request should be mirrored.
Default value is true.
type: boolean
mirrors:
description: Mirrors defines the list of mirrors where Traefik
will duplicate the traffic.

View file

@ -1207,6 +1207,7 @@ http:
The mirroring is able to mirror requests sent to a service to other services.
Please note that by default the whole request is buffered in memory while it is being mirrored.
See the maxBodySize option in the example below for how to modify this behaviour.
You can also omit the request body by setting the mirrorBody option to `false`.
!!! info "Supported Providers"
@ -1219,6 +1220,9 @@ http:
mirrored-api:
mirroring:
service: appv1
# mirrorBody defines whether the request body should be mirrored.
# Default value is true.
mirrorBody: false
# maxBodySize is the maximum size allowed for the body of the request.
# If the body is larger, the request is not mirrored.
# Default value is -1, which means unlimited size.
@ -1248,6 +1252,9 @@ http:
# If the body is larger, the request is not mirrored.
# Default value is -1, which means unlimited size.
maxBodySize = 1024
# mirrorBody defines whether the request body should be mirrored.
# Default value is true.
mirrorBody = false
[[http.services.mirrored-api.mirroring.mirrors]]
name = "appv2"
percent = 10

22
go.mod
View file

@ -17,7 +17,7 @@ require (
github.com/docker/go-connections v0.5.0
github.com/fatih/structs v1.1.0
github.com/fsnotify/fsnotify v1.7.0
github.com/go-acme/lego/v4 v4.17.4
github.com/go-acme/lego/v4 v4.18.0
github.com/go-kit/kit v0.13.0
github.com/go-kit/log v0.2.1
github.com/golang/protobuf v1.5.4
@ -64,7 +64,7 @@ require (
github.com/tetratelabs/wazero v1.7.2
github.com/tidwall/gjson v1.17.0
github.com/traefik/grpc-web v0.16.0
github.com/traefik/paerser v0.2.0
github.com/traefik/paerser v0.2.1
github.com/traefik/yaegi v0.16.1
github.com/unrolled/render v1.0.2
github.com/unrolled/secure v1.0.9
@ -85,8 +85,8 @@ require (
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // No tag on the repo.
golang.org/x/mod v0.18.0
golang.org/x/net v0.26.0
golang.org/x/sys v0.21.0
golang.org/x/text v0.16.0
golang.org/x/sys v0.23.0
golang.org/x/text v0.17.0
golang.org/x/time v0.5.0
golang.org/x/tools v0.22.0
google.golang.org/grpc v1.64.1
@ -221,7 +221,7 @@ require (
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/serf v0.10.1 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
@ -300,12 +300,12 @@ require (
github.com/selectel/go-selvpcclient/v3 v3.1.1 // indirect
github.com/shirou/gopsutil/v3 v3.23.12 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
github.com/softlayer/softlayer-go v1.1.5 // indirect
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
github.com/sony/gobreaker v0.5.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.898 // indirect
@ -317,7 +317,7 @@ require (
github.com/transip/gotransip/v6 v6.23.0 // indirect
github.com/ultradns/ultradns-go-sdk v1.6.1-20231103022937-8589b6a // indirect
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
github.com/vultr/govultr/v2 v2.17.2 // indirect
github.com/vultr/govultr/v3 v3.9.0 // indirect
github.com/yandex-cloud/go-genproto v0.0.0-20240318083951-4fe6125f286e // indirect
github.com/yandex-cloud/go-sdk v0.0.0-20240318084659-dfa50323a0b4 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
@ -338,10 +338,10 @@ require (
go.uber.org/ratelimit v0.3.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/arch v0.4.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/term v0.21.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/term v0.23.0 // indirect
google.golang.org/api v0.172.0 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect

48
go.sum
View file

@ -283,8 +283,8 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
@ -302,8 +302,8 @@ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwv
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/go-acme/lego/v4 v4.17.4 h1:h0nePd3ObP6o7kAkndtpTzCw8shOZuWckNYeUQwo36Q=
github.com/go-acme/lego/v4 v4.17.4/go.mod h1:dU94SvPNqimEeb7EVilGGSnS0nU1O5Exir0pQ4QFL4U=
github.com/go-acme/lego/v4 v4.18.0 h1:2hH8KcdRBSb+p5o9VZIm61GAOXYALgILUCSs1Q+OYsk=
github.com/go-acme/lego/v4 v4.18.0/go.mod h1:Blkg3izvXpl3zxk7WKngIuwR2I/hvYVP3vRnvgBp7m8=
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
@ -553,8 +553,8 @@ github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df h1:MZf03xP9WdakyXhOWuAD5uPK3wHh96wCsqe3hCMKh8E=
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
@ -922,8 +922,8 @@ github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnj
github.com/shoenig/test v1.7.0 h1:eWcHtTXa6QLnBvm0jgEabMRN/uJ4DMV3M8xUGgRkZmk=
github.com/shoenig/test v1.7.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -950,8 +950,8 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@ -1016,8 +1016,8 @@ github.com/traefik/grpc-web v0.16.0 h1:eeUWZaFg6ZU0I9dWOYE2D5qkNzRBmXzzuRlxdltas
github.com/traefik/grpc-web v0.16.0/go.mod h1:2ttniSv7pTgBWIU2HZLokxRfFX3SA60c/DTmQQgVml4=
github.com/traefik/http-wasm-host-go v0.0.0-20240618100324-3c53dcaa1a70 h1:I+oBnV0orhmasb87yaX54tOAfqrV9+yKoQ1Cum5mq8w=
github.com/traefik/http-wasm-host-go v0.0.0-20240618100324-3c53dcaa1a70/go.mod h1:zQB3w+df4hryDEqBorGyA1DwPJ86LfKIASNLFuj6CuI=
github.com/traefik/paerser v0.2.0 h1:zqCLGSXoNlcBd+mzqSCLjon/I6phqIjeJL2xFB2ysgQ=
github.com/traefik/paerser v0.2.0/go.mod h1:afzaVcgF8A+MpTnPG4wBr4whjanCSYA6vK5RwaYVtRc=
github.com/traefik/paerser v0.2.1 h1:LFgeak1NmjEHF53c9ENdXdL1UMkF/lD5t+7Evsz4hH4=
github.com/traefik/paerser v0.2.1/go.mod h1:7BBDd4FANoVgaTZG+yh26jI6CA2nds7D/4VTEdIsh24=
github.com/traefik/yaegi v0.16.1 h1:f1De3DVJqIDKmnasUF6MwmWv1dSEEat0wcpXhD2On3E=
github.com/traefik/yaegi v0.16.1/go.mod h1:4eVhbPb3LnD2VigQjhYbEJ69vDRFdT2HQNrXx8eEwUY=
github.com/transip/gotransip/v6 v6.23.0 h1:PsTdjortrEZ8IFFifEryzjVjOy9SgK4ahlnhKBBIQgA=
@ -1053,8 +1053,8 @@ github.com/vulcand/oxy/v2 v2.0.0 h1:V+scHhd2xBjO8ojBRgxCM+OdZxRA/YTs8M70w5tdNy8=
github.com/vulcand/oxy/v2 v2.0.0/go.mod h1:uIAz3sYafO7i+V3SC8oDlMn/lt1i9aWcyXuXqVswKzE=
github.com/vulcand/predicate v1.2.0 h1:uFsW1gcnnR7R+QTID+FVcs0sSYlIGntoGOTb3rQJt50=
github.com/vulcand/predicate v1.2.0/go.mod h1:VipoNYXny6c8N381zGUWkjuuNHiRbeAZhE7Qm9c+2GA=
github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs=
github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI=
github.com/vultr/govultr/v3 v3.9.0 h1:63V/22mpfquRA5DenJ9EF0VozHg0k+X4dhUWcDXHPyc=
github.com/vultr/govultr/v3 v3.9.0/go.mod h1:Rd8ebpXm7jxH3MDmhnEs+zrlYW212ouhx+HeUMfHm2o=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
@ -1161,8 +1161,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1253,8 +1253,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1322,8 +1322,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -1333,8 +1333,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -1348,8 +1348,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View file

@ -606,10 +606,8 @@ func (s *AccessLogSuite) TestAccessLogPreflightHeadersMiddleware() {
func (s *AccessLogSuite) TestAccessLogDisabledForInternals() {
ensureWorkingDirectoryIsClean()
file := s.adaptFile("fixtures/access_log/access_log_ping.toml", struct{}{})
// Start Traefik.
s.traefikCmd(withConfigFile(file))
s.traefikCmd(withConfigFile("fixtures/access_log/access_log_base.toml"))
defer func() {
traefikLog, err := os.ReadFile(traefikTestLogFile)
@ -619,7 +617,7 @@ func (s *AccessLogSuite) TestAccessLogDisabledForInternals() {
// waitForTraefik makes at least one call to the rawdata api endpoint,
// but the logs for this endpoint are ignored in checkAccessLogOutput.
s.waitForTraefik("customPing")
s.waitForTraefik("service3")
s.checkStatsForLogFile()
@ -636,8 +634,9 @@ func (s *AccessLogSuite) TestAccessLogDisabledForInternals() {
require.NoError(s.T(), err)
// Make some requests on the custom ping router.
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/ping", nil)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8010/ping", nil)
require.NoError(s.T(), err)
req.Host = "ping.docker.local"
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
require.NoError(s.T(), err)
@ -649,6 +648,25 @@ func (s *AccessLogSuite) TestAccessLogDisabledForInternals() {
require.Equal(s.T(), 0, count)
// Make some requests on the custom ping router in error.
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8010/ping-error", nil)
require.NoError(s.T(), err)
req.Host = "ping-error.docker.local"
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized), try.BodyContains("X-Forwarded-Host: ping-error.docker.local"))
require.NoError(s.T(), err)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized), try.BodyContains("X-Forwarded-Host: ping-error.docker.local"))
require.NoError(s.T(), err)
// Here we verify that the remove of observability doesn't break the metrics for the error page service.
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8080/metrics", nil)
require.NoError(s.T(), err)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.BodyContains("service3"))
require.NoError(s.T(), err)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.BodyNotContains("service=\"ping"))
require.NoError(s.T(), err)
// Verify no other Traefik problems.
s.checkNoOtherTraefikProblems()
}

View file

@ -53,3 +53,11 @@ profiles:
- HTTPRouteRequestTimeout
name: GATEWAY-HTTP
summary: Core tests succeeded. Extended tests succeeded.
- core:
result: success
statistics:
Failed: 0
Passed: 11
Skipped: 0
name: GATEWAY-TLS
summary: Core tests succeeded.

View file

@ -22,10 +22,17 @@
address = ":8008"
[entryPoints.preflight]
address = ":8009"
[entryPoints.ping]
address = ":8010"
[api]
insecure = true
[ping]
[metrics]
[metrics.prometheus]
[providers]
[providers.docker]
exposedByDefault = false

View file

@ -1,30 +0,0 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "ERROR"
filePath = "traefik.log"
[accessLog]
filePath = "access.log"
[entryPoints]
[entryPoints.web]
address = ":8000"
[api]
insecure = true
[ping]
[providers]
[providers.file]
filename = "{{ .SelfFilename }}"
## dynamic configuration ##
[http.routers]
[http.routers.customPing]
entryPoints = ["web"]
rule = "PathPrefix(`/ping`)"
service = "ping@internal"

View file

@ -2506,6 +2506,11 @@ spec:
Default value is -1, which means unlimited size.
format: int64
type: integer
mirrorBody:
description: |-
MirrorBody defines whether the body of the request should be mirrored.
Default value is true.
type: boolean
mirrors:
description: Mirrors defines the list of mirrors where Traefik
will duplicate the traffic.

View file

@ -28,6 +28,10 @@
service = "mirrorWithMaxBody"
rule = "Path(`/whoamiWithMaxBody`)"
[http.routers.router3]
service = "mirrorWithoutBody"
rule = "Path(`/whoamiWithoutBody`)"
[http.services]
[http.services.mirror.mirroring]
@ -49,6 +53,16 @@
name = "mirror2"
percent = 50
[http.services.mirrorWithoutBody.mirroring]
service = "service1"
mirrorBody = false
[[http.services.mirrorWithoutBody.mirroring.mirrors]]
name = "mirror1"
percent = 10
[[http.services.mirrorWithoutBody.mirroring.mirrors]]
name = "mirror2"
percent = 50
[http.services.service1.loadBalancer]
[[http.services.service1.loadBalancer.servers]]

View file

@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"slices"
"strings"
"testing"
"time"
@ -193,7 +194,11 @@ func (s *K8sConformanceSuite) TestK8sGatewayAPIConformance() {
Version: *k8sConformanceTraefikVersion,
Contact: []string{"@traefik/maintainers"},
},
ConformanceProfiles: sets.New(ksuite.GatewayHTTPConformanceProfileName, ksuite.GatewayGRPCConformanceProfileName),
ConformanceProfiles: sets.New(
ksuite.GatewayHTTPConformanceProfileName,
ksuite.GatewayGRPCConformanceProfileName,
ksuite.GatewayTLSConformanceProfileName,
),
SupportedFeatures: sets.New(
features.SupportGateway,
features.SupportGatewayPort8080,
@ -207,6 +212,7 @@ func (s *K8sConformanceSuite) TestK8sGatewayAPIConformance() {
features.SupportHTTPRoutePathRewrite,
features.SupportHTTPRoutePathRedirect,
features.SupportHTTPRouteResponseHeaderModification,
features.SupportTLSRoute,
),
})
require.NoError(s.T(), err)
@ -224,6 +230,11 @@ func (s *K8sConformanceSuite) TestK8sGatewayAPIConformance() {
// TODO: to publish this report automatically, we have to figure out how to handle the date diff.
report.Date = "-"
// Ordering profile reports for the serialized report to be comparable.
slices.SortFunc(report.ProfileReports, func(a, b v1.ProfileReport) int {
return strings.Compare(a.Name, b.Name)
})
rawReport, err := yaml.Marshal(report)
require.NoError(s.T(), err)
s.T().Logf("Conformance report:\n%s", string(rawReport))

View file

@ -94,3 +94,21 @@ services:
traefik.http.routers.rt-preflightCORS.middlewares: preflightCORS
traefik.http.middlewares.preflightCORS.headers.accessControlAllowMethods: OPTIONS, GET
traefik.http.services.preflightCORS.loadbalancer.server.port: 80
ping:
image: traefik/whoami
labels:
traefik.enable: true
traefik.http.routers.ping.entryPoints: ping
traefik.http.routers.ping.rule: PathPrefix(`/ping`)
traefik.http.routers.ping.service: ping@internal
traefik.http.routers.ping-error.entryPoints: ping
traefik.http.routers.ping-error.rule: PathPrefix(`/ping-error`)
traefik.http.routers.ping-error.middlewares: errors, basicauth
traefik.http.routers.ping-error.service: ping@internal
traefik.http.middlewares.basicauth.basicauth.users: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
traefik.http.middlewares.errors.errors.status: 401
traefik.http.middlewares.errors.errors.service: service3
traefik.http.middlewares.errors.errors.query: /
traefik.http.services.service3.loadbalancer.server.port: 80

View file

@ -1004,8 +1004,13 @@ func (s *SimpleSuite) TestMirrorWithBody() {
_, err = rand.Read(body5)
require.NoError(s.T(), err)
verifyBody := func(req *http.Request) {
// forceOkResponse is used to avoid errors when Content-Length is set but no body is received
verifyBody := func(req *http.Request, canBodyBeEmpty bool) (forceOkResponse bool) {
b, _ := io.ReadAll(req.Body)
if canBodyBeEmpty && req.Header.Get("NoBody") == "true" {
require.Empty(s.T(), b)
return true
}
switch req.Header.Get("Size") {
case "20":
require.Equal(s.T(), body20, b)
@ -1014,20 +1019,25 @@ func (s *SimpleSuite) TestMirrorWithBody() {
default:
s.T().Fatal("Size header not present")
}
return false
}
main := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
verifyBody(req)
verifyBody(req, false)
atomic.AddInt32(&count, 1)
}))
mirror1 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
verifyBody(req)
if verifyBody(req, true) {
rw.WriteHeader(http.StatusOK)
}
atomic.AddInt32(&countMirror1, 1)
}))
mirror2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
verifyBody(req)
if verifyBody(req, true) {
rw.WriteHeader(http.StatusOK)
}
atomic.AddInt32(&countMirror2, 1)
}))
@ -1104,6 +1114,28 @@ func (s *SimpleSuite) TestMirrorWithBody() {
assert.Equal(s.T(), int32(10), countTotal)
assert.Equal(s.T(), int32(0), val1)
assert.Equal(s.T(), int32(0), val2)
atomic.StoreInt32(&count, 0)
atomic.StoreInt32(&countMirror1, 0)
atomic.StoreInt32(&countMirror2, 0)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/whoamiWithoutBody", bytes.NewBuffer(body20))
require.NoError(s.T(), err)
req.Header.Set("Size", "20")
req.Header.Set("NoBody", "true")
for range 10 {
response, err := http.DefaultClient.Do(req)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
}
countTotal = atomic.LoadInt32(&count)
val1 = atomic.LoadInt32(&countMirror1)
val2 = atomic.LoadInt32(&countMirror2)
assert.Equal(s.T(), int32(10), countTotal)
assert.Equal(s.T(), int32(1), val1)
assert.Equal(s.T(), int32(5), val2)
}
func (s *SimpleSuite) TestMirrorCanceled() {

View file

@ -34,7 +34,7 @@
"entryPoints": [
"web"
],
"service": "default-http-app-1-my-gateway-web-0-wrr",
"service": "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr",
"rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)",
"ruleSyntax": "v3",
"priority": 100008,
@ -47,7 +47,7 @@
"entryPoints": [
"websecure"
],
"service": "default-http-app-1-my-https-gateway-websecure-0-wrr",
"service": "default-http-app-1-my-https-gateway-websecure-0-1c0cf64bde37d9d0df06-wrr",
"rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)",
"ruleSyntax": "v3",
"priority": 100008,
@ -96,7 +96,7 @@
"dashboard@internal"
]
},
"default-http-app-1-my-gateway-web-0-wrr@kubernetesgateway": {
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr@kubernetesgateway": {
"weighted": {
"services": [
{
@ -110,7 +110,7 @@
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06@kubernetesgateway"
]
},
"default-http-app-1-my-https-gateway-websecure-0-wrr@kubernetesgateway": {
"default-http-app-1-my-https-gateway-websecure-0-1c0cf64bde37d9d0df06-wrr@kubernetesgateway": {
"weighted": {
"services": [
{
@ -150,11 +150,11 @@
}
},
"tcpRouters": {
"default-tcp-app-1-my-tcp-gateway-footcp@kubernetesgateway": {
"default-tcp-app-1-my-tcp-gateway-footcp-0-e3b0c44298fc1c149afb@kubernetesgateway": {
"entryPoints": [
"footcp"
],
"service": "default-tcp-app-1-my-tcp-gateway-footcp-wrr-0",
"service": "default-tcp-app-1-my-tcp-gateway-footcp-0-e3b0c44298fc1c149afb-wrr",
"rule": "HostSNI(`*`)",
"ruleSyntax": "v3",
"priority": -1,
@ -163,11 +163,11 @@
"footcp"
]
},
"default-tcp-app-1-my-tls-gateway-footlsterminate@kubernetesgateway": {
"default-tcp-app-1-my-tls-gateway-footlsterminate-0-e3b0c44298fc1c149afb@kubernetesgateway": {
"entryPoints": [
"footlsterminate"
],
"service": "default-tcp-app-1-my-tls-gateway-footlsterminate-wrr-0",
"service": "default-tcp-app-1-my-tls-gateway-footlsterminate-0-e3b0c44298fc1c149afb-wrr",
"rule": "HostSNI(`*`)",
"ruleSyntax": "v3",
"priority": -1,
@ -179,11 +179,11 @@
"footlsterminate"
]
},
"default-tls-app-1-my-tls-gateway-footlspassthrough-2279fe75c5156dc5eb26@kubernetesgateway": {
"default-tls-app-1-my-tls-gateway-footlspassthrough-0-e3b0c44298fc1c149afb@kubernetesgateway": {
"entryPoints": [
"footlspassthrough"
],
"service": "default-tls-app-1-my-tls-gateway-footlspassthrough-2279fe75c5156dc5eb26-wrr-0",
"service": "default-tls-app-1-my-tls-gateway-footlspassthrough-0-e3b0c44298fc1c149afb-wrr",
"rule": "HostSNI(`foo.bar`)",
"ruleSyntax": "v3",
"priority": 18,
@ -197,7 +197,7 @@
}
},
"tcpServices": {
"default-tcp-app-1-my-tcp-gateway-footcp-wrr-0@kubernetesgateway": {
"default-tcp-app-1-my-tcp-gateway-footcp-0-e3b0c44298fc1c149afb-wrr@kubernetesgateway": {
"weighted": {
"services": [
{
@ -208,10 +208,10 @@
},
"status": "enabled",
"usedBy": [
"default-tcp-app-1-my-tcp-gateway-footcp@kubernetesgateway"
"default-tcp-app-1-my-tcp-gateway-footcp-0-e3b0c44298fc1c149afb@kubernetesgateway"
]
},
"default-tcp-app-1-my-tls-gateway-footlsterminate-wrr-0@kubernetesgateway": {
"default-tcp-app-1-my-tls-gateway-footlsterminate-0-e3b0c44298fc1c149afb-wrr@kubernetesgateway": {
"weighted": {
"services": [
{
@ -222,10 +222,10 @@
},
"status": "enabled",
"usedBy": [
"default-tcp-app-1-my-tls-gateway-footlsterminate@kubernetesgateway"
"default-tcp-app-1-my-tls-gateway-footlsterminate-0-e3b0c44298fc1c149afb@kubernetesgateway"
]
},
"default-tls-app-1-my-tls-gateway-footlspassthrough-2279fe75c5156dc5eb26-wrr-0@kubernetesgateway": {
"default-tls-app-1-my-tls-gateway-footlspassthrough-0-e3b0c44298fc1c149afb-wrr@kubernetesgateway": {
"weighted": {
"services": [
{
@ -236,7 +236,7 @@
},
"status": "enabled",
"usedBy": [
"default-tls-app-1-my-tls-gateway-footlspassthrough-2279fe75c5156dc5eb26@kubernetesgateway"
"default-tls-app-1-my-tls-gateway-footlspassthrough-0-e3b0c44298fc1c149afb@kubernetesgateway"
]
},
"default-whoamitcp-8080@kubernetesgateway": {

View file

@ -81,6 +81,7 @@ type RouterTLSConfig struct {
// Mirroring holds the Mirroring configuration.
type Mirroring struct {
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
MirrorBody *bool `json:"mirrorBody,omitempty" toml:"mirrorBody,omitempty" yaml:"mirrorBody,omitempty" export:"true"`
MaxBodySize *int64 `json:"maxBodySize,omitempty" toml:"maxBodySize,omitempty" yaml:"maxBodySize,omitempty" export:"true"`
Mirrors []MirrorService `json:"mirrors,omitempty" toml:"mirrors,omitempty" yaml:"mirrors,omitempty" export:"true"`
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
@ -88,6 +89,8 @@ type Mirroring struct {
// SetDefaults Default values for a WRRService.
func (m *Mirroring) SetDefaults() {
defaultMirrorBody := true
m.MirrorBody = &defaultMirrorBody
var defaultMaxBodySize int64 = -1
m.MaxBodySize = &defaultMaxBodySize
}

View file

@ -967,6 +967,11 @@ func (in *MirrorService) DeepCopy() *MirrorService {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Mirroring) DeepCopyInto(out *Mirroring) {
*out = *in
if in.MirrorBody != nil {
in, out := &in.MirrorBody, &out.MirrorBody
*out = new(bool)
**out = **in
}
if in.MaxBodySize != nil {
in, out := &in.MaxBodySize, &out.MaxBodySize
*out = new(int64)

View file

@ -212,6 +212,9 @@ type Tracing struct {
func (t *Tracing) SetDefaults() {
t.ServiceName = "traefik"
t.SampleRate = 1.0
t.OTLP = &opentelemetry.Config{}
t.OTLP.SetDefaults()
}
// Providers contains providers configuration.

View file

@ -77,6 +77,11 @@ const (
TLSCipher = "TLSCipher"
// TLSClientSubject is the string representation of the TLS client certificate's Subject.
TLSClientSubject = "TLSClientSubject"
// TraceID is the consistent identifier for tracking requests across services, including upstream ones managed by Traefik, shown as a 32-hex digit string.
TraceID = "TraceId"
// SpanID is the unique identifier for Traefik’s root span (EntryPoint) within a request trace, formatted as a 16-hex digit string.
SpanID = "SpanId"
)
// These are written out in the default case when no config is provided to specify keys of interest.

View file

@ -43,9 +43,21 @@ const capturedData key = "capturedData"
// It satisfies the alice.Constructor type.
func Wrap(next http.Handler) (http.Handler, error) {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
c := &Capture{}
newRW, newReq := c.renew(rw, req)
next.ServeHTTP(newRW, newReq)
capt, err := FromContext(req.Context())
if err != nil {
c := &Capture{}
newRW, newReq := c.renew(rw, req)
next.ServeHTTP(newRW, newReq)
return
}
if capt.NeedsReset(rw) {
newRW, newReq := capt.renew(rw, req)
next.ServeHTTP(newRW, newReq)
return
}
next.ServeHTTP(rw, req)
}), nil
}

View file

@ -11,6 +11,7 @@ import (
"github.com/containous/alice"
"github.com/traefik/traefik/v3/pkg/metrics"
"github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/accesslog"
"github.com/traefik/traefik/v3/pkg/tracing"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
@ -69,6 +70,12 @@ func (e *entryPointTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request)
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)
e.next.ServeHTTP(recorder, req)

View file

@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/require"
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v3/pkg/metrics"
"github.com/traefik/traefik/v3/pkg/middlewares/accesslog"
"github.com/traefik/traefik/v3/pkg/tracing"
"github.com/traefik/traefik/v3/pkg/types"
"go.opentelemetry.io/otel/attribute"
@ -181,3 +182,27 @@ func TestEntryPointMiddleware_metrics(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{}), nil, "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])
}

View file

@ -290,6 +290,7 @@ func (c configBuilder) buildMirroring(ctx context.Context, tService *traefikv1al
Mirroring: &dynamic.Mirroring{
Service: fullNameMain,
Mirrors: mirrorServices,
MirrorBody: tService.Spec.Mirroring.MirrorBody,
MaxBodySize: tService.Spec.Mirroring.MaxBodySize,
},
}

View file

@ -53,6 +53,9 @@ type TraefikServiceSpec struct {
type Mirroring struct {
LoadBalancerSpec `json:",inline"`
// MirrorBody defines whether the body of the request should be mirrored.
// Default value is true.
MirrorBody *bool `json:"mirrorBody,omitempty"`
// MaxBodySize defines the maximum size allowed for the body of the request.
// If the body is larger, the request is not mirrored.
// Default value is -1, which means unlimited size.

View file

@ -972,6 +972,11 @@ func (in *MirrorService) DeepCopy() *MirrorService {
func (in *Mirroring) DeepCopyInto(out *Mirroring) {
*out = *in
in.LoadBalancerSpec.DeepCopyInto(&out.LoadBalancerSpec)
if in.MirrorBody != nil {
in, out := &in.MirrorBody, &out.MirrorBody
*out = new(bool)
**out = **in
}
if in.MaxBodySize != nil {
in, out := &in.MaxBodySize, &out.MaxBodySize
*out = new(int64)

View file

@ -32,6 +32,10 @@ metadata:
name: TCP-app-1
namespace: default
spec:
parentRefs:
</