Merge current v3.1 into master
This commit is contained in:
commit
8dc9607db7
50 changed files with 159 additions and 128 deletions
2
.github/workflows/build.yaml
vendored
2
.github/workflows/build.yaml
vendored
|
@ -10,7 +10,7 @@ on:
|
||||||
- 'script/gcg/**'
|
- 'script/gcg/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: '1.22'
|
GO_VERSION: '1.23'
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
2
.github/workflows/experimental.yaml
vendored
2
.github/workflows/experimental.yaml
vendored
|
@ -7,7 +7,7 @@ on:
|
||||||
- v*
|
- v*
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: '1.22'
|
GO_VERSION: '1.23'
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
2
.github/workflows/test-integration.yaml
vendored
2
.github/workflows/test-integration.yaml
vendored
|
@ -10,7 +10,7 @@ on:
|
||||||
- 'script/gcg/**'
|
- 'script/gcg/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: '1.22'
|
GO_VERSION: '1.23'
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
2
.github/workflows/test-unit.yaml
vendored
2
.github/workflows/test-unit.yaml
vendored
|
@ -10,7 +10,7 @@ on:
|
||||||
- 'script/gcg/**'
|
- 'script/gcg/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: '1.22'
|
GO_VERSION: '1.23'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
|
|
4
.github/workflows/validate.yaml
vendored
4
.github/workflows/validate.yaml
vendored
|
@ -6,8 +6,8 @@ on:
|
||||||
- '*'
|
- '*'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: '1.22'
|
GO_VERSION: '1.23'
|
||||||
GOLANGCI_LINT_VERSION: v1.59.0
|
GOLANGCI_LINT_VERSION: v1.60.3
|
||||||
MISSSPELL_VERSION: v0.6.0
|
MISSSPELL_VERSION: v0.6.0
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
|
@ -200,8 +200,7 @@ linters:
|
||||||
- maintidx # kind of duplicate of gocyclo
|
- maintidx # kind of duplicate of gocyclo
|
||||||
- nonamedreturns # Too strict
|
- nonamedreturns # Too strict
|
||||||
- gosmopolitan # not relevant
|
- gosmopolitan # not relevant
|
||||||
- exportloopref # Useless with go1.22
|
- exportloopref # Not relevant since go1.22
|
||||||
- musttag
|
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
exclude-use-default: false
|
exclude-use-default: false
|
||||||
|
@ -281,3 +280,6 @@ issues:
|
||||||
- path: pkg/cli/loader_file.go
|
- path: pkg/cli/loader_file.go
|
||||||
linters:
|
linters:
|
||||||
- goconst
|
- goconst
|
||||||
|
- path: pkg/provider/acme/local_store.go
|
||||||
|
linters:
|
||||||
|
- musttag
|
||||||
|
|
|
@ -19,13 +19,13 @@ global_job_config:
|
||||||
prologue:
|
prologue:
|
||||||
commands:
|
commands:
|
||||||
- curl -sSfL https://raw.githubusercontent.com/ldez/semgo/master/godownloader.sh | sudo sh -s -- -b "/usr/local/bin"
|
- curl -sSfL https://raw.githubusercontent.com/ldez/semgo/master/godownloader.sh | sudo sh -s -- -b "/usr/local/bin"
|
||||||
- sudo semgo go1.22
|
- sudo semgo go1.23
|
||||||
- export "GOPATH=$(go env GOPATH)"
|
- export "GOPATH=$(go env GOPATH)"
|
||||||
- export "SEMAPHORE_GIT_DIR=${GOPATH}/src/github.com/traefik/${SEMAPHORE_PROJECT_NAME}"
|
- export "SEMAPHORE_GIT_DIR=${GOPATH}/src/github.com/traefik/${SEMAPHORE_PROJECT_NAME}"
|
||||||
- export "PATH=${GOPATH}/bin:${PATH}"
|
- export "PATH=${GOPATH}/bin:${PATH}"
|
||||||
- mkdir -vp "${SEMAPHORE_GIT_DIR}" "${GOPATH}/bin"
|
- mkdir -vp "${SEMAPHORE_GIT_DIR}" "${GOPATH}/bin"
|
||||||
- export GOPROXY=https://proxy.golang.org,direct
|
- export GOPROXY=https://proxy.golang.org,direct
|
||||||
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin" v1.59.0
|
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin" v1.60.3
|
||||||
- curl -sSfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | bash -s -- -b "${GOPATH}/bin"
|
- curl -sSfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | bash -s -- -b "${GOPATH}/bin"
|
||||||
- checkout
|
- checkout
|
||||||
- cache restore traefik-$(checksum go.sum)
|
- cache restore traefik-$(checksum go.sum)
|
||||||
|
|
|
@ -4,17 +4,11 @@ This page is maintained and updated periodically to reflect our roadmap and any
|
||||||
|
|
||||||
| Feature | Deprecated | End of Support | Removal |
|
| Feature | Deprecated | End of Support | Removal |
|
||||||
|----------------------------------------------------------------------------------------------------------------------|------------|----------------|---------|
|
|----------------------------------------------------------------------------------------------------------------------|------------|----------------|---------|
|
||||||
| [Kubernetes CRD Provider API Version `traefik.io/v1alpha1`](#kubernetes-crd-provider-api-version-traefikiov1alpha1) | 3.0 | N/A | 4.0 |
|
|
||||||
| [Kubernetes Ingress API Version `networking.k8s.io/v1beta1`](#kubernetes-ingress-api-version-networkingk8siov1beta1) | N/A | N/A | 3.0 |
|
| [Kubernetes Ingress API Version `networking.k8s.io/v1beta1`](#kubernetes-ingress-api-version-networkingk8siov1beta1) | N/A | N/A | 3.0 |
|
||||||
| [CRD API Version `apiextensions.k8s.io/v1beta1`](#kubernetes-ingress-api-version-networkingk8siov1beta1) | N/A | N/A | 3.0 |
|
| [CRD API Version `apiextensions.k8s.io/v1beta1`](#kubernetes-ingress-api-version-networkingk8siov1beta1) | N/A | N/A | 3.0 |
|
||||||
|
|
||||||
## Impact
|
## Impact
|
||||||
|
|
||||||
### Kubernetes CRD Provider API Version `traefik.io/v1alpha1`
|
|
||||||
|
|
||||||
The Kubernetes CRD provider API Version `traefik.io/v1alpha1` is deprecated in Traefik v3.
|
|
||||||
Please use the API Group `traefik.io/v1` instead.
|
|
||||||
|
|
||||||
### Kubernetes Ingress API Version `networking.k8s.io/v1beta1`
|
### Kubernetes Ingress API Version `networking.k8s.io/v1beta1`
|
||||||
|
|
||||||
The Kubernetes Ingress API Version `networking.k8s.io/v1beta1` support is removed in v3.
|
The Kubernetes Ingress API Version `networking.k8s.io/v1beta1` support is removed in v3.
|
||||||
|
|
|
@ -541,6 +541,19 @@ it is now unsupported and would prevent Traefik to start.
|
||||||
|
|
||||||
All Pilot related configuration should be removed from the static configuration.
|
All Pilot related configuration should be removed from the static configuration.
|
||||||
|
|
||||||
|
### Kubernetes Ingress Path Matching
|
||||||
|
|
||||||
|
In v3, the Kubernetes Ingress default path matching does not support regexes anymore.
|
||||||
|
|
||||||
|
#### Remediation
|
||||||
|
|
||||||
|
Two levels of remediation are possible:
|
||||||
|
|
||||||
|
- Interpret the default path matcher `PathPrefix` with v2 syntax.
|
||||||
|
This can done globally for all routers with the [static configuration](#configure-the-default-syntax-in-static-configuration) or on a per-router basis by using the [traefik.ingress.kubernetes.io/router.rulesyntax](../routing/providers/kubernetes-ingress.md#annotations) annotation.
|
||||||
|
|
||||||
|
- Adapt the path regex to be compatible with the Go regex syntax and change the default path matcher to use the `PathRegexp` matcher with the [`traefik.ingress.kubernetes.io/router.pathmatcher`](../routing/providers/kubernetes-ingress.md#annotations) annotation.
|
||||||
|
|
||||||
## Operations Changes
|
## Operations Changes
|
||||||
|
|
||||||
### Traefik RBAC Update
|
### Traefik RBAC Update
|
||||||
|
@ -555,6 +568,16 @@ One should use the `ContentType` middleware to enable the `Content-Type` header
|
||||||
|
|
||||||
### Observability
|
### Observability
|
||||||
|
|
||||||
|
#### Open Connections Metric
|
||||||
|
|
||||||
|
In v3, the open connections metric has been replaced with a global one because it was erroneously at the HTTP level, and providing misleading information.
|
||||||
|
While previously produced at the entryPoint, router, and service levels, it is now replaced with a global metric.
|
||||||
|
The equivalent to `traefik_entrypoint_open_connections`, `traefik_router_open_connections` and `traefik_service_open_connections` is now `traefik_open_connections`.
|
||||||
|
|
||||||
|
#### Configuration Reload Failures Metrics
|
||||||
|
|
||||||
|
In v3, the `traefik_config_reloads_failure_total` and `traefik_config_last_reload_failure` metrics have been suppressed since they could not be implemented.
|
||||||
|
|
||||||
#### gRPC Metrics
|
#### gRPC Metrics
|
||||||
|
|
||||||
In v3, the reported status code for gRPC requests is now the value of the `Grpc-Status` header.
|
In v3, the reported status code for gRPC requests is now the value of the `Grpc-Status` header.
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: ingressroutes.traefik.io
|
name: ingressroutes.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -369,7 +369,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: ingressroutetcps.traefik.io
|
name: ingressroutetcps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -507,7 +507,7 @@ spec:
|
||||||
hence fully terminating the connection.
|
hence fully terminating the connection.
|
||||||
It is a duration in milliseconds, defaulting to 100.
|
It is a duration in milliseconds, defaulting to 100.
|
||||||
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
||||||
Deprecated: TerminationDelay is not supported APIVersion traefik.io/v1, please use ServersTransport to configure the TerminationDelay instead.
|
Deprecated: TerminationDelay will not be supported in future APIVersions, please use ServersTransport to configure the TerminationDelay instead.
|
||||||
type: integer
|
type: integer
|
||||||
tls:
|
tls:
|
||||||
description: TLS determines whether to use TLS when dialing
|
description: TLS determines whether to use TLS when dialing
|
||||||
|
@ -616,7 +616,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: ingressrouteudps.traefik.io
|
name: ingressrouteudps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -727,7 +727,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: middlewares.traefik.io
|
name: middlewares.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -1831,7 +1831,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: middlewaretcps.traefik.io
|
name: middlewaretcps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -1918,7 +1918,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: serverstransports.traefik.io
|
name: serverstransports.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -2057,7 +2057,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: serverstransporttcps.traefik.io
|
name: serverstransporttcps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -2177,7 +2177,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: tlsoptions.traefik.io
|
name: tlsoptions.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -2291,7 +2291,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: tlsstores.traefik.io
|
name: tlsstores.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -2388,7 +2388,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: traefikservices.traefik.io
|
name: traefikservices.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: ingressroutes.traefik.io
|
name: ingressroutes.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: ingressroutetcps.traefik.io
|
name: ingressroutetcps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -141,7 +141,7 @@ spec:
|
||||||
hence fully terminating the connection.
|
hence fully terminating the connection.
|
||||||
It is a duration in milliseconds, defaulting to 100.
|
It is a duration in milliseconds, defaulting to 100.
|
||||||
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
||||||
Deprecated: TerminationDelay is not supported APIVersion traefik.io/v1, please use ServersTransport to configure the TerminationDelay instead.
|
Deprecated: TerminationDelay will not be supported in future APIVersions, please use ServersTransport to configure the TerminationDelay instead.
|
||||||
type: integer
|
type: integer
|
||||||
tls:
|
tls:
|
||||||
description: TLS determines whether to use TLS when dialing
|
description: TLS determines whether to use TLS when dialing
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: ingressrouteudps.traefik.io
|
name: ingressrouteudps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: middlewares.traefik.io
|
name: middlewares.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: middlewaretcps.traefik.io
|
name: middlewaretcps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: serverstransports.traefik.io
|
name: serverstransports.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: serverstransporttcps.traefik.io
|
name: serverstransporttcps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: tlsoptions.traefik.io
|
name: tlsoptions.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: tlsstores.traefik.io
|
name: tlsstores.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: traefikservices.traefik.io
|
name: traefikservices.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
|
|
@ -229,10 +229,18 @@ which in turn will create the resulting routers, services, handlers, etc.
|
||||||
traefik.ingress.kubernetes.io/router.priority: "42"
|
traefik.ingress.kubernetes.io/router.priority: "42"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? info "`traefik.ingress.kubernetes.io/router.rulesyntax`"
|
||||||
|
|
||||||
|
See [rule syntax](../routers/index.md#rulesyntax) for more information.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
traefik.ingress.kubernetes.io/router.rulesyntax: "v2"
|
||||||
|
```
|
||||||
|
|
||||||
??? info "`traefik.ingress.kubernetes.io/router.pathmatcher`"
|
??? info "`traefik.ingress.kubernetes.io/router.pathmatcher`"
|
||||||
|
|
||||||
Overrides the default router rule type used for a path.
|
Overrides the default router rule type used for a path.
|
||||||
Only path-related matcher name can be specified: `Path`, `PathPrefix`.
|
Only path-related matcher name should be specified: `Path`, `PathPrefix` or `PathRegexp`.
|
||||||
|
|
||||||
Default `PathPrefix`
|
Default `PathPrefix`
|
||||||
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,6 +1,6 @@
|
||||||
module github.com/traefik/traefik/v3
|
module github.com/traefik/traefik/v3
|
||||||
|
|
||||||
go 1.22.4
|
go 1.23.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.4.0
|
github.com/BurntSushi/toml v1.4.0
|
||||||
|
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: ingressroutes.traefik.io
|
name: ingressroutes.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -369,7 +369,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: ingressroutetcps.traefik.io
|
name: ingressroutetcps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -507,7 +507,7 @@ spec:
|
||||||
hence fully terminating the connection.
|
hence fully terminating the connection.
|
||||||
It is a duration in milliseconds, defaulting to 100.
|
It is a duration in milliseconds, defaulting to 100.
|
||||||
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
||||||
Deprecated: TerminationDelay is not supported APIVersion traefik.io/v1, please use ServersTransport to configure the TerminationDelay instead.
|
Deprecated: TerminationDelay will not be supported in future APIVersions, please use ServersTransport to configure the TerminationDelay instead.
|
||||||
type: integer
|
type: integer
|
||||||
tls:
|
tls:
|
||||||
description: TLS determines whether to use TLS when dialing
|
description: TLS determines whether to use TLS when dialing
|
||||||
|
@ -616,7 +616,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: ingressrouteudps.traefik.io
|
name: ingressrouteudps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -727,7 +727,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: middlewares.traefik.io
|
name: middlewares.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -1831,7 +1831,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: middlewaretcps.traefik.io
|
name: middlewaretcps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -1918,7 +1918,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: serverstransports.traefik.io
|
name: serverstransports.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -2057,7 +2057,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: serverstransporttcps.traefik.io
|
name: serverstransporttcps.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -2177,7 +2177,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: tlsoptions.traefik.io
|
name: tlsoptions.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -2291,7 +2291,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: tlsstores.traefik.io
|
name: tlsstores.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
@ -2388,7 +2388,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.14.0
|
controller-gen.kubebuilder.io/version: v0.16.1
|
||||||
name: traefikservices.traefik.io
|
name: traefikservices.traefik.io
|
||||||
spec:
|
spec:
|
||||||
group: traefik.io
|
group: traefik.io
|
||||||
|
|
|
@ -663,7 +663,7 @@ func (s *TracingSuite) TestNoInternals() {
|
||||||
err = json.Unmarshal(content, &out)
|
err = json.Unmarshal(content, &out)
|
||||||
require.NoError(s.T(), err)
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
s.NotEmptyf(len(out.Traces), "expected at least one trace")
|
s.NotEmptyf(out.Traces, "expected at least one trace")
|
||||||
|
|
||||||
for _, t := range out.Traces {
|
for _, t := range out.Traces {
|
||||||
baseURL, err := url.Parse("http://" + s.tempoIP + ":3200/api/traces/" + t.TraceID)
|
baseURL, err := url.Parse("http://" + s.tempoIP + ":3200/api/traces/" + t.TraceID)
|
||||||
|
@ -705,7 +705,7 @@ func (s *TracingSuite) checkTraceContent(expectedJSON []map[string]string) {
|
||||||
err = json.Unmarshal(content, &out)
|
err = json.Unmarshal(content, &out)
|
||||||
require.NoError(s.T(), err)
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
s.NotEmptyf(len(out.Traces), "expected at least one trace")
|
s.NotEmptyf(out.Traces, "expected at least one trace")
|
||||||
|
|
||||||
var contents []string
|
var contents []string
|
||||||
for _, t := range out.Traces {
|
for _, t := range out.Traces {
|
||||||
|
|
|
@ -93,7 +93,7 @@ func (c *searchCriterion) filterMiddleware(mns []string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func pagination(request *http.Request, max int) (pageInfo, error) {
|
func pagination(request *http.Request, maximum int) (pageInfo, error) {
|
||||||
perPage, err := getIntParam(request, "per_page", defaultPerPage)
|
perPage, err := getIntParam(request, "per_page", defaultPerPage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pageInfo{}, err
|
return pageInfo{}, err
|
||||||
|
@ -105,17 +105,17 @@ func pagination(request *http.Request, max int) (pageInfo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
startIndex := (page - 1) * perPage
|
startIndex := (page - 1) * perPage
|
||||||
if startIndex != 0 && startIndex >= max {
|
if startIndex != 0 && startIndex >= maximum {
|
||||||
return pageInfo{}, fmt.Errorf("invalid request: page: %d, per_page: %d", page, perPage)
|
return pageInfo{}, fmt.Errorf("invalid request: page: %d, per_page: %d", page, perPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
endIndex := startIndex + perPage
|
endIndex := startIndex + perPage
|
||||||
if endIndex >= max {
|
if endIndex >= maximum {
|
||||||
endIndex = max
|
endIndex = maximum
|
||||||
}
|
}
|
||||||
|
|
||||||
nextPage := 1
|
nextPage := 1
|
||||||
if page*perPage < max {
|
if page*perPage < maximum {
|
||||||
nextPage = page + 1
|
nextPage = page + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,7 @@ type providers struct {
|
||||||
ETCD *etcd `json:"etcd,omitempty" toml:"etcd,omitempty" yaml:"etcd,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
ETCD *etcd `json:"etcd,omitempty" toml:"etcd,omitempty" yaml:"etcd,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
Redis *redis `json:"redis,omitempty" toml:"redis,omitempty" yaml:"redis,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
Redis *redis `json:"redis,omitempty" toml:"redis,omitempty" yaml:"redis,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
HTTP *http `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
HTTP *http `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
KubernetesIngress *ingress `json:"kubernetesIngress,omitempty" toml:"kubernetesIngress,omitempty" yaml:"kubernetesIngress,omitempty" file:"allowEmpty"`
|
KubernetesIngress *ingress `json:"kubernetesIngress,omitempty" toml:"kubernetesIngress,omitempty" yaml:"kubernetesIngress,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *providers) deprecationNotice(logger zerolog.Logger) bool {
|
func (p *providers) deprecationNotice(logger zerolog.Logger) bool {
|
||||||
|
|
|
@ -21,11 +21,11 @@ const collectorURL = "https://collect.traefik.io/yYaUej3P42cziRVzv6T5w2aYy9po2Mr
|
||||||
|
|
||||||
// Collected data.
|
// Collected data.
|
||||||
type data struct {
|
type data struct {
|
||||||
Version string
|
Version string `json:"version"`
|
||||||
Codename string
|
Codename string `json:"codename"`
|
||||||
BuildDate string
|
BuildDate string `json:"buildDate"`
|
||||||
Configuration string
|
Configuration string `json:"configuration"`
|
||||||
Hash string
|
Hash string `json:"hash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect anonymous data.
|
// Collect anonymous data.
|
||||||
|
|
|
@ -199,7 +199,7 @@ func TestLoggerHeaderFields(t *testing.T) {
|
||||||
|
|
||||||
if config.FilePath != "" {
|
if config.FilePath != "" {
|
||||||
_, err = os.Stat(config.FilePath)
|
_, err = os.Stat(config.FilePath)
|
||||||
require.NoError(t, err, fmt.Sprintf("logger should create %s", config.FilePath))
|
require.NoErrorf(t, err, "logger should create %s", config.FilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
req := &http.Request{
|
req := &http.Request{
|
||||||
|
@ -704,7 +704,7 @@ func assertValidLogData(t *testing.T, expected string, logData []byte) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
if len(expected) == 0 {
|
if len(expected) == 0 {
|
||||||
assert.Zero(t, len(logData))
|
assert.Empty(t, logData)
|
||||||
t.Log(string(logData))
|
t.Log(string(logData))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -761,7 +761,7 @@ func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS bool) {
|
||||||
|
|
||||||
if config.FilePath != "" {
|
if config.FilePath != "" {
|
||||||
_, err = os.Stat(config.FilePath)
|
_, err = os.Stat(config.FilePath)
|
||||||
require.NoError(t, err, fmt.Sprintf("logger should create %s", config.FilePath))
|
require.NoErrorf(t, err, "logger should create %s", config.FilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
req := &http.Request{
|
req := &http.Request{
|
||||||
|
|
|
@ -128,9 +128,9 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
forwardReq, err := http.NewRequestWithContext(req.Context(), http.MethodGet, fa.address, nil)
|
forwardReq, err := http.NewRequestWithContext(req.Context(), http.MethodGet, fa.address, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logMessage := fmt.Sprintf("Error calling %s. Cause %s", fa.address, err)
|
logger.Debug().Msgf("Error calling %s. Cause %s", fa.address, err)
|
||||||
logger.Debug().Msg(logMessage)
|
observability.SetStatusErrorf(req.Context(), "Error calling %s. Cause %s", fa.address, err)
|
||||||
observability.SetStatusErrorf(req.Context(), logMessage)
|
|
||||||
rw.WriteHeader(http.StatusInternalServerError)
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -152,9 +152,8 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
forwardResponse, forwardErr := fa.client.Do(forwardReq)
|
forwardResponse, forwardErr := fa.client.Do(forwardReq)
|
||||||
if forwardErr != nil {
|
if forwardErr != nil {
|
||||||
logMessage := fmt.Sprintf("Error calling %s. Cause: %s", fa.address, forwardErr)
|
logger.Debug().Msgf("Error calling %s. Cause: %s", fa.address, forwardErr)
|
||||||
logger.Debug().Msg(logMessage)
|
observability.SetStatusErrorf(req.Context(), "Error calling %s. Cause: %s", fa.address, forwardErr)
|
||||||
observability.SetStatusErrorf(forwardReq.Context(), logMessage)
|
|
||||||
|
|
||||||
rw.WriteHeader(http.StatusInternalServerError)
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -163,9 +162,8 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
body, readError := io.ReadAll(forwardResponse.Body)
|
body, readError := io.ReadAll(forwardResponse.Body)
|
||||||
if readError != nil {
|
if readError != nil {
|
||||||
logMessage := fmt.Sprintf("Error reading body %s. Cause: %s", fa.address, readError)
|
logger.Debug().Msgf("Error reading body %s. Cause: %s", fa.address, readError)
|
||||||
logger.Debug().Msg(logMessage)
|
observability.SetStatusErrorf(req.Context(), "Error reading body %s. Cause: %s", fa.address, readError)
|
||||||
observability.SetStatusErrorf(forwardReq.Context(), logMessage)
|
|
||||||
|
|
||||||
rw.WriteHeader(http.StatusInternalServerError)
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -199,9 +197,8 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, http.ErrNoLocation) {
|
if !errors.Is(err, http.ErrNoLocation) {
|
||||||
logMessage := fmt.Sprintf("Error reading response location header %s. Cause: %s", fa.address, err)
|
logger.Debug().Msgf("Error reading response location header %s. Cause: %s", fa.address, err)
|
||||||
logger.Debug().Msg(logMessage)
|
observability.SetStatusErrorf(req.Context(), "Error reading response location header %s. Cause: %s", fa.address, err)
|
||||||
observability.SetStatusErrorf(forwardReq.Context(), logMessage)
|
|
||||||
|
|
||||||
rw.WriteHeader(http.StatusInternalServerError)
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
|
|
@ -95,9 +95,8 @@ func (c *CompressionHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||||
compressionWriter, err := newCompressionWriter(c.cfg.Algorithm, rw)
|
compressionWriter, err := newCompressionWriter(c.cfg.Algorithm, rw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger := middlewares.GetLogger(r.Context(), c.cfg.MiddlewareName, typeName)
|
logger := middlewares.GetLogger(r.Context(), c.cfg.MiddlewareName, typeName)
|
||||||
logMessage := fmt.Sprintf("create compression handler: %v", err)
|
logger.Debug().Msgf("Create compression handler: %v", err)
|
||||||
logger.Debug().Msg(logMessage)
|
observability.SetStatusErrorf(r.Context(), "Create compression handler: %v", err)
|
||||||
observability.SetStatusErrorf(r.Context(), logMessage)
|
|
||||||
rw.WriteHeader(http.StatusInternalServerError)
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,8 +70,8 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
logger := middlewares.GetLogger(req.Context(), c.name, typeName)
|
logger := middlewares.GetLogger(req.Context(), c.name, typeName)
|
||||||
|
|
||||||
if c.backendHandler == nil {
|
if c.backendHandler == nil {
|
||||||
logger.Error().Msg("Error pages: no backend handler.")
|
logger.Error().Msg("No backend handler.")
|
||||||
observability.SetStatusErrorf(req.Context(), "Error pages: no backend handler.")
|
observability.SetStatusErrorf(req.Context(), "No backend handler.")
|
||||||
c.next.ServeHTTP(rw, req)
|
c.next.ServeHTTP(rw, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,8 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
pageReq, err := newRequest("http://" + req.Host + query)
|
pageReq, err := newRequest("http://" + req.Host + query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Err(err).Send()
|
logger.Error().Msgf("Unable to create error page request: %v", err)
|
||||||
observability.SetStatusErrorf(req.Context(), err.Error())
|
observability.SetStatusErrorf(req.Context(), "Unable to create error page request: %v", err)
|
||||||
http.Error(rw, http.StatusText(code), code)
|
http.Error(rw, http.StatusText(code), code)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,9 +76,8 @@ func (al *ipAllowLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
clientIP := al.strategy.GetIP(req)
|
clientIP := al.strategy.GetIP(req)
|
||||||
err := al.allowLister.IsAuthorized(clientIP)
|
err := al.allowLister.IsAuthorized(clientIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("Rejecting IP %s: %v", clientIP, err)
|
logger.Debug().Msgf("Rejecting IP %s: %v", clientIP, err)
|
||||||
logger.Debug().Msg(msg)
|
observability.SetStatusErrorf(req.Context(), "Rejecting IP %s: %v", clientIP, err)
|
||||||
observability.SetStatusErrorf(req.Context(), msg)
|
|
||||||
reject(ctx, al.rejectStatusCode, rw)
|
reject(ctx, al.rejectStatusCode, rw)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,9 +66,8 @@ func (wl *ipWhiteLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
clientIP := wl.strategy.GetIP(req)
|
clientIP := wl.strategy.GetIP(req)
|
||||||
err := wl.whiteLister.IsAuthorized(clientIP)
|
err := wl.whiteLister.IsAuthorized(clientIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("Rejecting IP %s: %v", clientIP, err)
|
logger.Debug().Msgf("Rejecting IP %s: %v", clientIP, err)
|
||||||
logger.Debug().Msg(msg)
|
observability.SetStatusErrorf(req.Context(), "Rejecting IP %s: %v", clientIP, err)
|
||||||
observability.SetStatusErrorf(req.Context(), msg)
|
|
||||||
reject(ctx, rw)
|
reject(ctx, rw)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,7 +319,7 @@ func TestPassTLSClientCert_PEM(t *testing.T) {
|
||||||
res := httptest.NewRecorder()
|
res := httptest.NewRecorder()
|
||||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://example.com/foo", nil)
|
req := testhelpers.MustNewRequest(http.MethodGet, "http://example.com/foo", nil)
|
||||||
|
|
||||||
if test.certContents != nil && len(test.certContents) > 0 {
|
if len(test.certContents) > 0 {
|
||||||
req.TLS = buildTLSWith(test.certContents)
|
req.TLS = buildTLSWith(test.certContents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,7 +541,7 @@ func TestPassTLSClientCert_certInfo(t *testing.T) {
|
||||||
res := httptest.NewRecorder()
|
res := httptest.NewRecorder()
|
||||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://example.com/foo", nil)
|
req := testhelpers.MustNewRequest(http.MethodGet, "http://example.com/foo", nil)
|
||||||
|
|
||||||
if test.certContents != nil && len(test.certContents) > 0 {
|
if len(test.certContents) > 0 {
|
||||||
req.TLS = buildTLSWith(test.certContents)
|
req.TLS = buildTLSWith(test.certContents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,8 @@ func (r *replacePath) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
var err error
|
var err error
|
||||||
req.URL.Path, err = url.PathUnescape(req.URL.RawPath)
|
req.URL.Path, err = url.PathUnescape(req.URL.RawPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
middlewares.GetLogger(context.Background(), r.name, typeName).Error().Err(err).Send()
|
middlewares.GetLogger(context.Background(), r.name, typeName).Error().Msgf("Unable to unescape url raw path %q: %v", req.URL.RawPath, err)
|
||||||
observability.SetStatusErrorf(req.Context(), err.Error())
|
observability.SetStatusErrorf(req.Context(), "Unable to unescape url raw path %q: %v", req.URL.RawPath, err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,8 +62,8 @@ func (rp *replacePathRegex) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
||||||
var err error
|
var err error
|
||||||
req.URL.Path, err = url.PathUnescape(req.URL.RawPath)
|
req.URL.Path, err = url.PathUnescape(req.URL.RawPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
middlewares.GetLogger(context.Background(), rp.name, typeName).Error().Err(err).Send()
|
middlewares.GetLogger(context.Background(), rp.name, typeName).Error().Msgf("Unable to unescape url raw path %q: %v", req.URL.RawPath, err)
|
||||||
observability.SetStatusErrorf(req.Context(), err.Error())
|
observability.SetStatusErrorf(req.Context(), "Unable to unescape url raw path %q: %v", req.URL.RawPath, err)
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,8 +199,7 @@ func getPort(container dockerData, serverPort string) string {
|
||||||
nat.Sort(ports, less)
|
nat.Sort(ports, less)
|
||||||
|
|
||||||
if len(ports) > 0 {
|
if len(ports) > 0 {
|
||||||
min := ports[0]
|
return ports[0].Port()
|
||||||
return min.Port()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -316,8 +316,7 @@ func getPort(instance ecsInstance, serverPort string) string {
|
||||||
nat.Sort(ports, less)
|
nat.Sort(ports, less)
|
||||||
|
|
||||||
if len(ports) > 0 {
|
if len(ports) > 0 {
|
||||||
min := ports[0]
|
return ports[0].Port()
|
||||||
return min.Port()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -77,7 +77,7 @@ type ServiceTCP struct {
|
||||||
// hence fully terminating the connection.
|
// hence fully terminating the connection.
|
||||||
// It is a duration in milliseconds, defaulting to 100.
|
// It is a duration in milliseconds, defaulting to 100.
|
||||||
// A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
// A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
||||||
// Deprecated: TerminationDelay is not supported APIVersion traefik.io/v1, please use ServersTransport to configure the TerminationDelay instead.
|
// Deprecated: TerminationDelay will not be supported in future APIVersions, please use ServersTransport to configure the TerminationDelay instead.
|
||||||
TerminationDelay *int `json:"terminationDelay,omitempty"`
|
TerminationDelay *int `json:"terminationDelay,omitempty"`
|
||||||
// ProxyProtocol defines the PROXY protocol configuration.
|
// ProxyProtocol defines the PROXY protocol configuration.
|
||||||
// More info: https://doc.traefik.io/traefik/v3.1/routing/services/#proxy-protocol
|
// More info: https://doc.traefik.io/traefik/v3.1/routing/services/#proxy-protocol
|
||||||
|
|
|
@ -26,6 +26,7 @@ type RouterIng struct {
|
||||||
EntryPoints []string `json:"entryPoints,omitempty"`
|
EntryPoints []string `json:"entryPoints,omitempty"`
|
||||||
Middlewares []string `json:"middlewares,omitempty"`
|
Middlewares []string `json:"middlewares,omitempty"`
|
||||||
Priority int `json:"priority,omitempty"`
|
Priority int `json:"priority,omitempty"`
|
||||||
|
RuleSyntax string `json:"ruleSyntax,omitempty"`
|
||||||
TLS *dynamic.RouterTLSConfig `json:"tls,omitempty" label:"allowEmpty"`
|
TLS *dynamic.RouterTLSConfig `json:"tls,omitempty" label:"allowEmpty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ func Test_parseRouterConfig(t *testing.T) {
|
||||||
"traefik.ingress.kubernetes.io/router.entrypoints": "foobar,foobar",
|
"traefik.ingress.kubernetes.io/router.entrypoints": "foobar,foobar",
|
||||||
"traefik.ingress.kubernetes.io/router.middlewares": "foobar,foobar",
|
"traefik.ingress.kubernetes.io/router.middlewares": "foobar,foobar",
|
||||||
"traefik.ingress.kubernetes.io/router.priority": "42",
|
"traefik.ingress.kubernetes.io/router.priority": "42",
|
||||||
|
"traefik.ingress.kubernetes.io/router.rulesyntax": "foobar",
|
||||||
"traefik.ingress.kubernetes.io/router.tls": "true",
|
"traefik.ingress.kubernetes.io/router.tls": "true",
|
||||||
"traefik.ingress.kubernetes.io/router.tls.certresolver": "foobar",
|
"traefik.ingress.kubernetes.io/router.tls.certresolver": "foobar",
|
||||||
"traefik.ingress.kubernetes.io/router.tls.domains.0.main": "foobar",
|
"traefik.ingress.kubernetes.io/router.tls.domains.0.main": "foobar",
|
||||||
|
@ -38,6 +39,7 @@ func Test_parseRouterConfig(t *testing.T) {
|
||||||
EntryPoints: []string{"foobar", "foobar"},
|
EntryPoints: []string{"foobar", "foobar"},
|
||||||
Middlewares: []string{"foobar", "foobar"},
|
Middlewares: []string{"foobar", "foobar"},
|
||||||
Priority: 42,
|
Priority: 42,
|
||||||
|
RuleSyntax: "foobar",
|
||||||
TLS: &dynamic.RouterTLSConfig{
|
TLS: &dynamic.RouterTLSConfig{
|
||||||
CertResolver: "foobar",
|
CertResolver: "foobar",
|
||||||
Domains: []types.Domain{
|
Domains: []types.Domain{
|
||||||
|
@ -180,6 +182,7 @@ func Test_convertAnnotations(t *testing.T) {
|
||||||
"traefik.ingress.kubernetes.io/router.entrypoints": "foobar,foobar",
|
"traefik.ingress.kubernetes.io/router.entrypoints": "foobar,foobar",
|
||||||
"traefik.ingress.kubernetes.io/router.middlewares": "foobar,foobar",
|
"traefik.ingress.kubernetes.io/router.middlewares": "foobar,foobar",
|
||||||
"traefik.ingress.kubernetes.io/router.priority": "42",
|
"traefik.ingress.kubernetes.io/router.priority": "42",
|
||||||
|
"traefik.ingress.kubernetes.io/router.rulesyntax": "foobar",
|
||||||
"traefik.ingress.kubernetes.io/router.tls": "true",
|
"traefik.ingress.kubernetes.io/router.tls": "true",
|
||||||
"traefik.ingress.kubernetes.io/router.tls.certresolver": "foobar",
|
"traefik.ingress.kubernetes.io/router.tls.certresolver": "foobar",
|
||||||
"traefik.ingress.kubernetes.io/router.tls.domains.0.main": "foobar",
|
"traefik.ingress.kubernetes.io/router.tls.domains.0.main": "foobar",
|
||||||
|
@ -194,6 +197,7 @@ func Test_convertAnnotations(t *testing.T) {
|
||||||
"traefik.router.entrypoints": "foobar,foobar",
|
"traefik.router.entrypoints": "foobar,foobar",
|
||||||
"traefik.router.middlewares": "foobar,foobar",
|
"traefik.router.middlewares": "foobar,foobar",
|
||||||
"traefik.router.priority": "42",
|
"traefik.router.priority": "42",
|
||||||
|
"traefik.router.rulesyntax": "foobar",
|
||||||
"traefik.router.tls": "true",
|
"traefik.router.tls": "true",
|
||||||
"traefik.router.tls.certresolver": "foobar",
|
"traefik.router.tls.certresolver": "foobar",
|
||||||
"traefik.router.tls.domains[0].main": "foobar",
|
"traefik.router.tls.domains[0].main": "foobar",
|
||||||
|
|
|
@ -10,6 +10,7 @@ metadata:
|
||||||
traefik.ingress.kubernetes.io/router.entrypoints: ep1,ep2
|
traefik.ingress.kubernetes.io/router.entrypoints: ep1,ep2
|
||||||
traefik.ingress.kubernetes.io/router.middlewares: md1,md2
|
traefik.ingress.kubernetes.io/router.middlewares: md1,md2
|
||||||
traefik.ingress.kubernetes.io/router.priority: "42"
|
traefik.ingress.kubernetes.io/router.priority: "42"
|
||||||
|
traefik.ingress.kubernetes.io/router.rulesyntax: "v2"
|
||||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||||
traefik.ingress.kubernetes.io/router.tls.certresolver: foobar
|
traefik.ingress.kubernetes.io/router.tls.certresolver: foobar
|
||||||
traefik.ingress.kubernetes.io/router.tls.domains.0.main: domain.com
|
traefik.ingress.kubernetes.io/router.tls.domains.0.main: domain.com
|
||||||
|
|
|
@ -760,6 +760,7 @@ func loadRouter(rule netv1.IngressRule, pa netv1.HTTPIngressPath, rtConfig *Rout
|
||||||
}
|
}
|
||||||
|
|
||||||
if rtConfig != nil && rtConfig.Router != nil {
|
if rtConfig != nil && rtConfig.Router != nil {
|
||||||
|
rt.RuleSyntax = rtConfig.Router.RuleSyntax
|
||||||
rt.Priority = rtConfig.Router.Priority
|
rt.Priority = rtConfig.Router.Priority
|
||||||
rt.EntryPoints = rtConfig.Router.EntryPoints
|
rt.EntryPoints = rtConfig.Router.EntryPoints
|
||||||
rt.Middlewares = rtConfig.Router.Middlewares
|
rt.Middlewares = rtConfig.Router.Middlewares
|
||||||
|
|
|
@ -96,6 +96,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
Service: "testing-service1-80",
|
Service: "testing-service1-80",
|
||||||
Middlewares: []string{"md1", "md2"},
|
Middlewares: []string{"md1", "md2"},
|
||||||
Priority: 42,
|
Priority: 42,
|
||||||
|
RuleSyntax: "v2",
|
||||||
TLS: &dynamic.RouterTLSConfig{
|
TLS: &dynamic.RouterTLSConfig{
|
||||||
CertResolver: "foobar",
|
CertResolver: "foobar",
|
||||||
Domains: []types.Domain{
|
Domains: []types.Domain{
|
||||||
|
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errNoServersInPool = errors.New("no servers in the pool")
|
||||||
|
|
||||||
type server struct {
|
type server struct {
|
||||||
Handler
|
Handler
|
||||||
weight int
|
weight int
|
||||||
|
@ -34,8 +36,10 @@ func (b *WRRLoadBalancer) ServeTCP(conn WriteCloser) {
|
||||||
b.lock.Unlock()
|
b.lock.Unlock()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Error during load balancing")
|
if !errors.Is(err, errNoServersInPool) {
|
||||||
conn.Close()
|
log.Error().Err(err).Msg("Error during load balancing")
|
||||||
|
}
|
||||||
|
_ = conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,13 +65,13 @@ func (b *WRRLoadBalancer) AddWeightServer(serverHandler Handler, weight *int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *WRRLoadBalancer) maxWeight() int {
|
func (b *WRRLoadBalancer) maxWeight() int {
|
||||||
max := -1
|
maximum := -1
|
||||||
for _, s := range b.servers {
|
for _, s := range b.servers {
|
||||||
if s.weight > max {
|
if s.weight > maximum {
|
||||||
max = s.weight
|
maximum = s.weight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return max
|
return maximum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *WRRLoadBalancer) weightGcd() int {
|
func (b *WRRLoadBalancer) weightGcd() int {
|
||||||
|
@ -91,7 +95,7 @@ func gcd(a, b int) int {
|
||||||
|
|
||||||
func (b *WRRLoadBalancer) next() (Handler, error) {
|
func (b *WRRLoadBalancer) next() (Handler, error) {
|
||||||
if len(b.servers) == 0 {
|
if len(b.servers) == 0 {
|
||||||
return nil, errors.New("no servers in the pool")
|
return nil, errNoServersInPool
|
||||||
}
|
}
|
||||||
|
|
||||||
// The algo below may look messy, but is actually very simple
|
// The algo below may look messy, but is actually very simple
|
||||||
|
@ -99,8 +103,8 @@ func (b *WRRLoadBalancer) next() (Handler, error) {
|
||||||
// and allows us not to build an iterator every time we readjust weights
|
// and allows us not to build an iterator every time we readjust weights
|
||||||
|
|
||||||
// Maximum weight across all enabled servers
|
// Maximum weight across all enabled servers
|
||||||
max := b.maxWeight()
|
maximum := b.maxWeight()
|
||||||
if max == 0 {
|
if maximum == 0 {
|
||||||
return nil, errors.New("all servers have 0 weight")
|
return nil, errors.New("all servers have 0 weight")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +116,7 @@ func (b *WRRLoadBalancer) next() (Handler, error) {
|
||||||
if b.index == 0 {
|
if b.index == 0 {
|
||||||
b.currentWeight -= gcd
|
b.currentWeight -= gcd
|
||||||
if b.currentWeight <= 0 {
|
if b.currentWeight <= 0 {
|
||||||
b.currentWeight = max
|
b.currentWeight = maximum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
srv := b.servers[b.index]
|
srv := b.servers[b.index]
|
||||||
|
|
|
@ -61,13 +61,13 @@ func (b *WRRLoadBalancer) AddWeightedServer(serverHandler Handler, weight *int)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *WRRLoadBalancer) maxWeight() int {
|
func (b *WRRLoadBalancer) maxWeight() int {
|
||||||
max := -1
|
maximum := -1
|
||||||
for _, s := range b.servers {
|
for _, s := range b.servers {
|
||||||
if s.weight > max {
|
if s.weight > maximum {
|
||||||
max = s.weight
|
maximum = s.weight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return max
|
return maximum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *WRRLoadBalancer) weightGcd() int {
|
func (b *WRRLoadBalancer) weightGcd() int {
|
||||||
|
@ -99,8 +99,8 @@ func (b *WRRLoadBalancer) next() (Handler, error) {
|
||||||
// what interleaves servers and allows us not to build an iterator every time we readjust weights.
|
// what interleaves servers and allows us not to build an iterator every time we readjust weights.
|
||||||
|
|
||||||
// Maximum weight across all enabled servers
|
// Maximum weight across all enabled servers
|
||||||
max := b.maxWeight()
|
maximum := b.maxWeight()
|
||||||
if max == 0 {
|
if maximum == 0 {
|
||||||
return nil, errors.New("all servers have 0 weight")
|
return nil, errors.New("all servers have 0 weight")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ func (b *WRRLoadBalancer) next() (Handler, error) {
|
||||||
if b.index == 0 {
|
if b.index == 0 {
|
||||||
b.currentWeight -= gcd
|
b.currentWeight -= gcd
|
||||||
if b.currentWeight <= 0 {
|
if b.currentWeight <= 0 {
|
||||||
b.currentWeight = max
|
b.currentWeight = maximum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
srv := b.servers[b.index]
|
srv := b.servers[b.index]
|
||||||
|
|
|
@ -9,7 +9,7 @@ IMAGE_NAME="kubernetes-codegen:latest"
|
||||||
CURRENT_DIR="$(pwd)"
|
CURRENT_DIR="$(pwd)"
|
||||||
|
|
||||||
echo "Building codegen Docker image..."
|
echo "Building codegen Docker image..."
|
||||||
docker build --build-arg KUBE_VERSION=v0.29.1 \
|
docker build --build-arg KUBE_VERSION=v0.29.8 \
|
||||||
--build-arg USER="${USER}" \
|
--build-arg USER="${USER}" \
|
||||||
--build-arg UID="$(id -u)" \
|
--build-arg UID="$(id -u)" \
|
||||||
--build-arg GID="$(id -g)" \
|
--build-arg GID="$(id -g)" \
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM golang:1.22
|
FROM golang:1.23
|
||||||
|
|
||||||
ARG USER=$USER
|
ARG USER=$USER
|
||||||
ARG UID=$UID
|
ARG UID=$UID
|
||||||
|
@ -13,7 +13,7 @@ RUN go install k8s.io/code-generator/cmd/client-gen@$KUBE_VERSION
|
||||||
RUN go install k8s.io/code-generator/cmd/lister-gen@$KUBE_VERSION
|
RUN go install k8s.io/code-generator/cmd/lister-gen@$KUBE_VERSION
|
||||||
RUN go install k8s.io/code-generator/cmd/informer-gen@$KUBE_VERSION
|
RUN go install k8s.io/code-generator/cmd/informer-gen@$KUBE_VERSION
|
||||||
RUN go install k8s.io/code-generator/cmd/deepcopy-gen@$KUBE_VERSION
|
RUN go install k8s.io/code-generator/cmd/deepcopy-gen@$KUBE_VERSION
|
||||||
RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0
|
RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.1
|
||||||
|
|
||||||
RUN mkdir -p $GOPATH/src/k8s.io/code-generator
|
RUN mkdir -p $GOPATH/src/k8s.io/code-generator
|
||||||
RUN cp -R $GOPATH/pkg/mod/k8s.io/code-generator@$KUBE_VERSION/* $GOPATH/src/k8s.io/code-generator/
|
RUN cp -R $GOPATH/pkg/mod/k8s.io/code-generator@$KUBE_VERSION/* $GOPATH/src/k8s.io/code-generator/
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.16.12",
|
"@quasar/extras": "^1.16.12",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.4",
|
||||||
"bowser": "^2.11.0",
|
"bowser": "^2.11.0",
|
||||||
"chart.js": "^4.4.1",
|
"chart.js": "^4.4.1",
|
||||||
"core-js": "^3.35.1",
|
"core-js": "^3.35.1",
|
||||||
|
|
|
@ -2151,10 +2151,10 @@ available-typed-arrays@^1.0.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
possible-typed-array-names "^1.0.0"
|
possible-typed-array-names "^1.0.0"
|
||||||
|
|
||||||
axios@^1.7.2:
|
axios@^1.7.4:
|
||||||
version "1.7.2"
|
version "1.7.4"
|
||||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621"
|
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2"
|
||||||
integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==
|
integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects "^1.15.6"
|
follow-redirects "^1.15.6"
|
||||||
form-data "^4.0.0"
|
form-data "^4.0.0"
|
||||||
|
|
Loading…
Reference in a new issue