From 3a80aa172c6c5f863082949ea35ca003e95c5a81 Mon Sep 17 00:00:00 2001 From: Patrick Evans <31580846+holysoles@users.noreply.github.com> Date: Thu, 29 Aug 2024 03:40:05 -0500 Subject: [PATCH 01/13] Give valid examples for exposing dashboard with default Helm values --- .../getting-started/install-traefik.md | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/docs/content/getting-started/install-traefik.md b/docs/content/getting-started/install-traefik.md index 86057f6a3..705b335c1 100644 --- a/docs/content/getting-started/install-traefik.md +++ b/docs/content/getting-started/install-traefik.md @@ -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. From 6b1a584c2be2952854a4ace1f594e7597aa4b8dd Mon Sep 17 00:00:00 2001 From: Edward Eastman Date: Thu, 29 Aug 2024 09:50:06 +0100 Subject: [PATCH 02/13] Update quick-start-with-kubernetes.md to include required permissions --- .../quick-start-with-kubernetes.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/content/getting-started/quick-start-with-kubernetes.md b/docs/content/getting-started/quick-start-with-kubernetes.md index cfbbb7259..c371f0072 100644 --- a/docs/content/getting-started/quick-start-with-kubernetes.md +++ b/docs/content/getting-started/quick-start-with-kubernetes.md @@ -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)." From 3040f2659a595f359fdf2c4ede747b542c8b30ab Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 29 Aug 2024 10:54:05 +0200 Subject: [PATCH 03/13] Upgrade paerser to v0.2.1 --- go.mod | 18 +++++++++--------- go.sum | 40 ++++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index 1b875c0f1..de4a351d5 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154 // No tag on the repo. github.com/testcontainers/testcontainers-go v0.32.0 - github.com/traefik/paerser v0.2.0 + github.com/traefik/paerser v0.2.1 github.com/traefik/yaegi v0.16.1 github.com/uber/jaeger-client-go v2.30.0+incompatible github.com/uber/jaeger-lib v2.4.1+incompatible @@ -70,7 +70,7 @@ 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/text v0.16.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.63.1 @@ -211,7 +211,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 @@ -290,12 +290,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 @@ -328,11 +328,11 @@ require ( go.uber.org/zap v1.21.0 // indirect go4.org/intern v0.0.0-20230525184215-6c62f75575cb // indirect go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // 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/sys v0.21.0 // indirect - golang.org/x/term v0.21.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/term v0.23.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.172.0 // indirect google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect diff --git a/go.sum b/go.sum index 7e9d17a0c..cd95608e1 100644 --- a/go.sum +++ b/go.sum @@ -367,8 +367,8 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -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= @@ -672,8 +672,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-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 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= @@ -1109,8 +1109,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= @@ -1142,8 +1142,8 @@ github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z github.com/spf13/afero v1.6.0/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 v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= @@ -1196,8 +1196,8 @@ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+F github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -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= @@ -1349,8 +1349,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= @@ -1486,8 +1486,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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= @@ -1588,8 +1588,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-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1601,8 +1601,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.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1618,8 +1618,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-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 1417da4a21d96e1f84acf6b20449c6a2ee524bc8 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 29 Aug 2024 11:08:09 +0200 Subject: [PATCH 04/13] Update k8s quickstart permissions --- .../quick-start-with-kubernetes.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/content/getting-started/quick-start-with-kubernetes.md b/docs/content/getting-started/quick-start-with-kubernetes.md index e81cd07b0..ba94918e9 100644 --- a/docs/content/getting-started/quick-start-with-kubernetes.md +++ b/docs/content/getting-started/quick-start-with-kubernetes.md @@ -58,6 +58,23 @@ rules: - ingresses/status verbs: - update + - apiGroups: + - traefik.io + - traefik.containo.us + resources: + - middlewares + - middlewaretcps + - ingressroutes + - traefikservices + - ingressroutetcps + - ingressrouteudps + - tlsoptions + - tlsstores + - serverstransports + verbs: + - get + - list + - watch ``` !!! info "You can find the reference for this file [there](../../reference/dynamic-configuration/kubernetes-crd/#rbac)." From 2714831a4e6a0972a0eca5d46af2f82f9ed2efd9 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 29 Aug 2024 14:30:05 +0200 Subject: [PATCH 05/13] fix: otlp doc + potential panic --- docs/content/observability/tracing/overview.md | 4 +--- pkg/config/static/static_config.go | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/content/observability/tracing/overview.md b/docs/content/observability/tracing/overview.md index fcea5c548..b69aee46b 100644 --- a/docs/content/observability/tracing/overview.md +++ b/docs/content/observability/tracing/overview.md @@ -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 ``` diff --git a/pkg/config/static/static_config.go b/pkg/config/static/static_config.go index 2dae73cfc..1e0c5d61d 100644 --- a/pkg/config/static/static_config.go +++ b/pkg/config/static/static_config.go @@ -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. From bf715605154d0beee7bcb55dbf4852ace7a92a72 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 2 Sep 2024 15:42:05 +0200 Subject: [PATCH 06/13] Update go-acme/lego to v4.18.0 --- docs/content/https/acme.md | 6 +++++- go.mod | 4 ++-- go.sum | 8 ++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/content/https/acme.md b/docs/content/https/acme.md index 62509b32c..3355bdbb2 100644 --- a/docs/content/https/acme.md +++ b/docs/content/https/acme.md @@ -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) | diff --git a/go.mod b/go.mod index de4a351d5..c85e0412a 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/fatih/structs v1.1.0 github.com/fsnotify/fsnotify v1.7.0 github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2 // No tag on the repo. - 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 @@ -306,7 +306,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 diff --git a/go.sum b/go.sum index cd95608e1..75a34ba8f 100644 --- a/go.sum +++ b/go.sum @@ -382,8 +382,8 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= -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= @@ -1229,8 +1229,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= From eb99c8c7858eb3c6b0f1428367d44b751144e76b Mon Sep 17 00:00:00 2001 From: Matteo Paier Date: Mon, 2 Sep 2024 16:36:06 +0200 Subject: [PATCH 07/13] Add mirrorBody option to HTTP mirroring --- .../reference/dynamic-configuration/file.toml | 1 + .../reference/dynamic-configuration/file.yaml | 1 + .../kubernetes-crd-definition-v1.yml | 5 ++ .../kubernetes-crd-resource.yml | 1 + .../reference/dynamic-configuration/kv-ref.md | 1 + .../traefik.io_traefikservices.yaml | 5 ++ docs/content/routing/services/index.md | 7 ++ integration/fixtures/k8s/01-traefik-crd.yml | 5 ++ integration/fixtures/mirror.toml | 14 ++++ integration/simple_test.go | 40 +++++++++-- pkg/config/dynamic/http_config.go | 3 + pkg/config/dynamic/zz_generated.deepcopy.go | 5 ++ .../kubernetes/crd/kubernetes_http.go | 1 + .../crd/traefikio/v1alpha1/service.go | 3 + .../v1alpha1/zz_generated.deepcopy.go | 5 ++ pkg/provider/kv/kv_test.go | 2 + .../service/loadbalancer/mirror/mirror.go | 10 +-- .../loadbalancer/mirror/mirror_test.go | 66 +++++++++++++++---- pkg/server/service/service.go | 12 +++- 19 files changed, 165 insertions(+), 22 deletions(-) diff --git a/docs/content/reference/dynamic-configuration/file.toml b/docs/content/reference/dynamic-configuration/file.toml index 62958ccd4..269467380 100644 --- a/docs/content/reference/dynamic-configuration/file.toml +++ b/docs/content/reference/dynamic-configuration/file.toml @@ -82,6 +82,7 @@ [http.services.Service03] [http.services.Service03.mirroring] service = "foobar" + mirrorBody = true maxBodySize = 42 [[http.services.Service03.mirroring.mirrors]] diff --git a/docs/content/reference/dynamic-configuration/file.yaml b/docs/content/reference/dynamic-configuration/file.yaml index e4e82bea4..6f94af243 100644 --- a/docs/content/reference/dynamic-configuration/file.yaml +++ b/docs/content/reference/dynamic-configuration/file.yaml @@ -89,6 +89,7 @@ http: Service03: mirroring: service: foobar + mirrorBody: true maxBodySize: 42 mirrors: - name: foobar diff --git a/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml b/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml index 30038945a..96816d8a4 100644 --- a/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml +++ b/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml @@ -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. diff --git a/docs/content/reference/dynamic-configuration/kubernetes-crd-resource.yml b/docs/content/reference/dynamic-configuration/kubernetes-crd-resource.yml index 93f1a95ff..14e809a2e 100644 --- a/docs/content/reference/dynamic-configuration/kubernetes-crd-resource.yml +++ b/docs/content/reference/dynamic-configuration/kubernetes-crd-resource.yml @@ -63,6 +63,7 @@ spec: mirroring: name: wrr2 kind: TraefikService + mirrorBody: true # Optional maxBodySize: 2000000000 mirrors: diff --git a/docs/content/reference/dynamic-configuration/kv-ref.md b/docs/content/reference/dynamic-configuration/kv-ref.md index 205ef0efe..bd9b99a7a 100644 --- a/docs/content/reference/dynamic-configuration/kv-ref.md +++ b/docs/content/reference/dynamic-configuration/kv-ref.md @@ -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` | diff --git a/docs/content/reference/dynamic-configuration/traefik.io_traefikservices.yaml b/docs/content/reference/dynamic-configuration/traefik.io_traefikservices.yaml index 1e1b279d5..48e629bb8 100644 --- a/docs/content/reference/dynamic-configuration/traefik.io_traefikservices.yaml +++ b/docs/content/reference/dynamic-configuration/traefik.io_traefikservices.yaml @@ -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. diff --git a/docs/content/routing/services/index.md b/docs/content/routing/services/index.md index dad91d472..8e4cc41f0 100644 --- a/docs/content/routing/services/index.md +++ b/docs/content/routing/services/index.md @@ -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 diff --git a/integration/fixtures/k8s/01-traefik-crd.yml b/integration/fixtures/k8s/01-traefik-crd.yml index 30038945a..96816d8a4 100644 --- a/integration/fixtures/k8s/01-traefik-crd.yml +++ b/integration/fixtures/k8s/01-traefik-crd.yml @@ -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. diff --git a/integration/fixtures/mirror.toml b/integration/fixtures/mirror.toml index 4c99f83b8..b28878480 100644 --- a/integration/fixtures/mirror.toml +++ b/integration/fixtures/mirror.toml @@ -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]] diff --git a/integration/simple_test.go b/integration/simple_test.go index 018a4b67a..9aae5c1b2 100644 --- a/integration/simple_test.go +++ b/integration/simple_test.go @@ -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() { diff --git a/pkg/config/dynamic/http_config.go b/pkg/config/dynamic/http_config.go index 48b2e763c..d347df81e 100644 --- a/pkg/config/dynamic/http_config.go +++ b/pkg/config/dynamic/http_config.go @@ -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 } diff --git a/pkg/config/dynamic/zz_generated.deepcopy.go b/pkg/config/dynamic/zz_generated.deepcopy.go index da909e316..890e89700 100644 --- a/pkg/config/dynamic/zz_generated.deepcopy.go +++ b/pkg/config/dynamic/zz_generated.deepcopy.go @@ -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) diff --git a/pkg/provider/kubernetes/crd/kubernetes_http.go b/pkg/provider/kubernetes/crd/kubernetes_http.go index d81a02058..8f00ec238 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_http.go +++ b/pkg/provider/kubernetes/crd/kubernetes_http.go @@ -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, }, } diff --git a/pkg/provider/kubernetes/crd/traefikio/v1alpha1/service.go b/pkg/provider/kubernetes/crd/traefikio/v1alpha1/service.go index ed1955a8a..cdbd95b0e 100644 --- a/pkg/provider/kubernetes/crd/traefikio/v1alpha1/service.go +++ b/pkg/provider/kubernetes/crd/traefikio/v1alpha1/service.go @@ -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. diff --git a/pkg/provider/kubernetes/crd/traefikio/v1alpha1/zz_generated.deepcopy.go b/pkg/provider/kubernetes/crd/traefikio/v1alpha1/zz_generated.deepcopy.go index caa1bf9ec..466cc7577 100644 --- a/pkg/provider/kubernetes/crd/traefikio/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/provider/kubernetes/crd/traefikio/v1alpha1/zz_generated.deepcopy.go @@ -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) diff --git a/pkg/provider/kv/kv_test.go b/pkg/provider/kv/kv_test.go index 3610ec3b5..6cfcc7b61 100644 --- a/pkg/provider/kv/kv_test.go +++ b/pkg/provider/kv/kv_test.go @@ -61,6 +61,7 @@ func Test_buildConfiguration(t *testing.T) { "traefik/http/services/Service01/loadBalancer/servers/0/url": "foobar", "traefik/http/services/Service01/loadBalancer/servers/1/url": "foobar", "traefik/http/services/Service02/mirroring/service": "foobar", + "traefik/http/services/Service02/mirroring/mirrorBody": "true", "traefik/http/services/Service02/mirroring/maxBodySize": "42", "traefik/http/services/Service02/mirroring/mirrors/0/name": "foobar", "traefik/http/services/Service02/mirroring/mirrors/0/percent": "42", @@ -676,6 +677,7 @@ func Test_buildConfiguration(t *testing.T) { "Service02": { Mirroring: &dynamic.Mirroring{ Service: "foobar", + MirrorBody: func(v bool) *bool { return &v }(true), MaxBodySize: func(v int64) *int64 { return &v }(42), Mirrors: []dynamic.MirrorService{ { diff --git a/pkg/server/service/loadbalancer/mirror/mirror.go b/pkg/server/service/loadbalancer/mirror/mirror.go index 201dade9a..91cf364a3 100644 --- a/pkg/server/service/loadbalancer/mirror/mirror.go +++ b/pkg/server/service/loadbalancer/mirror/mirror.go @@ -25,6 +25,7 @@ type Mirroring struct { rw http.ResponseWriter routinePool *safe.Pool + mirrorBody bool maxBodySize int64 wantsHealthCheck bool @@ -33,11 +34,12 @@ type Mirroring struct { } // New returns a new instance of *Mirroring. -func New(handler http.Handler, pool *safe.Pool, maxBodySize int64, hc *dynamic.HealthCheck) *Mirroring { +func New(handler http.Handler, pool *safe.Pool, mirrorBody bool, maxBodySize int64, hc *dynamic.HealthCheck) *Mirroring { return &Mirroring{ routinePool: pool, handler: handler, rw: blackHoleResponseWriter{}, + mirrorBody: mirrorBody, maxBodySize: maxBodySize, wantsHealthCheck: hc != nil, } @@ -83,7 +85,7 @@ func (m *Mirroring) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } logger := log.Ctx(req.Context()) - rr, bytesRead, err := newReusableRequest(req, m.maxBodySize) + rr, bytesRead, err := newReusableRequest(req, m.mirrorBody, m.maxBodySize) if err != nil && !errors.Is(err, errBodyTooLarge) { http.Error(rw, fmt.Sprintf("%s: creating reusable request: %v", http.StatusText(http.StatusInternalServerError), err), http.StatusInternalServerError) @@ -200,11 +202,11 @@ var errBodyTooLarge = errors.New("request body too large") // if the returned error is errBodyTooLarge, newReusableRequest also returns the // bytes that were already consumed from the request's body. -func newReusableRequest(req *http.Request, maxBodySize int64) (*reusableRequest, []byte, error) { +func newReusableRequest(req *http.Request, mirrorBody bool, maxBodySize int64) (*reusableRequest, []byte, error) { if req == nil { return nil, nil, errors.New("nil input request") } - if req.Body == nil || req.ContentLength == 0 { + if req.Body == nil || req.ContentLength == 0 || !mirrorBody { return &reusableRequest{req: req}, nil, nil } diff --git a/pkg/server/service/loadbalancer/mirror/mirror_test.go b/pkg/server/service/loadbalancer/mirror/mirror_test.go index c48637006..94a4c62a0 100644 --- a/pkg/server/service/loadbalancer/mirror/mirror_test.go +++ b/pkg/server/service/loadbalancer/mirror/mirror_test.go @@ -21,7 +21,7 @@ func TestMirroringOn100(t *testing.T) { rw.WriteHeader(http.StatusOK) }) pool := safe.NewPool(context.Background()) - mirror := New(handler, pool, defaultMaxBodySize, nil) + mirror := New(handler, pool, true, defaultMaxBodySize, nil) err := mirror.AddMirror(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { atomic.AddInt32(&countMirror1, 1) }), 10) @@ -50,7 +50,7 @@ func TestMirroringOn10(t *testing.T) { rw.WriteHeader(http.StatusOK) }) pool := safe.NewPool(context.Background()) - mirror := New(handler, pool, defaultMaxBodySize, nil) + mirror := New(handler, pool, true, defaultMaxBodySize, nil) err := mirror.AddMirror(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { atomic.AddInt32(&countMirror1, 1) }), 10) @@ -74,7 +74,7 @@ func TestMirroringOn10(t *testing.T) { } func TestInvalidPercent(t *testing.T) { - mirror := New(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), safe.NewPool(context.Background()), defaultMaxBodySize, nil) + mirror := New(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), safe.NewPool(context.Background()), true, defaultMaxBodySize, nil) err := mirror.AddMirror(nil, -1) assert.Error(t, err) @@ -93,7 +93,7 @@ func TestHijack(t *testing.T) { rw.WriteHeader(http.StatusOK) }) pool := safe.NewPool(context.Background()) - mirror := New(handler, pool, defaultMaxBodySize, nil) + mirror := New(handler, pool, true, defaultMaxBodySize, nil) var mirrorRequest bool err := mirror.AddMirror(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { @@ -117,7 +117,7 @@ func TestFlush(t *testing.T) { rw.WriteHeader(http.StatusOK) }) pool := safe.NewPool(context.Background()) - mirror := New(handler, pool, defaultMaxBodySize, nil) + mirror := New(handler, pool, true, defaultMaxBodySize, nil) var mirrorRequest bool err := mirror.AddMirror(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { @@ -154,7 +154,7 @@ func TestMirroringWithBody(t *testing.T) { rw.WriteHeader(http.StatusOK) }) - mirror := New(handler, pool, defaultMaxBodySize, nil) + mirror := New(handler, pool, true, defaultMaxBodySize, nil) for range numMirrors { err := mirror.AddMirror(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { @@ -177,13 +177,55 @@ func TestMirroringWithBody(t *testing.T) { assert.Equal(t, numMirrors, int(val)) } +func TestMirroringWithIgnoredBody(t *testing.T) { + const numMirrors = 10 + + var ( + countMirror int32 + body = []byte(`body`) + emptyBody = []byte(``) + ) + + pool := safe.NewPool(context.Background()) + + handler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + assert.NotNil(t, r.Body) + bb, err := io.ReadAll(r.Body) + assert.NoError(t, err) + assert.Equal(t, body, bb) + rw.WriteHeader(http.StatusOK) + }) + + mirror := New(handler, pool, false, defaultMaxBodySize, nil) + + for range numMirrors { + err := mirror.AddMirror(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + assert.NotNil(t, r.Body) + bb, err := io.ReadAll(r.Body) + assert.NoError(t, err) + assert.Equal(t, emptyBody, bb) + atomic.AddInt32(&countMirror, 1) + }), 100) + assert.NoError(t, err) + } + + req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(body)) + + mirror.ServeHTTP(httptest.NewRecorder(), req) + + pool.Stop() + + val := atomic.LoadInt32(&countMirror) + assert.Equal(t, numMirrors, int(val)) +} + func TestCloneRequest(t *testing.T) { t.Run("http request body is nil", func(t *testing.T) { req, err := http.NewRequest(http.MethodPost, "/", nil) assert.NoError(t, err) ctx := req.Context() - rr, _, err := newReusableRequest(req, defaultMaxBodySize) + rr, _, err := newReusableRequest(req, true, defaultMaxBodySize) assert.NoError(t, err) // first call @@ -208,7 +250,7 @@ func TestCloneRequest(t *testing.T) { ctx := req.Context() req.ContentLength = int64(contentLength) - rr, _, err := newReusableRequest(req, defaultMaxBodySize) + rr, _, err := newReusableRequest(req, true, defaultMaxBodySize) assert.NoError(t, err) // first call @@ -231,7 +273,7 @@ func TestCloneRequest(t *testing.T) { req, err := http.NewRequest(http.MethodPost, "/", buf) assert.NoError(t, err) - _, expectedBytes, err := newReusableRequest(req, 2) + _, expectedBytes, err := newReusableRequest(req, true, 2) assert.Error(t, err) assert.Equal(t, expectedBytes, bb[:3]) }) @@ -243,7 +285,7 @@ func TestCloneRequest(t *testing.T) { req, err := http.NewRequest(http.MethodPost, "/", buf) assert.NoError(t, err) - rr, expectedBytes, err := newReusableRequest(req, 20) + rr, expectedBytes, err := newReusableRequest(req, true, 20) assert.NoError(t, err) assert.Nil(t, expectedBytes) assert.Len(t, rr.body, 10) @@ -255,14 +297,14 @@ func TestCloneRequest(t *testing.T) { req, err := http.NewRequest(http.MethodGet, "/", buf) assert.NoError(t, err) - rr, expectedBytes, err := newReusableRequest(req, 20) + rr, expectedBytes, err := newReusableRequest(req, true, 20) assert.NoError(t, err) assert.Nil(t, expectedBytes) assert.Empty(t, rr.body) }) t.Run("no request given", func(t *testing.T) { - _, _, err := newReusableRequest(nil, defaultMaxBodySize) + _, _, err := newReusableRequest(nil, true, defaultMaxBodySize) assert.Error(t, err) }) } diff --git a/pkg/server/service/service.go b/pkg/server/service/service.go index 247879bcf..38932f225 100644 --- a/pkg/server/service/service.go +++ b/pkg/server/service/service.go @@ -34,7 +34,10 @@ import ( "google.golang.org/grpc/status" ) -const defaultMaxBodySize int64 = -1 +const ( + defaultMirrorBody = true + defaultMaxBodySize int64 = -1 +) // RoundTripperGetter is a roundtripper getter interface. type RoundTripperGetter interface { @@ -197,11 +200,16 @@ func (m *Manager) getMirrorServiceHandler(ctx context.Context, config *dynamic.M return nil, err } + mirrorBody := defaultMirrorBody + if config.MirrorBody != nil { + mirrorBody = *config.MirrorBody + } + maxBodySize := defaultMaxBodySize if config.MaxBodySize != nil { maxBodySize = *config.MaxBodySize } - handler := mirror.New(serviceHandler, m.routinePool, maxBodySize, config.HealthCheck) + handler := mirror.New(serviceHandler, m.routinePool, mirrorBody, maxBodySize, config.HealthCheck) for _, mirrorConfig := range config.Mirrors { mirrorHandler, err := m.BuildHTTP(ctx, mirrorConfig.Name) if err != nil { From 6009aaed87161042d42563ccbb076c4924b3ea52 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 3 Sep 2024 09:44:04 +0200 Subject: [PATCH 08/13] Improve CI speed --- .github/workflows/build.yaml | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 18f66ed3b..022db925c 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -48,10 +48,33 @@ jobs: path: webui.tar.gz build: - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest + strategy: matrix: - os: [ ubuntu-latest, macos-latest, windows-latest ] + os: [ darwin, freebsd, linux, openbsd, windows ] + arch: [ amd64, arm64 ] + include: + - os: freebsd + arch: 386 + - os: linux + arch: 386 + - os: linux + arch: arm + goarm: 6 + - os: linux + arch: arm + goarm: 7 + - os: linux + arch: ppc64le + - os: linux + arch: riscv64 + - os: linux + arch: s390x + - os: openbsd + arch: 386 + - os: windows + arch: 386 needs: - build-webui @@ -63,6 +86,8 @@ jobs: - name: Set up Go ${{ env.GO_VERSION }} uses: actions/setup-go@v5 + env: + ImageOS: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.goarm }} with: go-version: ${{ env.GO_VERSION }} @@ -75,4 +100,8 @@ jobs: run: tar xvf webui.tar.gz - name: Build + env: + GOOS: ${{ matrix.os }} + GOARCH: ${{ matrix.arch }} + GOARM: ${{ matrix.goarm }} run: make binary From cf2869407dcc52e53e9540543ee3d25fb4a036bb Mon Sep 17 00:00:00 2001 From: Romain Date: Tue, 3 Sep 2024 10:30:08 +0200 Subject: [PATCH 09/13] Wrap capture for services used by pieces of middleware --- integration/access_log_test.go | 28 +++++++++++++---- .../fixtures/access_log/access_log_base.toml | 7 +++++ .../fixtures/access_log/access_log_ping.toml | 30 ------------------- integration/resources/compose/access_log.yml | 18 +++++++++++ pkg/middlewares/capture/capture.go | 18 +++++++++-- pkg/server/service/service.go | 12 ++++++++ 6 files changed, 75 insertions(+), 38 deletions(-) delete mode 100644 integration/fixtures/access_log/access_log_ping.toml diff --git a/integration/access_log_test.go b/integration/access_log_test.go index b5e4ec1ef..e1c4003e9 100644 --- a/integration/access_log_test.go +++ b/integration/access_log_test.go @@ -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() } diff --git a/integration/fixtures/access_log/access_log_base.toml b/integration/fixtures/access_log/access_log_base.toml index 8d954450e..5a88f75e9 100644 --- a/integration/fixtures/access_log/access_log_base.toml +++ b/integration/fixtures/access_log/access_log_base.toml @@ -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 diff --git a/integration/fixtures/access_log/access_log_ping.toml b/integration/fixtures/access_log/access_log_ping.toml deleted file mode 100644 index 4e85b93bc..000000000 --- a/integration/fixtures/access_log/access_log_ping.toml +++ /dev/null @@ -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" diff --git a/integration/resources/compose/access_log.yml b/integration/resources/compose/access_log.yml index c9cf06db7..c5be8f9e4 100644 --- a/integration/resources/compose/access_log.yml +++ b/integration/resources/compose/access_log.yml @@ -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 diff --git a/pkg/middlewares/capture/capture.go b/pkg/middlewares/capture/capture.go index b7e182117..04e411a20 100644 --- a/pkg/middlewares/capture/capture.go +++ b/pkg/middlewares/capture/capture.go @@ -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 } diff --git a/pkg/server/service/service.go b/pkg/server/service/service.go index e77fda54c..5003273d9 100644 --- a/pkg/server/service/service.go +++ b/pkg/server/service/service.go @@ -21,6 +21,7 @@ import ( "github.com/traefik/traefik/v3/pkg/healthcheck" "github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/middlewares/accesslog" + "github.com/traefik/traefik/v3/pkg/middlewares/capture" metricsMiddle "github.com/traefik/traefik/v3/pkg/middlewares/metrics" "github.com/traefik/traefik/v3/pkg/middlewares/observability" "github.com/traefik/traefik/v3/pkg/safe" @@ -342,6 +343,17 @@ func (m *Manager) getLoadBalancerServiceHandler(ctx context.Context, serviceName proxy = observability.NewService(ctx, serviceName, proxy) } + if m.observabilityMgr.ShouldAddAccessLogs(qualifiedSvcName) || m.observabilityMgr.ShouldAddMetrics(qualifiedSvcName) { + // Some piece of middleware, like the ErrorPage, are relying on this serviceBuilder to get the handler for a given service, + // to re-target the request to it. + // Those pieces of middleware can be configured on routes that expose a Traefik internal service. + // In such a case, observability for internals being optional, the capture probe could be absent from context (no wrap via the entrypoint). + // But if the service targeted by this piece of middleware is not an internal one, + // and requires observability, we still want the capture probe to be present in the request context. + // Makes sure a capture probe is in the request context. + proxy, _ = capture.Wrap(proxy) + } + lb.Add(proxyName, proxy, server.Weight) // servers are considered UP by default. From 3eb7ecce193615f86a7da077746b80145eb24306 Mon Sep 17 00:00:00 2001 From: Romain Date: Tue, 3 Sep 2024 12:10:04 +0200 Subject: [PATCH 10/13] Improve Kubernetes GatewayAPI TCPRoute and TLSRoute support --- .../experimental-v3.1-default-report.yaml | 8 + integration/k8s_conformance_test.go | 13 +- integration/testdata/rawdata-gateway.json | 32 +- .../tcproute/with_wrong_service_port.yml | 4 + .../tlsroute/with_wrong_service_port.yml | 6 +- pkg/provider/kubernetes/gateway/grpcroute.go | 6 +- pkg/provider/kubernetes/gateway/httproute.go | 16 +- pkg/provider/kubernetes/gateway/kubernetes.go | 36 +- .../kubernetes/gateway/kubernetes_test.go | 556 +++++++++--------- pkg/provider/kubernetes/gateway/tcproute.go | 314 ++++++---- pkg/provider/kubernetes/gateway/tlsroute.go | 183 ++++-- 11 files changed, 690 insertions(+), 484 deletions(-) diff --git a/integration/conformance-reports/v1.1.0/experimental-v3.1-default-report.yaml b/integration/conformance-reports/v1.1.0/experimental-v3.1-default-report.yaml index e668037eb..64047e5b2 100644 --- a/integration/conformance-reports/v1.1.0/experimental-v3.1-default-report.yaml +++ b/integration/conformance-reports/v1.1.0/experimental-v3.1-default-report.yaml @@ -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. diff --git a/integration/k8s_conformance_test.go b/integration/k8s_conformance_test.go index 70ec948ea..9316715af 100644 --- a/integration/k8s_conformance_test.go +++ b/integration/k8s_conformance_test.go @@ -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)) diff --git a/integration/testdata/rawdata-gateway.json b/integration/testdata/rawdata-gateway.json index d4dd467b0..15ee8b6ce 100644 --- a/integration/testdata/rawdata-gateway.json +++ b/integration/testdata/rawdata-gateway.json @@ -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": { diff --git a/pkg/provider/kubernetes/gateway/fixtures/tcproute/with_wrong_service_port.yml b/pkg/provider/kubernetes/gateway/fixtures/tcproute/with_wrong_service_port.yml index 6de20a14a..ee629a6db 100644 --- a/pkg/provider/kubernetes/gateway/fixtures/tcproute/with_wrong_service_port.yml +++ b/pkg/provider/kubernetes/gateway/fixtures/tcproute/with_wrong_service_port.yml @@ -32,6 +32,10 @@ metadata: name: TCP-app-1 namespace: default spec: + parentRefs: + - name: my-gateway + kind: Gateway + group: gateway.networking.k8s.io rules: - backendRefs: - name: whoami diff --git a/pkg/provider/kubernetes/gateway/fixtures/tlsroute/with_wrong_service_port.yml b/pkg/provider/kubernetes/gateway/fixtures/tlsroute/with_wrong_service_port.yml index c0c472a55..5d296c248 100644 --- a/pkg/provider/kubernetes/gateway/fixtures/tlsroute/with_wrong_service_port.yml +++ b/pkg/provider/kubernetes/gateway/fixtures/tlsroute/with_wrong_service_port.yml @@ -36,16 +36,16 @@ spec: group: "" allowedRoutes: kinds: - - kind: TCPRoute + - kind: TLSRoute group: gateway.networking.k8s.io namespaces: from: Same --- -kind: TCPRoute +kind: TLSRoute apiVersion: gateway.networking.k8s.io/v1alpha2 metadata: - name: tcp-app-1 + name: tls-app-1 namespace: default spec: parentRefs: diff --git a/pkg/provider/kubernetes/gateway/grpcroute.go b/pkg/provider/kubernetes/gateway/grpcroute.go index baee82876..9447943a0 100644 --- a/pkg/provider/kubernetes/gateway/grpcroute.go +++ b/pkg/provider/kubernetes/gateway/grpcroute.go @@ -216,7 +216,7 @@ func (p *Provider) loadGRPCService(conf *dynamic.Configuration, routeKey string, } func (p *Provider) loadGRPCBackendRef(route *gatev1.GRPCRoute, backendRef gatev1.GRPCBackendRef) (string, *dynamic.Service, *metav1.Condition) { - kind := ptr.Deref(backendRef.Kind, "Service") + kind := ptr.Deref(backendRef.Kind, kindService) group := groupCore if backendRef.Group != nil && *backendRef.Group != "" { @@ -230,7 +230,7 @@ func (p *Provider) loadGRPCBackendRef(route *gatev1.GRPCRoute, backendRef gatev1 serviceName := provider.Normalize(namespace + "-" + string(backendRef.Name)) - if group != groupCore || kind != "Service" { + if group != groupCore || kind != kindService { return serviceName, nil, &metav1.Condition{ Type: string(gatev1.RouteConditionResolvedRefs), Status: metav1.ConditionFalse, @@ -241,7 +241,7 @@ func (p *Provider) loadGRPCBackendRef(route *gatev1.GRPCRoute, backendRef gatev1 } } - if err := p.isReferenceGranted(groupGateway, kindGRPCRoute, route.Namespace, group, string(kind), string(backendRef.Name), namespace); err != nil { + if err := p.isReferenceGranted(kindGRPCRoute, route.Namespace, group, string(kind), string(backendRef.Name), namespace); err != nil { return serviceName, nil, &metav1.Condition{ Type: string(gatev1.RouteConditionResolvedRefs), Status: metav1.ConditionFalse, diff --git a/pkg/provider/kubernetes/gateway/httproute.go b/pkg/provider/kubernetes/gateway/httproute.go index ed4efc659..685a6fbfd 100644 --- a/pkg/provider/kubernetes/gateway/httproute.go +++ b/pkg/provider/kubernetes/gateway/httproute.go @@ -158,7 +158,7 @@ func (p *Provider) loadHTTPRoute(ctx context.Context, listener gatewayListener, default: var serviceCondition *metav1.Condition - router.Service, serviceCondition = p.loadService(conf, routeKey, routeRule, route) + router.Service, serviceCondition = p.loadWRRService(conf, routerName, routeRule, route) if serviceCondition != nil { condition = *serviceCondition } @@ -173,7 +173,7 @@ func (p *Provider) loadHTTPRoute(ctx context.Context, listener gatewayListener, return conf, condition } -func (p *Provider) loadService(conf *dynamic.Configuration, routeKey string, routeRule gatev1.HTTPRouteRule, route *gatev1.HTTPRoute) (string, *metav1.Condition) { +func (p *Provider) loadWRRService(conf *dynamic.Configuration, routeKey string, routeRule gatev1.HTTPRouteRule, route *gatev1.HTTPRoute) (string, *metav1.Condition) { name := routeKey + "-wrr" if _, ok := conf.HTTP.Services[name]; ok { return name, nil @@ -182,7 +182,7 @@ func (p *Provider) loadService(conf *dynamic.Configuration, routeKey string, rou var wrr dynamic.WeightedRoundRobin var condition *metav1.Condition for _, backendRef := range routeRule.BackendRefs { - svcName, svc, errCondition := p.loadHTTPService(route, backendRef) + svcName, svc, errCondition := p.loadService(route, backendRef) weight := ptr.To(int(ptr.Deref(backendRef.Weight, 1))) if errCondition != nil { condition = errCondition @@ -208,10 +208,10 @@ func (p *Provider) loadService(conf *dynamic.Configuration, routeKey string, rou return name, condition } -// loadHTTPService returns a dynamic.Service config corresponding to the given gatev1.HTTPBackendRef. +// loadService returns a dynamic.Service config corresponding to the given gatev1.HTTPBackendRef. // Note that the returned dynamic.Service config can be nil (for cross-provider, internal services, and backendFunc). -func (p *Provider) loadHTTPService(route *gatev1.HTTPRoute, backendRef gatev1.HTTPBackendRef) (string, *dynamic.Service, *metav1.Condition) { - kind := ptr.Deref(backendRef.Kind, "Service") +func (p *Provider) loadService(route *gatev1.HTTPRoute, backendRef gatev1.HTTPBackendRef) (string, *dynamic.Service, *metav1.Condition) { + kind := ptr.Deref(backendRef.Kind, kindService) group := groupCore if backendRef.Group != nil && *backendRef.Group != "" { @@ -225,7 +225,7 @@ func (p *Provider) loadHTTPService(route *gatev1.HTTPRoute, backendRef gatev1.HT serviceName := provider.Normalize(namespace + "-" + string(backendRef.Name)) - if err := p.isReferenceGranted(groupGateway, kindHTTPRoute, route.Namespace, group, string(kind), string(backendRef.Name), namespace); err != nil { + if err := p.isReferenceGranted(kindHTTPRoute, route.Namespace, group, string(kind), string(backendRef.Name), namespace); err != nil { return serviceName, nil, &metav1.Condition{ Type: string(gatev1.RouteConditionResolvedRefs), Status: metav1.ConditionFalse, @@ -236,7 +236,7 @@ func (p *Provider) loadHTTPService(route *gatev1.HTTPRoute, backendRef gatev1.HT } } - if group != groupCore || kind != "Service" { + if group != groupCore || kind != kindService { name, service, err := p.loadHTTPBackendRef(namespace, backendRef) if err != nil { return serviceName, nil, &metav1.Condition{ diff --git a/pkg/provider/kubernetes/gateway/kubernetes.go b/pkg/provider/kubernetes/gateway/kubernetes.go index 7a65ea977..b8c878627 100644 --- a/pkg/provider/kubernetes/gateway/kubernetes.go +++ b/pkg/provider/kubernetes/gateway/kubernetes.go @@ -47,6 +47,7 @@ const ( kindGRPCRoute = "GRPCRoute" kindTCPRoute = "TCPRoute" kindTLSRoute = "TLSRoute" + kindService = "Service" ) // Provider holds configurations of the provider. @@ -376,11 +377,19 @@ func (p *Provider) loadConfigurationFromGateways(ctx context.Context) *dynamic.C } } - gatewayStatus, err := p.makeGatewayStatus(gateway, listeners, addresses) - if err != nil { + gatewayStatus, errConditions := p.makeGatewayStatus(gateway, listeners, addresses) + if len(errConditions) > 0 { + messages := map[string]struct{}{} + for _, condition := range errConditions { + messages[condition.Message] = struct{}{} + } + var conditionsErr error + for message := range messages { + conditionsErr = multierror.Append(conditionsErr, errors.New(message)) + } logger.Error(). - Err(err). - Msg("Unable to create Gateway status") + Err(conditionsErr). + Msg("Gateway Not Accepted") } if err = p.client.UpdateGatewayStatus(ctx, ktypes.NamespacedName{Name: gateway.Name, Namespace: gateway.Namespace}, gatewayStatus); err != nil { @@ -576,7 +585,7 @@ func (p *Provider) loadGatewayListeners(ctx context.Context, gateway *gatev1.Gat certificateNamespace = string(*certificateRef.Namespace) } - if err := p.isReferenceGranted(groupGateway, kindGateway, gateway.Namespace, groupCore, "Secret", string(certificateRef.Name), certificateNamespace); err != nil { + if err := p.isReferenceGranted(kindGateway, gateway.Namespace, groupCore, "Secret", string(certificateRef.Name), certificateNamespace); err != nil { gatewayListeners[i].Status.Conditions = append(gatewayListeners[i].Status.Conditions, metav1.Condition{ Type: string(gatev1.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, @@ -631,10 +640,10 @@ func (p *Provider) loadGatewayListeners(ctx context.Context, gateway *gatev1.Gat return gatewayListeners } -func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewayListener, addresses []gatev1.GatewayStatusAddress) (gatev1.GatewayStatus, error) { +func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewayListener, addresses []gatev1.GatewayStatusAddress) (gatev1.GatewayStatus, []metav1.Condition) { gatewayStatus := gatev1.GatewayStatus{Addresses: addresses} - var result error + var errorConditions []metav1.Condition for _, listener := range listeners { if len(listener.Status.Conditions) == 0 { listener.Status.Conditions = append(listener.Status.Conditions, @@ -669,14 +678,11 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa continue } - for _, condition := range listener.Status.Conditions { - result = multierror.Append(result, errors.New(condition.Message)) - } - + errorConditions = append(errorConditions, listener.Status.Conditions...) gatewayStatus.Listeners = append(gatewayStatus.Listeners, *listener.Status) } - if result != nil { + if len(errorConditions) > 0 { // GatewayConditionReady "Ready", GatewayConditionReason "ListenersNotValid" gatewayStatus.Conditions = append(gatewayStatus.Conditions, metav1.Condition{ Type: string(gatev1.GatewayConditionAccepted), @@ -687,7 +693,7 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa Message: "All Listeners must be valid", }) - return gatewayStatus, result + return gatewayStatus, errorConditions } gatewayStatus.Conditions = append(gatewayStatus.Conditions, @@ -783,7 +789,7 @@ func (p *Provider) entryPointName(port gatev1.PortNumber, protocol gatev1.Protoc return "", fmt.Errorf("no matching entryPoint for port %d and protocol %q", port, protocol) } -func (p *Provider) isReferenceGranted(fromGroup, fromKind, fromNamespace, toGroup, toKind, toName, toNamespace string) error { +func (p *Provider) isReferenceGranted(fromKind, fromNamespace, toGroup, toKind, toName, toNamespace string) error { if toNamespace == fromNamespace { return nil } @@ -793,7 +799,7 @@ func (p *Provider) isReferenceGranted(fromGroup, fromKind, fromNamespace, toGrou return fmt.Errorf("listing ReferenceGrant: %w", err) } - refGrants = filterReferenceGrantsFrom(refGrants, fromGroup, fromKind, fromNamespace) + refGrants = filterReferenceGrantsFrom(refGrants, groupGateway, fromKind, fromNamespace) refGrants = filterReferenceGrantsTo(refGrants, toGroup, toKind, toName) if len(refGrants) == 0 { return errors.New("missing ReferenceGrant") diff --git a/pkg/provider/kubernetes/gateway/kubernetes_test.go b/pkg/provider/kubernetes/gateway/kubernetes_test.go index 414a85f19..79750f4c8 100644 --- a/pkg/provider/kubernetes/gateway/kubernetes_test.go +++ b/pkg/provider/kubernetes/gateway/kubernetes_test.go @@ -181,7 +181,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, { - desc: "Empty caused by multi ports service with wrong TargetPort", + desc: "Router with service in error caused by wrong TargetPort", entryPoints: map[string]Entrypoint{"web": { Address: ":80", }}, @@ -201,7 +201,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"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`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -209,7 +209,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -570,7 +570,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"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`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -578,7 +578,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -665,7 +665,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-websecure-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"websecure"}, - Service: "default-http-app-1-my-gateway-websecure-0-wrr", + Service: "default-http-app-1-my-gateway-websecure-0-1c0cf64bde37d9d0df06-wrr", Rule: "Host(`foo.com`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -674,7 +674,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-websecure-0-wrr": { + "default-http-app-1-my-gateway-websecure-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -736,7 +736,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-66e726cd8903b49727ae": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-66e726cd8903b49727ae-wrr", Rule: "(Host(`foo.com`) || Host(`bar.com`)) && PathPrefix(`/`)", Priority: 9, RuleSyntax: "v3", @@ -744,7 +744,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-66e726cd8903b49727ae-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -797,7 +797,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-baa117c0219e3878749f": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-baa117c0219e3878749f-wrr", Rule: "(Host(`foo.com`) || HostRegexp(`^[a-z0-9-\\.]+\\.bar\\.com$`)) && PathPrefix(`/`)", Priority: 11, RuleSyntax: "v3", @@ -805,7 +805,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-baa117c0219e3878749f-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -858,7 +858,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-45eba2eaf40ac792e036": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-45eba2eaf40ac792e036-wrr", Rule: "(Host(`foo.com`) || HostRegexp(`^[a-z0-9-\\.]+\\.foo\\.com$`)) && PathPrefix(`/`)", Priority: 11, RuleSyntax: "v3", @@ -866,7 +866,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-45eba2eaf40ac792e036-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -922,19 +922,19 @@ func TestLoadHTTPRoutes(t *testing.T) { Rule: "Host(`foo.com`) && Path(`/bar`)", Priority: 100009, RuleSyntax: "v3", - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr", }, "default-http-app-1-my-gateway-web-1-d737b4933fa88e68ab8a": { EntryPoints: []string{"web"}, Rule: "Host(`foo.com`) && Path(`/bir`)", Priority: 100008, RuleSyntax: "v3", - Service: "default-http-app-1-my-gateway-web-1-wrr", + Service: "default-http-app-1-my-gateway-web-1-d737b4933fa88e68ab8a-wrr", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -944,7 +944,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "default-http-app-1-my-gateway-web-1-wrr": { + "default-http-app-1-my-gateway-web-1-d737b4933fa88e68ab8a-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1016,12 +1016,12 @@ func TestLoadHTTPRoutes(t *testing.T) { Rule: "Host(`foo.com`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1099,14 +1099,14 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-http-web-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-http-web-0-wrr", + Service: "default-http-app-1-my-gateway-http-web-0-1c0cf64bde37d9d0df06-wrr", Rule: "Host(`foo.com`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", }, "default-http-app-1-my-gateway-https-websecure-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"websecure"}, - Service: "default-http-app-1-my-gateway-https-websecure-0-wrr", + Service: "default-http-app-1-my-gateway-https-websecure-0-1c0cf64bde37d9d0df06-wrr", Rule: "Host(`foo.com`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -1115,7 +1115,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-http-web-0-wrr": { + "default-http-app-1-my-gateway-http-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1125,7 +1125,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "default-http-app-1-my-gateway-https-websecure-0-wrr": { + "default-http-app-1-my-gateway-https-websecure-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1192,14 +1192,14 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"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`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", }, "default-http-app-1-my-gateway-websecure-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"websecure"}, - Service: "default-http-app-1-my-gateway-websecure-0-wrr", + Service: "default-http-app-1-my-gateway-websecure-0-1c0cf64bde37d9d0df06-wrr", Rule: "Host(`foo.com`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -1208,7 +1208,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1218,7 +1218,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "default-http-app-1-my-gateway-websecure-0-wrr": { + "default-http-app-1-my-gateway-websecure-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1283,26 +1283,26 @@ func TestLoadHTTPRoutes(t *testing.T) { Rule: "Host(`foo.com`) && (Path(`/bar`) || PathPrefix(`/bar/`)) && Header(`my-header`,`foo`) && Header(`my-header2`,`bar`)", Priority: 10610, RuleSyntax: "v3", - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-6cf37fa71907768d925c-wrr", }, "default-http-app-1-my-gateway-web-2-d23f7039bc8036fb918c": { EntryPoints: []string{"web"}, Rule: "Host(`foo.com`) && PathRegexp(`^/buzz/[0-9]+$`)", Priority: 11408, RuleSyntax: "v3", - Service: "default-http-app-1-my-gateway-web-2-wrr", + Service: "default-http-app-1-my-gateway-web-2-d23f7039bc8036fb918c-wrr", }, "default-http-app-1-my-gateway-web-1-aaba0f24fd26e1ca2276": { EntryPoints: []string{"web"}, Rule: "Host(`foo.com`) && Path(`/bar`) && Header(`my-header`,`bar`)", Priority: 100109, RuleSyntax: "v3", - Service: "default-http-app-1-my-gateway-web-1-wrr", + Service: "default-http-app-1-my-gateway-web-1-aaba0f24fd26e1ca2276-wrr", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-6cf37fa71907768d925c-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1312,7 +1312,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "default-http-app-1-my-gateway-web-2-wrr": { + "default-http-app-1-my-gateway-web-2-d23f7039bc8036fb918c-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1322,7 +1322,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "default-http-app-1-my-gateway-web-1-wrr": { + "default-http-app-1-my-gateway-web-1-aaba0f24fd26e1ca2276-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1378,12 +1378,12 @@ func TestLoadHTTPRoutes(t *testing.T) { Rule: "Host(`foo.com`) && (Path(`/foo`) || PathPrefix(`/foo/`)) && Method(`GET`)", Priority: 11408, RuleSyntax: "v3", - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-74ad70a7cf090becdd3c-wrr", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-74ad70a7cf090becdd3c-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1439,12 +1439,12 @@ func TestLoadHTTPRoutes(t *testing.T) { Rule: "Host(`foo.com`) && (Path(`/foo`) || PathPrefix(`/foo/`)) && Query(`foo`,`bar`) && QueryRegexp(`baz`,`buz`)", Priority: 10428, RuleSyntax: "v3", - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-bb7b03c9610e982fd627-wrr", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-bb7b03c9610e982fd627-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1497,7 +1497,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-default-my-gateway-web-0-efde1997778109a1f6eb": { EntryPoints: []string{"web"}, - Service: "default-http-app-default-my-gateway-web-0-wrr", + Service: "default-http-app-default-my-gateway-web-0-efde1997778109a1f6eb-wrr", Rule: "Host(`foo.com`) && Path(`/foo`)", Priority: 100008, RuleSyntax: "v3", @@ -1505,7 +1505,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-default-my-gateway-web-0-wrr": { + "default-http-app-default-my-gateway-web-0-efde1997778109a1f6eb-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1558,14 +1558,14 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-default-my-gateway-web-0-efde1997778109a1f6eb": { EntryPoints: []string{"web"}, - Service: "default-http-app-default-my-gateway-web-0-wrr", + Service: "default-http-app-default-my-gateway-web-0-efde1997778109a1f6eb-wrr", Rule: "Host(`foo.com`) && Path(`/foo`)", Priority: 100008, RuleSyntax: "v3", }, "bar-http-app-bar-my-gateway-web-0-66f5c78d03d948e36597": { EntryPoints: []string{"web"}, - Service: "bar-http-app-bar-my-gateway-web-0-wrr", + Service: "bar-http-app-bar-my-gateway-web-0-66f5c78d03d948e36597-wrr", Rule: "Host(`bar.com`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -1573,7 +1573,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-default-my-gateway-web-0-wrr": { + "default-http-app-default-my-gateway-web-0-efde1997778109a1f6eb-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1583,7 +1583,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "bar-http-app-bar-my-gateway-web-0-wrr": { + "bar-http-app-bar-my-gateway-web-0-66f5c78d03d948e36597-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1652,7 +1652,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "bar-http-app-bar-my-gateway-web-0-66f5c78d03d948e36597": { EntryPoints: []string{"web"}, - Service: "bar-http-app-bar-my-gateway-web-0-wrr", + Service: "bar-http-app-bar-my-gateway-web-0-66f5c78d03d948e36597-wrr", Rule: "Host(`bar.com`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -1660,7 +1660,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "bar-http-app-bar-my-gateway-web-0-wrr": { + "bar-http-app-bar-my-gateway-web-0-66f5c78d03d948e36597-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1713,7 +1713,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-wrr", Rule: "Host(`example.org`) && PathPrefix(`/`)", Priority: 13, RuleSyntax: "v3", @@ -1730,7 +1730,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1783,7 +1783,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-wrr", Rule: "Host(`example.org`) && PathPrefix(`/`)", Priority: 13, RuleSyntax: "v3", @@ -1800,7 +1800,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1853,7 +1853,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-wrr", Rule: "Host(`example.org`) && PathPrefix(`/`)", Priority: 13, RuleSyntax: "v3", @@ -1870,7 +1870,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-wrr": { Weighted: &dynamic.WeightedRoundRobin{}, }, }, @@ -1900,7 +1900,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-wrr", Rule: "Host(`example.org`) && PathPrefix(`/`)", Priority: 13, RuleSyntax: "v3", @@ -1917,7 +1917,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-wrr": { Weighted: &dynamic.WeightedRoundRobin{}, }, }, @@ -1947,7 +1947,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-wrr", Rule: "Host(`example.com`) && (Path(`/foo`) || PathPrefix(`/foo/`))", RuleSyntax: "v3", Priority: 10412, @@ -1962,7 +1962,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2015,7 +2015,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-wrr", Rule: "Host(`example.com`) && (Path(`/foo`) || PathPrefix(`/foo/`))", RuleSyntax: "v3", Priority: 10412, @@ -2030,7 +2030,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2083,7 +2083,7 @@ func TestLoadHTTPRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-wrr", Rule: "Host(`example.com`) && (Path(`/foo`) || PathPrefix(`/foo/`))", RuleSyntax: "v3", Priority: 10412, @@ -2100,7 +2100,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2203,7 +2203,7 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"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`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -2211,7 +2211,7 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2253,7 +2253,7 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"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`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -2261,7 +2261,7 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2305,7 +2305,7 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"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`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -2313,7 +2313,7 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2356,7 +2356,7 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"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`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -2364,7 +2364,7 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2408,7 +2408,7 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"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`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -2416,7 +2416,7 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2525,7 +2525,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"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`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -2534,7 +2534,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2591,7 +2591,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": { EntryPoints: []string{"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`) && Path(`/bar`)", Priority: 100008, RuleSyntax: "v3", @@ -2602,7 +2602,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) { "default-my-middleware": {Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}}, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2931,7 +2931,7 @@ func TestLoadTCPRoutes(t *testing.T) { }, }, { - desc: "Empty caused by multi ports service with wrong TargetPort", + desc: "Router with service in error caused by wrong TargetPort", entryPoints: map[string]Entrypoint{"TCP": { Address: ":8080", }}, @@ -2942,9 +2942,30 @@ func TestLoadTCPRoutes(t *testing.T) { Services: map[string]*dynamic.UDPService{}, }, TCP: &dynamic.TCPConfiguration{ - Routers: map[string]*dynamic.TCPRouter{}, - Middlewares: map[string]*dynamic.TCPMiddleware{}, - Services: map[string]*dynamic.TCPService{}, + Routers: map[string]*dynamic.TCPRouter{ + "default-TCP-app-1-my-gateway-TCP-0-e3b0c44298fc1c149afb": { + EntryPoints: []string{"TCP"}, + Rule: "HostSNI(`*`)", + RuleSyntax: "v3", + Service: "default-TCP-app-1-my-gateway-TCP-0-e3b0c44298fc1c149afb-wrr", + }, + }, + Middlewares: map[string]*dynamic.TCPMiddleware{}, + Services: map[string]*dynamic.TCPService{ + "default-TCP-app-1-my-gateway-TCP-0-e3b0c44298fc1c149afb-wrr": { + Weighted: &dynamic.TCPWeightedRoundRobin{ + Services: []dynamic.TCPWRRService{{ + Name: "default-TCP-app-1-my-gateway-TCP-0-e3b0c44298fc1c149afb-err-lb", + Weight: ptr.To(1), + }}, + }, + }, + "default-TCP-app-1-my-gateway-TCP-0-e3b0c44298fc1c149afb-err-lb": { + LoadBalancer: &dynamic.TCPServersLoadBalancer{ + Servers: []dynamic.TCPServer{}, + }, + }, + }, ServersTransports: map[string]*dynamic.TCPServersTransport{}, }, HTTP: &dynamic.HTTPConfiguration{ @@ -2969,16 +2990,16 @@ func TestLoadTCPRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-1-my-tcp-gateway-tcp": { + "default-tcp-app-1-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tcp-app-1-my-tcp-gateway-tcp-wrr-0", + Service: "default-tcp-app-1-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-1-my-tcp-gateway-tcp-wrr-0": { + "default-tcp-app-1-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3027,22 +3048,22 @@ func TestLoadTCPRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-1-my-tcp-gateway-tcp-1": { + "default-tcp-app-1-my-tcp-gateway-tcp-1-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp-1"}, - Service: "default-tcp-app-1-my-tcp-gateway-tcp-1-wrr-0", + Service: "default-tcp-app-1-my-tcp-gateway-tcp-1-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, - "default-tcp-app-2-my-tcp-gateway-tcp-2": { + "default-tcp-app-2-my-tcp-gateway-tcp-2-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp-2"}, - Service: "default-tcp-app-2-my-tcp-gateway-tcp-2-wrr-0", + Service: "default-tcp-app-2-my-tcp-gateway-tcp-2-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-1-my-tcp-gateway-tcp-1-wrr-0": { + "default-tcp-app-1-my-tcp-gateway-tcp-1-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3052,7 +3073,7 @@ func TestLoadTCPRoutes(t *testing.T) { }, }, }, - "default-tcp-app-2-my-tcp-gateway-tcp-2-wrr-0": { + "default-tcp-app-2-my-tcp-gateway-tcp-2-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3113,30 +3134,22 @@ func TestLoadTCPRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-my-tcp-gateway-tcp-1": { + "default-tcp-app-my-tcp-gateway-tcp-1-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp-1"}, - Service: "default-tcp-app-my-tcp-gateway-tcp-1-wrr", + Service: "default-tcp-app-my-tcp-gateway-tcp-1-0-e3b0c44298fc1c149afb-wrr", + Rule: "HostSNI(`*`)", + RuleSyntax: "v3", + }, + "default-tcp-app-my-tcp-gateway-tcp-1-1-e3b0c44298fc1c149afb": { + EntryPoints: []string{"tcp-1"}, + Service: "default-tcp-app-my-tcp-gateway-tcp-1-1-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-my-tcp-gateway-tcp-1-wrr": { - Weighted: &dynamic.TCPWeightedRoundRobin{ - Services: []dynamic.TCPWRRService{ - { - Name: "default-tcp-app-my-tcp-gateway-tcp-1-wrr-0", - Weight: ptr.To(1), - }, - { - Name: "default-tcp-app-my-tcp-gateway-tcp-1-wrr-1", - Weight: ptr.To(1), - }, - }, - }, - }, - "default-tcp-app-my-tcp-gateway-tcp-1-wrr-0": { + "default-tcp-app-my-tcp-gateway-tcp-1-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3146,7 +3159,7 @@ func TestLoadTCPRoutes(t *testing.T) { }, }, }, - "default-tcp-app-my-tcp-gateway-tcp-1-wrr-1": { + "default-tcp-app-my-tcp-gateway-tcp-1-1-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3205,16 +3218,16 @@ func TestLoadTCPRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-1-my-gateway-tcp": { + "default-tcp-app-1-my-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tcp-app-1-my-gateway-tcp-wrr-0", + Service: "default-tcp-app-1-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-1-my-gateway-tcp-wrr-0": { + "default-tcp-app-1-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3265,9 +3278,9 @@ func TestLoadTCPRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-1-my-gateway-tls": { + "default-tcp-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "default-tcp-app-1-my-gateway-tls-wrr-0", + Service: "default-tcp-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{}, @@ -3275,7 +3288,7 @@ func TestLoadTCPRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-1-my-gateway-tls-wrr-0": { + "default-tcp-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{{ Name: "default-whoamitcp-9000", @@ -3329,16 +3342,16 @@ func TestLoadTCPRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-default-my-tcp-gateway-tcp": { + "default-tcp-app-default-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tcp-app-default-my-tcp-gateway-tcp-wrr-0", + Service: "default-tcp-app-default-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-default-my-tcp-gateway-tcp-wrr-0": { + "default-tcp-app-default-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3385,22 +3398,22 @@ func TestLoadTCPRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-default-my-tcp-gateway-tcp": { + "default-tcp-app-default-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tcp-app-default-my-tcp-gateway-tcp-wrr-0", + Service: "default-tcp-app-default-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, - "bar-tcp-app-bar-my-tcp-gateway-tcp": { + "bar-tcp-app-bar-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "bar-tcp-app-bar-my-tcp-gateway-tcp-wrr-0", + Service: "bar-tcp-app-bar-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-default-my-tcp-gateway-tcp-wrr-0": { + "default-tcp-app-default-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3410,7 +3423,7 @@ func TestLoadTCPRoutes(t *testing.T) { }, }, }, - "bar-tcp-app-bar-my-tcp-gateway-tcp-wrr-0": { + "bar-tcp-app-bar-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3469,16 +3482,16 @@ func TestLoadTCPRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "bar-tcp-app-bar-my-tcp-gateway-tcp": { + "bar-tcp-app-bar-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "bar-tcp-app-bar-my-tcp-gateway-tcp-wrr-0", + Service: "bar-tcp-app-bar-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "bar-tcp-app-bar-my-tcp-gateway-tcp-wrr-0": { + "bar-tcp-app-bar-my-tcp-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3685,7 +3698,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, }, { - desc: "Empty caused by multi ports service with wrong TargetPort", + desc: "Router with service in error caused by wrong TargetPort", entryPoints: map[string]Entrypoint{"TCP": { Address: ":8080", }}, @@ -3696,9 +3709,31 @@ func TestLoadTLSRoutes(t *testing.T) { Services: map[string]*dynamic.UDPService{}, }, TCP: &dynamic.TCPConfiguration{ - Routers: map[string]*dynamic.TCPRouter{}, - Middlewares: map[string]*dynamic.TCPMiddleware{}, - Services: map[string]*dynamic.TCPService{}, + Routers: map[string]*dynamic.TCPRouter{ + "default-tls-app-1-my-gateway-TCP-0-e3b0c44298fc1c149afb": { + EntryPoints: []string{"TCP"}, + Rule: "HostSNI(`*`)", + RuleSyntax: "v3", + Service: "default-tls-app-1-my-gateway-TCP-0-e3b0c44298fc1c149afb-wrr", + TLS: &dynamic.RouterTCPTLSConfig{}, + }, + }, + Middlewares: map[string]*dynamic.TCPMiddleware{}, + Services: map[string]*dynamic.TCPService{ + "default-tls-app-1-my-gateway-TCP-0-e3b0c44298fc1c149afb-wrr": { + Weighted: &dynamic.TCPWeightedRoundRobin{ + Services: []dynamic.TCPWRRService{{ + Name: "default-tls-app-1-my-gateway-TCP-0-e3b0c44298fc1c149afb-err-lb", + Weight: ptr.To(1), + }}, + }, + }, + "default-tls-app-1-my-gateway-TCP-0-e3b0c44298fc1c149afb-err-lb": { + LoadBalancer: &dynamic.TCPServersLoadBalancer{ + Servers: []dynamic.TCPServer{}, + }, + }, + }, ServersTransports: map[string]*dynamic.TCPServersTransport{}, }, HTTP: &dynamic.HTTPConfiguration{ @@ -3766,9 +3801,9 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-1-my-tls-gateway-tcp": { + "default-tcp-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tcp-app-1-my-tls-gateway-tcp-wrr-0", + Service: "default-tcp-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{}, @@ -3776,7 +3811,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-1-my-tls-gateway-tcp-wrr-0": { + "default-tcp-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3832,9 +3867,9 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-1-my-tls-gateway-tcp": { + "default-tcp-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tcp-app-1-my-tls-gateway-tcp-wrr-0", + Service: "default-tcp-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -3844,7 +3879,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-1-my-tls-gateway-tcp-wrr-0": { + "default-tcp-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3891,9 +3926,9 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tls-app-1-my-tls-gateway-tcp-f0dd0dd89f82eae1c270": { + "default-tls-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tls-app-1-my-tls-gateway-tcp-f0dd0dd89f82eae1c270-wrr-0", + Service: "default-tls-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -3903,7 +3938,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tls-app-1-my-tls-gateway-tcp-f0dd0dd89f82eae1c270-wrr-0": { + "default-tls-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3951,16 +3986,16 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-1-my-tls-gateway-tls": { + "default-tcp-app-1-my-tls-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "default-tcp-app-1-my-tls-gateway-tls-wrr-0", + Service: "default-tcp-app-1-my-tls-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{}, }, - "default-tls-app-1-my-tls-gateway-tcp-673acf455cb2dab0b43a": { + "default-tls-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tls-app-1-my-tls-gateway-tcp-673acf455cb2dab0b43a-wrr-0", + Service: "default-tls-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -3970,7 +4005,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-1-my-tls-gateway-tls-wrr-0": { + "default-tcp-app-1-my-tls-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -3980,7 +4015,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, }, }, - "default-tls-app-1-my-tls-gateway-tcp-673acf455cb2dab0b43a-wrr-0": { + "default-tls-app-1-my-tls-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4048,9 +4083,9 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-1-my-gateway-tls": { + "default-tcp-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "default-tcp-app-1-my-gateway-tls-wrr-0", + Service: "default-tcp-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{}, @@ -4058,7 +4093,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-1-my-gateway-tls-wrr-0": { + "default-tcp-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4118,9 +4153,9 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270": { + "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0", + Service: "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -4130,7 +4165,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0": { + "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4177,9 +4212,9 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270": { + "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0", + Service: "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -4189,7 +4224,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0": { + "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4236,9 +4271,9 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270": { + "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0", + Service: "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -4248,7 +4283,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0": { + "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4295,9 +4330,9 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tls-app-1-my-gateway-tls-d5342d75658583f03593": { + "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "default-tls-app-1-my-gateway-tls-d5342d75658583f03593-wrr-0", + Service: "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`foo.example.com`) || HostSNI(`bar.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -4307,7 +4342,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tls-app-1-my-gateway-tls-d5342d75658583f03593-wrr-0": { + "default-tls-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4354,9 +4389,9 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5": { + "default-tls-app-default-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0", + Service: "default-tls-app-default-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`foo.default`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -4366,7 +4401,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0": { + "default-tls-app-default-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4413,18 +4448,18 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5": { + "default-tls-app-default-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0", + Service: "default-tls-app-default-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`foo.default`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ Passthrough: true, }, }, - "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26": { + "bar-tls-app-bar-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0", + Service: "bar-tls-app-bar-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`foo.bar`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -4434,7 +4469,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0": { + "default-tls-app-default-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4444,7 +4479,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, }, }, - "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0": { + "bar-tls-app-bar-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4503,9 +4538,9 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26": { + "bar-tls-app-bar-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0", + Service: "bar-tls-app-bar-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`foo.bar`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -4515,7 +4550,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0": { + "bar-tls-app-bar-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4562,9 +4597,18 @@ func TestLoadTLSRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a": { + "default-tls-app-my-gateway-tcp-1-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp-1"}, - Service: "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr", + Service: "default-tls-app-my-gateway-tcp-1-0-e3b0c44298fc1c149afb-wrr", + Rule: "HostSNI(`*`)", + RuleSyntax: "v3", + TLS: &dynamic.RouterTCPTLSConfig{ + Passthrough: true, + }, + }, + "default-tls-app-my-gateway-tcp-1-1-e3b0c44298fc1c149afb": { + EntryPoints: []string{"tcp-1"}, + Service: "default-tls-app-my-gateway-tcp-1-1-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -4574,21 +4618,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr": { - Weighted: &dynamic.TCPWeightedRoundRobin{ - Services: []dynamic.TCPWRRService{ - { - Name: "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr-0", - Weight: ptr.To(1), - }, - { - Name: "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr-1", - Weight: ptr.To(1), - }, - }, - }, - }, - "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr-0": { + "default-tls-app-my-gateway-tcp-1-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4598,7 +4628,7 @@ func TestLoadTLSRoutes(t *testing.T) { }, }, }, - "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr-1": { + "default-tls-app-my-gateway-tcp-1-1-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4809,22 +4839,22 @@ func TestLoadMixedRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-1-my-gateway-tcp": { + "default-tcp-app-1-my-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tcp-app-1-my-gateway-tcp-wrr-0", + Service: "default-tcp-app-1-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, - "default-tcp-app-1-my-gateway-tls-1": { + "default-tcp-app-1-my-gateway-tls-1-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-1"}, - Service: "default-tcp-app-1-my-gateway-tls-1-wrr-0", + Service: "default-tcp-app-1-my-gateway-tls-1-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{}, }, - "default-tls-app-1-my-gateway-tls-2-59130f7db6718b7700c1": { + "default-tls-app-1-my-gateway-tls-2-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-2"}, - Service: "default-tls-app-1-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0", + Service: "default-tls-app-1-my-gateway-tls-2-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`pass.tls.foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -4834,7 +4864,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-1-my-gateway-tcp-wrr-0": { + "default-tcp-app-1-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4844,7 +4874,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "default-tcp-app-1-my-gateway-tls-1-wrr-0": { + "default-tcp-app-1-my-gateway-tls-1-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4854,7 +4884,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "default-tls-app-1-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0": { + "default-tls-app-1-my-gateway-tls-2-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -4883,14 +4913,14 @@ func TestLoadMixedRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-1-my-gateway-web-0-a431b128267aabc954fd": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-0-wrr", + Service: "default-http-app-1-my-gateway-web-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", }, "default-http-app-1-my-gateway-websecure-0-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, - Service: "default-http-app-1-my-gateway-websecure-0-wrr", + Service: "default-http-app-1-my-gateway-websecure-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", @@ -4899,7 +4929,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-0-wrr": { + "default-http-app-1-my-gateway-web-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -4909,7 +4939,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "default-http-app-1-my-gateway-websecure-0-wrr": { + "default-http-app-1-my-gateway-websecure-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -4996,22 +5026,22 @@ func TestLoadMixedRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-default-my-gateway-tcp": { + "default-tcp-app-default-my-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tcp-app-default-my-gateway-tcp-wrr-0", + Service: "default-tcp-app-default-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, - "default-tcp-app-default-my-gateway-tls-1": { + "default-tcp-app-default-my-gateway-tls-1-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-1"}, - Service: "default-tcp-app-default-my-gateway-tls-1-wrr-0", + Service: "default-tcp-app-default-my-gateway-tls-1-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{}, }, - "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1": { + "default-tls-app-default-my-gateway-tls-2-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-2"}, - Service: "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0", + Service: "default-tls-app-default-my-gateway-tls-2-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`pass.tls.foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5021,7 +5051,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-default-my-gateway-tcp-wrr-0": { + "default-tcp-app-default-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5031,7 +5061,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "default-tcp-app-default-my-gateway-tls-1-wrr-0": { + "default-tcp-app-default-my-gateway-tls-1-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5041,7 +5071,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0": { + "default-tls-app-default-my-gateway-tls-2-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5070,14 +5100,14 @@ func TestLoadMixedRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-default-my-gateway-web-0-a431b128267aabc954fd": { EntryPoints: []string{"web"}, - Service: "default-http-app-default-my-gateway-web-0-wrr", + Service: "default-http-app-default-my-gateway-web-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", }, "default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, - Service: "default-http-app-default-my-gateway-websecure-0-wrr", + Service: "default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", @@ -5086,7 +5116,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-default-my-gateway-web-0-wrr": { + "default-http-app-default-my-gateway-web-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -5096,7 +5126,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "default-http-app-default-my-gateway-websecure-0-wrr": { + "default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -5155,37 +5185,37 @@ func TestLoadMixedRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-default-my-gateway-tcp": { + "default-tcp-app-default-my-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tcp-app-default-my-gateway-tcp-wrr-0", + Service: "default-tcp-app-default-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, - "default-tcp-app-default-my-gateway-tls-1": { + "default-tcp-app-default-my-gateway-tls-1-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-1"}, - Service: "default-tcp-app-default-my-gateway-tls-1-wrr-0", + Service: "default-tcp-app-default-my-gateway-tls-1-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{}, }, - "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1": { + "default-tls-app-default-my-gateway-tls-2-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-2"}, - Service: "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0", + Service: "default-tls-app-default-my-gateway-tls-2-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`pass.tls.foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ Passthrough: true, }, }, - "bar-tcp-app-bar-my-gateway-tcp": { + "bar-tcp-app-bar-my-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "bar-tcp-app-bar-my-gateway-tcp-wrr-0", + Service: "bar-tcp-app-bar-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, - "bar-tcp-app-bar-my-gateway-tls-1": { + "bar-tcp-app-bar-my-gateway-tls-1-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-1"}, - Service: "bar-tcp-app-bar-my-gateway-tls-1-wrr-0", + Service: "bar-tcp-app-bar-my-gateway-tls-1-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{}, @@ -5193,7 +5223,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-default-my-gateway-tcp-wrr-0": { + "default-tcp-app-default-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5203,7 +5233,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "default-tcp-app-default-my-gateway-tls-1-wrr-0": { + "default-tcp-app-default-my-gateway-tls-1-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5213,7 +5243,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0": { + "default-tls-app-default-my-gateway-tls-2-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5247,7 +5277,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "bar-tcp-app-bar-my-gateway-tcp-wrr-0": { + "bar-tcp-app-bar-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5257,7 +5287,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "bar-tcp-app-bar-my-gateway-tls-1-wrr-0": { + "bar-tcp-app-bar-my-gateway-tls-1-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5274,14 +5304,14 @@ func TestLoadMixedRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-default-my-gateway-web-0-a431b128267aabc954fd": { EntryPoints: []string{"web"}, - Service: "default-http-app-default-my-gateway-web-0-wrr", + Service: "default-http-app-default-my-gateway-web-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", }, "default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, - Service: "default-http-app-default-my-gateway-websecure-0-wrr", + Service: "default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", @@ -5289,14 +5319,14 @@ func TestLoadMixedRoutes(t *testing.T) { }, "bar-http-app-bar-my-gateway-web-0-a431b128267aabc954fd": { EntryPoints: []string{"web"}, - Service: "bar-http-app-bar-my-gateway-web-0-wrr", + Service: "bar-http-app-bar-my-gateway-web-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", }, "bar-http-app-bar-my-gateway-websecure-0-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, - Service: "bar-http-app-bar-my-gateway-websecure-0-wrr", + Service: "bar-http-app-bar-my-gateway-websecure-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", @@ -5305,7 +5335,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-default-my-gateway-web-0-wrr": { + "default-http-app-default-my-gateway-web-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -5315,7 +5345,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "default-http-app-default-my-gateway-websecure-0-wrr": { + "default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -5357,7 +5387,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "bar-http-app-bar-my-gateway-web-0-wrr": { + "bar-http-app-bar-my-gateway-web-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -5367,7 +5397,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "bar-http-app-bar-my-gateway-websecure-0-wrr": { + "bar-http-app-bar-my-gateway-websecure-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -5410,22 +5440,22 @@ func TestLoadMixedRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "bar-tcp-app-bar-my-gateway-tcp": { + "bar-tcp-app-bar-my-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "bar-tcp-app-bar-my-gateway-tcp-wrr-0", + Service: "bar-tcp-app-bar-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, - "bar-tcp-app-bar-my-gateway-tls-1": { + "bar-tcp-app-bar-my-gateway-tls-1-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-1"}, - Service: "bar-tcp-app-bar-my-gateway-tls-1-wrr-0", + Service: "bar-tcp-app-bar-my-gateway-tls-1-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{}, }, - "bar-tls-app-bar-my-gateway-tls-2-59130f7db6718b7700c1": { + "bar-tls-app-bar-my-gateway-tls-2-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-2"}, - Service: "bar-tls-app-bar-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0", + Service: "bar-tls-app-bar-my-gateway-tls-2-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`pass.tls.foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5447,7 +5477,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "bar-tcp-app-bar-my-gateway-tcp-wrr-0": { + "bar-tcp-app-bar-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5457,7 +5487,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "bar-tcp-app-bar-my-gateway-tls-1-wrr-0": { + "bar-tcp-app-bar-my-gateway-tls-1-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5467,7 +5497,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "bar-tls-app-bar-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0": { + "bar-tls-app-bar-my-gateway-tls-2-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5484,14 +5514,14 @@ func TestLoadMixedRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "bar-http-app-bar-my-gateway-web-0-a431b128267aabc954fd": { EntryPoints: []string{"web"}, - Service: "bar-http-app-bar-my-gateway-web-0-wrr", + Service: "bar-http-app-bar-my-gateway-web-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", }, "bar-http-app-bar-my-gateway-websecure-0-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, - Service: "bar-http-app-bar-my-gateway-websecure-0-wrr", + Service: "bar-http-app-bar-my-gateway-websecure-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", @@ -5516,7 +5546,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "bar-http-app-bar-my-gateway-web-0-wrr": { + "bar-http-app-bar-my-gateway-web-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -5526,7 +5556,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "bar-http-app-bar-my-gateway-websecure-0-wrr": { + "bar-http-app-bar-my-gateway-websecure-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -5568,15 +5598,15 @@ func TestLoadMixedRoutes(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-default-my-gateway-tcp": { + "default-tcp-app-default-my-gateway-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, - Service: "default-tcp-app-default-my-gateway-tcp-wrr-0", + Service: "default-tcp-app-default-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", }, - "default-tcp-app-default-my-gateway-tls": { + "default-tcp-app-default-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "default-tcp-app-default-my-gateway-tls-wrr-0", + Service: "default-tcp-app-default-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{}, @@ -5584,7 +5614,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-default-my-gateway-tcp-wrr-0": { + "default-tcp-app-default-my-gateway-tcp-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5594,7 +5624,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "default-tcp-app-default-my-gateway-tls-wrr-0": { + "default-tcp-app-default-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{ { @@ -5623,14 +5653,14 @@ func TestLoadMixedRoutes(t *testing.T) { Routers: map[string]*dynamic.Router{ "default-http-app-default-my-gateway-web-0-a431b128267aabc954fd": { EntryPoints: []string{"web"}, - Service: "default-http-app-default-my-gateway-web-0-wrr", + Service: "default-http-app-default-my-gateway-web-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", }, "default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, - Service: "default-http-app-default-my-gateway-websecure-0-wrr", + Service: "default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", Priority: 2, RuleSyntax: "v3", @@ -5639,7 +5669,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-default-my-gateway-web-0-wrr": { + "default-http-app-default-my-gateway-web-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -5649,7 +5679,7 @@ func TestLoadMixedRoutes(t *testing.T) { }, }, }, - "default-http-app-default-my-gateway-websecure-0-wrr": { + "default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -5851,9 +5881,9 @@ func TestLoadRoutesWithReferenceGrants(t *testing.T) { }, TCP: &dynamic.TCPConfiguration{ Routers: map[string]*dynamic.TCPRouter{ - "default-tcp-app-1-my-gateway-tls": { + "default-tcp-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, - Service: "default-tcp-app-1-my-gateway-tls-wrr-0", + Service: "default-tcp-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr", Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{}, @@ -5861,7 +5891,7 @@ func TestLoadRoutesWithReferenceGrants(t *testing.T) { }, Middlewares: map[string]*dynamic.TCPMiddleware{}, Services: map[string]*dynamic.TCPService{ - "default-tcp-app-1-my-gateway-tls-wrr-0": { + "default-tcp-app-1-my-gateway-tls-0-e3b0c44298fc1c149afb-wrr": { Weighted: &dynamic.TCPWeightedRoundRobin{ Services: []dynamic.TCPWRRService{{ Name: "default-whoamitcp-9000", @@ -6002,14 +6032,14 @@ func TestLoadRoutesWithReferenceGrants(t *testing.T) { "default-http-app-1-my-gateway-http-0-d40286ed9f4652ca2108": { EntryPoints: []string{"http"}, Rule: "Host(`foo.example.com`) && PathPrefix(`/`)", - Service: "default-http-app-1-my-gateway-http-0-wrr", + Service: "default-http-app-1-my-gateway-http-0-d40286ed9f4652ca2108-wrr", RuleSyntax: "v3", Priority: 17, }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-http-0-wrr": { + "default-http-app-1-my-gateway-http-0-d40286ed9f4652ca2108-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { diff --git a/pkg/provider/kubernetes/gateway/tcproute.go b/pkg/provider/kubernetes/gateway/tcproute.go index 23e7bcd80..63b2e214c 100644 --- a/pkg/provider/kubernetes/gateway/tcproute.go +++ b/pkg/provider/kubernetes/gateway/tcproute.go @@ -6,6 +6,7 @@ import ( "fmt" "net" "strconv" + "strings" "github.com/rs/zerolog/log" "github.com/traefik/traefik/v3/pkg/config/dynamic" @@ -108,182 +109,241 @@ func (p *Provider) loadTCPRoute(listener gatewayListener, route *gatev1alpha2.TC Reason: string(gatev1.RouteConditionResolvedRefs), } - router := dynamic.TCPRouter{ - Rule: "HostSNI(`*`)", - EntryPoints: []string{listener.EPName}, - RuleSyntax: "v3", - } - - if listener.Protocol == gatev1.TLSProtocolType && listener.TLS != nil { - // TODO support let's encrypt - router.TLS = &dynamic.RouterTCPTLSConfig{ - Passthrough: listener.TLS.Mode != nil && *listener.TLS.Mode == gatev1.TLSModePassthrough, - } - } - - // Adding the gateway desc and the entryPoint desc prevents overlapping of routers build from the same routes. - routerName := provider.Normalize(route.Namespace + "-" + route.Name + "-" + listener.GWName + "-" + listener.EPName) - - var ruleServiceNames []string - for i, rule := range route.Spec.Rules { + for ri, rule := range route.Spec.Rules { if rule.BackendRefs == nil { // Should not happen due to validation. // https://github.com/kubernetes-sigs/gateway-api/blob/v0.4.0/apis/v1alpha2/tcproute_types.go#L76 continue } - wrrService, subServices, err := p.loadTCPServices(route.Namespace, rule.BackendRefs) - if err != nil { - return conf, metav1.Condition{ - Type: string(gatev1.RouteConditionResolvedRefs), - Status: metav1.ConditionFalse, - ObservedGeneration: route.Generation, - LastTransitionTime: metav1.Now(), - Reason: string(gatev1.RouteReasonBackendNotFound), - Message: fmt.Sprintf("Cannot load TCPRoute service %s/%s: %v", route.Namespace, route.Name, err), + router := dynamic.TCPRouter{ + Rule: "HostSNI(`*`)", + EntryPoints: []string{listener.EPName}, + RuleSyntax: "v3", + } + + if listener.Protocol == gatev1.TLSProtocolType && listener.TLS != nil { + router.TLS = &dynamic.RouterTCPTLSConfig{ + Passthrough: listener.TLS.Mode != nil && *listener.TLS.Mode == gatev1.TLSModePassthrough, } } - for svcName, svc := range subServices { - conf.TCP.Services[svcName] = svc + // Adding the gateway desc and the entryPoint desc prevents overlapping of routers build from the same routes. + routeKey := provider.Normalize(fmt.Sprintf("%s-%s-%s-%s-%d", route.Namespace, route.Name, listener.GWName, listener.EPName, ri)) + // Routing criteria should be introduced at some point. + routerName := makeRouterName("", routeKey) + + if len(rule.BackendRefs) == 1 && isInternalService(rule.BackendRefs[0]) { + router.Service = string(rule.BackendRefs[0].Name) + conf.TCP.Routers[routerName] = &router + continue } - serviceName := fmt.Sprintf("%s-wrr-%d", routerName, i) - conf.TCP.Services[serviceName] = wrrService + var serviceCondition *metav1.Condition + router.Service, serviceCondition = p.loadTCPWRRService(conf, routerName, rule.BackendRefs, route) + if serviceCondition != nil { + condition = *serviceCondition + } - ruleServiceNames = append(ruleServiceNames, serviceName) - } - - if len(ruleServiceNames) == 1 { - router.Service = ruleServiceNames[0] conf.TCP.Routers[routerName] = &router - return conf, condition } - routeServiceKey := routerName + "-wrr" - routeService := &dynamic.TCPService{Weighted: &dynamic.TCPWeightedRoundRobin{}} - - for _, name := range ruleServiceNames { - service := dynamic.TCPWRRService{Name: name} - service.SetDefaults() - - routeService.Weighted.Services = append(routeService.Weighted.Services, service) - } - - conf.TCP.Services[routeServiceKey] = routeService - - router.Service = routeServiceKey - conf.TCP.Routers[routerName] = &router - return conf, condition } -// loadTCPServices is generating a WRR service, even when there is only one target. -func (p *Provider) loadTCPServices(namespace string, backendRefs []gatev1.BackendRef) (*dynamic.TCPService, map[string]*dynamic.TCPService, error) { - services := map[string]*dynamic.TCPService{} - - wrrSvc := &dynamic.TCPService{ - Weighted: &dynamic.TCPWeightedRoundRobin{ - Services: []dynamic.TCPWRRService{}, - }, +// loadTCPWRRService is generating a WRR service, even when there is only one target. +func (p *Provider) loadTCPWRRService(conf *dynamic.Configuration, routeKey string, backendRefs []gatev1.BackendRef, route *gatev1alpha2.TCPRoute) (string, *metav1.Condition) { + name := routeKey + "-wrr" + if _, ok := conf.TCP.Services[name]; ok { + return name, nil } + var wrr dynamic.TCPWeightedRoundRobin + var condition *metav1.Condition for _, backendRef := range backendRefs { - if backendRef.Group == nil || backendRef.Kind == nil { - // Should not happen as this is validated by kubernetes + svcName, svc, errCondition := p.loadTCPService(route, backendRef) + weight := ptr.To(int(ptr.Deref(backendRef.Weight, 1))) + + if errCondition != nil { + condition = errCondition + + errName := routeKey + "-err-lb" + conf.TCP.Services[errName] = &dynamic.TCPService{ + LoadBalancer: &dynamic.TCPServersLoadBalancer{ + Servers: []dynamic.TCPServer{}, + }, + } + + wrr.Services = append(wrr.Services, dynamic.TCPWRRService{ + Name: errName, + Weight: weight, + }) continue } - if isInternalService(backendRef) { - return nil, nil, fmt.Errorf("traefik internal service %s is not allowed in a WRR loadbalancer", backendRef.Name) + if svc != nil { + conf.TCP.Services[svcName] = svc } - weight := int(ptr.Deref(backendRef.Weight, 1)) + wrr.Services = append(wrr.Services, dynamic.TCPWRRService{ + Name: svcName, + Weight: weight, + }) + } - if isTraefikService(backendRef) { - wrrSvc.Weighted.Services = append(wrrSvc.Weighted.Services, dynamic.TCPWRRService{Name: string(backendRef.Name), Weight: &weight}) - continue + conf.TCP.Services[name] = &dynamic.TCPService{Weighted: &wrr} + return name, condition +} + +func (p *Provider) loadTCPService(route *gatev1alpha2.TCPRoute, backendRef gatev1.BackendRef) (string, *dynamic.TCPService, *metav1.Condition) { + kind := ptr.Deref(backendRef.Kind, kindService) + + group := groupCore + if backendRef.Group != nil && *backendRef.Group != "" { + group = string(*backendRef.Group) + } + + namespace := route.Namespace + if backendRef.Namespace != nil && *backendRef.Namespace != "" { + namespace = string(*backendRef.Namespace) + } + + serviceName := provider.Normalize(namespace + "-" + string(backendRef.Name)) + + if err := p.isReferenceGranted(kindTCPRoute, route.Namespace, group, string(kind), string(backendRef.Name), namespace); err != nil { + return serviceName, nil, &metav1.Condition{ + Type: string(gatev1.RouteConditionResolvedRefs), + Status: metav1.ConditionFalse, + ObservedGeneration: route.Generation, + LastTransitionTime: metav1.Now(), + Reason: string(gatev1.RouteReasonRefNotPermitted), + Message: fmt.Sprintf("Cannot load TCPRoute BackendRef %s/%s/%s/%s: %s", group, kind, namespace, backendRef.Name, err), } + } - if *backendRef.Group != "" && *backendRef.Group != groupCore && *backendRef.Kind != "Service" { - return nil, nil, fmt.Errorf("unsupported BackendRef %s/%s/%s", *backendRef.Group, *backendRef.Kind, backendRef.Name) - } - - if backendRef.Port == nil { - return nil, nil, errors.New("port is required for Kubernetes Service reference") - } - - service, exists, err := p.client.GetService(namespace, string(backendRef.Name)) + if group != groupCore || kind != kindService { + name, err := p.loadTCPBackendRef(backendRef) if err != nil { - return nil, nil, fmt.Errorf("getting service: %w", err) - } - if !exists { - return nil, nil, errors.New("service not found") + return serviceName, nil, &metav1.Condition{ + Type: string(gatev1.RouteConditionResolvedRefs), + Status: metav1.ConditionFalse, + ObservedGeneration: route.Generation, + LastTransitionTime: metav1.Now(), + Reason: string(gatev1.RouteReasonInvalidKind), + Message: fmt.Sprintf("Cannot load TCPRoute BackendRef %s/%s/%s/%s: %s", group, kind, namespace, backendRef.Name, err), + } } - var svcPort *corev1.ServicePort - for _, p := range service.Spec.Ports { - if p.Port == int32(*backendRef.Port) { - svcPort = &p + return name, nil, nil + } + + port := ptr.Deref(backendRef.Port, gatev1.PortNumber(0)) + if port == 0 { + return serviceName, nil, &metav1.Condition{ + Type: string(gatev1.RouteConditionResolvedRefs), + Status: metav1.ConditionFalse, + ObservedGeneration: route.Generation, + LastTransitionTime: metav1.Now(), + Reason: string(gatev1.RouteReasonUnsupportedProtocol), + Message: fmt.Sprintf("Cannot load TCPRoute BackendRef %s/%s/%s/%s port is required", group, kind, namespace, backendRef.Name), + } + } + + portStr := strconv.FormatInt(int64(port), 10) + serviceName = provider.Normalize(serviceName + "-" + portStr) + + lb, err := p.loadTCPServers(namespace, backendRef) + if err != nil { + return serviceName, nil, &metav1.Condition{ + Type: string(gatev1.RouteConditionResolvedRefs), + Status: metav1.ConditionFalse, + ObservedGeneration: route.Generation, + LastTransitionTime: metav1.Now(), + Reason: string(gatev1.RouteReasonBackendNotFound), + Message: fmt.Sprintf("Cannot load TCPRoute BackendRef %s/%s/%s/%s: %s", group, kind, namespace, backendRef.Name, err), + } + } + + return serviceName, &dynamic.TCPService{LoadBalancer: lb}, nil +} + +func (p *Provider) loadTCPServers(namespace string, backendRef gatev1.BackendRef) (*dynamic.TCPServersLoadBalancer, error) { + if backendRef.Port == nil { + return nil, errors.New("port is required for Kubernetes Service reference") + } + + service, exists, err := p.client.GetService(namespace, string(backendRef.Name)) + if err != nil { + return nil, fmt.Errorf("getting service: %w", err) + } + if !exists { + return nil, errors.New("service not found") + } + + var svcPort *corev1.ServicePort + for _, p := range service.Spec.Ports { + if p.Port == int32(*backendRef.Port) { + svcPort = &p + break + } + } + if svcPort == nil { + return nil, fmt.Errorf("service port %d not found", *backendRef.Port) + } + + endpointSlices, err := p.client.ListEndpointSlicesForService(namespace, string(backendRef.Name)) + if err != nil { + return nil, fmt.Errorf("getting endpointslices: %w", err) + } + if len(endpointSlices) == 0 { + return nil, errors.New("endpointslices not found") + } + + lb := &dynamic.TCPServersLoadBalancer{} + + addresses := map[string]struct{}{} + for _, endpointSlice := range endpointSlices { + var port int32 + for _, p := range endpointSlice.Ports { + if svcPort.Name == *p.Name { + port = *p.Port break } } - if svcPort == nil { - return nil, nil, fmt.Errorf("service port %d not found", *backendRef.Port) + if port == 0 { + continue } - endpointSlices, err := p.client.ListEndpointSlicesForService(namespace, string(backendRef.Name)) - if err != nil { - return nil, nil, fmt.Errorf("getting endpointslices: %w", err) - } - if len(endpointSlices) == 0 { - return nil, nil, errors.New("endpointslices not found") - } - - svc := dynamic.TCPService{LoadBalancer: &dynamic.TCPServersLoadBalancer{}} - - addresses := map[string]struct{}{} - for _, endpointSlice := range endpointSlices { - var port int32 - for _, p := range endpointSlice.Ports { - if svcPort.Name == *p.Name { - port = *p.Port - break - } - } - if port == 0 { + for _, endpoint := range endpointSlice.Endpoints { + if endpoint.Conditions.Ready == nil || !*endpoint.Conditions.Ready { continue } - for _, endpoint := range endpointSlice.Endpoints { - if endpoint.Conditions.Ready == nil || !*endpoint.Conditions.Ready { + for _, address := range endpoint.Addresses { + if _, ok := addresses[address]; ok { continue } - for _, address := range endpoint.Addresses { - if _, ok := addresses[address]; ok { - continue - } - - addresses[address] = struct{}{} - svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, dynamic.TCPServer{ - Address: net.JoinHostPort(address, strconv.Itoa(int(port))), - }) - } + addresses[address] = struct{}{} + lb.Servers = append(lb.Servers, dynamic.TCPServer{ + // TODO determine whether the servers needs TLS, from the port? + Address: net.JoinHostPort(address, strconv.Itoa(int(port))), + }) } } - - serviceName := provider.Normalize(service.Namespace + "-" + service.Name + "-" + strconv.Itoa(int(svcPort.Port))) - services[serviceName] = &svc - - wrrSvc.Weighted.Services = append(wrrSvc.Weighted.Services, dynamic.TCPWRRService{Name: serviceName, Weight: &weight}) } - if len(wrrSvc.Weighted.Services) == 0 { - return nil, nil, errors.New("no service has been created") + return lb, nil +} + +func (p *Provider) loadTCPBackendRef(backendRef gatev1.BackendRef) (string, error) { + // Support for cross-provider references (e.g: api@internal). + // This provides the same behavior as for IngressRoutes. + if *backendRef.Kind == "TraefikService" && strings.Contains(string(backendRef.Name), "@") { + return string(backendRef.Name), nil } - return wrrSvc, services, nil + return "", fmt.Errorf("unsupported BackendRef %s/%s/%s", *backendRef.Group, *backendRef.Kind, backendRef.Name) } func mergeTCPConfiguration(from, to *dynamic.Configuration) { diff --git a/pkg/provider/kubernetes/gateway/tlsroute.go b/pkg/provider/kubernetes/gateway/tlsroute.go index b8a853a44..adbff1da5 100644 --- a/pkg/provider/kubernetes/gateway/tlsroute.go +++ b/pkg/provider/kubernetes/gateway/tlsroute.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "regexp" + "strconv" "strings" "github.com/rs/zerolog/log" @@ -11,6 +12,7 @@ import ( "github.com/traefik/traefik/v3/pkg/provider" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ktypes "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" gatev1 "sigs.k8s.io/gateway-api/apis/v1" gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" ) @@ -109,74 +111,159 @@ func (p *Provider) loadTLSRoute(listener gatewayListener, route *gatev1alpha2.TL Reason: string(gatev1.RouteConditionResolvedRefs), } - router := dynamic.TCPRouter{ - RuleSyntax: "v3", - Rule: hostSNIRule(hostnames), - EntryPoints: []string{listener.EPName}, - TLS: &dynamic.RouterTCPTLSConfig{ - Passthrough: listener.TLS != nil && listener.TLS.Mode != nil && *listener.TLS.Mode == gatev1.TLSModePassthrough, - }, - } - - // Adding the gateway desc and the entryPoint desc prevents overlapping of routers build from the same routes. - routeKey := provider.Normalize(route.Namespace + "-" + route.Name + "-" + listener.GWName + "-" + listener.EPName) - routerName := makeRouterName(router.Rule, routeKey) - - var ruleServiceNames []string - for i, routeRule := range route.Spec.Rules { + for ri, routeRule := range route.Spec.Rules { if len(routeRule.BackendRefs) == 0 { // Should not happen due to validation. // https://github.com/kubernetes-sigs/gateway-api/blob/v0.4.0/apis/v1alpha2/tlsroute_types.go#L120 continue } - wrrService, subServices, err := p.loadTCPServices(route.Namespace, routeRule.BackendRefs) + router := dynamic.TCPRouter{ + RuleSyntax: "v3", + Rule: hostSNIRule(hostnames), + EntryPoints: []string{listener.EPName}, + TLS: &dynamic.RouterTCPTLSConfig{ + Passthrough: listener.TLS != nil && listener.TLS.Mode != nil && *listener.TLS.Mode == gatev1.TLSModePassthrough, + }, + } + + // Adding the gateway desc and the entryPoint desc prevents overlapping of routers build from the same routes. + routeKey := provider.Normalize(fmt.Sprintf("%s-%s-%s-%s-%d", route.Namespace, route.Name, listener.GWName, listener.EPName, ri)) + // Routing criteria should be introduced at some point. + routerName := makeRouterName("", routeKey) + + if len(routeRule.BackendRefs) == 1 && isInternalService(routeRule.BackendRefs[0]) { + router.Service = string(routeRule.BackendRefs[0].Name) + conf.TCP.Routers[routerName] = &router + continue + } + + var serviceCondition *metav1.Condition + router.Service, serviceCondition = p.loadTLSWRRService(conf, routerName, routeRule.BackendRefs, route) + if serviceCondition != nil { + condition = *serviceCondition + } + + conf.TCP.Routers[routerName] = &router + } + + return conf, condition +} + +// loadTLSWRRService is generating a WRR service, even when there is only one target. +func (p *Provider) loadTLSWRRService(conf *dynamic.Configuration, routeKey string, backendRefs []gatev1.BackendRef, route *gatev1alpha2.TLSRoute) (string, *metav1.Condition) { + name := routeKey + "-wrr" + if _, ok := conf.TCP.Services[name]; ok { + return name, nil + } + + var wrr dynamic.TCPWeightedRoundRobin + var condition *metav1.Condition + for _, backendRef := range backendRefs { + svcName, svc, errCondition := p.loadTLSService(route, backendRef) + weight := ptr.To(int(ptr.Deref(backendRef.Weight, 1))) + + if errCondition != nil { + condition = errCondition + + errName := routeKey + "-err-lb" + conf.TCP.Services[errName] = &dynamic.TCPService{ + LoadBalancer: &dynamic.TCPServersLoadBalancer{ + Servers: []dynamic.TCPServer{}, + }, + } + + wrr.Services = append(wrr.Services, dynamic.TCPWRRService{ + Name: errName, + Weight: weight, + }) + continue + } + + if svc != nil { + conf.TCP.Services[svcName] = svc + } + + wrr.Services = append(wrr.Services, dynamic.TCPWRRService{ + Name: svcName, + Weight: weight, + }) + } + + conf.TCP.Services[name] = &dynamic.TCPService{Weighted: &wrr} + return name, condition +} + +func (p *Provider) loadTLSService(route *gatev1alpha2.TLSRoute, backendRef gatev1.BackendRef) (string, *dynamic.TCPService, *metav1.Condition) { + kind := ptr.Deref(backendRef.Kind, kindService) + + group := groupCore + if backendRef.Group != nil && *backendRef.Group != "" { + group = string(*backendRef.Group) + } + + namespace := route.Namespace + if backendRef.Namespace != nil && *backendRef.Namespace != "" { + namespace = string(*backendRef.Namespace) + } + + serviceName := provider.Normalize(namespace + "-" + string(backendRef.Name)) + + if err := p.isReferenceGranted(kindTLSRoute, route.Namespace, group, string(kind), string(backendRef.Name), namespace); err != nil { + return serviceName, nil, &metav1.Condition{ + Type: string(gatev1.RouteConditionResolvedRefs), + Status: metav1.ConditionFalse, + ObservedGeneration: route.Generation, + LastTransitionTime: metav1.Now(), + Reason: string(gatev1.RouteReasonRefNotPermitted), + Message: fmt.Sprintf("Cannot load TLSRoute BackendRef %s/%s/%s/%s: %s", group, kind, namespace, backendRef.Name, err), + } + } + + if group != groupCore || kind != kindService { + name, err := p.loadTCPBackendRef(backendRef) if err != nil { - // update "ResolvedRefs" status true with "InvalidBackendRefs" reason - condition = metav1.Condition{ + return serviceName, nil, &metav1.Condition{ Type: string(gatev1.RouteConditionResolvedRefs), Status: metav1.ConditionFalse, ObservedGeneration: route.Generation, LastTransitionTime: metav1.Now(), - Reason: string(gatev1.RouteReasonBackendNotFound), - Message: fmt.Sprintf("Cannot load TLSRoute service %s/%s: %v", route.Namespace, route.Name, err), + Reason: string(gatev1.RouteReasonInvalidKind), + Message: fmt.Sprintf("Cannot load TLSRoute BackendRef %s/%s/%s/%s: %s", group, kind, namespace, backendRef.Name, err), } - continue } - for svcName, svc := range subServices { - conf.TCP.Services[svcName] = svc + return name, nil, nil + } + + port := ptr.Deref(backendRef.Port, gatev1.PortNumber(0)) + if port == 0 { + return serviceName, nil, &metav1.Condition{ + Type: string(gatev1.RouteConditionResolvedRefs), + Status: metav1.ConditionFalse, + ObservedGeneration: route.Generation, + LastTransitionTime: metav1.Now(), + Reason: string(gatev1.RouteReasonUnsupportedProtocol), + Message: fmt.Sprintf("Cannot load TLSRoute BackendRef %s/%s/%s/%s port is required", group, kind, namespace, backendRef.Name), } - - serviceName := fmt.Sprintf("%s-wrr-%d", routerName, i) - conf.TCP.Services[serviceName] = wrrService - - ruleServiceNames = append(ruleServiceNames, serviceName) } - if len(ruleServiceNames) == 1 { - router.Service = ruleServiceNames[0] - conf.TCP.Routers[routerName] = &router + portStr := strconv.FormatInt(int64(port), 10) + serviceName = provider.Normalize(serviceName + "-" + portStr) - return conf, condition + lb, err := p.loadTCPServers(namespace, backendRef) + if err != nil { + return serviceName, nil, &metav1.Condition{ + Type: string(gatev1.RouteConditionResolvedRefs), + Status: metav1.ConditionFalse, + ObservedGeneration: route.Generation, + LastTransitionTime: metav1.Now(), + Reason: string(gatev1.RouteReasonBackendNotFound), + Message: fmt.Sprintf("Cannot load TLSRoute BackendRef %s/%s/%s/%s: %s", group, kind, namespace, backendRef.Name, err), + } } - routeServiceKey := routerName + "-wrr" - routeService := &dynamic.TCPService{Weighted: &dynamic.TCPWeightedRoundRobin{}} - - for _, name := range ruleServiceNames { - service := dynamic.TCPWRRService{Name: name} - service.SetDefaults() - - routeService.Weighted.Services = append(routeService.Weighted.Services, service) - } - - conf.TCP.Services[routeServiceKey] = routeService - - router.Service = routeServiceKey - conf.TCP.Routers[routerName] = &router - - return conf, condition + return serviceName, &dynamic.TCPService{LoadBalancer: lb}, nil } func hostSNIRule(hostnames []gatev1.Hostname) string { From e8335a94a4868689e96f15f11b8bc6fae66ddbce Mon Sep 17 00:00:00 2001 From: weijiany Date: Tue, 3 Sep 2024 22:40:04 +0800 Subject: [PATCH 11/13] Record trace id and EntryPoint span id into access log --- docs/content/observability/access-logs.md | 2 ++ pkg/middlewares/accesslog/logdata.go | 5 ++++ pkg/middlewares/observability/entrypoint.go | 7 ++++++ .../observability/entrypoint_test.go | 25 +++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/docs/content/observability/access-logs.md b/docs/content/observability/access-logs.md index f5481eb96..eb30e0200 100644 --- a/docs/content/observability/access-logs.md +++ b/docs/content/observability/access-logs.md @@ -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 diff --git a/pkg/middlewares/accesslog/logdata.go b/pkg/middlewares/accesslog/logdata.go index ef3f3be6c..19dc43d6c 100644 --- a/pkg/middlewares/accesslog/logdata.go +++ b/pkg/middlewares/accesslog/logdata.go @@ -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. diff --git a/pkg/middlewares/observability/entrypoint.go b/pkg/middlewares/observability/entrypoint.go index 0de455b92..4849f25b2 100644 --- a/pkg/middlewares/observability/entrypoint.go +++ b/pkg/middlewares/observability/entrypoint.go @@ -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) diff --git a/pkg/middlewares/observability/entrypoint_test.go b/pkg/middlewares/observability/entrypoint_test.go index f32c052c8..3e7a90870 100644 --- a/pkg/middlewares/observability/entrypoint_test.go +++ b/pkg/middlewares/observability/entrypoint_test.go @@ -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]) +} From c2cb4fac106fc74efe30288348b6b1679d5dd7d0 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 5 Sep 2024 10:02:04 +0200 Subject: [PATCH 12/13] Sync docker images from docker hub to ghcr --- .github/workflows/sync-docker-images.yaml | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/sync-docker-images.yaml diff --git a/.github/workflows/sync-docker-images.yaml b/.github/workflows/sync-docker-images.yaml new file mode 100644 index 000000000..aa00da957 --- /dev/null +++ b/.github/workflows/sync-docker-images.yaml @@ -0,0 +1,25 @@ +name: Sync Docker Images + +on: + workflow_dispatch: + schedule: + - cron: "0 0 * * *" # Run every day + +jobs: + sync: + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + if: github.repository == 'traefik/traefik' + + steps: + - uses: actions/checkout@v4 + + - uses: imjasonh/setup-crane@v0.4 + + - name: Sync + run: | + EXCLUDED_TAGS="1.7.9-alpine v1.0.0-beta.392 v1.0.0-beta.404 v1.0.0-beta.704 v1.0.0-rc1 v1.7.9-alpine" + EXCLUDED_REGEX=$(echo $EXCLUDED_TAGS | sed 's/ /|/g') + diff <(crane ls traefik) <(crane ls ghcr.io/traefik/traefik) | grep '^<' | awk '{print $2}' | while read -r tag; do [[ "$tag" =~ ^($EXCLUDED_REGEX)$ ]] || (echo "Processing image: traefik:$tag"; crane cp "traefik:$tag" "ghcr.io/traefik/traefik:$tag"); done From 9dc2155e637318c347b8b00e084c3dd0c75f18e4 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 6 Sep 2024 09:56:03 +0200 Subject: [PATCH 13/13] Fix sync docker images latest tag --- .github/workflows/sync-docker-images.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/sync-docker-images.yaml b/.github/workflows/sync-docker-images.yaml index aa00da957..6f0b3c103 100644 --- a/.github/workflows/sync-docker-images.yaml +++ b/.github/workflows/sync-docker-images.yaml @@ -23,3 +23,4 @@ jobs: EXCLUDED_TAGS="1.7.9-alpine v1.0.0-beta.392 v1.0.0-beta.404 v1.0.0-beta.704 v1.0.0-rc1 v1.7.9-alpine" EXCLUDED_REGEX=$(echo $EXCLUDED_TAGS | sed 's/ /|/g') diff <(crane ls traefik) <(crane ls ghcr.io/traefik/traefik) | grep '^<' | awk '{print $2}' | while read -r tag; do [[ "$tag" =~ ^($EXCLUDED_REGEX)$ ]] || (echo "Processing image: traefik:$tag"; crane cp "traefik:$tag" "ghcr.io/traefik/traefik:$tag"); done + crane cp traefik:latest ghcr.io/traefik/traefik:latest